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 instanceof ComplexBuilderDAO)
00055 $this->strategy = FetchStrategy::join();
00056 else
00057 $this->strategy = FetchStrategy::cascade();
00058 }
00059
00060 public function __clone()
00061 {
00062 $this->logic = clone $this->logic;
00063 $this->order = clone $this->order;
00064 }
00065
00066 public function __sleep()
00067 {
00068 $this->daoClass = get_class($this->dao);
00069
00070 $vars = get_object_vars($this);
00071 unset($vars['dao']);
00072 return array_keys($vars);
00073 }
00074
00075 public function __wakeup()
00076 {
00077 $this->dao = Singleton::getInstance($this->daoClass);
00078 }
00079
00083 public function getDao()
00084 {
00085 return $this->dao;
00086 }
00087
00091 public function setDao(StorableDAO $dao)
00092 {
00093 if ($this->strategy->getId() == FetchStrategy::JOIN)
00094 Assert::isTrue(
00095 $dao instanceof ComplexBuilderDAO,
00096 'your DAO does not support join fetch strategy'
00097 );
00098
00099 $this->dao = $dao;
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()
00356 {
00357 try {
00358 return $this->dao->getCustom($this->toSelectQuery());
00359 } catch (ObjectNotFoundException $e) {
00360 if (!$this->isSilent())
00361 throw $e;
00362
00363 return null;
00364 }
00365 }
00366
00367 public function getCustomList()
00368 {
00369 try {
00370 return $this->dao->getCustomList($this->toSelectQuery());
00371 } catch (ObjectNotFoundException $e) {
00372 if (!$this->isSilent())
00373 throw $e;
00374
00375 return array();
00376 }
00377 }
00378
00379 public function getPropertyList()
00380 {
00381 try {
00382 return $this->dao->getCustomRowList($this->toSelectQuery());
00383 } catch (ObjectNotFoundException $e) {
00384 if (!$this->isSilent())
00385 throw $e;
00386
00387 return array();
00388 }
00389 }
00390
00391 public function toString()
00392 {
00393 return $this->toDialectString(
00394 $this->dao
00395 ? DBPool::getByDao($this->dao)->getDialect()
00396 : ImaginaryDialect::me()
00397 );
00398 }
00399
00400 public function toDialectString(Dialect $dialect)
00401 {
00402 return $this->toSelectQuery()->toDialectString($dialect);
00403 }
00404
00408 public function toSelectQuery()
00409 {
00410 Assert::isNotNull($this->dao, 'DAO not set');
00411
00412 if ($this->projection) {
00413 $query =
00414 $this->getProjection()->process(
00415 $this,
00416 OSQL::select()->from($this->dao->getTable())
00417 );
00418 } else
00419 $query = $this->dao->makeSelectHead();
00420
00421 $query->
00422 limit($this->limit, $this->offset)->
00423 setFetchStrategyId($this->strategy->getId());
00424
00425 if ($this->distinct)
00426 $query->distinct();
00427
00428 if ($this->logic->getSize()) {
00429 $query->
00430 andWhere(
00431 $this->logic->toMapped($this->dao, $query)
00432 );
00433 }
00434
00435 if ($this->order) {
00436 $query->setOrderChain($this->order->toMapped($this->dao, $query));
00437 }
00438
00439 if (
00440 !$this->projection
00441 && $this->strategy->getId() == FetchStrategy::JOIN
00442 ) {
00443 $this->joinProperties($query, $this->dao, $this->dao->getTable(), true);
00444 }
00445
00446 return $query;
00447 }
00448
00449 private function joinProperties(
00450 SelectQuery $query,
00451 ComplexBuilderDAO $parentDao,
00452 $parentTable,
00453 $parentRequired,
00454 $prefix = null
00455 )
00456 {
00457 $proto = call_user_func(array($parentDao->getObjectName(), 'proto'));
00458
00459 foreach ($proto->getPropertyList() as $property) {
00460 if (
00461 $property->getRelationId() == MetaRelation::ONE_TO_ONE
00462 && !$property->isGenericType()
00463 && !$property->getFetchStrategyId() == FetchStrategy::CASCADE
00464 ) {
00465 if (
00466 is_subclass_of(
00467 $property->getClassName(),
00468 'Enumeration'
00469 )
00470 ) {
00471 $query->get(
00472 new DBField(
00473 $property->getColumnName(),
00474 $parentTable
00475 )
00476 );
00477
00478 continue;
00479 }
00480
00481 $propertyDao = call_user_func(
00482 array($property->getClassName(), 'dao')
00483 );
00484
00485 $tableAlias = $propertyDao->getJoinName(
00486 $property->getColumnName(),
00487 $prefix
00488 );
00489
00490 $fields = $propertyDao->getFields();
00491
00492 if (!$query->hasJoinedTable($tableAlias)) {
00493 $logic =
00494 Expression::eq(
00495 DBField::create(
00496 $property->getColumnName(),
00497 $parentTable
00498 ),
00499
00500 DBField::create(
00501 $propertyDao->getIdName(),
00502 $tableAlias
00503 )
00504 );
00505
00506 if ($property->isRequired() && $parentRequired)
00507 $query->join($propertyDao->getTable(), $logic, $tableAlias);
00508 else
00509 $query->leftJoin($propertyDao->getTable(), $logic, $tableAlias);
00510 }
00511
00512 foreach ($fields as $field) {
00513 $query->get(
00514 new DBField($field, $tableAlias),
00515 $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00516 .$field
00517 );
00518 }
00519
00520 $this->joinProperties(
00521 $query,
00522 $propertyDao,
00523 $tableAlias,
00524 $property->isRequired() && $parentRequired,
00525 $propertyDao->getJoinPrefix($property->getColumnName(), $prefix)
00526 );
00527 }
00528 }
00529 }
00530
00534 private function getProto()
00535 {
00536 return
00537 call_user_func(
00538 array($this->dao->getObjectName(), 'proto')
00539 );
00540 }
00541 }
00542 ?>