/** * {@inheritdoc} */ protected function addToTransaction($record = null, $id = null, $extras = null, $rollback = false, $continue = false, $single = false) { $fields = ArrayUtils::get($extras, ApiOptions::FIELDS); $ssFilters = ArrayUtils::get($extras, 'ss_filters'); $updates = ArrayUtils::get($extras, 'updates'); $idFields = ArrayUtils::get($extras, 'id_fields'); $needToIterate = $single || $continue || 1 < count($this->tableIdsInfo); $requireMore = ArrayUtils::getBool($extras, 'require_more'); $client = $this->parent->getGuzzleClient(); $out = []; switch ($this->getAction()) { case Verbs::POST: $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters); if (empty($parsed)) { throw new BadRequestException('No valid fields were found in record.'); } $native = json_encode($parsed); $result = $this->parent->callGuzzle('POST', 'sobjects/' . $this->transactionTable . '/', null, $native, $client); if (!ArrayUtils::getBool($result, 'success', false)) { $msg = json_encode(ArrayUtils::get($result, 'errors')); throw new InternalServerErrorException("Record insert failed for table '{$this->transactionTable}'.\n" . $msg); } $id = ArrayUtils::get($result, 'id'); // add via record, so batch processing can retrieve extras return $requireMore ? parent::addToTransaction($id) : [$idFields => $id]; case Verbs::PUT: case Verbs::MERGE: case Verbs::PATCH: if (!empty($updates)) { $record = $updates; } $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true); if (empty($parsed)) { throw new BadRequestException('No valid fields were found in record.'); } static::removeIds($parsed, $idFields); $native = json_encode($parsed); $result = $this->parent->callGuzzle('PATCH', 'sobjects/' . $this->transactionTable . '/' . $id, null, $native, $client); if ($result && !ArrayUtils::getBool($result, 'success', false)) { $msg = ArrayUtils::get($result, 'errors'); throw new InternalServerErrorException("Record update failed for table '{$this->transactionTable}'.\n" . $msg); } // add via record, so batch processing can retrieve extras return $requireMore ? parent::addToTransaction($id) : [$idFields => $id]; case Verbs::DELETE: $result = $this->parent->callGuzzle('DELETE', 'sobjects/' . $this->transactionTable . '/' . $id, null, null, $client); if ($result && !ArrayUtils::getBool($result, 'success', false)) { $msg = ArrayUtils::get($result, 'errors'); throw new InternalServerErrorException("Record delete failed for table '{$this->transactionTable}'.\n" . $msg); } // add via record, so batch processing can retrieve extras return $requireMore ? parent::addToTransaction($id) : [$idFields => $id]; case Verbs::GET: if (!$needToIterate) { return parent::addToTransaction(null, $id); } $fields = $this->buildFieldList($this->transactionTable, $fields, $idFields); $result = $this->parent->callGuzzle('GET', 'sobjects/' . $this->transactionTable . '/' . $id, ['fields' => $fields]); if (empty($result)) { throw new NotFoundException("Record with identifier '" . print_r($id, true) . "' not found."); } $out = $result; break; } return $out; }
/** * {@inheritdoc} */ protected function addToRollback($record) { return parent::addToRollback($record); }
/** * {@inheritdoc} */ protected function addToTransaction($record = null, $id = null, $extras = null, $rollback = false, $continue = false, $single = false) { $ssFilters = ArrayUtils::get($extras, 'ss_filters'); $fields = ArrayUtils::get($extras, ApiOptions::FIELDS); $requireMore = ArrayUtils::get($extras, 'require_more'); $updates = ArrayUtils::get($extras, 'updates'); $partitionKey = ArrayUtils::get($extras, static::PARTITION_KEY); if (!is_array($id)) { $id = [static::ROW_KEY => $id, static::PARTITION_KEY => $partitionKey]; } if (!empty($partitionKey)) { $id[static::PARTITION_KEY] = $partitionKey; } if (!empty($updates)) { foreach ($id as $field => $value) { if (!isset($updates[$field])) { $updates[$field] = $value; } } $record = $updates; } elseif (!empty($record)) { if (!empty($partitionKey)) { $record[static::PARTITION_KEY] = $partitionKey; } } if (!empty($record)) { $forUpdate = false; switch ($this->getAction()) { case Verbs::PUT: case Verbs::MERGE: case Verbs::PATCH: $forUpdate = true; break; } $record = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, $forUpdate); if (empty($record)) { throw new BadRequestException('No valid fields were found in record.'); } $entity = static::parseRecordToEntity($record); } else { $entity = static::parseRecordToEntity($id); } $partKey = $entity->getPartitionKey(); if (empty($partKey)) { throw new BadRequestException('No valid partition key found in request.'); } $rowKey = $entity->getRowKey(); if (empty($rowKey)) { throw new BadRequestException('No valid row key found in request.'); } // only allow batch if rollback and same partition $batch = $rollback && !empty($partitionKey); $out = []; switch ($this->getAction()) { case Verbs::POST: if ($batch) { if (!isset($this->batchOps)) { $this->batchOps = new BatchOperations(); } $this->batchOps->addInsertEntity($this->transactionTable, $entity); // track record for output return parent::addToTransaction($record); } /** @var InsertEntityResult $result */ $result = $this->parent->getConnection()->insertEntity($this->transactionTable, $entity); if ($rollback) { $this->addToRollback($entity); } $out = static::parseEntityToRecord($result->getEntity(), $fields); break; case Verbs::PUT: if ($batch) { if (!isset($this->batchOps)) { $this->batchOps = new BatchOperations(); } $this->batchOps->addUpdateEntity($this->transactionTable, $entity); // track record for output return parent::addToTransaction($record); } if ($rollback) { $old = $this->parent->getConnection()->getEntity($this->transactionTable, $entity->getRowKey(), $entity->getPartitionKey()); $this->addToRollback($old); } /** @var UpdateEntityResult $result */ $this->parent->getConnection()->updateEntity($this->transactionTable, $entity); $out = static::parseEntityToRecord($entity, $fields); break; case Verbs::MERGE: case Verbs::PATCH: if ($batch) { if (!isset($this->batchOps)) { $this->batchOps = new BatchOperations(); } $this->batchOps->addMergeEntity($this->transactionTable, $entity); // track id for output return parent::addToTransaction(null, $rowKey); } if ($rollback || $requireMore) { $old = $this->parent->getConnection()->getEntity($this->transactionTable, $rowKey, $partKey); if ($rollback) { $this->addToRollback($old); } if ($requireMore) { $out = array_merge(static::parseEntityToRecord($old, $fields), static::parseEntityToRecord($entity, $fields)); } } $out = empty($out) ? static::parseEntityToRecord($entity, $fields) : $out; /** @var UpdateEntityResult $result */ $this->parent->getConnection()->mergeEntity($this->transactionTable, $entity); break; case Verbs::DELETE: if ($batch) { if (!isset($this->batchOps)) { $this->batchOps = new BatchOperations(); } $this->batchOps->addDeleteEntity($this->transactionTable, $partKey, $rowKey); // track id for output return parent::addToTransaction(null, $rowKey); } if ($rollback || $requireMore) { $old = $this->parent->getConnection()->getEntity($this->transactionTable, $partKey, $rowKey); if ($rollback) { $this->addToRollback($old); } if ($requireMore) { $out = static::parseEntityToRecord($old, $fields); } } $this->parent->getConnection()->deleteEntity($this->transactionTable, $partKey, $rowKey); $out = empty($out) ? static::parseEntityToRecord($entity, $fields) : $out; break; case Verbs::GET: if (!empty($partitionKey)) { // track id for output return parent::addToTransaction(null, $rowKey); } /** @var GetEntityResult $result */ $result = $this->parent->getConnection()->getEntity($this->transactionTable, $partKey, $rowKey); $out = static::parseEntityToRecord($result->getEntity(), $fields); break; } return $out; }
/** * {@inheritdoc} */ protected function addToTransaction($record = null, $id = null, $extras = null, $rollback = false, $continue = false, $single = false) { $ssFilters = ArrayUtils::get($extras, 'ss_filters'); $fields = ArrayUtils::get($extras, ApiOptions::FIELDS); $requireMore = ArrayUtils::get($extras, 'require_more'); $updates = ArrayUtils::get($extras, 'updates'); // convert to native format $id = static::idToMongoId($id); $fieldArray = $rollback ? null : static::buildFieldArray($fields); $out = []; switch ($this->getAction()) { case Verbs::POST: $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters); if (empty($parsed)) { throw new BadRequestException('No valid fields were found in record.'); } if (!$continue && !$rollback && !$single) { return parent::addToTransaction($parsed, $id); } $result = $this->collection->insert($parsed); static::processResult($result); $out = static::cleanRecord($parsed, $fields, static::DEFAULT_ID_FIELD); if ($rollback) { $this->addToRollback(static::recordAsId($parsed, static::DEFAULT_ID_FIELD)); } break; case Verbs::PUT: if (!empty($updates)) { $parsed = $this->parseRecord($updates, $this->tableFieldsInfo, $ssFilters, true); $updates = $parsed; } else { $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true); } if (empty($parsed)) { throw new BadRequestException('No valid fields were found in record.'); } // only update/patch by ids can use batching if (!$continue && !$rollback && !$single && !empty($updates)) { return parent::addToTransaction(null, $id); } $options = ['new' => !$rollback]; if (empty($updates)) { $out = static::cleanRecord($record, $fields, static::DEFAULT_ID_FIELD); static::removeIds($parsed, static::DEFAULT_ID_FIELD); $updates = $parsed; } else { $record = $updates; $record[static::DEFAULT_ID_FIELD] = $id; $out = static::cleanRecord($record, $fields, static::DEFAULT_ID_FIELD); } // simple update overwrite existing record $filter = [static::DEFAULT_ID_FIELD => $id]; $criteria = $this->buildCriteriaArray($filter, null, $ssFilters); $result = $this->collection->findAndModify($criteria, $updates, $fieldArray, $options); if (empty($result)) { throw new NotFoundException("Record with id '{$id}' not found."); } if ($rollback) { $this->addToRollback($result); } else { $out = static::fromMongoObjects($result); } break; case Verbs::MERGE: case Verbs::PATCH: if (!empty($updates)) { $parsed = $this->parseRecord($updates, $this->tableFieldsInfo, $ssFilters, true); $updates = $parsed; } else { $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true); } if (empty($parsed)) { throw new BadRequestException('No valid fields were found in record.'); } // only update/patch by ids can use batching if (!$continue && !$rollback && !$single && !empty($updates)) { return parent::addToTransaction(null, $id); } $options = ['new' => !$rollback]; if (empty($updates)) { static::removeIds($parsed, static::DEFAULT_ID_FIELD); $updates = $parsed; } $updates = ['$set' => $updates]; // simple merge with existing record $filter = [static::DEFAULT_ID_FIELD => $id]; $criteria = $this->buildCriteriaArray($filter, null, $ssFilters); $result = $this->collection->findAndModify($criteria, $updates, $fieldArray, $options); if (empty($result)) { throw new NotFoundException("Record with id '{$id}' not found."); } if ($rollback) { $this->addToRollback($result); // need to retrieve the full record here if ($requireMore) { $result = $this->collection->findOne($criteria, $fieldArray); } else { $result = [static::DEFAULT_ID_FIELD => $id]; } } $out = static::fromMongoObjects($result); break; case Verbs::DELETE: if (!$continue && !$rollback && !$single) { return parent::addToTransaction(null, $id); } $options = ['remove' => true]; // simple delete existing record $filter = [static::DEFAULT_ID_FIELD => $id]; $criteria = $this->buildCriteriaArray($filter, null, $ssFilters); $result = $this->collection->findAndModify($criteria, null, $fieldArray, $options); if (empty($result)) { throw new NotFoundException("Record with id '{$id}' not found."); } if ($rollback) { $this->addToRollback($result); $out = static::cleanRecord($record, $fields, static::DEFAULT_ID_FIELD); } else { $out = static::fromMongoObjects($result); } break; case Verbs::GET: if ($continue && !$single) { return parent::addToTransaction(null, $id); } $filter = [static::DEFAULT_ID_FIELD => $id]; $criteria = $this->buildCriteriaArray($filter, null, $ssFilters); $result = $this->collection->findOne($criteria, $fieldArray); if (empty($result)) { throw new NotFoundException("Record with id '{$id}' not found."); } $out = static::fromMongoObjects($result); break; } return $out; }
/** * @return array */ public function getApiDocInfo() { $base = parent::getApiDocInfo(); // $addTableParameters = [ // [ // 'name' => 'related', // 'description' => 'Comma-delimited list of relationship names to retrieve for each record, or \'*\' to retrieve all.', // 'allowMultiple' => true, // 'type' => 'string', // 'paramType' => 'query', // 'required' => false, // ] // ]; // // $addTableNotes = // 'Use the <b>related</b> parameter to return related records for each resource. ' . // 'By default, no related records are returned.<br/> '; $base['models'] = array_merge($base['models'], static::getApiDocCommonModels()); return $base; }