![]() |
|
Snippets |
|
Features:
dynamically enhance a base model object with getter methods
dynamically populate a custom model object with getters from a custom query
supports prepared statements
Why? Building complex queries with Criteria is still hard (e.g. a 24-relation-join-query with functions, stored procedures etc. is still impossible to understand respectively hard to code). The snippet code takes the column names to build the setters and getters automatically. And! It's fast to code.
Example 1: ->doTree(0,200) : a model function that i wrote, returns a nested set result set.
Example 2: a simple custom query
Example 3: a custom prepared join query using sf_guard model tables
Example 4: a more complex prepared custom join query using sf_guard model tables
<?php define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); define('SF_APP', 'backend'); define('SF_ENVIRONMENT', 'prod'); define('SF_DEBUG', false); require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); class CustomObject { private $objectName; public function __construct($name){ $this->objectName = $name; } public function getObjectName(){ return $this->objectName(); } public function __call($funcname, $args = array()) { if (!function_exists($funcname)){ $method = substr($funcname, 3); $methodType = substr($funcname, 0, 3); switch($methodType){ case "set": $this->{$method} = $args[0]; break; case "get": return $this->{$method}; break; } } else { trigger_error("Call to Function with call_user_func_array failed", E_USER_ERROR); } } public function __set($name, $value){ $this->{$name} = $value; } public function __get($name){ return $this->{$name}; } } class CustomQueryResultSet { private $columns; private $queryColumns; private $resultSet; public function __construct($callerObject = false, $className = false, $peerClassName = false) { if (is_object($callerObject) && !empty($className) && !empty($peerClassName)){ $fieldConstants = call_user_func(array($peerClassName, 'getFieldNames'), BasePeer::TYPE_FIELDNAME ); $phpConstants = call_user_func(array($peerClassName, 'getFieldNames'), BasePeer::TYPE_PHPNAME ); foreach($callerObject as $key => $object){ if(1===$key){ $this->queryColumns = array_keys($object); $this->columns = array_merge( $phpConstants, array_diff($this->queryColumns, $fieldConstants )); } $this->populateCustomObject($object, $key, $className); } } elseif (is_object($callerObject) && empty($className) && empty($peerClassName)){ foreach($callerObject as $key => $object){ if(1===$key){ $this->queryColumns = array_keys($object); foreach($this->queryColumns as $name){ $this->columns[] = sfInflector::camelize($name); } } $this->populateCustomObject($object, $key, "CustomQuery"); } } else { trigger_error("You lost the object", E_USER_ERROR); } } private function populateCustomObject($callerObject, $key, $className){ $customObject = new CustomObject($className); foreach($this->queryColumns as $ckey => $columnName){ $methodName = "set" . ucfirst($this->columns[$ckey]); $customObject->{$methodName}($callerObject[$columnName]); } $this->resultSet[$key-1] = $customObject; } public function getResultSet(){ return $this->resultSet; } public function getColumns(){ return $this->columns; } } class CustomQueryObject { private $className; private $peerClassName; private $module; private $properties; private $caller; private $resultSet; private $customized = false; public function __construct($callerClassName = false) { if (class_exists($callerClassName)){ $this->caller = new $callerClassName(); $this->setClass($callerClassName); $this->setPeerClass($callerClassName); } else if(false===$callerClassName){ $this->customized = true; } } public function __call($funcname, $args = array()) { if (false===$this->isCustomized() && is_object($this->caller) && function_exists('call_user_func_array')){ $this->caller = call_user_func_array(array(&$this->caller, $funcname), $args); $resultSet = new CustomQueryResultSet($this->caller, $this->getClass(), $this->getPeerClass()); return $resultSet->getResultSet(); } else { trigger_error("Call to Function with call_user_func_array failed", E_USER_ERROR); } } protected function isCustomized(){ return $this->customized; } public function query($query){ $connection = Propel::getConnection(); $statement = $connection->createStatement(); $this->caller = $statement->executeQuery( $query ); $resultSet = new CustomQueryResultSet($this->caller); return $resultSet->getResultSet(); } public function prepare($query, $parameters = array()){ $connection = Propel::getConnection(); $statement = $connection->prepareStatement($query); if(!empty($parameters)){ $increment = 1; foreach($parameters as $parameter){ foreach($parameter as $type => $value){ switch($type){ case "int": case "integer": $statement->setInt($increment, $value); break; case "str": case "string": $statement->setString($increment, $value); break; case "decimal": case "float": $statement->setFloat($increment, $value); break; case "bool": case "boolean": $statement->setBoolean($increment, $value); break; case "blob": $statement->setBlob($increment, $value); break; case "cblob": $statement->setClob($increment, $value); break; case "date": $statement->setDate($increment, $value); break; case "time": $statement->setTime($increment, $value); break; case "timestamp": $statement->setTimestamp($increment, $value); break; case "array": $statement->setArray($increment, $value); break; case "NULL": case "null": $statement->setNull($increment, $value); break; case "double": $statement->setDouble($increment, $value); break; } $increment++; } } } $this->caller = $statement->executeQuery(); $resultSet = new CustomQueryResultSet($this->caller); return $resultSet->getResultSet(); } public function getColumns(){ return $this->resultSetColumns; } public function getPeerClass(){ return $this->peerClassName; } public function setPeerClass($name){ $this->peerClassName = $name . "Peer"; } public function getClass(){ return $this->className; } public function setClass($name){ $this->className = $name ; } } ?><html> <body> <p> <?php $case = 4; switch($case){ case 1: // executing a custom query from an existing model object $custom = "sfNavigation"; $customObject = new CustomQueryObject("sfNavigation"); $objects = $customObject->doTree(0,50); foreach($objects as $key => $object){ echo $object->getComponentId() . " " . $object->getCaption() . " " . $object->getAction() . " Level: " . $object->getTreeLevel(). "<br>"; } break; case 2: //executing a custom query and create a custom object $customObject = new CustomQueryObject(); $objects = $customObject->query("SELECT * FROM md_components"); foreach($objects as $key => $object){ echo $object->getComponentId() . " " . $object->getCaption() . " " . $object->getAction() . "<br>"; } break; case 3: // custom object with prepared statement $customObject = new CustomQueryObject(); $objects = $customObject->prepare("SELECT u.username , g.id, g.name FROM sf_guard_user AS u Left Join sf_guard_user_group AS ug ON ug.user_id = u.id Right Join sf_guard_group AS g ON g.id = ug.group_id WHERE u.id = ? ; ", array( array( "integer" => sfContext::getInstance()->getRequest()->getParameter("id") ) ) ); foreach($objects as $key => $object){ echo $object->getUsername() . " " . $object->getId() . " " . $object->getName() . "<br>"; } break; case 4: // custom object with prepared statement $customObject = new CustomQueryObject(); $objects = $customObject->prepare("SELECT u.username AS user_name, g.id AS user_id, g.name AS group_name, p.name AS permission_name FROM sf_guard_user AS u Left Join sf_guard_user_group AS ug ON ug.user_id = u.id Right Join sf_guard_group AS g ON ug.group_id = g.id Left Join sf_guard_group_permission AS gp ON g.id = gp.group_id Left Join sf_guard_permission AS p ON p.id = gp.permission_id WHERE u.id = ? ; ", array( array( "integer" => sfContext::getInstance()->getRequest()->getParameter("id") ) ) ); foreach($objects as $key => $object){ echo $object->getUserName() . " " . $object->getUserId() . " " . $object->getGroupName() . " ". $object->getPermissionName() . "<br>"; } break; } ?> </p> </body> </html>