1 <?php
2
3 /**
4 * ArangoDB PHP client: document handler
5 *
6 * @package triagens\ArangoDb
7 * @author Jan Steemann
8 * @author Frank Mayer
9 * @copyright Copyright 2012, triagens GmbH, Cologne, Germany
10 */
11
12 namespace triagens\ArangoDb;
13
14
15 /**
16 * A handler that manages documents
17 *
18 * A document handler that fetches documents from the server and
19 * persists them on the server. It does so by issuing the
20 * appropriate HTTP requests to the server.<br>
21 *
22 * <br>
23 *
24 * @package triagens\ArangoDb
25 * @since 0.2
26 */
27 class DocumentHandler extends
28 Handler
29 {
30 /**
31 * documents array index
32 */
33 const ENTRY_DOCUMENTS = 'documents';
34
35 /**
36 * collection parameter
37 */
38 const OPTION_COLLECTION = 'collection';
39
40 /**
41 * example parameter
42 */
43 const OPTION_EXAMPLE = 'example';
44
45
46 /**
47 * Get a single document from a collection
48 *
49 * Alias method for getById()
50 *
51 * @throws Exception
52 *
53 * @param string $collection - collection id as a string or number
54 * @param mixed $documentId - document identifier
55 * @param array $options - optional, array of options
56 * <p>Options are :
57 * <li>'_includeInternals' - true to include the internal attributes. Defaults to false</li>
58 * <li>'_ignoreHiddenAttributes' - true to show hidden attributes. Defaults to false</li>
59 * <li>'revision' - the documents revision</li>
60 * <li>'ifMatch' - boolean if given revision should match or not</li>
61 * </p>
62 *
63 * @return Document - the document fetched from the server
64 */
65 public function get($collection, $documentId, array $options = [])
66 {
67 return $this->getById($collection, $documentId, $options);
68 }
69
70
71 /**
72 * Check if a document exists
73 *
74 * This will call self::get() internally and checks if there
75 * was an exception thrown which represents an 404 request.
76 *
77 * @throws Exception When any other error than a 404 occurs
78 *
79 * @param string $collection - collection id as a string or number
80 * @param mixed $documentId - document identifier
81 *
82 * @return boolean
83 */
84 public function has($collection, $documentId)
85 {
86 try {
87 // will throw ServerException if entry could not be retrieved
88 $this->get($collection, $documentId);
89
90 return true;
91 } catch (ServerException $e) {
92 // we are expecting a 404 to return boolean false
93 if ($e->getCode() === 404) {
94 return false;
95 }
96
97 // just rethrow
98 throw $e;
99 }
100
101 }
102
103
104 /**
105 * Get a single document from a collection
106 *
107 * This will throw if the document cannot be fetched from the server.
108 *
109 * @throws Exception
110 *
111 * @param string $collection - collection id as a string or number
112 * @param mixed $documentId - document identifier
113 * @param array $options - optional, array of options
114 * <p>Options are :
115 * <li>'_includeInternals' - true to include the internal attributes. Defaults to false</li>
116 * <li>'_ignoreHiddenAttributes' - true to show hidden attributes. Defaults to false</li>
117 * <li>'ifMatch' - boolean if given revision should match or not</li>
118 * <li>'revision' - The document is returned if it matches/not matches revision.</li>
119 * </p>
120 *
121 * @return Document - the document fetched from the server
122 */
123 public function getById($collection, $documentId, array $options = [])
124 {
125 $data = $this->getDocument(Urls::URL_DOCUMENT, $collection, $documentId, $options);
126 $options['_isNew'] = false;
127
128 return $this->createFromArrayWithContext($data, $options);
129 }
130
131
132 /**
133 * Get a single document (internal method)
134 *
135 * This method is the workhorse for getById() in this handler and the edges handler
136 *
137 * @throws Exception
138 *
139 * @param string $url - the server-side URL being called
140 * @param string $collection - collection id as a string or number
141 * @param mixed $documentId - document identifier
142 * @param array $options - optional, array of options
143 * <p>Options are :
144 * <li>'_includeInternals' - true to include the internal attributes. Defaults to false</li>
145 * <li>'_ignoreHiddenAttributes' - true to show hidden attributes. Defaults to false</li>
146 * <li>'ifMatch' - boolean if given revision should match or not</li>
147 * <li>'revision' - The document is returned if it matches/not matches revision.</li>
148 * </p>
149 *
150 * @internal
151 *
152 * @return array - the document fetched from the server
153 */
154 protected function getDocument($url, $collection, $documentId, array $options = [])
155 {
156 $collection = $this->makeCollection($collection);
157
158 $url = UrlHelper::buildUrl($url, [$collection, $documentId]);
159 $headerElements = [];
160 if (array_key_exists('ifMatch', $options) && array_key_exists('revision', $options)) {
161 if ($options['ifMatch'] === true) {
162 $headerElements['If-Match'] = '"' . $options['revision'] . '"';
163 } else {
164 $headerElements['If-None-Match'] = '"' . $options['revision'] . '"';
165 }
166 }
167
168 $response = $this->getConnection()->get($url, $headerElements);
169
170 if ($response->getHttpCode() === 304) {
171 throw new ClientException('Document has not changed.');
172 }
173
174 return $response->getJson();
175 }
176
177
178 /**
179 * Gets information about a single documents from a collection
180 *
181 * This will throw if the document cannot be fetched from the server
182 *
183 *
184 * @throws Exception
185 *
186 * @param string $collection - collection id as a string or number.
187 * @param mixed $documentId - document identifier.
188 * @param boolean $ifMatch - boolean if given revision should match or not.
189 * @param string $revision - The document is returned if it matches/not matches revision.
190 *
191 * @return array - an array containing the complete header including the key httpCode.
192 */
193 public function getHead($collection, $documentId, $revision = null, $ifMatch = null)
194 {
195 return $this->head(Urls::URL_DOCUMENT, $collection, $documentId, $revision, $ifMatch);
196 }
197
198
199 /**
200 * Get meta-data for a single document (internal method)
201 *
202 * This method is the workhorse for getHead() in this handler and the edges handler
203 *
204 * @throws Exception
205 *
206 * @param string $url - the server-side URL being called
207 * @param string $collection - collection id as a string or number
208 * @param mixed $documentId - document identifier
209 * @param mixed $revision - optional document revision
210 * @param boolean $ifMatch - boolean if given revision should match or not.
211 *
212 * @internal
213 *
214 * @return array - the document meta-data
215 */
216 protected function head($url, $collection, $documentId, $revision = null, $ifMatch = null)
217 {
218 $collection = $this->makeCollection($collection);
219
220 $url = UrlHelper::buildUrl($url, [$collection, $documentId]);
221 $headerElements = [];
222 if ($revision !== null && $ifMatch !== null) {
223 if ($ifMatch) {
224 $headerElements['If-Match'] = '"' . $revision . '"';
225 } else {
226 $headerElements['If-None-Match'] = '"' . $revision . '"';
227 }
228 }
229
230 $response = $this->getConnection()->head($url, $headerElements);
231 $headers = $response->getHeaders();
232 $headers['httpCode'] = $response->getHttpCode();
233
234 return $headers;
235 }
236
237
238 /**
239 * Intermediate function to call the createFromArray function from the right context
240 *
241 * @param $data
242 * @param $options
243 *
244 * @return Document
245 * @throws \triagens\ArangoDb\ClientException
246 */
247 protected function createFromArrayWithContext($data, $options)
248 {
249 return Document::createFromArray($data, $options);
250 }
251
252
253 /**
254 * Store a document to a collection
255 *
256 * This is an alias/shortcut to save() and replace(). Instead of having to determine which of the 3 functions to use,
257 * simply pass the document to store() and it will figure out which one to call.
258 *
259 * This will throw if the document cannot be saved or replaced.
260 *
261 * @throws Exception
262 *
263 * @param Document $document - the document to be added, can be passed as a document or an array
264 * @param mixed $collection - collection id as string or number
265 * @param array $options - optional, array of options
266 * <p>Options are :<br>
267 * <li>'createCollection' - create the collection if it does not yet exist.</li>
268 * <li>'waitForSync' - if set to true, then all removal operations will instantly be synchronised to disk / If this is not specified, then the collection's default sync behavior will be applied.</li>
269 * </p>
270 *
271 * @return mixed - id of document created
272 * @since 1.0
273 */
274 public function store(Document $document, $collection = null, array $options = [])
275 {
276 if ($document->getIsNew()) {
277
278 if ($collection === null) {
279 throw new ClientException('A collection id is required to store a new document.');
280 }
281
282 $result = $this->save($collection, $document, $options);
283 $document->setIsNew(false);
284
285 return $result;
286 } else {
287
288 if ($collection) {
289 throw new ClientException('An existing document cannot be stored into a new collection');
290 }
291
292 return $this->replace($document, $options);
293 }
294 }
295
296
297 /**
298 * save a document to a collection
299 *
300 * This will add the document to the collection and return the document's id
301 *
302 * This will throw if the document cannot be saved
303 *
304 * @throws Exception
305 *
306 * @param mixed $collection - collection id as string or number
307 * @param Document|array $document - the document to be added, can be passed as a document or an array
308 * @param array $options - optional, array of options
309 * <p>Options are :<br>
310 * <li>'createCollection' - create the collection if it does not yet exist.</li>
311 * <li>'waitForSync' - if set to true, then all removal operations will instantly be synchronised to disk / If this is not specified, then the collection's default sync behavior will be applied.</li>
312 * </p>
313 *
314 * @return mixed - id of document created
315 * @since 1.0
316 */
317 public function save($collection, $document, array $options = [])
318 {
319 $collection = $this->makeCollection($collection);
320
321 $params = $this->includeOptionsInParams(
322 $options, [
323 'waitForSync' => null,
324 'silent' => false,
325 'createCollection' => $this->getConnection()->getOption(ConnectionOptions::OPTION_CREATE)
326 ]
327 );
328
329 $this->createCollectionIfOptions($collection, $params);
330
331 $url = UrlHelper::appendParamsUrl(Urls::URL_DOCUMENT . '/' . $collection, $params);
332
333 if (is_array($document)) {
334 $data = $document;
335 } else {
336 $data = $document->getAllForInsertUpdate();
337 }
338
339 $response = $this->getConnection()->post($url, $this->json_encode_wrapper($data));
340 $json = $response->getJson();
341
342 // This makes sure that if we're in batch mode, it will not go further and choke on the checks below.
343 // Caution: Instead of a document ID, we are returning the batchpart object
344 // The Id of the BatchPart can be retrieved by calling getId() on it.
345 // We're basically returning an object here, in order not to accidentally use the batch part id as the document id
346 if ($batchPart = $response->getBatchPart()) {
347 return $batchPart;
348 }
349
350 if (is_array($document)) {
351 return $json[Document::ENTRY_KEY];
352 }
353
354 $location = $response->getLocationHeader();
355 if (!$location) {
356 throw new ClientException('Did not find location header in server response');
357 }
358
359 $id = UrlHelper::getDocumentIdFromLocation($location);
360
361 $document->setInternalId($json[Document::ENTRY_ID]);
362 $document->setRevision($json[Document::ENTRY_REV]);
363
364 if ($id !== $document->getId()) {
365 throw new ClientException('Got an invalid response from the server');
366 }
367
368 $document->setIsNew(false);
369
370 return $document->getId();
371 }
372
373 /**
374 * Update an existing document in a collection, identified by the including _id and optionally _rev in the patch document.
375 * Attention - The behavior of this method has changed since version 1.1
376 *
377 * This will update the document on the server
378 *
379 * This will throw if the document cannot be updated
380 *
381 * If policy is set to error (locally or globally through the ConnectionOptions)
382 * and the passed document has a _rev value set, the database will check
383 * that the revision of the document to-be-replaced is the same as the one given.
384 *
385 * @throws Exception
386 *
387 * @param Document $document - The patch document that will update the document in question
388 * @param array $options - optional, array of options
389 * <p>Options are :
390 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
391 * <li>'keepNull' - can be used to instruct ArangoDB to delete existing attributes instead setting their values to null. Defaults to true (keep attributes when set to null)</li>
392 * <li>'waitForSync' - can be used to force synchronisation of the document update operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
393 * </p>
394 *
395 * @return bool - always true, will throw if there is an error
396 */
397 public function update(Document $document, array $options = [])
398 {
399 $documentId = $this->getDocumentId($document);
400
401 return $this->updateById($document, $documentId, $document, $options);
402 }
403
404
405 /**
406 * Update an existing document in a collection, identified by collection id and document id
407 * Attention - The behavior of this method has changed since version 1.1
408 *
409 * This will update the document on the server
410 *
411 * This will throw if the document cannot be updated
412 *
413 * If policy is set to error (locally or globally through the ConnectionOptions)
414 * and the passed document has a _rev value set, the database will check
415 * that the revision of the document to-be-updated is the same as the one given.
416 *
417 * @throws Exception
418 *
419 * @param string $collection - collection id as string or number
420 * @param mixed $documentId - document id as string or number
421 * @param Document $document - patch document which contains the attributes and values to be updated
422 * @param array $options - optional, array of options
423 * <p>Options are :
424 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
425 * <li>'keepNull' - can be used to instruct ArangoDB to delete existing attributes instead setting their values to null. Defaults to true (keep attributes when set to null)</li>
426 * <li>'waitForSync' - can be used to force synchronisation of the document update operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
427 * </p>
428 *
429 * @return bool - always true, will throw if there is an error
430 */
431 public function updateById($collection, $documentId, Document $document, array $options = [])
432 {
433 return $this->patch(Urls::URL_DOCUMENT, $collection, $documentId, $document, $options);
434 }
435
436
437 /**
438 * Update an existing document in a collection (internal method)
439 *
440 * @throws Exception
441 *
442 * @param string $url - server-side URL being called
443 * @param string $collection - collection id as string or number
444 * @param mixed $documentId - document id as string or number
445 * @param Document $document - patch document which contains the attributes and values to be updated
446 * @param array $options - optional, array of options
447 * <p>Options are :
448 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
449 * <li>'keepNull' - can be used to instruct ArangoDB to delete existing attributes instead setting their values to null. Defaults to true (keep attributes when set to null)</li>
450 * <li>'waitForSync' - can be used to force synchronisation of the document update operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
451 * </p>
452 *
453 * @internal
454 *
455 * @return bool - always true, will throw if there is an error
456 */
457 protected function patch($url, $collection, $documentId, Document $document, array $options = [])
458 {
459 $collection = $this->makeCollection($collection);
460
461 $params = $this->includeOptionsInParams(
462 $options, [
463 'waitForSync' => $this->getConnectionOption(ConnectionOptions::OPTION_WAIT_SYNC),
464 'keepNull' => true,
465 'silent' => false,
466 'ignoreRevs' => true,
467 'policy' => $this->getConnectionOption(ConnectionOptions::OPTION_UPDATE_POLICY)
468 ]
469 );
470
471
472 $headers = [];
473 if (isset($params[ConnectionOptions::OPTION_UPDATE_POLICY]) &&
474 $params[ConnectionOptions::OPTION_UPDATE_POLICY] === UpdatePolicy::ERROR
475 ) {
476
477 $revision = $document->getRevision();
478 if (null !== $revision) {
479 $params['ignoreRevs'] = false;
480 $headers['if-match'] = '"' . $revision . '"';
481 }
482 }
483
484 $url = UrlHelper::buildUrl($url, [$collection, $documentId]);
485 $url = UrlHelper::appendParamsUrl($url, $params);
486
487 $result = $this->getConnection()->patch($url, $this->json_encode_wrapper($document->getAllForInsertUpdate()), $headers);
488 $json = $result->getJson();
489 $document->setRevision($json[Document::ENTRY_REV]);
490
491 return true;
492 }
493
494
495 /**
496 * Replace an existing document in a collection, identified by the document itself
497 *
498 * This will update the document on the server
499 *
500 * This will throw if the document cannot be updated
501 *
502 * If policy is set to error (locally or globally through the ConnectionOptions)
503 * and the passed document has a _rev value set, the database will check
504 * that the revision of the to-be-replaced document is the same as the one given.
505 *
506 * @throws Exception
507 *
508 * @param Document $document - document to be updated
509 * @param array $options - optional, array of options
510 * <p>Options are :
511 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
512 * <li>'waitForSync' - can be used to force synchronisation of the document update operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
513 * </p>
514 *
515 * @return bool - always true, will throw if there is an error
516 */
517 public function replace(Document $document, array $options = [])
518 {
519 $documentId = $this->getDocumentId($document);
520
521 return $this->replaceById($document, $documentId, $document, $options);
522 }
523
524
525 /**
526 * Replace an existing document in a collection, identified by collection id and document id
527 *
528 * This will update the document on the server
529 *
530 * This will throw if the document cannot be Replaced
531 *
532 * If policy is set to error (locally or globally through the ConnectionOptions)
533 * and the passed document has a _rev value set, the database will check
534 * that the revision of the to-be-replaced document is the same as the one given.
535 *
536 * @throws Exception
537 *
538 * @param mixed $collection - collection id as string or number
539 * @param mixed $documentId - document id as string or number
540 * @param Document $document - document to be updated
541 * @param array $options - optional, array of options
542 * <p>Options are :
543 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
544 * <li>'waitForSync' - can be used to force synchronisation of the document replacement operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
545 * </p>
546 *
547 * @return bool - always true, will throw if there is an error
548 */
549 public function replaceById($collection, $documentId, Document $document, array $options = [])
550 {
551 return $this->put(Urls::URL_DOCUMENT, $collection, $documentId, $document, $options);
552 }
553
554
555 /**
556 * Replace an existing document in a collection (internal method)
557 *
558 * @throws Exception
559 *
560 * @param string $url - the server-side URL being called
561 * @param string $collection - collection id as string or number
562 * @param mixed $documentId - document id as string or number
563 * @param Document $document - document to be updated
564 * @param array $options - optional, array of options
565 * <p>Options are :
566 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
567 * <li>'waitForSync' - can be used to force synchronisation of the document replacement operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
568 * <li>'ifMatch' - boolean if given revision should match or not</li>
569 * <li>'revision' - The document is returned if it matches/not matches revision.</li></p>
570 *
571 * @internal
572 *
573 * @return bool - always true, will throw if there is an error
574 */
575 protected function put($url, $collection, $documentId, Document $document, array $options = [])
576 {
577 $collection = $this->makeCollection($collection);
578
579 $params = $this->includeOptionsInParams(
580 $options, [
581 'waitForSync' => $this->getConnectionOption(ConnectionOptions::OPTION_WAIT_SYNC),
582 'silent' => false,
583 'ignoreRevs' => true,
584 'policy' => $this->getConnectionOption(ConnectionOptions::OPTION_REPLACE_POLICY)
585 ]
586 );
587
588 $headers = [];
589 if (isset($params[ConnectionOptions::OPTION_REPLACE_POLICY]) &&
590 $params[ConnectionOptions::OPTION_REPLACE_POLICY] === UpdatePolicy::ERROR
591 ) {
592 if (null !== $options['revision']) {
593 $params['ignoreRevs'] = false;
594 $headers['if-match'] = '"' . $options['revision'] . '"';
595 }
596 }
597
598 $data = $document->getAllForInsertUpdate();
599
600 $url = UrlHelper::buildUrl($url, [$collection, $documentId]);
601 $url = UrlHelper::appendParamsUrl($url, $params);
602 $result = $this->getConnection()->put($url, $this->json_encode_wrapper($data), $headers);
603 $json = $result->getJson();
604 $document->setRevision($json[Document::ENTRY_REV]);
605
606 return true;
607 }
608
609
610 /**
611 * Remove a document from a collection, identified by the document itself
612 *
613 * @throws Exception
614 *
615 * @param Document $document - document to be removed
616 * @param array $options - optional, array of options
617 * <p>Options are :
618 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
619 * <li>'waitForSync' - can be used to force synchronisation of the document removal operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
620 * </p>
621 *
622 * @return bool - always true, will throw if there is an error
623 */
624 public function remove(Document $document, array $options = [])
625 {
626 $documentId = $this->getDocumentId($document);
627
628 $revision = $this->getRevision($document);
629
630 return $this->removeById($document, $documentId, $revision, $options);
631 }
632
633
634 /**
635 * Remove a document from a collection, identified by the collection id and document id
636 *
637 * @throws Exception
638 *
639 * @param mixed $collection - collection id as string or number
640 * @param mixed $documentId - document id as string or number
641 * @param mixed $revision - optional revision of the document to be deleted
642 * @param array $options - optional, array of options
643 * <p>Options are :
644 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
645 * <li>'waitForSync' - can be used to force synchronisation of the document removal operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
646 * </p>
647 *
648 * @return bool - always true, will throw if there is an error
649 */
650 public function removeById($collection, $documentId, $revision = null, array $options = [])
651 {
652 return $this->erase(Urls::URL_DOCUMENT, $collection, $documentId, $revision, $options);
653 }
654
655
656 /**
657 * Remove a document from a collection (internal method)
658 *
659 * @throws Exception
660 *
661 * @param string $url - the server-side URL being called
662 * @param string $collection - collection id as string or number
663 * @param mixed $documentId - document id as string or number
664 * @param mixed $revision - optional revision of the document to be deleted
665 * @param array $options - optional, array of options
666 * <p>Options are :
667 * <li>'policy' - update policy to be used in case of conflict ('error', 'last' or NULL [use default])</li>
668 * <li>'waitForSync' - can be used to force synchronisation of the document removal operation to disk even in case that the waitForSync flag had been disabled for the entire collection</li>
669 * </p>
670 *
671 * @internal
672 *
673 * @return bool - always true, will throw if there is an error
674 */
675 protected function erase($url, $collection, $documentId, $revision = null, array $options = [])
676 {
677 $collection = $this->makeCollection($collection);
678
679 $params = $this->includeOptionsInParams(
680 $options, [
681 'waitForSync' => $this->getConnectionOption(ConnectionOptions::OPTION_WAIT_SYNC),
682 'silent' => false,
683 'ignoreRevs' => true,
684 'policy' => $this->getConnectionOption(ConnectionOptions::OPTION_DELETE_POLICY)
685 ]
686 );
687
688 $headers = [];
689 if (isset($params[ConnectionOptions::OPTION_DELETE_POLICY]) &&
690 $params[ConnectionOptions::OPTION_DELETE_POLICY] === UpdatePolicy::ERROR
691 ) {
692
693 if (null !== $revision) {
694 $params['ignoreRevs'] = false;
695 $headers['if-match'] = '"' . $revision . '"';
696 }
697 }
698
699 $url = UrlHelper::buildUrl($url, [$collection, $documentId]);
700 $url = UrlHelper::appendParamsUrl($url, $params);
701 $this->getConnection()->delete($url, $headers);
702
703 return true;
704 }
705
706
707 /**
708 * Helper function to get a document id from a document or a document id value
709 *
710 * @throws ClientException
711 *
712 * @param mixed $document - document id OR document to be updated
713 *
714 * @return mixed - document id, will throw if there is an error
715 */
716 private function getDocumentId($document)
717 {
718 $documentId = $document;
719 if ($document instanceof Document) {
720 $documentId = $document->getId();
721 }
722
723 if (!(is_int($documentId) || is_string($documentId) || is_float($documentId) || trim($documentId) === '')) {
724 throw new ClientException('Cannot alter a document without a document id');
725 }
726
727 return $documentId;
728 }
729
730
731 /**
732 * Helper function to get a document id from a document or a document id value
733 *
734 * @throws ClientException
735 *
736 * @param mixed $document - document id OR document to be updated
737 *
738 * @return mixed - document id, will throw if there is an error
739 */
740 private function getRevision($document)
741 {
742 $revision = null;
743
744 if ($document instanceof Document) {
745 $revision = $document->getRevision();
746 }
747
748 return $revision;
749 }
750
751 /**
752 * @param $collection mixed collection name or id
753 * @param array $options - optional, array of options
754 * <p>Options are :
755 * <li>'createCollection' - true to create the collection if it does not exist</li>
756 * <li>'createCollectionType' - "document" or 2 for document collection</li>
757 * <li> "edge" or 3 for edge collection</li>
758 * </p>
759 */
760 protected function createCollectionIfOptions($collection, $options)
761 {
762 if (!array_key_exists(CollectionHandler::OPTION_CREATE_COLLECTION, $options)) {
763 return;
764 }
765
766 $value = (bool) $options[CollectionHandler::OPTION_CREATE_COLLECTION];
767
768 if (!$value) {
769 return;
770 }
771
772 $collectionHandler = new CollectionHandler($this->getConnection());
773
774 if (array_key_exists('createCollectionType', $options)) {
775 $options['type'] = $options['createCollectionType'];
776 unset($options['createCollectionType']);
777 }
778 unset($options['createCollection']);
779 try {
780 // attempt to create the collection
781 $collectionHandler->create($collection, $options);
782 } catch (Exception $e) {
783 // collection may have existed already
784 }
785 }
786 }
787