OqlSelectParser.class.php

Go to the documentation of this file.
00001 <?php
00002 /****************************************************************************
00003  *   Copyright (C) 2008 by Vladlen Y. Koshelev                              *
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 
00032     final class OqlSelectParser extends OqlParser
00033     {
00034         // states
00035         const PROPERTY_STATE    = 1;
00036         const FROM_STATE        = 2;
00037         const WHERE_STATE       = 3;
00038         const GROUP_BY_STATE    = 4;
00039         const ORDER_BY_STATE    = 5;
00040         const HAVING_STATE      = 6;
00041         const LIMIT_STATE       = 7;
00042         const OFFSET_STATE      = 8;
00043         
00047         public static function create()
00048         {
00049             return new self;
00050         }
00051         
00055         protected function makeOqlObject()
00056         {
00057             return OqlSelectQuery::create();
00058         }
00059         
00060         protected function handleState()
00061         {
00062             switch ($this->state) {
00063                 case self::INITIAL_STATE:
00064                 case self::PROPERTY_STATE:
00065                     return $this->propertyState();
00066                 
00067                 case self::FROM_STATE:
00068                     return $this->fromState();
00069                 
00070                 case self::WHERE_STATE:
00071                     return $this->whereState();
00072                 
00073                 case self::GROUP_BY_STATE:
00074                     return $this->groupByState();
00075                 
00076                 case self::ORDER_BY_STATE:
00077                     return $this->orderByState();
00078                 
00079                 case self::HAVING_STATE:
00080                     return $this->havingState();
00081                 
00082                 case self::LIMIT_STATE:
00083                     return $this->limitState();
00084                 
00085                 case self::OFFSET_STATE:
00086                     return $this->offsetState();
00087             }
00088             
00089             throw new WrongStateException('state machine is broken');
00090         }
00091         
00092         private function propertyState()
00093         {
00094             $token = $this->tokenizer->peek();
00095             
00096             if (!$token)
00097                 $this->error("expecting 'from' clause");
00098             
00099             if ($this->checkKeyword($token, 'from'))
00100                 return self::FROM_STATE;
00101             
00102             $clause = OqlSelectPropertiesParser::create()->
00103                 setTokenizer($this->tokenizer)->
00104                 parse();
00105             
00106             $this->oqlObject->addProperties($clause);
00107             if ($clause->isDistinct())
00108                 $this->oqlObject->setDistinct(true);
00109             
00110             return self::FROM_STATE;
00111         }
00112         
00113         private function fromState()
00114         {
00115             if ($this->checkKeyword($this->tokenizer->peek(), 'from')) {
00116                 $this->tokenizer->next();
00117                 
00118                 $class = $this->tokenizer->next();
00119                 $className = $this->getTokenValue($class, true);
00120                 
00121                 if (
00122                     !$this->checkIdentifier($class)
00123                     || !ClassUtils::isClassName($className)
00124                 ) {
00125                     $this->error('invalid class name:', $className);
00126                 }
00127                 
00128                 if (!class_exists($className, true))
00129                     $this->error('class does not exists:', $className);
00130                 
00131                 if (!ClassUtils::isInstanceOf($className, 'DAOConnected'))
00132                     $this->error('class must implement DAOConnected interface:', $className);
00133                 
00134                 $this->oqlObject->setDao(
00135                     call_user_func(array($className, 'dao'))
00136                 );
00137             
00138             } else
00139                 $this->error("expecting 'from' clause");
00140             
00141             return self::WHERE_STATE;
00142         }
00143         
00144         private function whereState()
00145         {
00146             if ($this->checkKeyword($this->tokenizer->peek(), 'where')) {
00147                 $this->tokenizer->next();
00148                 
00149                 $this->oqlObject->where(
00150                     OqlWhereParser::create()->
00151                         setTokenizer($this->tokenizer)->
00152                         parse()
00153                 );
00154             }
00155             
00156             return self::GROUP_BY_STATE;
00157         }
00158         
00159         private function groupByState()
00160         {
00161             if ($this->checkKeyword($this->tokenizer->peek(), 'group by')) {
00162                 $this->tokenizer->next();
00163                 
00164                 $this->oqlObject->addGroupBy(
00165                     OqlGroupByParser::create()->
00166                         setTokenizer($this->tokenizer)->
00167                         parse()
00168                 );
00169             }
00170             
00171             return self::ORDER_BY_STATE;
00172         }
00173         
00174         private function orderByState()
00175         {
00176             if ($this->checkKeyword($this->tokenizer->peek(), 'order by')) {
00177                 $this->tokenizer->next();
00178                 
00179                 $this->oqlObject->addOrderBy(
00180                     OqlOrderByParser::create()->
00181                         setTokenizer($this->tokenizer)->
00182                         parse()
00183                 );
00184             }
00185             
00186             return self::HAVING_STATE;
00187         }
00188         
00189         private function havingState()
00190         {
00191             if ($this->checkKeyword($this->tokenizer->peek(), 'having')) {
00192                 $this->tokenizer->next();
00193                 
00194                 $this->oqlObject->addHaving(
00195                     OqlHavingParser::create()->
00196                         setTokenizer($this->tokenizer)->
00197                         parse()
00198                 );
00199             }
00200             
00201             return self::LIMIT_STATE;
00202         }
00203         
00204         private function limitState()
00205         {
00206             if ($this->checkKeyword($this->tokenizer->peek(), 'limit')) {
00207                 $this->tokenizer->next();
00208                 
00209                 $token = $this->tokenizer->next();
00210                 if (
00211                     $this->checkToken($token, OqlToken::NUMBER)
00212                     || $this->checkToken($token, OqlToken::SUBSTITUTION)
00213                 ) {
00214                     $this->oqlObject->setLimit(
00215                         $this->makeQueryParameter($token)
00216                     );
00217                 
00218                 } else {
00219                     $this->error("expecting 'limit' expression");
00220                 }
00221             }
00222             
00223             return self::OFFSET_STATE;
00224         }
00225         
00226         private function offsetState()
00227         {
00228             if ($this->checkKeyword($this->tokenizer->peek(), 'offset')) {
00229                 $this->tokenizer->next();
00230                 
00231                 $token = $this->tokenizer->next();
00232                 if (
00233                     $this->checkToken($token, OqlToken::NUMBER)
00234                     || $this->checkToken($token, OqlToken::SUBSTITUTION)
00235                 ) {
00236                     $this->oqlObject->setOffset(
00237                         $this->makeQueryParameter($token)
00238                     );
00239                 
00240                 } else {
00241                     $this->error("expecting 'offset' expression");
00242                 }
00243             }
00244             
00245             if ($token = $this->tokenizer->peek())
00246                 $this->error('unexpected:', $this->getTokenValue($token, true));
00247             
00248             return self::FINAL_STATE;
00249         }
00250     }
00251 ?>