ArangoDB-PHP API Documentation
  • Namespace
  • Class
  • Deprecated

Namespaces

  • triagens
    • ArangoDb

Classes

  • triagens\ArangoDb\AdminHandler
  • triagens\ArangoDb\AqlUserFunction
  • triagens\ArangoDb\Autoloader
  • triagens\ArangoDb\Batch
  • triagens\ArangoDb\BatchPart
  • triagens\ArangoDb\BindVars
  • triagens\ArangoDb\Collection
  • triagens\ArangoDb\CollectionHandler
  • triagens\ArangoDb\Connection
  • triagens\ArangoDb\ConnectionOptions
  • triagens\ArangoDb\Cursor
  • triagens\ArangoDb\Database
  • triagens\ArangoDb\DefaultValues
  • triagens\ArangoDb\Document
  • triagens\ArangoDb\DocumentHandler
  • triagens\ArangoDb\Edge
  • triagens\ArangoDb\EdgeDefinition
  • triagens\ArangoDb\EdgeHandler
  • triagens\ArangoDb\Endpoint
  • triagens\ArangoDb\Export
  • triagens\ArangoDb\ExportCursor
  • triagens\ArangoDb\Graph
  • triagens\ArangoDb\GraphHandler
  • triagens\ArangoDb\Handler
  • triagens\ArangoDb\HttpHelper
  • triagens\ArangoDb\HttpResponse
  • triagens\ArangoDb\QueryCacheHandler
  • triagens\ArangoDb\QueryHandler
  • triagens\ArangoDb\Statement
  • triagens\ArangoDb\TraceRequest
  • triagens\ArangoDb\TraceResponse
  • triagens\ArangoDb\Transaction
  • triagens\ArangoDb\Traversal
  • triagens\ArangoDb\UpdatePolicy
  • triagens\ArangoDb\UrlHelper
  • triagens\ArangoDb\Urls
  • triagens\ArangoDb\User
  • triagens\ArangoDb\UserHandler
  • triagens\ArangoDb\ValueValidator
  • triagens\ArangoDb\Vertex
  • triagens\ArangoDb\VertexHandler

