Go to the documentation of this file.00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00017 final class Criteria extends QueryIdentification
00018 {
00019 private $dao = null;
00020 private $daoClass = null;
00021 private $logic = null;
00022 private $order = null;
00023 private $strategy = null;
00024 private $projection = null;
00025
00026 private $distinct = false;
00027
00028 private $limit = null;
00029 private $offset = null;
00030
00031 private $collections = array();
00032
00033
00034 private $silent = true;
00035
00039 public static function create( $dao = null)
00040 {
00041 return new self($dao);
00042 }
00043
00044 public function __construct( $dao = null)
00045 {
00046 if ($dao)
00047 Assert::isTrue($dao instanceof ProtoDAO);
00048
00049 $this->dao = $dao;
00050 $this->logic = Expression::andBlock();
00051 $this->order = new OrderChain();
00052 $this->strategy = FetchStrategy::join();
00053 $this->projection = Projection::chain();
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 $this->projection = clone $this->projection;
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(ProtoDAO $dao)
00090 {
00091 $this->dao = $dao;
00092
00093 return $this;
00094 }
00095
00099 public function getLogic()
00100 {
00101 return $this->logic;
00102 }
00103
00107 public function add(LogicalObject $logic)
00108 {
00109 $this->logic->expAnd($logic);
00110
00111 return $this;
00112 }
00113
00117 public function getOrder()
00118 {
00119 return $this->order;
00120 }
00121
00125 public function addOrder( $order)
00126 {
00127 if (!$order instanceof MappableObject)
00128 $order = new OrderBy($order);
00129
00130 $this->order->add($order);
00131
00132 return $this;
00133 }
00134
00138 public function prependOrder( $order)
00139 {
00140 if (!$order instanceof MappableObject)
00141 $order = new OrderBy($order);
00142
00143 $this->order->prepend($order);
00144
00145 return $this;
00146 }
00147
00151 public function dropOrder()
00152 {
00153 $this->order = new OrderChain();
00154
00155 return $this;
00156 }
00157
00158 public function getLimit()
00159 {
00160 return $this->limit;
00161 }
00162
00166 public function setLimit($limit)
00167 {
00168 $this->limit = $limit;
00169
00170 return $this;
00171 }
00172
00173 public function getOffset()
00174 {
00175 return $this->offset;
00176 }
00177
00181 public function setOffset($offset)
00182 {
00183 $this->offset = $offset;
00184
00185 return $this;
00186 }
00187
00191 public function getFetchStrategy()
00192 {
00193 return $this->strategy;
00194 }
00195
00199 public function setFetchStrategy(FetchStrategy $strategy)
00200 {
00201 $this->strategy = $strategy;
00202
00203 return $this;
00204 }
00205
00209 public function setProjection(ObjectProjection $chain)
00210 {
00211 if ($chain instanceof ProjectionChain)
00212 $this->projection = $chain;
00213 else
00214 $this->projection = Projection::chain()->add($chain);
00215
00216 return $this;
00217 }
00218
00222 public function addProjection(ObjectProjection $projection)
00223 {
00224 if (
00225 !$projection instanceof ProjectionChain
00226 || !$projection->isEmpty()
00227 )
00228 $this->projection->add($projection);
00229
00230 return $this;
00231 }
00232
00236 public function getProjection()
00237 {
00238 return $this->projection;
00239 }
00240
00244 public function dropProjection()
00245 {
00246 $this->projection = Projection::chain();
00247
00248 return $this;
00249 }
00250
00254 public function setDistinct($orly = true)
00255 {
00256 $this->distinct = ($orly === true);
00257
00258 return $this;
00259 }
00260
00261 public function isDistinct()
00262 {
00263 return $this->distinct;
00264 }
00265
00266 public function isSilent()
00267 {
00268 return $this->silent;
00269 }
00270
00274 public function setSilent($silent)
00275 {
00276 Assert::isBoolean($silent);
00277
00278 $this->silent = $silent;
00279
00280 return $this;
00281 }
00282
00286 public function fetchCollection(
00287 $path,
00288 $lazy = false,
00289 $criteria = null
00290 )
00291 {
00292 Assert::isBoolean($lazy);
00293 Assert::isTrue(
00294 ($criteria === null)
00295 || ($criteria instanceof Criteria)
00296 );
00297
00298 $this->collections[$path]['lazy'] = $lazy;
00299 $this->collections[$path]['criteria'] = $criteria;
00300 $this->collections[$path]['propertyPath']
00301 = new PropertyPath($this->dao->getObjectName(), $path);
00302
00303 return $this;
00304 }
00305
00306 public function get()
00307 {
00308 try {
00309 $list = array($this->dao->getByQuery($this->toSelectQuery()));
00310 } catch (ObjectNotFoundException $e) {
00311 if (!$this->isSilent())
00312 throw $e;
00313
00314 return null;
00315 }
00316
00317 if (!$this->collections || !$list)
00318 return reset($list);
00319
00320 $list = $this->dao->fetchCollections($this->collections, $list);
00321
00322 return reset($list);
00323 }
00324
00325 public function getList()
00326 {
00327 try {
00328 $list = $this->dao->getListByQuery($this->toSelectQuery());
00329 } catch (ObjectNotFoundException $e) {
00330 if (!$this->isSilent())
00331 throw $e;
00332
00333 return array();
00334 }
00335
00336 if (!$this->collections || !$list)
00337 return $list;
00338
00339 return $this->dao->fetchCollections($this->collections, $list);
00340 }
00341
00345 public function getResult()
00346 {
00347 $result = $this->dao->getQueryResult($this->toSelectQuery());
00348
00349 if (!$this->collections || !$result->getCount())
00350 return $result;
00351
00352 return $result->setList(
00353 $this->dao->fetchCollections(
00354 $this->collections,
00355 $result->getList()
00356 )
00357 );
00358 }
00359
00360 public function getCustom($index = null)
00361 {
00362 try {
00363 $result = $this->dao->getCustom($this->toSelectQuery());
00364
00365 if ($index) {
00366 if (array_key_exists($index, $result))
00367 return $result[$index];
00368
00369 throw new MissingElementException(
00370 'No such key: "'.$index.'" in result set.'
00371 );
00372 }
00373
00374 return $result;
00375 } catch (ObjectNotFoundException $e) {
00376 if (!$this->isSilent())
00377 throw $e;
00378
00379 return null;
00380 }
00381 }
00382
00383 public function getCustomList()
00384 {
00385 try {
00386 return $this->dao->getCustomList($this->toSelectQuery());
00387 } catch (ObjectNotFoundException $e) {
00388 if (!$this->isSilent())
00389 throw $e;
00390
00391 return array();
00392 }
00393 }
00394
00395 public function getPropertyList()
00396 {
00397 try {
00398 return $this->dao->getCustomRowList($this->toSelectQuery());
00399 } catch (ObjectNotFoundException $e) {
00400 if (!$this->isSilent())
00401 throw $e;
00402
00403 return array();
00404 }
00405 }
00406
00407 public function toString()
00408 {
00409 return $this->toDialectString(
00410 $this->dao
00411 ? DBPool::getByDao($this->dao)->getDialect()
00412 : ImaginaryDialect::me()
00413 );
00414 }
00415
00416 public function toDialectString(Dialect $dialect)
00417 {
00418 return $this->toSelectQuery()->toDialectString($dialect);
00419 }
00420
00424 public function toSelectQuery()
00425 {
00426 Assert::isNotNull($this->dao, 'DAO not set');
00427
00428 if (!$this->projection->isEmpty()) {
00429 $query =
00430 $this->getProjection()->process(
00431 $this,
00432 $this->dao->makeSelectHead()->
00433 dropFields()
00434 );
00435 } else
00436 $query = $this->dao->makeSelectHead();
00437
00438 if ($this->distinct)
00439 $query->distinct();
00440
00441 return $this->fillSelectQuery($query);
00442 }
00443
00447 public function fillSelectQuery(SelectQuery $query)
00448 {
00449 $query->
00450 limit($this->limit, $this->offset);
00451
00452 if ($this->distinct)
00453 $query->distinct();
00454
00455 if ($this->logic->getSize()) {
00456 $query->
00457 andWhere(
00458 $this->logic->toMapped($this->dao, $query)
00459 );
00460 }
00461
00462 if ($this->order) {
00463 $query->setOrderChain($this->order->toMapped($this->dao, $query));
00464 }
00465
00466 if (
00467 $this->projection->isEmpty()
00468 && (
00469 $this->strategy->getId() <> FetchStrategy::CASCADE
00470 )
00471 ) {
00472 $this->joinProperties($query, $this->dao, $this->dao->getTable(), true);
00473 }
00474
00475 return $query;
00476 }
00477
00481 public function dropProjectionByType( $dropTypes)
00482 {
00483 Assert::isInstance($this->projection, 'ProjectionChain');
00484
00485 $this->projection->dropByType($dropTypes);
00486
00487 return $this;
00488 }
00489
00490 private function joinProperties(
00491 SelectQuery $query,
00492 ProtoDAO $parentDao,
00493 $parentTable,
00494 $parentRequired,
00495 $prefix = null
00496 )
00497 {
00498 $proto = call_user_func(array($parentDao->getObjectName(), 'proto'));
00499
00500 foreach ($proto->getPropertyList() as $property) {
00501 if (
00502 ($property instanceof LightMetaProperty)
00503 && $property->getRelationId() == MetaRelation::ONE_TO_ONE
00504 && !$property->isGenericType()
00505 && (
00506 (
00507 !$property->getFetchStrategyId()
00508 && (
00509 $this->getFetchStrategy()->getId()
00510 == FetchStrategy::JOIN
00511 )
00512 ) || (
00513 $property->getFetchStrategyId()
00514 == FetchStrategy::JOIN
00515 )
00516 )
00517 ) {
00518 if (
00519 is_subclass_of(
00520 $property->getClassName(),
00521 'Enumeration'
00522 )
00523 ) {
00524
00525 continue;
00526 } elseif ($property->isInner()) {
00527 $proto = call_user_func(
00528 array($property->getClassName(), 'proto')
00529 );
00530
00531 foreach ($proto->getPropertyList() as $innerProperty)
00532 $query->get(
00533 new DBField(
00534 $innerProperty->getColumnName(),
00535 $parentTable
00536 )
00537 );
00538
00539 continue;
00540 }
00541
00542 $propertyDao = call_user_func(
00543 array($property->getClassName(), 'dao')
00544 );
00545
00546
00547 if (!$propertyDao instanceof ProtoDAO)
00548 continue;
00549
00550 $tableAlias = $propertyDao->getJoinName(
00551 $property->getColumnName(),
00552 $prefix
00553 );
00554
00555 $fields = $propertyDao->getFields();
00556
00557 if (!$query->hasJoinedTable($tableAlias)) {
00558 $logic =
00559 Expression::eq(
00560 DBField::create(
00561 $property->getColumnName(),
00562 $parentTable
00563 ),
00564
00565 DBField::create(
00566 $propertyDao->getIdName(),
00567 $tableAlias
00568 )
00569 );
00570
00571 if ($property->isRequired() && $parentRequired)
00572 $query->join($propertyDao->getTable(), $logic, $tableAlias);
00573 else
00574 $query->leftJoin($propertyDao->getTable(), $logic, $tableAlias);
00575 }
00576
00577 foreach ($fields as $field) {
00578 $query->get(
00579 new DBField($field, $tableAlias),
00580 $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00581 .$field
00582 );
00583 }
00584
00585 $this->joinProperties(
00586 $query,
00587 $propertyDao,
00588 $tableAlias,
00589 $property->isRequired() && $parentRequired,
00590 $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00591 );
00592 }
00593 }
00594 }
00595
00599 private function getProto()
00600 {
00601 return
00602 call_user_func(
00603 array($this->dao->getObjectName(), 'proto')
00604 );
00605 }
00606 }
00607 ?>