/** * Execute a batch create operation. * * @param Request $request * @param null|AdapterInterface $adapter Custom adapter * @return Response */ protected function executeBatchCreate(Request $request, AdapterInterface $adapter) { $t = $this->getTranslator(); if (!is_array($request->getContent())) { throw new Exception\BadRequestException($t->translate('Invalid batch operation request data.')); } // Create a simulated request for individual create events. $createRequest = new Request(Request::CREATE, $request->getResource()); // Trigger the create.pre event for every resource. foreach ($request->getContent() as $content) { $createRequest->setContent($content); $createEvent = new Event(Event::API_CREATE_PRE, $adapter, ['request' => $createRequest]); $adapter->getEventManager()->trigger($createEvent); } $response = $adapter->batchCreate($request); // Do not trigger create.post events if an error has occured or if the // response does not return valid content. if ($response->isError() || !is_array($response->getContent())) { return $response; } // Trigger the create.post event for every created resource. foreach ($response->getContent() as $resource) { $createRequest->setContent($resource); $createEvent = new Event(Event::API_CREATE_POST, $adapter, ['request' => $createRequest, 'response' => new Response($resource)]); $adapter->getEventManager()->trigger($createEvent); } return $response; }
/** * Batch create entities. * * Preserves the keys of the request content array as the keys of the * response content array. This is helpful for implementations that need to * map original identifiers to the newly created entity IDs. * * There are two outcomes if an exception is thrown during a batch. If * continueOnError is set to the request, the current entity is thrown away * but the operation continues. Otherwise, all previously created entities * are removed. * * Detaches entities after they've been created to minimize memory usage. * Because the entities are detached, this returns resource references * (containing only the entity ID) instead of full entity representations. * * {@inheritDoc} */ public function batchCreate(Request $request) { $errorStore = new ErrorStore(); $logger = $this->getServiceLocator()->get('Omeka\\Logger'); $entities = []; foreach ($request->getContent() as $key => $datum) { $entityClass = $this->getEntityClass(); $entity = new $entityClass(); $subRequest = new Request(Request::CREATE, $request->getResource()); $subRequest->setContent($datum); try { $this->hydrateEntity($subRequest, $entity, $errorStore); } catch (\Exception $e) { if ($request->continueOnError()) { $logger->err((string) $e); continue; } // Remove previously persisted entities before re-throwing. foreach ($entities as $entity) { $this->getEntityManager()->remove($entity); } $this->getEntityManager()->flush(); throw $e; } $this->getEntityManager()->persist($entity); $entities[$key] = $entity; } $this->getEntityManager()->flush(); $references = []; foreach ($entities as $key => $entity) { $references[$key] = new ResourceReference($entity, $this); $this->getEntityManager()->detach($entity); } return new Response($references); }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { parent::hydrate($request, $entity, $errorStore); if ($this->shouldHydrate($request, 'o:item_set')) { $itemSetsData = $request->getValue('o:item_set', []); $itemSetAdapter = $this->getAdapter('item_sets'); $itemSets = $entity->getItemSets(); $itemSetsToRetain = []; foreach ($itemSetsData as $itemSetData) { if (is_array($itemSetData) && array_key_exists('o:id', $itemSetData) && is_numeric($itemSetData['o:id'])) { $itemSetId = $itemSetData['o:id']; } elseif (is_numeric($itemSetData)) { $itemSetId = $itemSetData; } else { continue; } if (!($itemSet = $itemSets->get($itemSetId))) { // Item set not already assigned. Assign it. $itemSet = $itemSetAdapter->findEntity($itemSetId); $itemSets->add($itemSet); } $itemSetsToRetain[] = $itemSet; } // Unassign item sets that were not included in the passed data. foreach ($itemSets as $itemSet) { if (!in_array($itemSet, $itemSetsToRetain)) { $itemSets->removeElement($itemSet); } } } if ($this->shouldHydrate($request, 'o:media')) { $mediasData = $request->getValue('o:media', []); $adapter = $this->getAdapter('media'); $class = $adapter->getEntityClass(); $retainMedia = []; $position = 1; foreach ($mediasData as $mediaData) { $subErrorStore = new ErrorStore(); if (isset($mediaData['o:id'])) { $media = $adapter->findEntity($mediaData['o:id']); $media->setPosition($position); if (isset($mediaData['o:is_public'])) { $media->setIsPublic($mediaData['o:is_public']); } $retainMedia[] = $media; } else { // Create a new media. $media = new $class(); $media->setItem($entity); $media->setPosition($position); $subrequest = new Request(Request::CREATE, 'media'); $subrequest->setContent($mediaData); $subrequest->setFileData($request->getFileData()); try { $adapter->hydrateEntity($subrequest, $media, $subErrorStore); } catch (Exception\ValidationException $e) { $errorStore->mergeErrors($e->getErrorStore(), 'o:media'); } $entity->getMedia()->add($media); $retainMedia[] = $media; } $position++; } // Remove media not included in request. foreach ($entity->getMedia() as $media) { if (!in_array($media, $retainMedia, true)) { $entity->getMedia()->removeElement($media); } } } }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $this->hydrateOwner($request, $entity); if ($this->shouldHydrate($request, 'o:namespace_uri')) { $entity->setNamespaceUri($request->getValue('o:namespace_uri')); } if ($this->shouldHydrate($request, 'o:prefix')) { $entity->setPrefix($request->getValue('o:prefix')); } if ($this->shouldHydrate($request, 'o:label')) { $entity->setLabel($request->getValue('o:label')); } if ($this->shouldHydrate($request, 'o:comment')) { $entity->setComment($request->getValue('o:comment')); } if ($this->shouldHydrate($request, 'o:class')) { $classesData = $request->getValue('o:class', []); $adapter = $this->getAdapter('resource_classes'); $class = $adapter->getEntityClass(); $retainResourceClasses = []; $retainResourceClassIds = []; foreach ($classesData as $classData) { if (isset($classData['o:id'])) { // Do not update existing resource classes. $retainResourceClassIds[] = $classData['o:id']; } else { // Create a new resource class. $resourceClass = new $class(); $resourceClass->setVocabulary($entity); $subrequest = new Request(Request::CREATE, 'resource_classes'); $subrequest->setContent($classData); $adapter->hydrateEntity($subrequest, $resourceClass, $errorStore); $entity->getResourceClasses()->add($resourceClass); $retainResourceClasses[] = $resourceClass; } } // Remove resource classes not included in request. foreach ($entity->getResourceClasses() as $resourceClass) { if (!in_array($resourceClass, $retainResourceClasses, true) && !in_array($resourceClass->getId(), $retainResourceClassIds)) { $entity->getResourceClasses()->removeElement($resourceClass); } } } if ($this->shouldHydrate($request, 'o:property')) { $propertiesData = $request->getValue('o:property', []); $adapter = $this->getAdapter('properties'); $class = $adapter->getEntityClass(); $retainProperties = []; $retainPropertyIds = []; foreach ($propertiesData as $propertyData) { if (isset($propertyData['o:id'])) { // Do not update existing properties. $retainPropertyIds[] = $propertyData['o:id']; } else { // Create a new property. $property = new $class(); $property->setVocabulary($entity); $subrequest = new Request(Request::CREATE, 'properties'); $subrequest->setContent($propertyData); $adapter->hydrateEntity($subrequest, $property, $errorStore); $entity->getProperties()->add($property); $retainProperties[] = $property; } } // Remove resource classes not included in request. foreach ($entity->getProperties() as $property) { if (!in_array($property, $retainProperties, true) && !in_array($property->getId(), $retainPropertyIds)) { $entity->getProperties()->removeElement($property); } } } }