SitePoint Sponsor |
|
User Tag List
Results 1 to 7 of 7
Thread: __call orm
-
Sep 4, 2006, 16:39 #1
- Join Date
- Mar 2005
- Posts
- 53
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
__call orm
Wrote this little thing a few days ago. I thought it was pretty neat, anyone seen any projects using this technique?
PHP Code:/**
* Generate dynamic sql call method used to handle method strings like
* getById, deleteById, getByNameAndDob, etc. with method arguments
* which are parsed between the instances of "and" within the string.
*
*/
public function __call($method, $args)
{
$deleteIndex = 6;
$getIndex = 3;
$index = 0;
$deletePrefix = strtolower(substr($method, 0, $deleteIndex));
$getPrefix = strtolower(substr($method, 0, $getIndex));
if($deletePrefix == 'delete')
{
$index = $deleteIndex;
}
else if($getPrefix == 'get')
{
$index = $getIndex;
}
else
{
throw new Exception("Invalid method call to '$method'");
}
$queryArguments = strtolower(substr($method, $index));
// now we need to account for 'by'
$queryArguments = substr($queryArguments, 2);
// explode by and
$argumentList = explode('and', $queryArguments);
// determine what's legal...
$possibleArgs = array_keys($this->vo->export()); // << THIS VO object is just a ValueObject and export() turns it into an array.
// this line is a little tricky. Basically it's using the two arrays ($argumentList, $possibleArgs) to see if all the arguments in $argumentList exist within $possibleArgs by getting a count of that, and comparing
$intersectionIndex = count(array_intersect($argumentList, $possibleArgs));
$argumentListCount = count($argumentList);
$tableName = $this->vo->getTableName();
if($intersectionIndex != $argumentListCount)
{
$argsToString = implode(', ', $argumentList);
throw new Exception("Nonexistent property attempted as a parameter to dynamic method '$method': $argsToString");
}
else if(count($args) != $argumentListCount)
{
$argsToString = implode(', ', $argumentList);
throw new Exception("Invalid number of parameters relative to the number of arguments defined within the method name '$method': $argsToString");
}
else if($index == $deleteIndex)
{
$sql = 'DELETE FROM ' . $tableName . ' WHERE ';
}
else if($index == $getIndex)
{
$sql = 'SELECT * FROM ' . $tableName . ' WHERE ';
}
else
{
throw new Exception("Invalid dynamic method type '$method'");
}
$where = '';
foreach($argumentList as $key => $arg)
{
$where .= "$arg = :$arg";
$where .= $argumentListCount - 1 == $key ? '' : ' AND ';
}
$setString = $sql . $where;
// USING PDO
$st = $this->db->prepare($setString);
// now go ahead and set the field values...
foreach($argumentList as $key => $arg)
{
$metaVal = MetaClass::$arg;
$type = $metaVal['pdo_param_type'];
$st->bindValue($arg, $args[$key], $type);
}
if($st->execute())
{
return $st;
}
else
{
return null;
}
}
-
Sep 4, 2006, 19:29 #2
- Join Date
- Sep 2004
- Location
- New Zealand
- Posts
- 13
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
After a quick scan, it looks good.
Just a quick note:
Originally Posted by illusina
PHP Code:if(strpos( strtolower( $method ), 'delete' ) === 0)
{
$index = 6;
}
else if(strpos( strtolower( $method ), 'get' ) === 0)
{
$index = 3;
}
else
{
throw new Exception("Invalid method call to '$method'");
}
-
Sep 4, 2006, 21:39 #3
- Join Date
- Mar 2005
- Posts
- 53
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Nice, thanks for the tip
. I thought it was pretty neat, the idea of using a domain specific language is pretty neat.
-
Sep 18, 2006, 12:16 #4
- Join Date
- Mar 2005
- Posts
- 4
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I have used something similar in my XML library (like finyByattributeName ()). It's definitely an interesting approach...
-
Sep 18, 2006, 12:51 #5
- Join Date
- Sep 2003
- Location
- Wixom, Michigan
- Posts
- 591
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I have to say I strongly disagree with this approach to dynamically generating (is it truly generating?) class methods. With a properly designed base class, methods such as "getById" and "deleteById" would be readily available to all your children data object classes, no need for obscure magic and trickery. Other, more class-specific methods, such as "deleteByUsername" or "getByAddress" should be so easy to create in a good ORM, that it would make no sense to dynamically wire them via _call magic.
Among other things, with this approach you expose yourself to a big hole in the documentation of your model methods (where can I get a list of the available methods in the class? what about IDE features like intellisense / autocomplete? Can I create PHPdoc type documentation from these "ghost" methods?), as well as setting yourself up for a potential disaster the day you accidentaly use "deleteByxxx" instead of "deleteByYYY" when one of the methods should have never existed in the first place.
Given that the model is arguably the most fundamental part of any system, it should be clean, self-documenting and leave no room for costly mistakes of this nature.Garcia
-
Sep 18, 2006, 13:06 #6
- Join Date
- Apr 2006
- Location
- Stockholm, Sweden
- Posts
- 18
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I agree with ghurtado. I can't help but feel that it's like begging for problems. Besides, what's so bad about just doing $foo->delete('field', $param) instead of spending like 100 lines of code worrying about string management?
-
Sep 23, 2006, 22:24 #7
- Join Date
- Mar 2005
- Posts
- 53
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by ghurtado
Originally Posted by ghurtado
Bookmarks