Skip to content

Commit 948c443

Browse files
committed
added insertMany method
1 parent cc468ca commit 948c443

File tree

5 files changed

+338
-57
lines changed

5 files changed

+338
-57
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## Release notes for the ArangoDB-PHP driver 3.8.x
44

5+
Added CollectionHandler::insertMany() method to simplify insertion of multiple documents
6+
at once. This is now the preferred way of inserting mutliple documents in a single
7+
request, and will perform much better than using the `Batch` functionality, which is
8+
now deprecated.
9+
510
The driver now supports connecting via JWT if the server's JWT secret is known.
611
In order to use a JWT to connect, set the following values in ConnectionOptions:
712
```

lib/ArangoDBClient/Connection.php

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -904,24 +904,19 @@ public static function check_encoding($data)
904904
* internally it calls the check_encoding() method. If that method does not throw
905905
* an Exception, this method will happily return the json_encoded data.
906906
*
907-
* @param mixed $data the data to encode
908-
* @param mixed $options the options for the json_encode() call
907+
* @param mixed $data the data to encode
908+
* @param bool $forceObjects whether or not to force JSON objects on empty data
909909
*
910910
* @return string the result of the json_encode
911911
* @throws \ArangoDBClient\ClientException
912912
*/
913-
public function json_encode_wrapper($data, $options = 0)
913+
public function json_encode_wrapper($data, $forceObjects = true)
914914
{
915915
if ($this->_options[ConnectionOptions::OPTION_CHECK_UTF8_CONFORM] === true) {
916916
self::check_encoding($data);
917917
}
918-
if (empty($data)) {
919-
$response = json_encode($data, $options | JSON_FORCE_OBJECT);
920-
} else {
921-
$response = json_encode($data, $options);
922-
}
923918

924-
return $response;
919+
return json_encode($data, (empty($data) && $forceObjects) ? JSON_FORCE_OBJECT : 0);
925920
}
926921

927922

lib/ArangoDBClient/DocumentHandler.php

Lines changed: 117 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ protected function createFromArrayWithContext($data, $options)
302302
* </p>
303303
*
304304
* @return mixed - id of document created
305+
* @deprecated use insert with overwriteMode=update or overwriteMode=replace instead
305306
* @since 1.0
306307
*/
307308
public function store(Document $document, $collection = null, array $options = [])
@@ -355,42 +356,13 @@ public function store(Document $document, $collection = null, array $options = [
355356
*/
356357
public function insert($collection, $document, array $options = [])
357358
{
358-
$headers = [];
359-
$this->addTransactionHeader($headers, $collection);
360-
361-
$collection = $this->makeCollection($collection);
362-
$_documentClass = $this->_documentClass;
363-
364-
if (!isset($options[self::OPTION_OVERWRITE_MODE]) &&
365-
isset($options[self::OPTION_OVERWRITE])) {
366-
// map "overwrite" to "overwriteMode"
367-
$options[self::OPTION_OVERWRITE_MODE] = $options[self::OPTION_OVERWRITE] ? 'replace' : 'conflict';
368-
unset($options[self::OPTION_OVERWRITE]);
369-
}
370-
371-
$params = $this->includeOptionsInParams(
372-
$options, [
373-
'waitForSync' => $this->getConnectionOption(ConnectionOptions::OPTION_WAIT_SYNC),
374-
'returnOld' => (bool) @$options[self::OPTION_RETURN_OLD],
375-
'returnNew' => (bool) @$options[self::OPTION_RETURN_NEW],
376-
]
377-
);
378-
379-
if ((isset($options['createCollection']) && $options['createCollection']) ||
380-
$this->getConnection()->getOption(ConnectionOptions::OPTION_CREATE)) {
381-
$this->lazyCreateCollection($collection, $params);
382-
}
383-
384-
$url = UrlHelper::appendParamsUrl(Urls::URL_DOCUMENT . '/' . $collection, $params);
385-
386359
if (is_array($document)) {
387360
$data = $document;
388361
} else {
389362
$data = $document->getAllForInsertUpdate();
390363
}
391-
392-
$response = $this->getConnection()->post($url, $this->json_encode_wrapper($data), $headers);
393-
$json = $response->getJson();
364+
365+
$response = $this->post($collection, $data, $options);
394366

395367
// This makes sure that if we're in batch mode, it will not go further and choke on the checks below.
396368
// Caution: Instead of a document ID, we are returning the batchpart object
@@ -400,30 +372,32 @@ public function insert($collection, $document, array $options = [])
400372
return $batchPart;
401373
}
402374

403-
if (@$params[self::OPTION_SILENT]) {
375+
if (@$options[self::OPTION_SILENT]) {
404376
// nothing will be returned here
405377
return null;
406378
}
379+
380+
$json = $response->getJson();
407381

408-
if ($params[self::OPTION_RETURN_OLD] || $params[self::OPTION_RETURN_NEW]) {
382+
if (@$options[self::OPTION_RETURN_OLD] || @$options[self::OPTION_RETURN_NEW]) {
409383
return $json;
410384
}
411385

386+
$_documentClass = $this->_documentClass;
412387
if (is_array($document)) {
413388
return $json[$_documentClass::ENTRY_KEY];
414389
}
415390

391+
$document->setInternalKey($json[$_documentClass::ENTRY_KEY]);
392+
$document->setInternalId($json[$_documentClass::ENTRY_ID]);
393+
$document->setRevision($json[$_documentClass::ENTRY_REV]);
394+
416395
$location = $response->getLocationHeader();
417396
if (!$location) {
418397
throw new ClientException('Did not find location header in server response');
419398
}
420399

421400
$id = UrlHelper::getDocumentIdFromLocation($location);
422-
423-
$document->setInternalKey($json[$_documentClass::ENTRY_KEY]);
424-
$document->setInternalId($json[$_documentClass::ENTRY_ID]);
425-
$document->setRevision($json[$_documentClass::ENTRY_REV]);
426-
427401
if ($id !== $document->getId()) {
428402
throw new ClientException('Got an invalid response from the server');
429403
}
@@ -433,10 +407,111 @@ public function insert($collection, $document, array $options = [])
433407
return $document->getId();
434408
}
435409

410+
411+
/**
412+
* insert multiple document into a collection
413+
*
414+
* This will add the documents to the collection and return the documents' metadata
415+
*
416+
* This will throw if the documents cannot be saved
417+
*
418+
* @throws Exception
419+
*
420+
* @param mixed $collection - collection id as string or number
421+
* @param array $documents - the documents to be added, always an array
422+
* @param array $options - optional, array of options
423+
* <p>Options are :<br>
424+
* <li>'createCollection' - create the collection if it does not yet exist.</li>
425+
* <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>
426+
* <li>'keepNull' - can be used to instruct ArangoDB to delete existing attributes on update instead setting their values to null. Defaults to true (keep attributes when set to null). only useful with overwriteMode = update</li>
427+
* <li>'mergeObjects' - if true, updates to object attributes will merge the previous and the new objects. if false, replaces the object attribute with the new value. only useful with overwriteMode = update</li>
428+
* <li>'overwriteMode' - determines overwrite behavior in case a document with the same _key already exists. possible values: 'ignore', 'update', 'replace', 'conflict'.</li>
429+
* <li>'overwrite' - deprecated: if set to true, will turn the insert into a replace operation if a document with the specified key already exists.</li>
430+
* <li>'returnNew' - if set to true, then the newly created document will be returned.</li>
431+
* <li>'returnOld' - if set to true, then the updated/replaced document will be returned - useful only when using overwriteMode = insert/update.</li>
432+
* <li>'silent' - whether or not to return information about the created document (e.g. _key and _rev).</li>
433+
* </p>
434+
*
435+
* @return array - array of document metadata (one entry per document)
436+
* @since 3.8
437+
*/
438+
public function insertMany($collection, array $documents, array $options = [])
439+
{
440+
$data = [];
441+
foreach ($documents as $document) {
442+
if (is_array($document)) {
443+
$data[] = $document;
444+
} else {
445+
$data[] = $document->getAllForInsertUpdate();
446+
}
447+
}
448+
449+
$response = $this->post($collection, $data, $options);
450+
451+
// This makes sure that if we're in batch mode, it will not go further and choke on the checks below.
452+
// Caution: Instead of a document ID, we are returning the batchpart object
453+
// The Id of the BatchPart can be retrieved by calling getId() on it.
454+
// We're basically returning an object here, in order not to accidentally use the batch part id as the document id
455+
if ($batchPart = $response->getBatchPart()) {
456+
return $batchPart;
457+
}
458+
459+
return $response->getJson();
460+
}
461+
462+
463+
/**
464+
* Insert documents into a collection (internal method)
465+
*
466+
* @throws Exception
467+
*
468+
* @param string $collection - collection id as string or number
469+
* @param mixed $data - document data
470+
* @param array $options - array of options
471+
*
472+
* @internal
473+
*
474+
* @return HttpResponse - the insert response
475+
*/
476+
protected function post($collection, $data, array $options)
477+
{
478+
$headers = [];
479+
$this->addTransactionHeader($headers, $collection);
480+
481+
$collection = $this->makeCollection($collection);
482+
483+
if (!isset($options[self::OPTION_OVERWRITE_MODE]) &&
484+
isset($options[self::OPTION_OVERWRITE])) {
485+
// map "overwrite" to "overwriteMode"
486+
$options[self::OPTION_OVERWRITE_MODE] = $options[self::OPTION_OVERWRITE] ? 'replace' : 'conflict';
487+
unset($options[self::OPTION_OVERWRITE]);
488+
}
489+
490+
$params = $this->includeOptionsInParams(
491+
$options, [
492+
'waitForSync' => $this->getConnectionOption(ConnectionOptions::OPTION_WAIT_SYNC),
493+
'returnOld' => (bool) @$options[self::OPTION_RETURN_OLD],
494+
'returnNew' => (bool) @$options[self::OPTION_RETURN_NEW],
495+
]
496+
);
497+
498+
if ((isset($options['createCollection']) && $options['createCollection']) ||
499+
$this->getConnection()->getOption(ConnectionOptions::OPTION_CREATE)) {
500+
$this->lazyCreateCollection($collection, $params);
501+
}
502+
503+
$url = UrlHelper::appendParamsUrl(Urls::URL_DOCUMENT . '/' . $collection, $params);
504+
505+
return $this->getConnection()->post($url, $this->json_encode_wrapper($data, false), $headers);
506+
}
507+
508+
436509
/**
437510
* Insert a document into a collection
438511
*
439512
* This is an alias for insert().
513+
*
514+
* * @deprecated use insert instead
440515
*/
441516
public function save($collection, $document, array $options = [])
442517
{
@@ -534,7 +609,6 @@ protected function patch($url, $collection, $documentId, Document $document, arr
534609
$this->addTransactionHeader($headers, $collection);
535610

536611
$collection = $this->makeCollection($collection);
537-
$_documentClass = $this->_documentClass;
538612

539613
$params = $this->includeOptionsInParams(
540614
$options, [
@@ -568,7 +642,8 @@ protected function patch($url, $collection, $documentId, Document $document, arr
568642
return null;
569643
}
570644

571-
$json = $result->getJson();
645+
$json = $result->getJson();
646+
$_documentClass = $this->_documentClass;
572647
$document->setRevision($json[$_documentClass::ENTRY_REV]);
573648

574649
if (@$options[self::OPTION_RETURN_OLD] || @$options[self::OPTION_RETURN_NEW]) {
@@ -668,7 +743,6 @@ protected function put($url, $collection, $documentId, Document $document, array
668743
$this->addTransactionHeader($headers, $collection);
669744

670745
$collection = $this->makeCollection($collection);
671-
$_documentClass = $this->_documentClass;
672746

673747
$params = $this->includeOptionsInParams(
674748
$options, [
@@ -700,7 +774,8 @@ protected function put($url, $collection, $documentId, Document $document, array
700774
return null;
701775
}
702776

703-
$json = $result->getJson();
777+
$json = $result->getJson();
778+
$_documentClass = $this->_documentClass;
704779
$document->setRevision($json[$_documentClass::ENTRY_REV]);
705780

706781
if (@$options[self::OPTION_RETURN_OLD] || @$options[self::OPTION_RETURN_NEW]) {

lib/ArangoDBClient/Handler.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,15 @@ protected function getConnectionOption($optionName)
7272
* Return a json encoded string for the array passed.
7373
* This is a convenience function that calls json_encode_wrapper on the connection
7474
*
75-
* @param array $body - The body to encode into json
75+
* @param mixed $data the data to encode
76+
* @param bool $forceObjects whether or not to force JSON objects on empty data
7677
*
7778
* @return string - json string of the body that was passed
7879
* @throws \ArangoDBClient\ClientException
7980
*/
80-
protected function json_encode_wrapper($body)
81+
protected function json_encode_wrapper($data, $forceObjects = true)
8182
{
82-
return $this->getConnection()->json_encode_wrapper($body);
83+
return $this->getConnection()->json_encode_wrapper($data, $forceObjects);
8384
}
8485

8586

0 commit comments

Comments
 (0)