Overview

Namespaces

  • zsql
  • PHP

Classes

  • Database
  • Delete
  • Expression
  • ExtendedQuery
  • Insert
  • Model
  • Query
  • Result
  • Select
  • Update

Exceptions

  • Exception
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace zsql;
  4: 
  5: /**
  6:  * Base abstract query
  7:  */
  8: abstract class Query
  9: {
 10:   /**
 11:    * The database adapter for this query
 12:    * 
 13:    * @var \zsql\Database
 14:    */
 15:   protected $database;
 16:   
 17:   /**
 18:    * Toggle whether to interpolate parameters into the query
 19:    * 
 20:    * @var boolean
 21:    */
 22:   protected $interpolation = false;
 23:   
 24:   /**
 25:    * The table
 26:    * 
 27:    * @var string
 28:    */
 29:   protected $table;
 30:   
 31:   /**
 32:    * The parameters to bind
 33:    * 
 34:    * @var array
 35:    */
 36:   protected $params;
 37:   
 38:   /**
 39:    * Array of query fragments
 40:    * 
 41:    * @var array
 42:    */
 43:   protected $parts;
 44:   
 45:   /**
 46:    * Callback to quote a string
 47:    * 
 48:    * @var callback
 49:    */
 50:   protected $quoteCallback;
 51:   
 52:   /**
 53:    * The current query
 54:    * 
 55:    * @var string
 56:    */
 57:   protected $query;
 58:   
 59:   /**
 60:    * The function to proxy calls to query to
 61:    * 
 62:    * @var callback
 63:    */
 64:   protected $queryCallback;
 65:   
 66:   /**
 67:    * The character to use to quote strings
 68:    * 
 69:    * @var string
 70:    */
 71:   protected $quoteChar = "'";
 72:   
 73:   /**
 74:    * The character to use to quote identifiers
 75:    * 
 76:    * @var string
 77:    */
 78:   protected $quoteIdentifierChar = '`';
 79:   
 80:   /**
 81:    * Constructor 
 82:    * 
 83:    * @param callback $queryCallback
 84:    */
 85:   public function __construct($queryCallback = null)
 86:   {
 87:     if( $queryCallback instanceof \zsql\Database ) {
 88:       $this->database = $queryCallback;
 89:       $this->interpolation();
 90:     } else if( is_callable($queryCallback) ) {
 91:       $this->queryCallback = $queryCallback;
 92:     } else if( $queryCallback !== null ) {
 93:       throw new \zsql\Exception('Invalid query executor');
 94:     }
 95:   }
 96:   
 97:   /**
 98:    * Magic string conversion. Alias of {@link Query::toString()}
 99:    * 
100:    * @return string
101:    */
102:   public function __toString()
103:   {
104:     try {
105:       return $this->toString();
106:     } catch( Exception $e ) {
107:       trigger_error($e->getMessage(), E_USER_WARNING);
108:       return '';
109:     }
110:   }
111:   
112:   /**
113:    * Assemble parts
114:    */
115:   abstract protected function assemble();
116:   
117:   /**
118:    * Interpolate parameters into query
119:    * 
120:    * @throws \zsql\Exception
121:    */
122:   protected function interpolateParams()
123:   {
124:     if( count($this->params) <= 0 ) {
125:       return;
126:     }
127:     if( $this->quoteCallback ) {
128:       $cb = $this->quoteCallback;
129:     } else if( $this->database ) {
130:       $cb = array($this->database, 'quote');
131:     } else {
132:       throw new \zsql\Exception('Interpolation not available without ' 
133:               . 'setting a quote callback or database adapter');
134:     }
135:     if( substr_count($this->query, '?') != count($this->params) ) {
136:       throw new \zsql\Exception('Parameter count mismatch');
137:     }
138:     
139:     $parts = explode('?', $this->query);
140:     $query = $parts[0];
141:     for( $i = 0, $l = count($this->params); $i < $l; $i++ ) {
142:       $query .= call_user_func($cb, $this->params[$i]) . $parts[$i+1];
143:     }
144:     $this->query = $query;
145:   }
146:   
147:   /**
148:    * Toggle whether to interpolate parameters into the query
149:    * 
150:    * @return \zsql\Query
151:    */
152:   public function interpolation($interpolation = true)
153:   {
154:     $this->interpolation = (bool) $interpolation;
155:     return $this;
156:   }
157:   
158:   /**
159:    * Get the parameters
160:    * 
161:    * @return array
162:    */
163:   public function params()
164:   {
165:     return (array) $this->params;
166:   }
167:   
168:   /**
169:    * Get the array of parts
170:    * 
171:    * @return array
172:    */
173:   public function parts()
174:   {
175:     return (array) $this->parts;
176:   }
177:   
178:   /**
179:    * Push an arbitrary string onto parts
180:    * 
181:    * @param string $string
182:    * @return \zsql\Query
183:    */
184:   protected function push($string)
185:   {
186:     $this->parts[] = $string;
187:     return $this;
188:   }
189:   
190:   /**
191:    * Push table onto parts
192:    * 
193:    * @return \zsql\Query
194:    * @throws \zsql\Exception
195:    */
196:   protected function pushTable()
197:   {
198:     if( empty($this->table) ) {
199:       throw new \zsql\Exception('No table specified');
200:     }
201:     $this->parts[] = $this->quoteIdentifierIfNotExpression($this->table);
202:     return $this;
203:   }
204:   
205:   /**
206:    * Push values onto parts
207:    * 
208:    * @return \zsql\Query
209:    * @throws \zsql\Exception
210:    */
211:   protected function pushValues()
212:   {
213:     if( empty($this->values) ) {
214:       throw new \zsql\Exception('No values specified');
215:     }
216:     foreach( $this->values as $key => $value ) {
217:       if( !is_int($key) ) {
218:         $this->parts[] = $this->quoteIdentifierIfNotExpression($key);
219:         $this->parts[] = '=';
220:       }
221:       if( $value instanceof Expression ) {
222:         $this->parts[] = (string) $value;
223:       } else if( !is_int($key) ) {
224:         $this->parts[] = '?';
225:         $this->params[] = $value;
226:       }
227:       $this->parts[] = ',';
228:     }
229:     array_pop($this->parts);
230:     
231:     return $this;
232:   }
233:   
234:   /**
235:    * Proxy to query callback
236:    * 
237:    * @return \zsql\Result|boolean
238:    * @throws \zsql\Exception
239:    */
240:   public function query()
241:   {
242:     if( $this->database ) {
243:       $this->interpolateParams();
244:       return $this->database->query($this);
245:     } else if( $this->queryCallback ) {
246:       $query = $this->toString();
247:       $params = $this->params();
248:       if( $this->interpolation ) {
249:         return call_user_func($this->queryCallback, $query);
250:       } else {
251:         return call_user_func($this->queryCallback, $query, $params);
252:       }
253:     } else {
254:       throw new \zsql\Exception('query() called when no callback or database adapter set');
255:     }
256:   }
257:   
258:   /**
259:    * Quotes an identifier
260:    * 
261:    * @param string $identifier
262:    * @return string
263:    */
264:   protected function quoteIdentifier($identifier)
265:   {
266:     $c = $this->quoteIdentifierChar;
267:     return $c . str_replace('.', 
268:         $c . '.' . $c, 
269:         str_replace($c, $c . $c, $identifier)) . $c;
270:   }
271:   
272:   /**
273:    * Quotes an identifier if not an {@link Expression}
274:    * 
275:    * @param mixed $identifier
276:    * @return string
277:    */
278:   protected function quoteIdentifierIfNotExpression($identifier)
279:   {
280:     if( $identifier instanceof Expression ) {
281:       return (string) $identifier;
282:     } else {
283:       return $this->quoteIdentifier($identifier);
284:     }
285:   }
286:   
287:   /**
288:    * Set the function to use to quote strings
289:    * 
290:    * @param type $callback
291:    * @return \zsql\Query
292:    * @throws \zsql\Exception
293:    */
294:   public function setQuoteCallback($callback)
295:   {
296:     if( !is_callable($callback) ) {
297:       throw new \zsql\Exception('Invalid callback specified');
298:     }
299:     $this->quoteCallback = $callback;
300:     return $this;
301:   }
302:   
303:   /**
304:    * Set the table
305:    * 
306:    * @param mixed $table
307:    * @return \zsql\Query
308:    */
309:   public function table($table)
310:   {
311:     if( $table instanceof Expression ) {
312:       $this->table = $table;
313:     } else {
314:       $this->table = (string) $table;
315:     }
316:     return $this;
317:   }
318:   
319:   /**
320:    * Convert to string
321:    * 
322:    * @return string
323:    */
324:   public function toString()
325:   {
326:     $this->parts = array();
327:     $this->params = array();
328:     $this->assemble();
329:     $this->query = join(' ', $this->parts);
330:     if( $this->interpolation ) {
331:       $this->interpolateParams();
332:     }
333:     return $this->query;
334:   }
335: }
336: 
API documentation generated by ApiGen 2.8.0