Exceptions

  • triagens\ArangoDb\ClientException
  • triagens\ArangoDb\ConnectException
  • triagens\ArangoDb\Exception
  • triagens\ArangoDb\ServerException
  1 <?php
  2 
  3 /**
  4  * ArangoDB PHP client: statement
  5  *
  6  * @package   triagens\ArangoDb
  7  * @author    Jan Steemann
  8  * @copyright Copyright 2012, triagens GmbH, Cologne, Germany
  9  */
 10 
 11 namespace triagens\ArangoDb;
 12 
 13 /**
 14  * Container for an AQL query
 15  *
 16  * Optional bind parameters can be used when issuing the AQL query to separate
 17  * the query from the values.
 18  * Executing a query will result in a cursor being created.
 19  *
 20  * There is an important distinction between two different types of statements:
 21  * <ul>
 22  * <li> statements that produce an array of documents as their result AND<br />
 23  * <li> statements that do not produce documents
 24  * </ul>
 25  *
 26  * For example, a statement such as "FOR e IN example RETURN e" will produce
 27  * an array of documents as its result. The result can be treated as an array of
 28  * documents, and each document can be updated and sent back to the server by
 29  * the client.<br />
 30  * <br />
 31  * However, the query "RETURN 1 + 1" will not produce an array of documents as
 32  * its result, but an array with a single scalar value (the number 2).
 33  * "2" is not a valid document so creating a document from it will fail.<br />
 34  * <br />
 35  * To turn the results of this query into a document, the following needs to
 36  * be done:
 37  * <ul>
 38  * <li> modify the query to "RETURN { value: 1 + 1 }". The result will then be a
 39  *   an array of documents with a "value" attribute<br />
 40  * <li> use the "_flat" option for the statement to indicate that you don't want
 41  *   to treat the statement result as an array of documents, but as a flat array
 42  * </ul>
 43  *
 44  * @package triagens\ArangoDb
 45  * @since   0.2
 46  */
 47 class Statement
 48 {
 49     /**
 50      * The connection object
 51      *
 52      * @var Connection
 53      */
 54     private $_connection;
 55 
 56     /**
 57      * The bind variables and values used for the statement
 58      *
 59      * @var BindVars
 60      */
 61     private $_bindVars;
 62 
 63     /**
 64      * The current batch size (number of result documents retrieved per round-trip)
 65      *
 66      * @var mixed
 67      */
 68     private $_batchSize;
 69 
 70     /**
 71      * The count flag (should server return total number of results)
 72      *
 73      * @var bool
 74      */
 75     private $_doCount = false;
 76 
 77     /**
 78      * The count flag (should server return total number of results ignoring the limit)
 79      * Be careful! This option also prevents ArangoDB from using some server side optimizations!
 80      *
 81      * @var bool
 82      */
 83     private $_fullCount = false;
 84 
 85     /**
 86      * The query string
 87      *
 88      * @var string
 89      */
 90     private $_query;
 91 
 92     /**
 93      * "flat" flag (if set, the query results will be treated as a simple array, not documents)
 94      *
 95      * @var bool
 96      */
 97     private $_flat = false;
 98 
 99     /**
100      * Sanitation flag (if set, the _id and _rev attributes will be removed from the results)
101      *
102      * @var bool
103      */
104     private $_sanitize = false;
105 
106     /**
107      * Number of retries in case a deadlock occurs
108      *
109      * @var bool
110      */
111     private $_retries = 0;
112 
113     /**
114      * Whether or not the query cache should be consulted
115      *
116      * @var bool
117      */
118     private $_cache;
119 
120     /**
121      * resultType
122      *
123      * @var string
124      */
125     private $resultType;
126 
127 
128     /**
129      * Query string index
130      */
131     const ENTRY_QUERY = 'query';
132 
133     /**
134      * Count option index
135      */
136     const ENTRY_COUNT = 'count';
137 
138     /**
139      * Batch size index
140      */
141     const ENTRY_BATCHSIZE = 'batchSize';
142 
143     /**
144      * Retries index
145      */
146     const ENTRY_RETRIES = 'retries';
147 
148     /**
149      * Bind variables index
150      */
151     const ENTRY_BINDVARS = 'bindVars';
152 
153     /**
154      * Full count option index
155      */
156     const FULL_COUNT = 'fullCount';
157 
158     /**
159      * Initialise the statement
160      *
161      * The $data property can be used to specify the query text and further
162      * options for the query.
163      *
164      * An important consideration when creating a statement is whether the
165      * statement will produce a list of documents as its result or any other
166      * non-document value. When a statement is created, by default it is
167      * assumed that the statement will produce documents. If this is not the
168      * case, executing a statement that returns non-documents will fail.
169      *
170      * To explicitly mark the statement as returning non-documents, the '_flat'
171      * option should be specified in $data.
172      *
173      * @throws Exception
174      *
175      * @param Connection $connection - the connection to be used
176      * @param array      $data       - statement initialization data
177      */
178     public function __construct(Connection $connection, array $data)
179     {
180         $this->_connection = $connection;
181         $this->_bindVars   = new BindVars();
182 
183         if (isset($data[self::ENTRY_QUERY])) {
184             $this->setQuery($data[self::ENTRY_QUERY]);
185         }
186 
187         if (isset($data[self::ENTRY_COUNT])) {
188             $this->setCount($data[self::ENTRY_COUNT]);
189         }
190 
191         if (isset($data[self::ENTRY_BATCHSIZE])) {
192             $this->setBatchSize($data[self::ENTRY_BATCHSIZE]);
193         }
194 
195         if (isset($data[self::ENTRY_BINDVARS])) {
196             $this->_bindVars->set($data[self::ENTRY_BINDVARS]);
197         }
198 
199         if (isset($data[self::FULL_COUNT])) {
200             $this->_fullCount = (bool) $data[Cursor::FULL_COUNT];
201         }
202 
203         if (isset($data[Cursor::ENTRY_SANITIZE])) {
204             $this->_sanitize = (bool) $data[Cursor::ENTRY_SANITIZE];
205         }
206 
207         if (isset($data[self::ENTRY_RETRIES])) {
208             $this->_retries = (int) $data[self::ENTRY_RETRIES];
209         }
210 
211         if (isset($data[Cursor::ENTRY_FLAT])) {
212             $this->_flat = (bool) $data[Cursor::ENTRY_FLAT];
213         }
214 
215         if (isset($data[Cursor::ENTRY_CACHE])) {
216             $this->_cache = (bool) $data[Cursor::ENTRY_CACHE];
217         }
218     }
219 
220     /**
221      * Return the connection object
222      *
223      * @return Connection - the connection object
224      */
225     protected function getConnection()
226     {
227         return $this->_connection;
228     }
229 
230     /**
231      * Execute the statement
232      *
233      * This will post the query to the server and return the results as
234      * a Cursor. The cursor can then be used to iterate the results.
235      *
236      * @throws Exception
237      * @return Cursor
238      */
239     public function execute()
240     {
241         if (!is_string($this->_query)) {
242             throw new ClientException('Query should be a string');
243         }
244 
245         $data = $this->buildData();
246 
247         $tries = 0;
248         while (true) {
249             try {
250                 $response = $this->_connection->post(Urls::URL_CURSOR, $this->getConnection()->json_encode_wrapper($data), []);
251 
252                 return new Cursor($this->_connection, $response->getJson(), $this->getCursorOptions());
253             } catch (ServerException $e) {
254                 if ($tries++ >= $this->_retries) {
255                     throw $e;
256                 }
257                 if ($e->getServerCode() !== 29) {
258                     // 29 is "deadlock detected"
259                     throw $e;
260                 }
261                 // try again
262             }
263         }
264     }
265 
266 
267     /**
268      * Explain the statement's execution plan
269      *
270      * This will post the query to the server and return the execution plan as an array.
271      *
272      * @throws Exception
273      * @return array
274      */
275     public function explain()
276     {
277         $data     = $this->buildData();
278         $response = $this->_connection->post(Urls::URL_EXPLAIN, $this->getConnection()->json_encode_wrapper($data), []);
279 
280         return $response->getJson();
281     }
282 
283 
284     /**
285      * Validates the statement
286      *
287      * This will post the query to the server for validation and return the validation result as an array.
288      *
289      * @throws Exception
290      * @return array
291      */
292     public function validate()
293     {
294         $data     = $this->buildData();
295         $response = $this->_connection->post(Urls::URL_QUERY, $this->getConnection()->json_encode_wrapper($data), []);
296 
297         return $response->getJson();
298     }
299 
300 
301     /**
302      * Invoke the statement
303      *
304      * This will simply call execute(). Arguments are ignored.
305      *
306      * @throws Exception
307      *
308      * @param mixed $args - arguments for invocation, will be ignored
309      *
310      * @return Cursor - the result cursor
311      */
312     public function __invoke($args)
313     {
314         return $this->execute();
315     }
316 
317     /**
318      * Return a string representation of the statement
319      *
320      * @return string - the current query string
321      */
322     public function __toString()
323     {
324         return $this->_query;
325     }
326 
327     /**
328      * Bind a parameter to the statement
329      *
330      * This method can either be called with a string $key and a
331      * separate value in $value, or with an array of all bind
332      * bind parameters in $key, with $value being NULL.
333      *
334      * Allowed value types for bind parameters are string, int,
335      * double, bool and array. Arrays must not contain any other
336      * than these types.
337      *
338      * @throws Exception
339      *
340      * @param mixed $key   - name of bind variable OR an array of all bind variables
341      * @param mixed $value - value for bind variable
342      *
343      * @return void
344      */
345     public function bind($key, $value = null)
346     {
347         $this->_bindVars->set($key, $value);
348     }
349 
350     /**
351      * Get all bind parameters as an array
352      *
353      * @return array - array of bind variables/values
354      */
355     public function getBindVars()
356     {
357         return $this->_bindVars->getAll();
358     }
359 
360     /**
361      * Set the query string
362      *
363      * @throws ClientException
364      *
365      * @param string $query - query string
366      *
367      * @return void
368      */
369     public function setQuery($query)
370     {
371         if (!is_string($query)) {
372             throw new ClientException('Query should be a string');
373         }
374 
375         $this->_query = $query;
376     }
377 
378     /**
379      * Get the query string
380      *
381      * @return string - current query string value
382      */
383     public function getQuery()
384     {
385         return $this->_query;
386     }
387 
388     /**
389      * setResultType
390      *
391      * @param $resultType
392      *
393      * @return string - resultType of the query
394      */
395     public function setResultType($resultType)
396     {
397         return $this->resultType = $resultType;
398     }
399 
400     /**
401      * Set the count option for the statement
402      *
403      * @param bool $value - value for count option
404      *
405      * @return void
406      */
407     public function setCount($value)
408     {
409         $this->_doCount = (bool) $value;
410     }
411 
412     /**
413      * Get the count option value of the statement
414      *
415      * @return bool - current value of count option
416      */
417     public function getCount()
418     {
419         return $this->_doCount;
420     }
421 
422     /**
423      * Set the full count option for the statement
424      *
425      * @param bool $value - value for full count option
426      *
427      * @return void
428      */
429     public function setFullCount($value)
430     {
431         $this->_fullCount = (bool) $value;
432     }
433 
434     /**
435      * Get the full count option value of the statement
436      *
437      * @return bool - current value of full count option
438      */
439     public function getFullCount()
440     {
441         return $this->_fullCount;
442     }
443 
444     /**
445      * Set the caching option for the statement
446      *
447      * @param bool $value - value for 'cache' option
448      *
449      * @return void
450      */
451     public function setCache($value)
452     {
453         $this->_cache = (bool) $value;
454     }
455 
456     /**
457      * Get the caching option value of the statement
458      *
459      * @return bool - current value of 'cache' option
460      */
461     public function getCache()
462     {
463         return $this->_cache;
464     }
465 
466     /**
467      * Set the batch size for the statement
468      *
469      * The batch size is the number of results to be transferred
470      * in one server round-trip. If a query produces more results
471      * than the batch size, it creates a server-side cursor that
472      * provides the additional results.
473      *
474      * The server-side cursor can be accessed by the client with subsequent HTTP requests.
475      *
476      * @throws ClientException
477      *
478      * @param int $value - batch size value
479      *
480      * @return void
481      */
482     public function setBatchSize($value)
483     {
484         if (!is_int($value) || (int) $value <= 0) {
485             throw new ClientException('Batch size should be a positive integer');
486         }
487 
488         $this->_batchSize = (int) $value;
489     }
490 
491     /**
492      * Get the batch size for the statement
493      *
494      * @return int - current batch size value
495      */
496     public function getBatchSize()
497     {
498         return $this->_batchSize;
499     }
500 
501 
502     /**
503      * Build an array of data to be posted to the server when issuing the statement
504      *
505      * @return array - array of data to be sent to server
506      */
507     private function buildData()
508     {
509         $data = [
510             self::ENTRY_QUERY => $this->_query,
511             self::ENTRY_COUNT => $this->_doCount,
512             'options'         => [
513                 self::FULL_COUNT => $this->_fullCount
514             ]
515         ];
516 
517         if ($this->_cache !== null) {
518             $data[Cursor::ENTRY_CACHE] = $this->_cache;
519         }
520 
521         if ($this->_bindVars->getCount() > 0) {
522             $data[self::ENTRY_BINDVARS] = $this->_bindVars->getAll();
523         }
524 
525         if ($this->_batchSize > 0) {
526             $data[self::ENTRY_BATCHSIZE] = $this->_batchSize;
527         }
528 
529         return $data;
530     }
531 
532     /**
533      * Return an array of cursor options
534      *
535      * @return array - array of options
536      */
537     private function getCursorOptions()
538     {
539         $result = [
540             Cursor::ENTRY_SANITIZE => (bool) $this->_sanitize,
541             Cursor::ENTRY_FLAT     => (bool) $this->_flat,
542             Cursor::ENTRY_BASEURL  => Urls::URL_CURSOR
543         ];
544         if (null !== $this->resultType) {
545             $result[Cursor::ENTRY_TYPE] = $this->resultType;
546         }
547 
548         return $result;
549     }
550 }
551 
ArangoDB-PHP API Documentation API documentation generated by ApiGen