SelectQuery.class.php

Go to the documentation of this file.
00001 <?php
00002 /****************************************************************************
00003  *   Copyright (C) 2004-2007 by Konstantin V. Arkhipov, Anton E. Lebedevich *
00004  *                                                                          *
00005  *   This program is free software; you can redistribute it and/or modify   *
00006  *   it under the terms of the GNU Lesser General Public License as         *
00007  *   published by the Free Software Foundation; either version 3 of the     *
00008  *   License, or (at your option) any later version.                        *
00009  *                                                                          *
00010  ****************************************************************************/
00011 
00015     final class SelectQuery
00016         extends QuerySkeleton
00017         implements Named, JoinCapableQuery, Aliased
00018     {
00019         private $distinct       = false;
00020         
00021         private $name           = null;
00022         
00023         private $joiner         = null;
00024         
00025         private $limit          = null;
00026         private $offset         = null;
00027         
00028         private $fields         = array();
00029         
00030         private $order          = null;
00031         
00032         private $group          = array();
00033         
00034         private $having         = null;
00035         
00036         public function __construct()
00037         {
00038             $this->joiner = new Joiner();
00039             $this->order = new OrderChain();
00040         }
00041         
00042         public function __clone()
00043         {
00044             $this->joiner = clone $this->joiner;
00045             $this->order = clone $this->order;
00046         }
00047         
00048         public function hasAliasInside($alias)
00049         {
00050             return isset($this->aliases[$alias]);
00051         }
00052         
00053         public function getAlias()
00054         {
00055             return $this->name;
00056         }
00057         
00058         public function getName()
00059         {
00060             return $this->name;
00061         }
00062         
00066         public function setName($name)
00067         {
00068             $this->name = $name;
00069             $this->aliases[$name] = true;
00070             
00071             return $this;
00072         }
00073         
00077         public function distinct()
00078         {
00079             $this->distinct = true;
00080             return $this;
00081         }
00082         
00083         public function isDistinct()
00084         {
00085             return $this->distinct;
00086         }
00087         
00091         public function unDistinct()
00092         {
00093             $this->distinct = false;
00094             return $this;
00095         }
00096         
00097         public function hasJoinedTable($table)
00098         {
00099             return $this->joiner->hasJoinedTable($table);
00100         }
00101         
00105         public function join($table, LogicalObject $logic, $alias = null)
00106         {
00107             $this->joiner->join(new SQLJoin($table, $logic, $alias));
00108             $this->aliases[$alias] = true;
00109             
00110             return $this;
00111         }
00112         
00116         public function leftJoin($table, LogicalObject $logic, $alias = null)
00117         {
00118             $this->joiner->leftJoin(new SQLLeftJoin($table, $logic, $alias));
00119             $this->aliases[$alias] = true;
00120             
00121             return $this;
00122         }
00123         
00127         public function rightJoin($table, LogicalObject $logic, $alias = null)
00128         {
00129             $this->joiner->rightJoin(new SQLRightJoin($table, $logic, $alias));
00130             $this->aliases[$alias] = true;
00131             
00132             return $this;
00133         }
00134         
00138         public function setOrderChain(OrderChain $chain)
00139         {
00140             $this->order = $chain;
00141             
00142             return $this;
00143         }
00144         
00148         public function orderBy($field, $table = null)
00149         {
00150             $this->order->add($this->makeOrder($field, $table));
00151             
00152             return $this;
00153         }
00154         
00158         public function prependOrderBy($field, $table = null)
00159         {
00160             $this->order->prepend($this->makeOrder($field, $table));
00161             
00162             return $this;
00163         }
00164         
00169         public function desc()
00170         {
00171             if (!$last = $this->order->getLast())
00172                 throw new WrongStateException('no fields to sort');
00173             
00174             $last->desc();
00175             
00176             return $this;
00177         }
00178         
00183         public function asc()
00184         {
00185             if (!$last = $this->order->getLast())
00186                 throw new WrongStateException('no fields to sort');
00187             
00188             $last->asc();
00189             
00190             return $this;
00191         }
00192         
00196         public function groupBy($field, $table = null)
00197         {
00198             if ($field instanceof DialectString)
00199                 $this->group[] = $field;
00200             else
00201                 $this->group[] =
00202                     new DBField($field, $this->getLastTable($table));
00203             
00204             return $this;
00205         }
00206         
00210         public function dropGroupBy()
00211         {
00212             $this->group = array();
00213             return $this;
00214         }
00215         
00219         public function having(LogicalObject $exp)
00220         {
00221             $this->having = $exp;
00222             
00223             return $this;
00224         }
00225         
00226         public function getLimit()
00227         {
00228             return $this->limit;
00229         }
00230         
00231         public function getOffset()
00232         {
00233             return $this->offset;
00234         }
00235         
00240         public function limit($limit = null, $offset = null)
00241         {
00242             if ($limit !== null)
00243                 Assert::isPositiveInteger($limit, 'invalid limit specified');
00244                 
00245             if ($offset !== null)
00246                 Assert::isInteger($offset, 'invalid offset specified');
00247             
00248             $this->limit = $limit;
00249             $this->offset = $offset;
00250             
00251             return $this;
00252         }
00253         
00257         public function from($table, $alias = null)
00258         {
00259             $this->joiner->from(new FromTable($table, $alias));
00260             
00261             $this->aliases[$alias] = true;
00262             
00263             return $this;
00264         }
00265         
00266         public function getFirstTable()
00267         {
00268             return $this->joiner->getFirstTable();
00269         }
00270         
00275         public function get($field, $alias = null)
00276         {
00277             $this->fields[] =
00278                 $this->resolveSelectField(
00279                     $field,
00280                     $alias,
00281                     $this->getLastTable()
00282                 );
00283             
00284             if ($alias = $this->resolveAliasByField($field, $alias)) {
00285                 $this->aliases[$alias] = true;
00286             }
00287             
00288             return $this;
00289         }
00290         
00294         public function multiGet(/* ... */)
00295         {
00296             $size = func_num_args();
00297         
00298             if ($size && $args = func_get_args())
00299                 for ($i = 0; $i < $size; ++$i)
00300                     $this->get($args[$i]);
00301         
00302             return $this;
00303         }
00304         
00308         public function arrayGet($array, $prefix = null)
00309         {
00310             $size = count($array);
00311             
00312             if ($prefix) {
00313                 for ($i = 0; $i < $size; ++$i) {
00314                     if ($array[$i] instanceof DialectString) {
00315                         if ($array[$i] instanceof DBField) {
00316                             $alias = $prefix.$array[$i]->getField();
00317                         } else {
00318                             if ($array[$i] instanceof SQLFunction) {
00319                                 $alias =
00320                                     $array[$i]->setAlias(
00321                                         $prefix.$array[$i]->getName()
00322                                     )->
00323                                     getAlias();
00324                             } else {
00325                                 $alias = $array[$i];
00326                             }
00327                         }
00328                     } else {
00329                         $alias = $prefix.$array[$i];
00330                     }
00331                     
00332                     $this->get($array[$i], $alias);
00333                 }
00334             } else {
00335                 for ($i = 0; $i < $size; ++$i) {
00336                     $this->get($array[$i]);
00337                 }
00338             }
00339             
00340             return $this;
00341         }
00342         
00343         public function getFieldsCount()
00344         {
00345             return count($this->fields);
00346         }
00347         
00348         public function getTablesCount()
00349         {
00350             return $this->joiner->getTablesCount();
00351         }
00352         
00353         public function getFieldNames()
00354         {
00355             $nameList = array();
00356             
00357             foreach ($this->fields as $field) {
00358                 if ($field instanceof SelectField)
00359                     if ($alias = $field->getAlias()) {
00360                         $nameList[] = $alias;
00361                         continue;
00362                     }
00363                 
00364                 $nameList[] = $field->getName();
00365             }
00366             
00367             return $nameList;
00368         }
00369         
00370         public function returning($field, $alias = null)
00371         {
00372             throw new UnsupportedMethodException();
00373         }
00374         
00375         public function toDialectString(Dialect $dialect)
00376         {
00377             $fieldList = array();
00378             
00379             foreach ($this->fields as $field)
00380                 $fieldList[] = $this->toDialectStringField($field, $dialect);
00381             
00382             $query =
00383                 'SELECT '.($this->distinct ? 'DISTINCT ' : null)
00384                 .implode(', ', $fieldList)
00385                 .$this->joiner->toDialectString($dialect);
00386                 
00387             // WHERE
00388             $query .= parent::toDialectString($dialect);
00389             
00390             if ($this->group) {
00391                 $groupList = array();
00392                 
00393                 foreach ($this->group as $group)
00394                     $groupList[] = $group->toDialectString($dialect);
00395                 
00396                 if ($groupList)
00397                     $query .= ' GROUP BY '.implode(', ', $groupList);
00398             }
00399             
00400             if ($this->having)
00401                 $query .= ' HAVING '.$this->having->toDialectString($dialect);
00402             
00403             if ($this->order->getCount()) {
00404                 $query .= ' ORDER BY '.$this->order->toDialectString($dialect);
00405             }
00406             
00407             if ($this->limit)
00408                 $query .= ' LIMIT '.$this->limit;
00409             
00410             if ($this->offset)
00411                 $query .= ' OFFSET '.$this->offset;
00412             
00413             return $query;
00414         }
00415         
00419         public function dropFields()
00420         {
00421             $this->fields = array();
00422             return $this;
00423         }
00424         
00428         public function dropOrder()
00429         {
00430             $this->order = new OrderChain();
00431             return $this;
00432         }
00433         
00437         public function dropLimit()
00438         {
00439             $this->limit = $this->offset = null;
00440             return $this;
00441         }
00442         
00443         private function getLastTable($table = null)
00444         {
00445             if (!$table && ($last = $this->joiner->getLastTable()))
00446                 return $last;
00447             
00448             return $table;
00449         }
00450         
00454         private function makeOrder($field, $table = null)
00455         {
00456             if (
00457                 $field instanceof OrderBy
00458                 || $field instanceof DialectString
00459             )
00460                 return $field;
00461             else
00462                 return
00463                     new OrderBy(
00464                         new DBField($field, $this->getLastTable($table))
00465                     );
00466         }
00467     }
00468 ?>