/** * Executes all queued document upserts. * * Queued documents with an ID are upserted individually. * * If no upserts are queued, invoking this method is a NOOP. * * @param array $options Options for batchInsert() and update() driver methods */ public function executeUpserts(array $options = array()) { if (!$this->queuedUpserts) { return; } foreach ($this->queuedUpserts as $oid => $document) { $data = $this->pb->prepareUpsertData($document); // Set the initial version for each upsert if ($this->class->isVersioned) { $versionMapping = $this->class->fieldMappings[$this->class->versionField]; if ($versionMapping['type'] === 'int') { $nextVersion = max(1, (int) $this->class->reflFields[$this->class->versionField]->getValue($document)); $this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersion); } elseif ($versionMapping['type'] === 'date') { $nextVersionDateTime = new \DateTime(); $nextVersion = new \MongoDate($nextVersionDateTime->getTimestamp()); $this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersionDateTime); } $data['$set'][$versionMapping['name']] = $nextVersion; } try { $this->executeUpsert($data, $options); $this->handleCollections($document, $options); unset($this->queuedUpserts[$oid]); } catch (\MongoException $e) { unset($this->queuedUpserts[$oid]); throw $e; } } }
/** * Executes a single upsert in {@link executeUpserts} * * @param object $document * @param array $options */ private function executeUpsert($document, array $options) { $options['upsert'] = true; $criteria = $this->getQueryForDocument($document); $data = $this->pb->prepareUpsertData($document); // Set the initial version for each upsert if ($this->class->isVersioned) { $versionMapping = $this->class->fieldMappings[$this->class->versionField]; if ($versionMapping['type'] === 'int') { $nextVersion = max(1, (int) $this->class->reflFields[$this->class->versionField]->getValue($document)); $this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersion); } elseif ($versionMapping['type'] === 'date') { $nextVersionDateTime = new \DateTime(); $nextVersion = new \MongoDate($nextVersionDateTime->getTimestamp()); $this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersionDateTime); } $data['$set'][$versionMapping['name']] = $nextVersion; } foreach (array_keys($criteria) as $field) { unset($data['$set'][$field]); } // Do not send an empty $set modifier if (empty($data['$set'])) { unset($data['$set']); } /* If there are no modifiers remaining, we're upserting a document with * an identifier as its only field. Since a document with the identifier * may already exist, the desired behavior is "insert if not exists" and * NOOP otherwise. MongoDB 2.6+ does not allow empty modifiers, so $set * the identifier to the same value in our criteria. * * This will fail for versions before MongoDB 2.6, which require an * empty $set modifier. The best we can do (without attempting to check * server versions in advance) is attempt the 2.6+ behavior and retry * after the relevant exception. * * See: https://jira.mongodb.org/browse/SERVER-12266 */ if (empty($data)) { $retry = true; $data = array('$set' => array('_id' => $criteria['_id'])); } try { $this->collection->update($criteria, $data, $options); return; } catch (\MongoCursorException $e) { if (empty($retry) || strpos($e->getMessage(), 'Mod on _id not allowed') === false) { throw $e; } } $this->collection->update($criteria, array('$set' => new \stdClass()), $options); }
/** * Executes all queued document upserts. * * Queued documents with an ID are upserted individually. * * If no upserts are queued, invoking this method is a NOOP. * * @param array $options Options for batchInsert() and update() driver methods */ public function executeUpserts(array $options = array()) { if (!$this->queuedUpserts) { return; } foreach ($this->queuedUpserts as $oid => $document) { $data = $this->pb->prepareUpsertData($document); try { $this->executeUpsert($data, $options); unset($this->queuedUpserts[$oid]); } catch (\MongoException $e) { unset($this->queuedUpserts[$oid]); throw $e; } } }