Criteria.class.php

Go to the documentation of this file.
00001 <?php
00002 /****************************************************************************
00003  *   Copyright (C) 2006-2007 by Konstantin V. Arkhipov, Anton E. Lebedevich *
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: Criteria.class.php 4687 2007-12-09 18:57:18Z voxus $ */
00012 
00018     final class Criteria implements Stringable, DialectString
00019     {
00020         private $dao        = null;
00021         private $daoClass   = null;
00022         private $logic      = null;
00023         private $order      = null;
00024         private $strategy   = null;
00025         private $projection = null;
00026         
00027         private $distinct   = false;
00028         
00029         private $limit  = null;
00030         private $offset = null;
00031         
00032         private $collections = array();
00033         
00034         // dao-like behaviour: will throw ObjectNotFoundException when 'false'
00035         private $silent = true;
00036         
00040         public static function create(/* StorableDAO */ $dao = null)
00041         {
00042             return new self($dao);
00043         }
00044         
00045         public function __construct(/* StorableDAO */ $dao = null)
00046         {
00047             if ($dao)
00048                 Assert::isTrue($dao instanceof StorableDAO);
00049             
00050             $this->dao = $dao;
00051             $this->logic = Expression::andBlock();
00052             $this->order = new OrderChain();
00053             
00054             if ($dao)
00055                 $this->setDao($dao);
00056         }
00057         
00058         public function __clone()
00059         {
00060             $this->logic = clone $this->logic;
00061             $this->order = clone $this->order;
00062         }
00063         
00064         public function __sleep()
00065         {
00066             $this->daoClass = get_class($this->dao);
00067             
00068             $vars = get_object_vars($this);
00069             unset($vars['dao']);
00070             return array_keys($vars);
00071         }
00072         
00073         public function __wakeup()
00074         {
00075             $this->dao = Singleton::getInstance($this->daoClass);
00076         }
00077         
00081         public function getDao()
00082         {
00083             return $this->dao;
00084         }
00085         
00089         public function setDao(StorableDAO $dao)
00090         {
00091             $this->dao = $dao;
00092             
00093             if ($dao instanceof ComplexBuilderDAO) {
00094                 $this->setFetchStrategy(
00095                     new FetchStrategy($dao->getDefaultStrategyId())
00096                 );
00097             } else {
00098                 $this->strategy = FetchStrategy::cascade();
00099             }
00100             
00101             return $this;
00102         }
00103         
00107         public function getLogic()
00108         {
00109             return $this->logic;
00110         }
00111         
00115         public function add(LogicalObject $logic)
00116         {
00117             $this->logic->expAnd($logic);
00118             
00119             return $this;
00120         }
00121         
00125         public function getOrder()
00126         {
00127             return $this->order;
00128         }
00129         
00133         public function addOrder(/* MapableObject */ $order)
00134         {
00135             if (!$order instanceof MappableObject)
00136                 $order = new OrderBy($order);
00137             
00138             $this->order->add($order);
00139             
00140             return $this;
00141         }
00142         
00146         public function dropOrder()
00147         {
00148             $this->order = new OrderChain();
00149             
00150             return $this;
00151         }
00152         
00153         public function getLimit()
00154         {
00155             return $this->limit;
00156         }
00157         
00161         public function setLimit($limit)
00162         {
00163             $this->limit = $limit;
00164             
00165             return $this;
00166         }
00167         
00168         public function getOffset()
00169         {
00170             return $this->offset;
00171         }
00172         
00176         public function setOffset($offset)
00177         {
00178             $this->offset = $offset;
00179             
00180             return $this;
00181         }
00182         
00186         public function getFetchStrategy()
00187         {
00188             return $this->strategy;
00189         }
00190         
00194         public function setFetchStrategy(FetchStrategy $strategy)
00195         {
00196             if (
00197                 $this->dao
00198                 && ($strategy->getId() == FetchStrategy::JOIN)
00199             ) {
00200                 Assert::isTrue(
00201                     $this->dao instanceof ComplexBuilderDAO,
00202                     'your DAO does not support join fetch strategy'
00203                 );
00204             }
00205             
00206             $this->strategy = $strategy;
00207             
00208             return $this;
00209         }
00210         
00214         public function setProjection(ObjectProjection $chain)
00215         {
00216             $this->projection = $chain;
00217             
00218             return $this;
00219         }
00220         
00224         public function getProjection()
00225         {
00226             return $this->projection;
00227         }
00228         
00232         public function dropProjection()
00233         {
00234             $this->projection = null;
00235             
00236             return $this;
00237         }
00238         
00242         public function setDistinct($orly = true)
00243         {
00244             $this->distinct = ($orly === true);
00245             
00246             return $this;
00247         }
00248         
00249         public function isDistinct()
00250         {
00251             return $this->distinct;
00252         }
00253         
00254         public function isSilent()
00255         {
00256             return $this->silent;
00257         }
00258         
00262         public function setSilent($silent)
00263         {
00264             Assert::isBoolean($silent);
00265             
00266             $this->silent = $silent;
00267             
00268             return $this;
00269         }
00270         
00274         public function fetchCollection(
00275             $path, // to collection
00276             $lazy = false, // fetching mode
00277             /* Criteria */ $criteria = null
00278         )
00279         {
00280             Assert::isBoolean($lazy);
00281             Assert::isTrue(
00282                 ($criteria === null)
00283                 || ($criteria instanceof Criteria)
00284             );
00285             
00286             $this->collections[$path]['lazy'] = $lazy;
00287             $this->collections[$path]['criteria'] = $criteria;
00288             $this->collections[$path]['propertyPath']
00289                 = new PropertyPath($this->dao->getObjectName(), $path);
00290             
00291             return $this;
00292         }
00293         
00294         public function get()
00295         {
00296             try {
00297                 $list = array($this->dao->getByQuery($this->toSelectQuery()));
00298             } catch (ObjectNotFoundException $e) {
00299                 if (!$this->isSilent())
00300                     throw $e;
00301                 
00302                 return null;
00303             }
00304             
00305             if (!$this->collections)
00306                 return reset($list);
00307             
00308             $list = $this->dao->fetchCollections($this->collections, $list);
00309             
00310             return reset($list);
00311         }
00312         
00313         public function getList()
00314         {
00315             try {
00316                 $list = $this->dao->getListByQuery($this->toSelectQuery());
00317             } catch (ObjectNotFoundException $e) {
00318                 if (!$this->isSilent())
00319                     throw $e;
00320                 
00321                 return array();
00322             }
00323             
00324             if (!$this->collections)
00325                 return $list;
00326             
00327             return $this->dao->fetchCollections($this->collections, $list);
00328         }
00329         
00333         public function getResult()
00334         {
00335             try {
00336                 $result = $this->dao->getQueryResult($this->toSelectQuery());
00337             } catch (ObjectNotFoundException $e) {
00338                 if (!$this->isSilent())
00339                     throw $e;
00340                 
00341                 return new QueryResult();
00342             }
00343             
00344             if (!$this->collections)
00345                 return $result;
00346             
00347             return $result->setList(
00348                 $this->dao->fetchCollections(
00349                     $this->collections,
00350                     $result->getList()
00351                 )
00352             );
00353         }
00354         
00355         public function getCustom($index = null)
00356         {
00357             try {
00358                 $result = $this->dao->getCustom($this->toSelectQuery());
00359                 
00360                 if ($index) {
00361                     if (isset($result[$index]))
00362                         return $result[$index];
00363                     
00364                     throw new MissingElementException();
00365                 }
00366                 
00367                 return $result;
00368             } catch (ObjectNotFoundException $e) {
00369                 if (!$this->isSilent())
00370                     throw $e;
00371                 
00372                 return null;
00373             }
00374         }
00375         
00376         public function getCustomList()
00377         {
00378             try {
00379                 return $this->dao->getCustomList($this->toSelectQuery());
00380             } catch (ObjectNotFoundException $e) {
00381                 if (!$this->isSilent())
00382                     throw $e;
00383                 
00384                 return array();
00385             }
00386         }
00387         
00388         public function getPropertyList()
00389         {
00390             try {
00391                 return $this->dao->getCustomRowList($this->toSelectQuery());
00392             } catch (ObjectNotFoundException $e) {
00393                 if (!$this->isSilent())
00394                     throw $e;
00395                 
00396                 return array();
00397             }
00398         }
00399         
00400         public function toString()
00401         {
00402             return $this->toDialectString(
00403                 $this->dao
00404                     ? DBPool::getByDao($this->dao)->getDialect()
00405                     : ImaginaryDialect::me()
00406             );
00407         }
00408         
00409         public function toDialectString(Dialect $dialect)
00410         {
00411             return $this->toSelectQuery()->toDialectString($dialect);
00412         }
00413         
00417         public function toSelectQuery()
00418         {
00419             Assert::isNotNull($this->dao, 'DAO not set');
00420             
00421             if ($this->projection) {
00422                 $query =
00423                     $this->getProjection()->process(
00424                         $this,
00425                         OSQL::select()->from($this->dao->getTable())
00426                     );
00427             } else
00428                 $query = $this->dao->makeSelectHead();
00429             
00430             return $this->fillSelectQuery($query);
00431         }
00432         
00436         public function fillSelectQuery(SelectQuery $query)
00437         {
00438             $query->
00439                 limit($this->limit, $this->offset)->
00440                 setFetchStrategyId($this->strategy->getId());
00441             
00442             if ($this->distinct)
00443                 $query->distinct();
00444             
00445             if ($this->logic->getSize()) {
00446                 $query->
00447                     andWhere(
00448                         $this->logic->toMapped($this->dao, $query)
00449                     );
00450             }
00451             
00452             if ($this->order) {
00453                 $query->setOrderChain($this->order->toMapped($this->dao, $query));
00454             }
00455             
00456             if (
00457                 !$this->projection
00458                 && $this->strategy->getId() == FetchStrategy::JOIN
00459             ) {
00460                 $this->joinProperties($query, $this->dao, $this->dao->getTable(), true);
00461             }
00462             
00463             return $query;
00464         }
00465         
00466         private function joinProperties(
00467             SelectQuery $query,
00468             ComplexBuilderDAO $parentDao,
00469             $parentTable,
00470             $parentRequired,
00471             $prefix = null
00472         )
00473         {
00474             $proto = call_user_func(array($parentDao->getObjectName(), 'proto'));
00475             
00476             foreach ($proto->getPropertyList() as $property) {
00477                 if (
00478                     $property->getRelationId() == MetaRelation::ONE_TO_ONE
00479                     && !$property->isGenericType()
00480                     && !$property->getFetchStrategyId() == FetchStrategy::CASCADE
00481                 ) {
00482                     if (
00483                         is_subclass_of(
00484                             $property->getClassName(),
00485                             'Enumeration'
00486                         )
00487                     ) {
00488                         // field already added by makeSelectHead
00489                         continue;
00490                     }
00491                     
00492                     $propertyDao = call_user_func(
00493                         array($property->getClassName(), 'dao')
00494                     );
00495                     
00496                     $tableAlias = $propertyDao->getJoinName(
00497                         $property->getColumnName(),
00498                         $prefix
00499                     );
00500                     
00501                     $fields = $propertyDao->getFields();
00502                     
00503                     if (!$query->hasJoinedTable($tableAlias)) {
00504                         $logic =
00505                             Expression::eq(
00506                                 DBField::create(
00507                                     $property->getColumnName(),
00508                                     $parentTable
00509                                 ),
00510                                 
00511                                 DBField::create(
00512                                     $propertyDao->getIdName(),
00513                                     $tableAlias
00514                                 )
00515                             );
00516                         
00517                         if ($property->isRequired() && $parentRequired)
00518                             $query->join($propertyDao->getTable(), $logic, $tableAlias);
00519                         else
00520                             $query->leftJoin($propertyDao->getTable(), $logic, $tableAlias);
00521                     }
00522                     
00523                     foreach ($fields as $field) {
00524                         $query->get(
00525                             new DBField($field, $tableAlias),
00526                             $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00527                                 .$field
00528                         );
00529                     }
00530                     
00531                     $this->joinProperties(
00532                         $query,
00533                         $propertyDao,
00534                         $tableAlias,
00535                         $property->isRequired() && $parentRequired,
00536                         $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00537                     );
00538                 }
00539             }
00540         }
00541         
00545         private function getProto()
00546         {
00547             return
00548                 call_user_func(
00549                     array($this->dao->getObjectName(), 'proto')
00550                 );
00551         }
00552     }
00553 ?>

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