Path

ez components / documentation / api reference / 2008.1 / database


Database

[ Tutorial ] [ Class tree ] [ Element index ] [ ChangeLog ] [ Credits ]

Source for file query.php

Documentation is available at query.php

  1. <?php
  2. /**
  3.  * File containing the ezcQuery class.
  4.  *
  5.  * @package Database
  6.  * @version 1.4
  7.  * @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
  8.  * @license http://ez.no/licenses/new_bsd New BSD License
  9.  */
 10.  
 11. /**
 12.  * The ezcQuery class provides the common API for all Query objects.
 13.  *
 14.  * ezcQuery has three main purposes:
 15.  * - it provides a common API for building queries through the getQuery() method.
 16.  * - it provides a common API for binding parameters to queries through
 17.  *   bindValue() and bindParam()
 18.  * - it provides internal aliasing functionality that allows you to use
 19.  *   aliases for table and column names. The substitution is done inside of the
 20.  *   query classes before the query itself is built.
 21.  *
 22.  * Through the bind methods you can bind parameters and values to your
 23.  * query. Finally you can use prepare to get a PDOStatement object
 24.  * from your query object.
 25.  *
 26.  * Subclasses should provide functionality to build an actual query.
 27.  *
 28.  * @package Database
 29.  * @version 1.4
 30.  */
 31. abstract class ezcQuery
 32. {
 33.     /**
 34.      * A pointer to the database handler to use for this query.
 35.      *
 36.      * @var PDO 
 37.      */
 38.     protected $db;
 39.  
 40.     /**
 41.      * The column and table name aliases.
 42.      *
 43.      * Format: array('alias' => 'realName')
 44.      * @var array(string=>string) 
 45.      */
 46.     private $aliases null;
 47.  
 48.     /**
 49.      * Counter used to create unique ids in the bind methods.
 50.      *
 51.      * @var int 
 52.      */
 53.     private $boundCounter 0;
 54.  
 55.     /**
 56.      * Stores the list of parameters that will be bound with doBind().
 57.      *
 58.      * Format: array( ':name' => &mixed )
 59.      * @var array(string=>&mixed) 
 60.      */
 61.     private $boundParameters array();
 62.  
 63.     /**
 64.      * Stores the type of a value which will we used when the value is bound.
 65.      * 
 66.      * @var array(string=>int) 
 67.      */
 68.     private $boundParametersType array();
 69.  
 70.     /**
 71.      * Stores the list of values that will be bound with doBind().
 72.      *
 73.      * Format: array( ':name' => mixed )
 74.      * @var array(string=>mixed) 
 75.      */
 76.     private $boundValues array();
 77.  
 78.     /**
 79.      * Stores the type of a value which will we used when the value is bound.
 80.      * 
 81.      * @var array(string=>int) 
 82.      */
 83.     private $boundValuesType array();
 84.  
 85.     /**
 86.      * The expression object for this class.
 87.      *
 88.      * @var ezcQueryExpression 
 89.      */
 90.     public $expr = null;
 91.  
 92.     /**
 93.      * Constructs a new ezcQuery that works on the database $db and with the aliases $aliases.
 94.      *
 95.      * The aliases can be used to substitute the column and table names with more
 96.      * friendly names. E.g PersistentObject uses it to allow using property and class
 97.      * names instead of column and table names.
 98.      *
 99.      * @param PDO $db 
100.      * @param array(string=>string) $aliases 
101.      */
102.     public function __constructPDO $dbarray $aliases array() )
103.     {
104.         $this->db = $db;
105.         if $this->expr == null )
106.         {
107.             $this->expr = $db->createExpression();
108.         }
109.         if !empty$aliases ) )
110.         {
111.             $this->aliases $aliases;
112.             $this->expr->setAliases$this->aliases );
113.         }
114.     }
115.  
116.     /**
117.      * Sets the aliases $aliases for this object.
118.      *
119.      * The aliases should be in the form array( "aliasName" => "databaseName" )
120.      * Each alias defines a relation between a user-defined name and a name
121.      * in the database. This is supported for table names as column names.
122.      *
123.      * The aliases can be used to substitute the column and table names with more
124.      * friendly names. The substitution is done when the query is built, not using
125.      * AS statements in the database itself.
126.      *
127.      * Example of a select query with aliases:
128.      * <code>
129.      * <?php
130.      * $q->setAliases( array( 'Identifier' => 'id', 'Company' => 'company' ) );
131.      * $q->select( 'Company' )
132.      *   ->from( 'table' )
133.      *   ->where( $q->expr->eq( 'Identifier', 5 ) );
134.      * echo $q->getQuery();
135.      * ?>
136.      * </code>
137.      *
138.      * This example will output SQL similar to:
139.      * <code>
140.      * SELECT company FROM table WHERE id = 5
141.      * </code>
142.      *
143.      * Aliasses also take effect for composite names in the form
144.      * tablename.columnname as the following example shows:
145.      * <code>
146.      * <?php
147.      * $q->setAliases( array( 'Order' => 'orders', 'Recipient' => 'company' ) );
148.      * $q->select( 'Order.Recipient' )
149.      *   ->from( 'Order' );
150.      * echo $q->getQuery();
151.      * ?>
152.      * </code>
153.      *
154.      * This example will output SQL similar to:
155.      * <code>
156.      * SELECT orders.company FROM orders;
157.      * </code>
158.      *
159.      * It is even possible to have an alias point to a table name/column name
160.      * combination. This will only work for alias names without a . (dot):
161.      * <code>
162.      * <?php
163.      * $q->setAliases( array( 'Order' => 'orders', 'Recipient' => 'orders.company' ) );
164.      * $q->select( 'Recipient' )
165.      *   ->from( 'Order' );
166.      * echo $q->getQuery();
167.      * ?>
168.      * </code>
169.      *
170.      * This example will output SQL similar to:
171.      * <code>
172.      * SELECT orders.company FROM orders;
173.      * </code>
174.      *
175.      * In the following example, the Recipient alias will not be used, as it is
176.      * points to a fully qualified name - the Order alias however is used:
177.      * <code>
178.      * <?php
179.      * $q->setAliases( array( 'Order' => 'orders', 'Recipient' => 'orders.company' ) );
180.      * $q->select( 'Order.Recipient' )
181.      *   ->from( 'Order' );
182.      * echo $q->getQuery();
183.      * ?>
184.      * </code>
185.      *
186.      * This example will output SQL similar to:
187.      * <code>
188.      * SELECT orders.Recipient FROM orders;
189.      * </code>
190.      *
191.      * @param array(string=>string) $aliases 
192.      * @return void 
193.      */
194.     public function setAliasesarray $aliases )
195.     {
196.         $this->aliases $aliases;
197.         $this->expr->setAliases$aliases );
198.     }
199.  
200.     /**
201.      * Returns true if this object has aliases.
202.      *
203.      * @return bool 
204.      */
205.     public function hasAliases()
206.     {
207.         return $this->aliases !== null true false;
208.     }
209.  
210.     /**
211.      * Returns the correct identifier for the alias $alias.
212.      *
213.      * If the alias does not exists in the list of aliases
214.      * it is returned unchanged.
215.      *
216.      * This can method handles composite identifiers separated by a dot ('.').
217.      *
218.      * @param string $alias 
219.      * @return string 
220.      */
221.     protected function getIdentifier$alias )
222.     {
223.         $aliasParts explode'.'$alias );
224.         $identifiers array();
225.         // If the alias consists of one part, then we just look it up in the
226.         // array. If we find it, we use it, otherwise we return the name as-is
227.         // and assume it's just a column name. The alias target can be a fully
228.         // qualified name (table.column).
229.         if count$aliasParts == )
230.         {
231.             if $this->aliases !== null &&
232.                 array_key_exists$alias$this->aliases ) )
233.             {
234.                 $alias $this->aliases[$alias];
235.             }
236.             return $alias;
237.         }
238.         // If the passed name consist of two parts, we need to check all parts
239.         // of the passed-in name for aliases, because an alias can be made for
240.         // both a table name and a column name. For each element we try to find
241.         // whether we have an alias mapping. Unlike the above case, the alias
242.         // target can in this case *not* consist of a fully qualified name as
243.         // this would introduce another part of the name (with two dots).
244.         for $i 0$i count$aliasParts )$i++ )
245.         {
246.             if $this->aliases !== null &&
247.                 array_key_exists$aliasParts[$i]$this->aliases ) )
248.             {
249.                 // We only use the found alias if the alias target is not a fully
250.                 // qualified name (table.column).
251.                 $tmpAlias $this->aliases[$aliasParts[$i]];
252.                 if countexplode'.'$tmpAlias ) ) === )
253.                 {
254.                     $aliasParts[$i$this->aliases[$aliasParts[$i]];
255.                 }
256.             }
257.         }
258.         $alias join'.'$aliasParts );
259.         return $alias;
260.     }
261.  
262.     /**
263.      * Returns the correct identifiers for the aliases found in $aliases.
264.      *
265.      * This method is similar to getIdentifier except that it works on an array.
266.      *
267.      * @param array(string) $aliasList 
268.      * @return array(string) 
269.      */
270.     protected function getIdentifiersarray $aliasList )
271.     {
272.         if $this->aliases !== null )
273.         {
274.             foreach $aliasList as $key => $alias )
275.             {
276.                 $aliasList[$key$this->getIdentifier$alias );
277.             }
278.         }
279.         return $aliasList;
280.     }
281.  
282.     /**
283.      * Binds the value $value to the specified variable name $placeHolder.
284.      *
285.      * This method provides a shortcut for PDOStatement::bindValue
286.      * when using prepared statements.
287.      *
288.      * The parameter $value specifies the value that you want to bind. If
289.      * $placeholder is not provided bindValue() will automatically create a
290.      * placeholder for you. An automatic placeholder will be of the name
291.      * 'ezcValue1', 'ezcValue2' etc.
292.      *
293.      * For more information see {@link http://php.net/pdostatement-bindparam}
294.      *
295.      * Example:
296.      * <code>
297.      * $value = 2;
298.      * $q->eq( 'id', $q->bindValue( $value ) );
299.      * $stmt = $q->prepare(); // the value 2 is bound to the query.
300.      * $value = 4;
301.      * $stmt->execute(); // executed with 'id = 2'
302.      * </code>
303.      *
304.      * @see doBind()
305.      * @param mixed $value 
306.      * @param string $placeHolder the name to bind with. The string must start with a colon ':'.
307.      * @return string the placeholder name used.
308.      */
309.     public function bindValue$value$placeHolder null$type PDO::PARAM_STR )
310.     {
311.         if $placeHolder === null )
312.         {
313.             $this->boundCounter++;
314.             $placeHolder ":ezcValue{$this->boundCounter}";
315.         }
316.  
317.         $this->boundValues[$placeHolder$value;
318.         $this->boundValuesType[$placeHolder$type;
319.  
320.         return $placeHolder;
321.     }
322.  
323.     /**
324.      * Binds the parameter $param to the specified variable name $placeHolder..
325.      *
326.      * This method provides a shortcut for PDOStatement::bindParam
327.      * when using prepared statements.
328.      *
329.      * The parameter $param specifies the variable that you want to bind. If
330.      * $placeholder is not provided bind() will automatically create a
331.      * placeholder for you. An automatic placeholder will be of the name
332.      * 'ezcValue1', 'ezcValue2' etc.
333.      *
334.      * For more information see {@link http://php.net/pdostatement-bindparam}
335.      *
336.      * Example:
337.      * <code>
338.      * $value = 2;
339.      * $q->eq( 'id', $q->bindParam( $value ) );
340.      * $stmt = $q->prepare(); // the parameter $value is bound to the query.
341.      * $value = 4;
342.      * $stmt->execute(); // executed with 'id = 4'
343.      * </code>
344.      *
345.      * @see doBind()
346.      * @param &mixed $param 
347.      * @param string $placeHolder the name to bind with. The string must start with a colon ':'.
348.      * @return string the placeholder name used.
349.      */
350.     public function bindParam&$param$placeHolder null$type PDO::PARAM_STR )
351.     {
352.         if $placeHolder === null )
353.         {
354.             $this->boundCounter++;
355.             $placeHolder ":ezcValue{$this->boundCounter}";
356.         }
357.         
358.         $this->boundParameters[$placeHolder=$param;
359.         $this->boundParametersType[$placeHolder$type;
360.  
361.         return $placeHolder;
362.     }
363.  
364.     /**
365.      * Resets the bound values and parameters to empty.
366.      *
367.      * This is useful if your query can be reset and used multiple times.
368.      *
369.      * @return void 
370.      */
371.     protected function resetBinds()
372.     {
373.         $this->boundCounter 0;
374.         $this->boundParameters array();
375.         $this->boundValues array();
376.     }
377.  
378.     /**
379.      * Performs binding of variables bound with bindValue and bindParam on the statement $stmt.
380.      *
381.      * This method must be called if you have used the bind methods
382.      * in your query and you build the method yourself using build.
383.      *
384.      * @param PDOStatement $stmt 
385.      * @return void 
386.      */
387.     public function doBindPDOStatement $stmt )
388.     {
389.         foreach $this->boundValues as $key => $value )
390.         {
391.             try
392.             {
393.                 $stmt->bindValue$key$value$this->boundValuesType[$key);
394.             }
395.             catch PDOException $e )
396.             {
397.                 // see comment below
398.             }
399.         }
400.         foreach $this->boundParameters as $key => &$value )
401.         {
402.             try
403.             {
404.                 $stmt->bindParam$key$value$this->boundParametersType[$key);
405.             }
406.             catch PDOException $e )
407.             {
408.                 // we are ignoring this exception since it may only occur when
409.                 // a bound parameter is not found in the query anymore.
410.                 // this can happen if either drop an expression with a bound value
411.                 // created with this query or if you remove a bind in a query by
412.                 // replacing it with another one.
413.                 // the only other way to avoid this problem is parse the string for the
414.                 // bound variables. Note that a simple search will not do since the variable
415.                 // name may occur in a string.
416.             }
417.         }
418.     }
419.  
420.     /**
421.      * Returns a prepared statement from this query which can be used for execution.
422.      *
423.      * The returned object is a PDOStatement for which you can find extensive
424.      * documentation in the PHP manual:
425.      * {@link http://php.net/pdostatement-bindcolumn}
426.      *
427.      * prepare() automatically calls doBind() on the statement.
428.      * @return PDOStatement 
429.      */
430.     public function prepare()
431.     {
432.         $stmt $this->db->prepare$this->getQuery() );
433.         $this->doBind$stmt );
434.         return $stmt;
435.     }
436.  
437.     /**
438.      * Returns all the elements in $array as one large single dimensional array.
439.      *
440.      * @todo public? Currently this is needed for QueryExpression.
441.      * @param array $array 
442.      * @return array 
443.      */
444.     static public function arrayFlattenarray $array )
445.     {
446.         $flat array();
447.         foreach $array as $arg )
448.         {
449.             switch gettype$arg ) )
450.             {
451.                 case 'array':
452.                     $flat array_merge$flat$arg );
453.                     break;
454.  
455.                 default:
456.                     $flat[$arg;
457.                     break;
458.             }
459.         }
460.         return $flat;
461.     }
462.  
463.     /**
464.      * Return SQL string for query.
465.      *
466.      * Typecasting to (string) should be used to make __toString() to be called
467.      * with PHP 5.1.  This will not be needed in PHP 5.2 and higher when this
468.      * object is used in a string context.
469.      *
470.      * Example:
471.      * <code>
472.      * $q->select('*')
473.      *   ->from( 'table1' )
474.      *   ->where ( $q->expr->eq( 'name', $q->bindValue( "Beeblebrox" ) ) );
475.      * echo $q, "\n";
476.      * </code>
477.      *
478.      * @return string 
479.      */
480.     public function __toString()
481.     {
482.         return $this->getQuery();
483.     }
484.  
485.     /**
486.      * Returns the ezcQuerySubSelect query object.
487.      *
488.      * This method creates new ezcQuerySubSelect object
489.      * that could be used for building correct
490.      * subselect inside query.
491.      *
492.      * @return ezcQuerySubSelect 
493.      */
494.     public function subSelect()
495.     {
496.         return new ezcQuerySubSelect$this );
497.     }
498.  
499.     /**
500.      * Returns the query string for this query object.
501.      *
502.      * @throws ezcQueryInvalidException if it was not possible to build a valid query.
503.      * @return string 
504.      */
505.     abstract public function getQuery();
506.  
507. ?>
Last updated: Wed, 18 Jun 2008