00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00027 final class SelectQuery
00028 extends QuerySkeleton
00029 implements Named, JoinCapableQuery, Aliased
00030 {
00031 private $distinct = false;
00032
00033 private $name = null;
00034
00035 private $joiner = null;
00036
00038 private $strategyId = null;
00039
00040 private $limit = null;
00041 private $offset = null;
00042
00043 private $fields = array();
00044
00045 private $order = null;
00046
00047 private $group = array();
00048
00049 private $having = null;
00050
00051 private $aliases = array();
00052
00053 public function __construct()
00054 {
00055 $this->joiner = new Joiner();
00056 $this->order = new OrderChain();
00057 }
00058
00059 public function __clone()
00060 {
00061 $this->joiner = clone $this->joiner;
00062 $this->order = clone $this->order;
00063 }
00064
00065 public function getFetchStrategyId()
00066 {
00067 return $this->strategyId;
00068 }
00069
00073 public function setFetchStrategyId($id)
00074 {
00075 $this->strategyId = $id;
00076
00077 return $this;
00078 }
00079
00080 public function hasAliasInside($alias)
00081 {
00082 return isset($this->aliases[$alias]);
00083 }
00084
00085 public function getAlias()
00086 {
00087 return $this->name;
00088 }
00089
00090 public function getName()
00091 {
00092 return $this->name;
00093 }
00094
00098 public function setName($name)
00099 {
00100 $this->name = $name;
00101 $this->aliases[$name] = true;
00102
00103 return $this;
00104 }
00105
00109 public function distinct()
00110 {
00111 $this->distinct = true;
00112 return $this;
00113 }
00114
00115 public function isDistinct()
00116 {
00117 return $this->distinct;
00118 }
00119
00123 public function unDistinct()
00124 {
00125 $this->distinct = false;
00126 return $this;
00127 }
00128
00129 public function hasJoinedTable($table)
00130 {
00131 return $this->joiner->hasJoinedTable($table);
00132 }
00133
00137 public function join($table, LogicalObject $logic, $alias = null)
00138 {
00139 $this->joiner->join(new SQLJoin($table, $logic, $alias));
00140 $this->aliases[$alias] = true;
00141
00142 return $this;
00143 }
00144
00148 public function leftJoin($table, LogicalObject $logic, $alias = null)
00149 {
00150 $this->joiner->leftJoin(new SQLLeftJoin($table, $logic, $alias));
00151 $this->aliases[$alias] = true;
00152
00153 return $this;
00154 }
00155
00159 public function setOrderChain(OrderChain $chain)
00160 {
00161 $this->order = $chain;
00162
00163 return $this;
00164 }
00165
00169 public function orderBy($field, $table = null)
00170 {
00171 $this->order->add($this->makeOrder($field, $table));
00172
00173 return $this;
00174 }
00175
00179 public function prependOrderBy($field, $table = null)
00180 {
00181 $this->order->prepend($this->makeOrder($field, $table));
00182
00183 return $this;
00184 }
00185
00190 public function desc()
00191 {
00192 if (!$last = $this->order->getLast())
00193 throw new WrongStateException('no fields to sort');
00194
00195 $last->desc();
00196
00197 return $this;
00198 }
00199
00204 public function asc()
00205 {
00206 if (!$last = $this->order->getLast())
00207 throw new WrongStateException('no fields to sort');
00208
00209 $last->asc();
00210
00211 return $this;
00212 }
00213
00217 public function groupBy($field, $table = null)
00218 {
00219 if ($field instanceof DialectString)
00220 $this->group[] = $field;
00221 else
00222 $this->group[] =
00223 new DBField($field, $this->getLastTable($table));
00224
00225 return $this;
00226 }
00227
00231 public function having(LogicalObject $exp)
00232 {
00233 $this->having = $exp;
00234
00235 return $this;
00236 }
00237
00238 public function getLimit()
00239 {
00240 return $this->limit;
00241 }
00242
00243 public function getOffset()
00244 {
00245 return $this->offset;
00246 }
00247
00252 public function limit($limit = null, $offset = null)
00253 {
00254 if ($limit !== null)
00255 Assert::isPositiveInteger($limit, 'invalid limit specified');
00256
00257 if ($offset !== null)
00258 Assert::isInteger($offset, 'invalid offset specified');
00259
00260 $this->limit = $limit;
00261 $this->offset = $offset;
00262
00263 return $this;
00264 }
00265
00269 public function from($table, $alias = null)
00270 {
00271 $this->joiner->from(new FromTable($table, $alias));
00272
00273 $this->aliases[$alias] = true;
00274
00275 return $this;
00276 }
00277
00284 public function get($field, $alias = null)
00285 {
00286 $table = null;
00287 if (is_object($field)) {
00288 if (
00289 ($field instanceof DBField)
00290 && ($field->getTable() === null)
00291 ) {
00292 $this->fields[] = new SelectField(
00293 $field->setTable($this->getLastTable()),
00294 $alias
00295 );
00296 } elseif ($field instanceof SelectQuery) {
00297 $this->fields[] = $field;
00298 $this->aliases[$field->getAlias()] = true;
00299 } elseif ($field instanceof DialectString) {
00300 $this->fields[] = new SelectField($field, $alias);
00301
00302 if ($field instanceof Aliased)
00303 $this->aliases[$field->getAlias()] = true;
00304 elseif ($alias)
00305 $this->aliases[$alias] = true;
00306 } else
00307 throw new WrongArgumentException('unknown field type');
00308
00309 return $this;
00310
00311 } elseif (false !== strpos($field, '*'))
00312 throw new WrongArgumentException(
00313 'do not fsck with us: specify fields explicitly'
00314 );
00315 elseif (false !== strpos($field, '.'))
00316 throw new WrongArgumentException(
00317 'forget about dot: use DBField'
00318 );
00319 else
00320 $fieldName = $field;
00321
00322 $this->fields[] = new SelectField(
00323 new DBField($fieldName, $this->getLastTable($table)), $alias
00324 );
00325
00326 $this->aliases[$alias] = true;
00327
00328 return $this;
00329 }
00330
00334 public function multiGet()
00335 {
00336 $size = func_num_args();
00337
00338 if ($size && $args = func_get_args())
00339 for ($i = 0; $i < $size; ++$i)
00340 $this->get($args[$i]);
00341
00342 return $this;
00343 }
00344
00348 public function arrayGet($array, $prefix = null)
00349 {
00350 $size = count($array);
00351
00352 if ($prefix) {
00353 for ($i = 0; $i < $size; ++$i) {
00354 if ($array[$i] instanceof DialectString) {
00355 if ($array[$i] instanceof DBField) {
00356 $alias = $prefix.$array[$i]->getField();
00357 } else {
00358 if ($array[$i] instanceof SQLFunction) {
00359 $alias =
00360 $array[$i]->setAlias(
00361 $prefix.$array[$i]->getName()
00362 )->
00363 getAlias();
00364 } else {
00365 $alias = $array[$i];
00366 }
00367 }
00368 } else {
00369 $alias = $prefix.$array[$i];
00370 }
00371
00372 $this->get($array[$i], $alias);
00373 }
00374 } else {
00375 for ($i = 0; $i < $size; ++$i) {
00376 $this->get($array[$i]);
00377 }
00378 }
00379
00380 return $this;
00381 }
00382
00383 public function getFieldsCount()
00384 {
00385 return count($this->fields);
00386 }
00387
00388 public function getTablesCount()
00389 {
00390 return $this->joiner->getTablesCount();
00391 }
00392
00393 public function getFieldNames()
00394 {
00395 $nameList = array();
00396
00397 foreach ($this->fields as $field) {
00398 if ($field instanceof SelectField)
00399 if ($alias = $field->getAlias()) {
00400 $nameList[] = $alias;
00401 continue;
00402 }
00403
00404 $nameList[] = $field->getName();
00405 }
00406
00407 return $nameList;
00408 }
00409
00410 public function toDialectString(Dialect $dialect)
00411 {
00412 $fieldList = array();
00413 foreach ($this->fields as $field) {
00414
00415 if ($field instanceof SelectQuery) {
00416
00417 Assert::isTrue(
00418 null !== $alias = $field->getName(),
00419 'can not use SelectQuery without name as get field'
00420 );
00421
00422 $fieldList[] =
00423 "({$field->toDialectString($dialect)}) AS ".
00424 $dialect->quoteField($alias);
00425 } else
00426 $fieldList[] = $field->toDialectString($dialect);
00427 }
00428
00429 $query =
00430 'SELECT '.($this->distinct ? 'DISTINCT ' : null)
00431 .implode(', ', $fieldList)
00432 .$this->joiner->toDialectString($dialect);
00433
00434
00435 $query .= parent::toDialectString($dialect);
00436
00437 if ($this->group) {
00438 $groupList = array();
00439
00440 foreach ($this->group as $group)
00441 $groupList[] = $group->toDialectString($dialect);
00442
00443 if ($groupList)
00444 $query .= " GROUP BY ".implode(', ', $groupList);
00445 }
00446
00447 if ($this->having)
00448 $query .= ' HAVING '.$this->having->toDialectString($dialect);
00449
00450 if ($this->order->getCount()) {
00451 $query .= ' ORDER BY '.$this->order->toDialectString($dialect);
00452 }
00453
00454 if ($this->limit)
00455 $query .= " LIMIT {$this->limit}";
00456
00457 if ($this->offset)
00458 $query .= " OFFSET {$this->offset}";
00459
00460 return $query;
00461 }
00462
00466 public function dropFields()
00467 {
00468 $this->fields = array();
00469 return $this;
00470 }
00471
00475 public function dropOrder()
00476 {
00477 $this->order = new OrderChain();
00478 return $this;
00479 }
00480
00481 private function getLastTable($table = null)
00482 {
00483 if (!$table && ($last = $this->joiner->getLastTable()))
00484 return $last;
00485
00486 return $table;
00487 }
00488
00492 private function makeOrder($field, $table = null)
00493 {
00494 if (
00495 $field instanceof OrderBy
00496 || $field instanceof DialectString
00497 )
00498 return $field;
00499 else
00500 return
00501 new OrderBy(
00502 new DBField($field, $this->getLastTable($table))
00503 );
00504 }
00505 }
00506 ?>