00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00016 final class SelectQuery
00017 extends QuerySkeleton
00018 implements Named, JoinCapableQuery, Aliased
00019 {
00020 private $distinct = false;
00021
00022 private $name = null;
00023
00024 private $joiner = null;
00025
00026 private $limit = null;
00027 private $offset = null;
00028
00029 private $fields = array();
00030
00031 private $order = null;
00032
00033 private $group = array();
00034
00035 private $having = null;
00036
00037 private $aliases = array();
00038
00039 public function __construct()
00040 {
00041 $this->joiner = new Joiner();
00042 $this->order = new OrderChain();
00043 }
00044
00045 public function __clone()
00046 {
00047 $this->joiner = clone $this->joiner;
00048 $this->order = clone $this->order;
00049 }
00050
00051 public function hasAliasInside($alias)
00052 {
00053 return isset($this->aliases[$alias]);
00054 }
00055
00056 public function getAlias()
00057 {
00058 return $this->name;
00059 }
00060
00061 public function getName()
00062 {
00063 return $this->name;
00064 }
00065
00069 public function setName($name)
00070 {
00071 $this->name = $name;
00072 $this->aliases[$name] = true;
00073
00074 return $this;
00075 }
00076
00080 public function distinct()
00081 {
00082 $this->distinct = true;
00083 return $this;
00084 }
00085
00086 public function isDistinct()
00087 {
00088 return $this->distinct;
00089 }
00090
00094 public function unDistinct()
00095 {
00096 $this->distinct = false;
00097 return $this;
00098 }
00099
00100 public function hasJoinedTable($table)
00101 {
00102 return $this->joiner->hasJoinedTable($table);
00103 }
00104
00108 public function join($table, LogicalObject $logic, $alias = null)
00109 {
00110 $this->joiner->join(new SQLJoin($table, $logic, $alias));
00111 $this->aliases[$alias] = true;
00112
00113 return $this;
00114 }
00115
00119 public function leftJoin($table, LogicalObject $logic, $alias = null)
00120 {
00121 $this->joiner->leftJoin(new SQLLeftJoin($table, $logic, $alias));
00122 $this->aliases[$alias] = true;
00123
00124 return $this;
00125 }
00126
00130 public function setOrderChain(OrderChain $chain)
00131 {
00132 $this->order = $chain;
00133
00134 return $this;
00135 }
00136
00140 public function orderBy($field, $table = null)
00141 {
00142 $this->order->add($this->makeOrder($field, $table));
00143
00144 return $this;
00145 }
00146
00150 public function prependOrderBy($field, $table = null)
00151 {
00152 $this->order->prepend($this->makeOrder($field, $table));
00153
00154 return $this;
00155 }
00156
00161 public function desc()
00162 {
00163 if (!$last = $this->order->getLast())
00164 throw new WrongStateException('no fields to sort');
00165
00166 $last->desc();
00167
00168 return $this;
00169 }
00170
00175 public function asc()
00176 {
00177 if (!$last = $this->order->getLast())
00178 throw new WrongStateException('no fields to sort');
00179
00180 $last->asc();
00181
00182 return $this;
00183 }
00184
00188 public function groupBy($field, $table = null)
00189 {
00190 if ($field instanceof DialectString)
00191 $this->group[] = $field;
00192 else
00193 $this->group[] =
00194 new DBField($field, $this->getLastTable($table));
00195
00196 return $this;
00197 }
00198
00202 public function having(LogicalObject $exp)
00203 {
00204 $this->having = $exp;
00205
00206 return $this;
00207 }
00208
00209 public function getLimit()
00210 {
00211 return $this->limit;
00212 }
00213
00214 public function getOffset()
00215 {
00216 return $this->offset;
00217 }
00218
00223 public function limit($limit = null, $offset = null)
00224 {
00225 if ($limit !== null)
00226 Assert::isPositiveInteger($limit, 'invalid limit specified');
00227
00228 if ($offset !== null)
00229 Assert::isInteger($offset, 'invalid offset specified');
00230
00231 $this->limit = $limit;
00232 $this->offset = $offset;
00233
00234 return $this;
00235 }
00236
00240 public function from($table, $alias = null)
00241 {
00242 $this->joiner->from(new FromTable($table, $alias));
00243
00244 $this->aliases[$alias] = true;
00245
00246 return $this;
00247 }
00248
00255 public function get($field, $alias = null)
00256 {
00257 $table = null;
00258 if (is_object($field)) {
00259 if (
00260 ($field instanceof DBField)
00261 && ($field->getTable() === null)
00262 ) {
00263 $this->fields[] = new SelectField(
00264 $field->setTable($this->getLastTable()),
00265 $alias
00266 );
00267 } elseif ($field instanceof SelectQuery) {
00268 $this->fields[] = $field;
00269 $this->aliases[$field->getAlias()] = true;
00270 } elseif ($field instanceof DialectString) {
00271 $this->fields[] = new SelectField($field, $alias);
00272
00273 if ($field instanceof Aliased)
00274 $this->aliases[$field->getAlias()] = true;
00275 elseif ($alias)
00276 $this->aliases[$alias] = true;
00277 } else
00278 throw new WrongArgumentException('unknown field type');
00279
00280 return $this;
00281
00282 } elseif (false !== strpos($field, '*'))
00283 throw new WrongArgumentException(
00284 'do not fsck with us: specify fields explicitly'
00285 );
00286 elseif (false !== strpos($field, '.'))
00287 throw new WrongArgumentException(
00288 'forget about dot: use DBField'
00289 );
00290 else
00291 $fieldName = $field;
00292
00293 $this->fields[] = new SelectField(
00294 new DBField($fieldName, $this->getLastTable($table)), $alias
00295 );
00296
00297 $this->aliases[$alias] = true;
00298
00299 return $this;
00300 }
00301
00305 public function multiGet()
00306 {
00307 $size = func_num_args();
00308
00309 if ($size && $args = func_get_args())
00310 for ($i = 0; $i < $size; ++$i)
00311 $this->get($args[$i]);
00312
00313 return $this;
00314 }
00315
00319 public function arrayGet($array, $prefix = null)
00320 {
00321 $size = count($array);
00322
00323 if ($prefix) {
00324 for ($i = 0; $i < $size; ++$i) {
00325 if ($array[$i] instanceof DialectString) {
00326 if ($array[$i] instanceof DBField) {
00327 $alias = $prefix.$array[$i]->getField();
00328 } else {
00329 if ($array[$i] instanceof SQLFunction) {
00330 $alias =
00331 $array[$i]->setAlias(
00332 $prefix.$array[$i]->getName()
00333 )->
00334 getAlias();
00335 } else {
00336 $alias = $array[$i];
00337 }
00338 }
00339 } else {
00340 $alias = $prefix.$array[$i];
00341 }
00342
00343 $this->get($array[$i], $alias);
00344 }
00345 } else {
00346 for ($i = 0; $i < $size; ++$i) {
00347 $this->get($array[$i]);
00348 }
00349 }
00350
00351 return $this;
00352 }
00353
00354 public function getFieldsCount()
00355 {
00356 return count($this->fields);
00357 }
00358
00359 public function getTablesCount()
00360 {
00361 return $this->joiner->getTablesCount();
00362 }
00363
00364 public function getFieldNames()
00365 {
00366 $nameList = array();
00367
00368 foreach ($this->fields as $field) {
00369 if ($field instanceof SelectField)
00370 if ($alias = $field->getAlias()) {
00371 $nameList[] = $alias;
00372 continue;
00373 }
00374
00375 $nameList[] = $field->getName();
00376 }
00377
00378 return $nameList;
00379 }
00380
00381 public function toDialectString(Dialect $dialect)
00382 {
00383 $fieldList = array();
00384 foreach ($this->fields as $field) {
00385
00386 if ($field instanceof SelectQuery) {
00387
00388 Assert::isTrue(
00389 null !== $alias = $field->getName(),
00390 'can not use SelectQuery without name as get field'
00391 );
00392
00393 $fieldList[] =
00394 "({$field->toDialectString($dialect)}) AS ".
00395 $dialect->quoteField($alias);
00396 } else
00397 $fieldList[] = $field->toDialectString($dialect);
00398 }
00399
00400 $query =
00401 'SELECT '.($this->distinct ? 'DISTINCT ' : null)
00402 .implode(', ', $fieldList)
00403 .$this->joiner->toDialectString($dialect);
00404
00405
00406 $query .= parent::toDialectString($dialect);
00407
00408 if ($this->group) {
00409 $groupList = array();
00410
00411 foreach ($this->group as $group)
00412 $groupList[] = $group->toDialectString($dialect);
00413
00414 if ($groupList)
00415 $query .= ' GROUP BY '.implode(', ', $groupList);
00416 }
00417
00418 if ($this->having)
00419 $query .= ' HAVING '.$this->having->toDialectString($dialect);
00420
00421 if ($this->order->getCount()) {
00422 $query .= ' ORDER BY '.$this->order->toDialectString($dialect);
00423 }
00424
00425 if ($this->limit)
00426 $query .= ' LIMIT '.$this->limit;
00427
00428 if ($this->offset)
00429 $query .= ' OFFSET '.$this->offset;
00430
00431 return $query;
00432 }
00433
00437 public function dropFields()
00438 {
00439 $this->fields = array();
00440 return $this;
00441 }
00442
00446 public function dropOrder()
00447 {
00448 $this->order = new OrderChain();
00449 return $this;
00450 }
00451
00452 private function getLastTable($table = null)
00453 {
00454 if (!$table && ($last = $this->joiner->getLastTable()))
00455 return $last;
00456
00457 return $table;
00458 }
00459
00463 private function makeOrder($field, $table = null)
00464 {
00465 if (
00466 $field instanceof OrderBy
00467 || $field instanceof DialectString
00468 )
00469 return $field;
00470 else
00471 return
00472 new OrderBy(
00473 new DBField($field, $this->getLastTable($table))
00474 );
00475 }
00476 }
00477 ?>