onPHP

main/Criteria/Criteria.class.php Source File

 

Criteria.class.php

Go to the documentation of this file.
00001 <?php
00002 /****************************************************************************
00003  *   Copyright (C) 2006-2008 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 5209 2008-06-17 12:39:25Z 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(/* ProtoDAO */ $dao = null)
00041         {
00042             return new self($dao);
00043         }
00044         
00045         public function __construct(/* ProtoDAO */ $dao = null)
00046         {
00047             if ($dao)
00048                 Assert::isTrue($dao instanceof ProtoDAO);
00049             
00050             $this->dao = $dao;
00051             $this->logic = Expression::andBlock();
00052             $this->order = new OrderChain();
00053             $this->strategy = FetchStrategy::join();
00054         }
00055         
00056         public function __clone()
00057         {
00058             $this->logic = clone $this->logic;
00059             $this->order = clone $this->order;
00060             $this->strategy = clone $this->strategy;
00061         }
00062         
00063         public function __sleep()
00064         {
00065             $this->daoClass = get_class($this->dao);
00066             
00067             $vars = get_object_vars($this);
00068             unset($vars['dao']);
00069             return array_keys($vars);
00070         }
00071         
00072         public function __wakeup()
00073         {
00074             $this->dao = Singleton::getInstance($this->daoClass);
00075         }
00076         
00080         public function getDao()
00081         {
00082             return $this->dao;
00083         }
00084         
00088         public function setDao(ProtoDAO $dao)
00089         {
00090             $this->dao = $dao;
00091             
00092             return $this;
00093         }
00094         
00098         public function getLogic()
00099         {
00100             return $this->logic;
00101         }
00102         
00106         public function add(LogicalObject $logic)
00107         {
00108             $this->logic->expAnd($logic);
00109             
00110             return $this;
00111         }
00112         
00116         public function getOrder()
00117         {
00118             return $this->order;
00119         }
00120         
00124         public function addOrder(/* MapableObject */ $order)
00125         {
00126             if (!$order instanceof MappableObject)
00127                 $order = new OrderBy($order);
00128             
00129             $this->order->add($order);
00130             
00131             return $this;
00132         }
00133         
00137         public function prependOrder(/* MapableObject */ $order)
00138         {
00139             if (!$order instanceof MappableObject)
00140                 $order = new OrderBy($order);
00141             
00142             $this->order->prepend($order);
00143             
00144             return $this;
00145         }
00146         
00150         public function dropOrder()
00151         {
00152             $this->order = new OrderChain();
00153             
00154             return $this;
00155         }
00156         
00157         public function getLimit()
00158         {
00159             return $this->limit;
00160         }
00161         
00165         public function setLimit($limit)
00166         {
00167             $this->limit = $limit;
00168             
00169             return $this;
00170         }
00171         
00172         public function getOffset()
00173         {
00174             return $this->offset;
00175         }
00176         
00180         public function setOffset($offset)
00181         {
00182             $this->offset = $offset;
00183             
00184             return $this;
00185         }
00186         
00190         public function getFetchStrategy()
00191         {
00192             return $this->strategy;
00193         }
00194         
00198         public function setFetchStrategy(FetchStrategy $strategy)
00199         {
00200             $this->strategy = $strategy;
00201             
00202             return $this;
00203         }
00204         
00208         public function setProjection(ObjectProjection $chain)
00209         {
00210             $this->projection = $chain;
00211             
00212             return $this;
00213         }
00214         
00218         public function getProjection()
00219         {
00220             return $this->projection;
00221         }
00222         
00226         public function dropProjection()
00227         {
00228             $this->projection = null;
00229             
00230             return $this;
00231         }
00232         
00236         public function setDistinct($orly = true)
00237         {
00238             $this->distinct = ($orly === true);
00239             
00240             return $this;
00241         }
00242         
00243         public function isDistinct()
00244         {
00245             return $this->distinct;
00246         }
00247         
00248         public function isSilent()
00249         {
00250             return $this->silent;
00251         }
00252         
00256         public function setSilent($silent)
00257         {
00258             Assert::isBoolean($silent);
00259             
00260             $this->silent = $silent;
00261             
00262             return $this;
00263         }
00264         
00268         public function fetchCollection(
00269             $path, // to collection
00270             $lazy = false, // fetching mode
00271             /* Criteria */ $criteria = null
00272         )
00273         {
00274             Assert::isBoolean($lazy);
00275             Assert::isTrue(
00276                 ($criteria === null)
00277                 || ($criteria instanceof Criteria)
00278             );
00279             
00280             $this->collections[$path]['lazy'] = $lazy;
00281             $this->collections[$path]['criteria'] = $criteria;
00282             $this->collections[$path]['propertyPath']
00283                 = new PropertyPath($this->dao->getObjectName(), $path);
00284             
00285             return $this;
00286         }
00287         
00288         public function get()
00289         {
00290             try {
00291                 $list = array($this->dao->getByQuery($this->toSelectQuery()));
00292             } catch (ObjectNotFoundException $e) {
00293                 if (!$this->isSilent())
00294                     throw $e;
00295                 
00296                 return null;
00297             }
00298             
00299             if (!$this->collections)
00300                 return reset($list);
00301             
00302             $list = $this->dao->fetchCollections($this->collections, $list);
00303             
00304             return reset($list);
00305         }
00306         
00307         public function getList()
00308         {
00309             try {
00310                 $list = $this->dao->getListByQuery($this->toSelectQuery());
00311             } catch (ObjectNotFoundException $e) {
00312                 if (!$this->isSilent())
00313                     throw $e;
00314                 
00315                 return array();
00316             }
00317             
00318             if (!$this->collections)
00319                 return $list;
00320             
00321             return $this->dao->fetchCollections($this->collections, $list);
00322         }
00323         
00327         public function getResult()
00328         {
00329             $result = $this->dao->getQueryResult($this->toSelectQuery());
00330             
00331             if (!$this->collections)
00332                 return $result;
00333             
00334             return $result->setList(
00335                 $this->dao->fetchCollections(
00336                     $this->collections,
00337                     $result->getList()
00338                 )
00339             );
00340         }
00341         
00342         public function getCustom($index = null)
00343         {
00344             try {
00345                 $result = $this->dao->getCustom($this->toSelectQuery());
00346                 
00347                 if ($index) {
00348                     if (isset($result[$index]))
00349                         return $result[$index];
00350                     
00351                     throw new MissingElementException();
00352                 }
00353                 
00354                 return $result;
00355             } catch (ObjectNotFoundException $e) {
00356                 if (!$this->isSilent())
00357                     throw $e;
00358                 
00359                 return null;
00360             }
00361         }
00362         
00363         public function getCustomList()
00364         {
00365             try {
00366                 return $this->dao->getCustomList($this->toSelectQuery());
00367             } catch (ObjectNotFoundException $e) {
00368                 if (!$this->isSilent())
00369                     throw $e;
00370                 
00371                 return array();
00372             }
00373         }
00374         
00375         public function getPropertyList()
00376         {
00377             try {
00378                 return $this->dao->getCustomRowList($this->toSelectQuery());
00379             } catch (ObjectNotFoundException $e) {
00380                 if (!$this->isSilent())
00381                     throw $e;
00382                 
00383                 return array();
00384             }
00385         }
00386         
00387         public function toString()
00388         {
00389             return $this->toDialectString(
00390                 $this->dao
00391                     ? DBPool::getByDao($this->dao)->getDialect()
00392                     : ImaginaryDialect::me()
00393             );
00394         }
00395         
00396         public function toDialectString(Dialect $dialect)
00397         {
00398             return $this->toSelectQuery()->toDialectString($dialect);
00399         }
00400         
00404         public function toSelectQuery()
00405         {
00406             Assert::isNotNull($this->dao, 'DAO not set');
00407             
00408             if ($this->projection) {
00409                 $query =
00410                     $this->getProjection()->process(
00411                         $this,
00412                         $this->dao->makeSelectHead()->
00413                             dropFields()
00414                     );
00415             } else
00416                 $query = $this->dao->makeSelectHead();
00417             
00418             return $this->fillSelectQuery($query);
00419         }
00420         
00424         public function fillSelectQuery(SelectQuery $query)
00425         {
00426             $query->
00427                 limit($this->limit, $this->offset);
00428             
00429             if ($this->distinct)
00430                 $query->distinct();
00431             
00432             if ($this->logic->getSize()) {
00433                 $query->
00434                     andWhere(
00435                         $this->logic->toMapped($this->dao, $query)
00436                     );
00437             }
00438             
00439             if ($this->order) {
00440                 $query->setOrderChain($this->order->toMapped($this->dao, $query));
00441             }
00442             
00443             if (
00444                 !$this->projection
00445                 && (
00446                     $this->strategy->getId() <> FetchStrategy::CASCADE
00447                 )
00448             ) {
00449                 $this->joinProperties($query, $this->dao, $this->dao->getTable(), true);
00450             }
00451             
00452             return $query;
00453         }
00454         
00455         private function joinProperties(
00456             SelectQuery $query,
00457             ProtoDAO $parentDao,
00458             $parentTable,
00459             $parentRequired,
00460             $prefix = null
00461         )
00462         {
00463             $proto = call_user_func(array($parentDao->getObjectName(), 'proto'));
00464             
00465             foreach ($proto->getPropertyList() as $property) {
00466                 if (
00467                     ($property instanceof LightMetaProperty)
00468                     && $property->getRelationId() == MetaRelation::ONE_TO_ONE
00469                     && !$property->isGenericType()
00470                     && $property->getFetchStrategyId() <> FetchStrategy::CASCADE
00471                 ) {
00472                     if (
00473                         is_subclass_of(
00474                             $property->getClassName(),
00475                             'Enumeration'
00476                         )
00477                     ) {
00478                         // field already added by makeSelectHead
00479                         continue;
00480                     } elseif ($property->isInner()) {
00481                         $proto = call_user_func(
00482                             array($property->getClassName(), 'proto')
00483                         );
00484                         
00485                         foreach ($proto->getPropertyList() as $innerProperty)
00486                             $query->get(
00487                                 new DBField(
00488                                     $innerProperty->getColumnName(),
00489                                     $parentTable
00490                                 )
00491                             );
00492                         
00493                         continue;
00494                     }
00495                     
00496                     $propertyDao = call_user_func(
00497                         array($property->getClassName(), 'dao')
00498                     );
00499                     
00500                     // add's custom dao's injection possibility
00501                     if (!$propertyDao instanceof ProtoDAO)
00502                         continue;
00503                     
00504                     $tableAlias = $propertyDao->getJoinName(
00505                         $property->getColumnName(),
00506                         $prefix
00507                     );
00508                     
00509                     $fields = $propertyDao->getFields();
00510                     
00511                     if (!$query->hasJoinedTable($tableAlias)) {
00512                         $logic =
00513                             Expression::eq(
00514                                 DBField::create(
00515                                     $property->getColumnName(),
00516                                     $parentTable
00517                                 ),
00518                                 
00519                                 DBField::create(
00520                                     $propertyDao->getIdName(),
00521                                     $tableAlias
00522                                 )
00523                             );
00524                         
00525                         if ($property->isRequired() && $parentRequired)
00526                             $query->join($propertyDao->getTable(), $logic, $tableAlias);
00527                         else
00528                             $query->leftJoin($propertyDao->getTable(), $logic, $tableAlias);
00529                     }
00530                     
00531                     foreach ($fields as $field) {
00532                         $query->get(
00533                             new DBField($field, $tableAlias),
00534                             $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00535                                 .$field
00536                         );
00537                     }
00538                     
00539                     $this->joinProperties(
00540                         $query,
00541                         $propertyDao,
00542                         $tableAlias,
00543                         $property->isRequired() && $parentRequired,
00544                         $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00545                     );
00546                 }
00547             }
00548         }
00549         
00553         private function getProto()
00554         {
00555             return
00556                 call_user_func(
00557                     array($this->dao->getObjectName(), 'proto')
00558                 );
00559         }
00560     }
00561 ?>

generated by doxygen-1.5.5
for onPHP at Tue Jun 17 16:42:54 2008