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: batch
  5  *
  6  * @package triagens\ArangoDb
  7  * @author  Frank Mayer
  8  * @since   1.1
  9  *
 10  */
 11 
 12 namespace triagens\ArangoDb;
 13 
 14 /**
 15  * Provides batching functionality
 16  *
 17  * <br>
 18  *
 19  * @package   triagens\ArangoDb
 20  * @since     1.1
 21  */
 22 class Batch
 23 {
 24     /**
 25      * Batch Response Object
 26      *
 27      * @var HttpResponse $_batchResponse
 28      */
 29     public $_batchResponse;
 30 
 31 
 32     /**
 33      * Flag that signals if this batch was processed or not. Processed => true ,or not processed => false
 34      *
 35      * @var boolean $_processed
 36      */
 37     private $_processed = false;
 38 
 39 
 40     /**
 41      * The array of BatchPart objects
 42      *
 43      * @var array $_batchParts
 44      */
 45     private $_batchParts = [];
 46 
 47 
 48     /**
 49      * The next batch part id
 50      *
 51      * @var integer|string $_nextBatchPartId
 52      */
 53     private $_nextBatchPartId;
 54 
 55 
 56     /**
 57      * An array of BatchPartCursor options
 58      *
 59      * @var array $_batchParts
 60      */
 61     private $_batchPartCursorOptions = [];
 62 
 63 
 64     /**
 65      * The connection object
 66      *
 67      * @var Connection $_connection
 68      */
 69     private $_connection;
 70 
 71     /**
 72      * The sanitize default value
 73      *
 74      * @var bool $_sanitize
 75      */
 76     private $_sanitize = false;
 77 
 78     /**
 79      * The Batch NextId
 80      *
 81      * @var integer|string $_nextId
 82      */
 83     private $_nextId = 0;
 84 
 85 
 86     /**
 87      * Constructor for Batch instance. Batch instance by default starts capturing request after initiated.
 88      * To disable this, pass startCapture=>false inside the options array parameter
 89      *
 90      * @param Connection $connection that this batch class will monitor for requests in order to batch them. Connection parameter is mandatory.
 91      * @param array      $options    An array of options for Batch construction. See below for options:
 92      *
 93      * <p>Options are :
 94      * <li>'_sanitize' - True to remove _id and _rev attributes from result documents returned from this batch. Defaults to false.</li>
 95      * <li>'startCapture' - Start batch capturing immediately after batch instantiation. Defaults to true.</li>
 96      * <li>'batchSize' - Defines a fixed array size for holding the batch parts. The id's of the batch parts can only be integers.
 97      *                   When this option is defined, the batch mechanism will use an SplFixedArray instead of the normal PHP arrays.
 98      *                   In most cases, this will result in increased performance of about 5% to 15%, depending on batch size and data.</li>
 99      * </p>
100      */
101     public function __construct(Connection $connection, array $options = [])
102     {
103         $startCapture = true;
104         $sanitize     = false;
105         $batchSize    = 0;
106         $options      = array_merge($options, $this->getCursorOptions());
107         extract($options, EXTR_IF_EXISTS);
108         $this->_sanitize = $sanitize;
109         $this->batchSize = $batchSize;
110 
111         if ($this->batchSize > 0) {
112             $this->_batchParts = new \SplFixedArray($this->batchSize);
113         }
114 
115         $this->setConnection($connection);
116 
117         // set default cursor options. Sanitize is currently the only local one.
118         $this->_batchPartCursorOptions = [Cursor::ENTRY_SANITIZE => (bool) $this->_sanitize];
119 
120         if ($startCapture === true) {
121             $this->startCapture();
122         }
123     }
124 
125 
126     /**
127      * Sets the connection for he current batch. (mostly internal function)
128      *
129      * @param Connection $connection
130      *
131      * @return Batch
132      */
133     public function setConnection($connection)
134     {
135         $this->_connection = $connection;
136 
137         return $this;
138     }
139 
140 
141     /**
142      * Start capturing requests. To stop capturing, use stopCapture()
143      *
144      * see triagens\ArangoDb\Batch::stopCapture()
145      *
146      *
147      * @return Batch
148      *
149      */
150     public function startCapture()
151     {
152         $this->activate();
153 
154         return $this;
155     }
156 
157 
158     /**
159      * Stop capturing requests. If the batch has not been processed yet, more requests can be appended by calling startCapture() again.
160      *
161      * see Batch::startCapture()
162      *
163      * @throws ClientException
164      * @return Batch
165      */
166     public function stopCapture()
167     {
168         // check if this batch is the active one... and capturing. Ignore, if we're not capturing...
169         if ($this->isActive() && $this->isCapturing()) {
170             $this->setCapture(false);
171 
172             return $this;
173         } else {
174             throw new ClientException('Cannot stop capturing with this batch. Batch is not active...');
175         }
176     }
177 
178 
179     /**
180      * Returns true, if this batch is active in its associated connection.
181      *
182      * @return bool
183      */
184     public function isActive()
185     {
186         $activeBatch = $this->getActive($this->_connection);
187 
188         return $activeBatch === $this;
189     }
190 
191 
192     /**
193      * Returns true, if this batch is capturing requests.
194      *
195      * @return bool
196      */
197     public function isCapturing()
198     {
199         return $this->getConnectionCaptureMode($this->_connection);
200     }
201 
202 
203     /**
204      * Activates the batch. This sets the batch active in its associated connection and also starts capturing.
205      *
206      * @return Batch $this
207      */
208     public function activate()
209     {
210         $this->setActive();
211         $this->setCapture(true);
212 
213         return $this;
214     }
215 
216 
217     /**
218      * Sets the batch active in its associated connection.
219      *
220      * @return Batch $this
221      */
222     public function setActive()
223     {
224         $this->_connection->setActiveBatch($this);
225 
226         return $this;
227     }
228 
229 
230     /**
231      * Sets the batch's associated connection into capture mode.
232      *
233      * @param boolean $state
234      *
235      * @return Batch $this
236      */
237     public function setCapture($state)
238     {
239         $this->_connection->setCaptureBatch($state);
240 
241         return $this;
242     }
243 
244 
245     /**
246      * Gets active batch in given connection.
247      *
248      * @param Connection $connection
249      *
250      * @return $this
251      */
252     public function getActive($connection)
253     {
254         $connection->getActiveBatch();
255 
256         return $this;
257     }
258 
259 
260     /**
261      * Returns true, if given connection is in batch-capture mode.
262      *
263      * @param Connection $connection
264      *
265      * @return bool
266      */
267     public function getConnectionCaptureMode($connection)
268     {
269         return $connection->isInBatchCaptureMode();
270     }
271 
272 
273     /**
274      * Sets connection into Batch-Request mode. This is necessary to distinguish between normal and the batch request.
275      *
276      * @param boolean $state
277      *
278      * @return $this
279      */
280     private function setBatchRequest($state)
281     {
282         $this->_connection->setBatchRequest($state);
283         $this->_processed = true;
284 
285         return $this;
286     }
287 
288 
289     /**
290      * Sets the id of the next batch-part. The id can later be used to retrieve the batch-part.
291      *
292      * @param mixed $batchPartId
293      *
294      * @return Batch
295      */
296     public function nextBatchPartId($batchPartId)
297     {
298         $this->_nextBatchPartId = $batchPartId;
299 
300         return $this;
301     }
302 
303 
304     /**
305      * Set client side cursor options (for example: sanitize) for the next batch part.
306      *
307      * @param mixed $batchPartCursorOptions
308      *
309      * @return Batch
310      */
311     public function nextBatchPartCursorOptions($batchPartCursorOptions)
312     {
313         $this->_batchPartCursorOptions = $batchPartCursorOptions;
314 
315         return $this;
316     }
317 
318 
319     /**
320      * Append the request to the batch-part
321      *
322      * @param mixed $method  - The method of the request (GET, POST...)
323      * @param mixed $request - The request that will get appended to the batch
324      *
325      * @return HttpResponse
326      *
327      * @throws \triagens\ArangoDb\ClientException
328      */
329     public function append($method, $request)
330     {
331         preg_match('%/_api/simple/(?P<simple>\w*)|/_api/(?P<direct>\w*)%ix', $request, $regs);
332 
333         if (!isset($regs['direct'])) {
334             $regs['direct'] = '';
335         }
336         $type = $regs['direct'] !== '' ? $regs['direct'] : $regs['simple'];
337 
338         if ($method === 'GET' && $type === $regs['direct']) {
339             $type = 'get' . $type;
340         }
341 
342         if (null === $this->_nextBatchPartId) {
343             if (is_a($this->_batchParts, 'SplFixedArray')) {
344                 $nextNumeric = $this->_nextId;
345                 $this->_nextId++;
346             } else {
347                 $nextNumeric = count($this->_batchParts);
348             }
349             $batchPartId = $nextNumeric;
350         } else {
351             $batchPartId            = $this->_nextBatchPartId;
352             $this->_nextBatchPartId = null;
353         }
354 
355         $eol = HttpHelper::EOL;
356 
357         $result = 'HTTP/1.1 202 Accepted' . $eol;
358         $result .= 'location: /_db/_system/_api/document/0/0' . $eol;
359         $result .= 'content-type: application/json; charset=utf-8' . $eol;
360         $result .= 'etag: "0"' . $eol;
361         $result .= 'connection: Close' . $eol . $eol;
362         $result .= '{"error":false,"_id":"0/0","id":"0","_rev":0,"hasMore":1, "result":[{}], "documents":[{}]}' . $eol . $eol;
363 
364         $response  = new HttpResponse($result);
365         $batchPart = new BatchPart($this, $batchPartId, $type, $request, $response, ['cursorOptions' => $this->_batchPartCursorOptions]);
366 
367         $this->_batchParts[$batchPartId] = $batchPart;
368 
369         $response->setBatchPart($batchPart);
370 
371         return $response;
372     }
373 
374 
375     /**
376      * Split batch request and use ContentId as array key
377      *
378      * @param mixed $pattern
379      * @param mixed $string
380      *
381      * @return array $array - Array of batch-parts
382      *
383      * @throws \triagens\ArangoDb\ClientException
384      */
385     public function splitWithContentIdKey($pattern, $string)
386     {
387         $array    = [];
388         $exploded = explode($pattern, $string);
389         foreach ($exploded as $key => $value) {
390             $response  = new HttpResponse($value);
391             $contentId = $response->getHeader('Content-Id');
392 
393             if (null !== $contentId) {
394                 $array[$contentId] = $value;
395             } else {
396                 $array[$key] = $value;
397             }
398         }
399 
400         return $array;
401     }
402 
403 
404     /**
405      * Processes this batch. This sends the captured requests to the server as one batch.
406      *
407      * @return HttpResponse|Batch - Batch if processing of the batch was successful or the HttpResponse object in case of a failure. A successful process just means that tha parts were processed. Each part has it's own response though and should be checked on its own.
408      *
409      * @throws ClientException
410      * @throws \triagens\ArangoDb\Exception
411      */
412     public function process()
413     {
414         if ($this->isCapturing()) {
415             $this->stopCapture();
416         }
417         $this->setBatchRequest(true);
418         $data       = '';
419         $batchParts = $this->getBatchParts();
420 
421         if (count($batchParts) === 0) {
422             throw new ClientException('Can\'t process empty batch.');
423         }
424 
425         /** @var $partValue BatchPart */
426         foreach ($batchParts as $partValue) {
427             if (null !== $partValue) {
428                 $data .= '--' . HttpHelper::MIME_BOUNDARY . HttpHelper::EOL;
429                 $data .= 'Content-Type: application/x-arango-batchpart' . HttpHelper::EOL;
430 
431                 if (null !== $partValue->getId()) {
432                     $data .= 'Content-Id: ' . (string) $partValue->getId() . HttpHelper::EOL . HttpHelper::EOL;
433                 } else {
434                     $data .= HttpHelper::EOL;
435                 }
436 
437                 $data .= (string) $partValue->getRequest() . HttpHelper::EOL;
438             }
439         }
440         $data .= '--' . HttpHelper::MIME_BOUNDARY . '--' . HttpHelper::EOL . HttpHelper::EOL;
441 
442         $params               = [];
443         $url                  = UrlHelper::appendParamsUrl(Urls::URL_BATCH, $params);
444         $this->_batchResponse = $this->_connection->post($url, $data);
445         if ($this->_batchResponse->getHttpCode() !== 200) {
446             return $this->_batchResponse;
447         }
448         $body       = $this->_batchResponse->getBody();
449         $body       = trim($body, '--' . HttpHelper::MIME_BOUNDARY . '--');
450         $batchParts = $this->splitWithContentIdKey('--' . HttpHelper::MIME_BOUNDARY . HttpHelper::EOL, $body);
451 
452         foreach ($batchParts as $partKey => $partValue) {
453             $response                     = new HttpResponse($partValue);
454             $body                         = $response->getBody();
455             $response                     = new HttpResponse($body);
456             $batchPartResponses[$partKey] = $response;
457             $this->getPart($partKey)->setResponse($batchPartResponses[$partKey]);
458         }
459 
460         return $this;
461     }
462 
463 
464     /**
465      * Get the total count of the batch parts
466      *
467      * @return integer $count
468      */
469     public function countParts()
470     {
471         return count($this->_batchParts);
472     }
473 
474 
475     /**
476      * Get the batch part identified by the array key (0...n) or its id (if it was set with nextBatchPartId($id) )
477      *
478      * @param mixed $partId the batch part id. Either it's numeric key or a given name.
479      *
480      * @return mixed $batchPart
481      *
482      * @throws ClientException
483      */
484     public function getPart($partId)
485     {
486         if (!isset($this->_batchParts[$partId])) {
487             throw new ClientException('Request batch part does not exist.');
488         }
489 
490         return $this->_batchParts[$partId];
491     }
492 
493 
494     /**
495      * Get the batch part identified by the array key (0...n) or its id (if it was set with nextBatchPartId($id) )
496      *
497      * @param mixed $partId the batch part id. Either it's numeric key or a given name.
498      *
499      * @return mixed $partId
500      *
501      * @throws \triagens\ArangoDb\ClientException
502      */
503     public function getPartResponse($partId)
504     {
505         return $this->getPart($partId)->getResponse();
506     }
507 
508 
509     /**
510      * Get the batch part identified by the array key (0...n) or its id (if it was set with nextBatchPartId($id) )
511      *
512      * @param mixed $partId the batch part id. Either it's numeric key or a given name.
513      *
514      * @return mixed $partId
515      *
516      * @throws \triagens\ArangoDb\ClientException
517      */
518     public function getProcessedPartResponse($partId)
519     {
520         return $this->getPart($partId)->getProcessedResponse();
521     }
522 
523 
524     /**
525      * Returns the array of batch-parts
526      *
527      * @return array $_batchParts
528      */
529     public function getBatchParts()
530     {
531         return $this->_batchParts;
532     }
533 
534 
535     /**
536      * Return an array of cursor options
537      *
538      * @return array - array of options
539      */
540     private function getCursorOptions()
541     {
542         return $this->_batchPartCursorOptions;
543     }
544 
545 
546     /**
547      * Return this batch's connection
548      *
549      * @return Connection
550      */
551     public function getConnection()
552     {
553         return $this->_connection;
554     }
555 }
556 
ArangoDB-PHP API Documentation API documentation generated by ApiGen