. * * @package PhpMyObject * @subpackage PMO_Core * @author Nicolas Boiteux * @author Louis Lapointe * @link http://pmo.developpez.com/ * @since PhpMyObject v0.1x * @version $Revision: $ * @copyright Copyright (C) 2007-2008 Nicolas Boiteux * @copyright Copyright (C) 2008 Louis Lapointe * @license GPLv3 {@link http://www.gnu.org/licenses/gpl} * @filesource * */ /** requires the interface */ require_once(dirname(__FILE__).'/PMO_Controller.php'); /** requires all the needed classes */ $dirname = dirname(__FILE__); require_once($dirname.'/PMO_MyObject.php'); require_once($dirname.'/PMO_MyMap.php'); require_once($dirname.'/PMO_MyParser.php'); require_once($dirname.'/PMO_MyTable.php'); require_once($dirname.'/PMO_MyDbms.php'); require_once($dirname.'/PMO_MyConfig.php'); require_once($dirname.'/PMO_MyRequest.php'); require_once($dirname.'/PMO_MyArray.php'); require_once($dirname.'/PMO_MyMemCache.php'); require_once($dirname.'/PMO_MyLog.php'); /** * PMO_MyController enable you to send queries to you database * and returns the data. * * This class also enables you to execute raw sql query and transform * each tuples result into distinct {@link PMO_Object}. * * Iterations schema is
* For each tuple > For each Table > Build an object > For each column > Set the value of object * * Before instanciation, a new object controller checks if it already exists * in a hash map. If it does exist, the controller will retrieve its reference. * * Objects are always referenced in this hash map after their instanciation. * * @package PhpMyObject * @subpackage PMO_Core */ class PMO_MyController implements PMO_Controller { /** * the Dbms instance * @var object * @access protected */ protected $dbms_instance; /** * the map of PMO_MyObject objects this controller holds * * @var object a {@link PMO_MyMap} object that holds the retrieved objects * @access protected */ protected $map_objects; /** * a map of PMO_MyTable objects * * @var object a {@link PMO_MyMapTable} objects * @access protected */ protected $map_tables; /** * ArrayIterator SPL Object. * * @var object a {@link ArrayIterator} object * @access protected */ protected $array_iterator; /** * the SQL parser object * * @var object a {@link PMO_MyParser} object * @access protected */ protected $parsersql; /** * the constructor * the constrortor instanciates the Ddms engine and initialize itself * * @param object $object a PDO object to use fr the database requests. * If NULL, the Ddms driver specified by the * configuration will be used * @return object returns the PMO_MyController object */ public function __construct(pdo $object = NULL) { $this->dbms_instance = PMO_MyDbms::factory($object); $this->init(); } /** * Short description * @todo bonyenne que j'en ai à apprendre! à quoi sert le collecteur? */ private function populateCollector(){ while($sqlfunction = $this->parsersql->fetchFunction()){ if(!isset($collector)){ $collector = new PMO_MyTable(); $collector->setTableName(PMO_MyConfig::factory()->get('PMO_MyController.OBJECT_COLLECTOR_NAME')); $this->map_tables->append($collector); } $tmparray = array("Field"=>$sqlfunction, "Type" => "", "Null" => "", "Key"=> "PRI", "Default"=> "", "Extra"=> "", "Perm"=>"rw"); $collector->set($tmparray); } } /** * Retrieve the name of tables from an sql query, * instanciate the tables objects PMO_Table corresponding and * put them in a PMO_MapTable * * @param string $query the SQL query to get the table names from * @return void */ private function populateMapTables($query){ // identifie les tables, champs et fonctions de la requête SQL $this->parsersql->parseRequest($query); $numfields = $this->parsersql->countFields(); // pour chaque table de la requête // on crée son objet et on l'ajoute à la map while($table = $this->parsersql->fetchTable()){ $objecttable = PMO_MyTable::factory($table); $this->map_tables->append($objecttable); // si on a des champs if($numfields > 0) { // init à read only $objecttable->setPermForAll("r"); // isset Attibute signifie que lechamp a été lu // todo vérifier si ça sert réellement. // si je lis juste 1 ou 2 champs, les autre vont-ils être ro? while($field = $this->parsersql->fetchField()){ if($objecttable->issetAttribute($field)) $objecttable->setPerm($field, "rw"); } } PMO_MyLog::factory()->log($objecttable); } } /** * Transform results of an sql query to objects * and put them in a map of objects * * @param string $query the SQL query * @return PMO_Map * @throws Exception */ private function populateMapObjects($query){ $numtables = $this->map_tables->count(); $log = PMO_MyLog::factory()->log("numtables = $numtables"); /** * SQL request with more than 1 table */ if($numtables > 1){ $this->array_iterator = new ArrayIterator(); $this->dbms_instance->query($query); /** * Foreach row of raw results, we build a row of objects */ while($db_result = $this->dbms_instance->fetchArray()) { $log->log(array('db_result'=>$db_result)); $row = array(); while($table = $this->map_tables->fetch()){ $log->log('in the loop'); $tablename = $table->getTableName(); $log->log('after call to table->getTableName()'); $fingerprint = ""; $arrayofpk = $table->getPk(); $log->log('after call to table->getPk()'); $log->log(array("arrayofpk for $tablename"=>$arrayofpk)); $log->log('under the hood'); /** * Build unique fingerprint for object * from primary keys */ foreach($arrayofpk as $pk) $fingerprint = $fingerprint.$pk.$db_result[$pk]; $log->log('fingerprint = '.$fingerprint); /** * We retrieve the object reference in arrayIterator * if object is not present, we create it * add it in the arrayIterator, and reference it * into a row and put the row into the PMO_Map */ if($this->array_iterator->offsetExists($tablename.$fingerprint)){ $currentobject = $this->array_iterator->offsetGet($tablename.$fingerprint); }else{ $currentobject = PMO_MyObject::internalfactory($table); $tablefields = $table->getColumns(); foreach( $tablefields as $key=>$field){ if($table->getPerm($field) == "rw") $currentobject->set($field, $db_result[$field]); } $this->array_iterator->offsetSet($tablename.$fingerprint, $currentobject); } $row[$tablename] = $currentobject; } $log->log(array('row'=>$row)); $this->map_objects->add($row); } $log->log('end of work'); }else{ $table = $this->map_tables->fetch(); $tablename = $table->getTableName(); $tablefields = $table->getColumns(); $this->dbms_instance->query($query); while($db_result = $this->dbms_instance->fetchArray()) { $line = array(); $currentobject = PMO_MyObject::internalfactory($table); foreach( $tablefields as $key=>$field){ if($table->getPerm($field) == "rw") $currentobject->set($field, $db_result[$field]); } $line[$tablename] = $currentobject; $this->map_objects->add($line); } } $log->log("nombre de map_objects : ".$this->map_objects->count()); if ($this->map_objects->count() > 0) return $this->map_objects; else throw new Exception("Error: PMO_Map is empty"); } /** * Return map of objects allready * loaded by query() * * @return PMO_Map * @throws Exception */ public function getMapObjects(){ if(isset($this->map_objects)) return $this->map_objects; throw new Exception("Error: Map is empty"); } /** * Execute a PMO_MyRequest query * * @param object request a {@link PMO_Request} object * that has been used to build the query * @return PMO_Map a {@link PMO_Map} object * @deprecated use {@link request} instead as it is going * to be the preferred way to request data. * objectquery will be dropped in 0.2.0 */ public function objectquery(PMO_Request $request){ return $this->request($request); } /** * Execute a PMO_MyRequest query. * * @param object request a {@link PMO_Request} object * that has been used to build the query * @return PMO_Map a {@link PMO_Map} object */ public function request(PMO_Request $request) { PMO_MyLog::factory()->log($request); return $this->query($request->toString()); } /** * Execute an sql query and * return the corresponding PMO_Map fill with PMO_Object * * @param string $query the SQL query to execute * @return PMO_Map * @throws Exception */ public function query($query){ $this->init(); $this->populateMapTables($query); $this->populateCollector(); $this->populateMapObjects($query); return $this->getMapObjects(); } /** * Execute an sql query without treatment * * @param string $query the SQL query * @return object|resource the method will return either a PDO object * or a DBMS resource link, depending on the * selected driver */ public function rawquery($query){ $this->dbms_instance->query($query); return $this->dbms_instance; } /** * Should not be use * return all tuples of one table * equivalent : SELECT * FROM table; * * @param object $table a {@link PMO_Table} object * @return PMO_Map * @throws Exception */ public function queryAll(PMO_Table $table){ $this->init(); $tablename = $table->getTableName(); $this->dbms_instance->query("SELECT * FROM $tablename;"); while($db_result = $this->dbms_instance->fetchArray()) { $currentobject = PMO_MyObject::internalfactory($table); $currentobject->initObjectMap($this->map_objects); $tablefields = $table->getColumns(); foreach( $tablefields as $key=>$field) $currentobject->set($field, $db_result[$field]); $this->map_objects->addLine($currentobject); } return $this->map_objects; } /** * initializes the controller */ public function init(){ $this->map_objects = new PMO_MyMap(); $this->map_tables = new PMO_MyArray(); $this->parsersql = new PMO_MyParser(); } public function getDbms() { return $this->dbms_instance; } } ?>