onPHP

main/DAOs/ProtoDAO.class.php Source File

 

ProtoDAO.class.php

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

generated by doxygen-1.5.6
for onPHP at Mon Sep 15 02:36:46 2008