ProtoDAO.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2007 by Konstantin V. Arkhipov                          *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Lesser General Public License as        *
00007  *   published by the Free Software Foundation; either version 3 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  ***************************************************************************/
00011 /* $Id: ProtoDAO.class.php 4687 2007-12-09 18:57:18Z voxus $ */
00012 
00016     abstract class ProtoDAO extends GenericDAO
00017     {
00018         public function fetchCollections(
00019             /* array */ $collections, /* array */ $list
00020         )
00021         {
00022             $ids = ArrayUtils::getIdsArray($list);
00023             
00024             $mainId = DBField::create(
00025                 $this->getIdName(),
00026                 $this->getTable()
00027             );
00028             
00029             foreach ($collections as $path => $info) {
00030                 $lazy = $info['lazy'];
00031                 
00032                 $query =
00033                     OSQL::select()->get($mainId)->
00034                     from($this->getTable());
00035                 
00036                 if ($criteria = $info['criteria']) {
00037                     $query = $criteria->setDao($this)->fillSelectQuery($query);
00038                 }
00039                 
00040                 $proto = reset($list)->proto();
00041                 
00042                 $this->processPath($proto, $path, $query, $this->getTable());
00043                 
00044                 $query->andWhere(
00045                     Expression::in($mainId, $ids)
00046                 );
00047                 
00048                 $propertyPath = $info['propertyPath'];
00049                 
00050                 $property   = $propertyPath->getFinalProperty();
00051                 $proto      = $propertyPath->getFinalProto();
00052                 $dao        = $propertyPath->getFinalDao();
00053                 
00054                 $selfName = $this->getObjectName();
00055                 $self = new $selfName;
00056                 $getter = 'get'.ucfirst($property->getName());
00057                 
00058                 Assert::isTrue(
00059                     $property->getRelationId() == MetaRelation::ONE_TO_MANY
00060                     || $property->getRelationId() == MetaRelation::MANY_TO_MANY
00061                 );
00062                 
00063                 $table = $dao->getJoinName($property->getColumnName());
00064                 
00065                 $id = $this->getIdName();
00066                 $collection = array();
00067                 
00068                 if ($lazy) {
00069                     if ($property->getRelationId() == MetaRelation::MANY_TO_MANY) {
00070                         $childId = $self->$getter()->getChildIdField();
00071                     } else {
00072                         $childId = $dao->getIdName();
00073                     }
00074                     
00075                     $alias = 'cid'; // childId, collectionId, whatever
00076                     
00077                     $field = DBField::create($childId);
00078                     
00079                     $query->get($field, $alias);
00080                     
00081                     if (!$property->isRequired())
00082                         $query->andWhere(Expression::notNull($field));
00083                     
00084                     try {
00085                         $rows = $dao->getCustomList($query);
00086                         
00087                         foreach ($rows as $row)
00088                             if (!empty($row[$alias]))
00089                                 $collection[$row[$id]][] = $row[$alias];
00090                         
00091                     } catch (ObjectNotFoundException $e) {/*_*/}
00092                 } else {
00093                     $prefix = $table.'_';
00094                     
00095                     foreach ($dao->getFields() as $field) {
00096                         $query->get(
00097                             DBField::create(
00098                                 $field, $table
00099                             ),
00100                             $prefix.$field
00101                         );
00102                     }
00103                     
00104                     if (!$property->isRequired()) {
00105                         $query->andWhere(
00106                             Expression::notNull(
00107                                 DBField::create($dao->getIdName(), $table)
00108                             )
00109                         );
00110                     }
00111                     
00112                     try {
00113                         // otherwise we don't know which object
00114                         // belongs to which collection
00115                         $rows = $dao->getCustomList($query);
00116                         
00117                         foreach ($rows as $row) {
00118                             $collection[$row[$id]][] =
00119                                 $dao->makeObject($row, $prefix);
00120                         }
00121                     } catch (ObjectNotFoundException $e) {/*_*/}
00122                 }
00123                 
00124                 $method = 'fill'.ucfirst($property->getName());
00125                 
00126                 Assert::isTrue(
00127                     method_exists(reset($list), $method),
00128                     'can not find filler method'
00129                 );
00130                 
00131                 foreach ($list as $object) {
00132                     if (!empty($collection[$object->getId()]))
00133                         $object->$method($collection[$object->getId()], $lazy);
00134                     else
00135                         $object->$method(array(), $lazy);
00136                 }
00137             }
00138             
00139             return $list;
00140         }
00141         
00142         private function processPath(
00143             AbstractProtoClass $proto,
00144             $probablyPath,
00145             JoinCapableQuery $query,
00146             $table,
00147             $parentRequired = true,
00148             $prefix = null
00149         )
00150         {
00151             $path = explode('.', $probablyPath);
00152             
00153             try {
00154                 $property = $proto->getPropertyByName($path[0]);
00155             } catch (MissingElementException $e) {
00156                 // oh, it's a value, not a property
00157                 return new DBValue($probablyPath);
00158             }
00159             
00160             unset($path[0]);
00161             
00162             Assert::isTrue(
00163                 $property->getRelationId() != null
00164                 && !$property->isGenericType()
00165             );
00166             
00167             $propertyDao = call_user_func(
00168                 array(
00169                     $property->getClassName(),
00170                     'dao'
00171                 )
00172             );
00173             
00174             Assert::isNotNull(
00175                 $propertyDao,
00176                 'can not find target dao for "'.$property->getName().'" property'
00177                 .' at "'.get_class($proto).'"'
00178             );
00179             
00180             $alias = $propertyDao->getJoinName(
00181                 $property->getColumnName(),
00182                 $prefix
00183             );
00184             
00185             if (
00186                 $property->getRelationId() == MetaRelation::ONE_TO_MANY
00187                 || $property->getRelationId() == MetaRelation::MANY_TO_MANY
00188             ) {
00189                 $remoteName = $property->getClassName();
00190                 $selfName = $this->getObjectName();
00191                 $self = new $selfName;
00192                 $getter = 'get'.ucfirst($property->getName());
00193                 $dao = call_user_func(array($remoteName, 'dao'));
00194                 
00195                 if ($property->getRelationId() == MetaRelation::MANY_TO_MANY) {
00196                     $helperTable = $self->$getter()->getHelperTable();
00197                     $helperAlias = $helperTable;
00198                     
00199                     if (!$query->hasJoinedTable($helperAlias)) {
00200                         $logic =
00201                             Expression::eq(
00202                                 DBField::create(
00203                                     $this->getIdName(),
00204                                     $table
00205                                 ),
00206                                 
00207                                 DBField::create(
00208                                     $self->$getter()->getParentIdField(),
00209                                     $helperAlias
00210                                 )
00211                             );
00212                         
00213                         if ($property->isRequired())
00214                             $query->join($helperTable, $logic, $helperAlias);
00215                         else
00216                             $query->leftJoin($helperTable, $logic, $helperAlias);
00217                     }
00218                     
00219                     $logic =
00220                         Expression::eq(
00221                             DBField::create(
00222                                 $propertyDao->getIdName(),
00223                                 $alias
00224                             ),
00225                             
00226                             DBField::create(
00227                                 $self->$getter()->getChildIdField(),
00228                                 $helperAlias
00229                             )
00230                         );
00231                 } else {
00232                     $logic =
00233                         Expression::eq(
00234                             DBField::create(
00235                                 $self->$getter()->getParentIdField(),
00236                                 $alias
00237                             ),
00238                             
00239                             DBField::create(
00240                                 $this->getIdName(),
00241                                 $table
00242                             )
00243                         );
00244                 }
00245                 
00246                 if (!$query->hasJoinedTable($alias)) {
00247                     if ($property->isRequired() && $parentRequired)
00248                         $query->join($dao->getTable(), $logic, $alias);
00249                     else
00250                         $query->leftJoin($dao->getTable(), $logic, $alias);
00251                 }
00252             } else { // OneToOne, lazy OneToOne
00253                 
00254                 // prevents useless joins
00255                 if (
00256                     isset($path[1])
00257                     && (count($path) == 1)
00258                     && ($path[1] == $propertyDao->getIdName())
00259                 )
00260                     return
00261                         new DBField(
00262                             $property->getColumnName(),
00263                             $table
00264                         );
00265 
00266                 if (!$query->hasJoinedTable($alias)) {
00267                     $logic =
00268                         Expression::eq(
00269                             DBField::create(
00270                                 $property->getColumnName(),
00271                                 $table
00272                             ),
00273                             
00274                             DBField::create(
00275                                 $propertyDao->getIdName(),
00276                                 $alias
00277                             )
00278                         );
00279                     
00280                     if ($property->isRequired() && $parentRequired)
00281                         $query->join($propertyDao->getTable(), $logic, $alias);
00282                     else
00283                         $query->leftJoin($propertyDao->getTable(), $logic, $alias);
00284                 }
00285             }
00286             
00287             return $propertyDao->guessAtom(
00288                 implode('.', $path),
00289                 $query,
00290                 $alias,
00291                 $property->isRequired() && $parentRequired,
00292                 $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00293             );
00294         }
00295         
00296         public function guessAtom(
00297             $atom,
00298             JoinCapableQuery $query,
00299             $table = null,
00300             $parentRequired = true,
00301             $prefix = null
00302         )
00303         {
00304             if ($table === null)
00305                 $table = $this->getTable();
00306 
00307             if (is_string($atom)) {
00308                 if (strpos($atom, '.') !== false) {
00309                     return
00310                         $this->processPath(
00311                             call_user_func(
00312                                 array($this->getObjectName(), 'proto')
00313                             ),
00314                             $atom,
00315                             $query,
00316                             $table,
00317                             $parentRequired,
00318                             $prefix
00319                         );
00320                 } elseif (
00321                     array_key_exists(
00322                         $atom,
00323                         $mapping = $this->getMapping()
00324                     )
00325                 ) {
00326                     // BC, <0.9
00327                     if (!$mapping[$atom])
00328                         return new DBField($atom, $table);
00329                     
00330                     return new DBField($mapping[$atom], $table);
00331                 } elseif (
00332                     ($query instanceof SelectQuery)
00333                     && $query->hasAliasInside($atom)
00334                 ) {
00335                     return new DBField($atom);
00336                 }
00337             } elseif ($atom instanceof MappableObject)
00338                 return $atom->toMapped($this, $query);
00339             elseif (
00340                 ($atom instanceof DBValue)
00341                 || ($atom instanceof DBField)
00342             ) {
00343                 return $atom;
00344             }
00345             
00346             return new DBValue($atom);
00347         }
00348     }
00349 ?>

Generated on Sun Dec 9 21:56:23 2007 for onPHP by  doxygen 1.5.4