00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00035 private $silent = true;
00036
00040 public static function create( $dao = null)
00041 {
00042 return new self($dao);
00043 }
00044
00045 public function __construct( $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( $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,
00276 $lazy = false,
00277 $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
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 ?>