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 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( $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( $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,
00270 $lazy = false,
00271 $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
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
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 ?>