/** * Render an individual entity * * Creates a hash representation of the Entity. The entity is first * converted to an array, and its associated links are injected as the * "_links" member. If any members of the entity are themselves * Entity objects, they are extracted into an "_embedded" hash. * * @param Entity $halEntity * @param bool $renderEntity * @param int $depth depth of the current rendering recursion * @param int $maxDepth maximum rendering depth for the current metadata * @throws Exception\CircularReferenceException * @return array */ public function renderEntity(Entity $halEntity, $renderEntity = true, $depth = 0, $maxDepth = null) { $this->getEventManager()->trigger(__FUNCTION__, $this, ['entity' => $halEntity]); $entity = $halEntity->getEntity(); $entityLinks = clone $halEntity->getLinks(); // Clone to prevent link duplication $metadataMap = $this->getMetadataMap(); if (is_object($entity)) { if ($maxDepth === null && $metadataMap->has($entity)) { $maxDepth = $metadataMap->get($entity)->getMaxDepth(); } if ($maxDepth === null) { $entityHash = spl_object_hash($entity); if (isset($this->entityHashStack[$entityHash])) { // we need to clear the stack, as the exception may be caught and the plugin may be invoked again $this->entityHashStack = []; throw new Exception\CircularReferenceException(sprintf("Circular reference detected in '%s'. %s", get_class($entity), "Either set a 'max_depth' metadata attribute or remove the reference")); } $this->entityHashStack[$entityHash] = get_class($entity); } } if (!$renderEntity || $maxDepth !== null && $depth > $maxDepth) { $entity = []; } if (!is_array($entity)) { $entity = $this->getEntityExtractor()->extract($entity); } foreach ($entity as $key => $value) { if (is_object($value) && $metadataMap->has($value)) { $value = $this->getResourceFactory()->createEntityFromMetadata($value, $metadataMap->get($value), $this->getRenderEmbeddedEntities()); } if ($value instanceof Entity) { $this->extractEmbeddedEntity($entity, $key, $value, $depth + 1, $maxDepth); } if ($value instanceof Collection) { $this->extractEmbeddedCollection($entity, $key, $value, $depth + 1, $maxDepth); } if ($value instanceof Link) { // We have a link; add it to the entity if it's not already present. $entityLinks = $this->injectPropertyAsLink($value, $entityLinks); unset($entity[$key]); } if ($value instanceof LinkCollection) { foreach ($value as $link) { $entityLinks = $this->injectPropertyAsLink($link, $entityLinks); } unset($entity[$key]); } } $halEntity->setLinks($entityLinks); $entity['_links'] = $this->fromResource($halEntity); $payload = new ArrayObject($entity); $this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, ['payload' => $payload, 'entity' => $halEntity]); if (isset($entityHash)) { unset($this->entityHashStack[$entityHash]); } return $payload->getArrayCopy(); }
public function testRendersEmbeddedEntitiesOfIndividualPaginatedCollections() { $routeClass = class_exists(V2Segment::class) ? V2Segment::class : Segment::class; $this->router->addRoute('user', new $routeClass('/user[/:id]')); $child = new Entity(['id' => 'matthew', 'name' => 'matthew', 'github' => 'weierophinney'], 'matthew'); $link = new Link('self'); $link->setRoute('user')->setRouteParams(['id' => 'matthew']); $child->getLinks()->add($link); $prototype = ['foo' => 'bar', 'user' => $child]; $items = []; foreach (range(1, 3) as $id) { $item = $prototype; $item['id'] = $id; $items[] = $item; } $adapter = new ArrayPaginator($items); $paginator = new Paginator($adapter); $collection = new Collection($paginator); $collection->setPageSize(5); $collection->setPage(1); $collection->setCollectionRoute('resource'); $collection->setEntityRoute('resource'); $links = $collection->getLinks(); $self = new Link('self'); $self->setRoute('resource'); $links->add($self); $result = $this->plugin->renderCollection($collection); $this->assertInternalType('array', $result, var_export($result, 1)); $collection = $result['_embedded']['items']; foreach ($collection as $item) { $this->assertArrayHasKey('_embedded', $item, var_export($item, 1)); $embedded = $item['_embedded']; $this->assertArrayHasKey('user', $embedded); $user = $embedded['user']; $this->assertRelationalLinkContains('/user/matthew', 'self', $user); foreach ($child->getEntity() as $key => $value) { $this->assertArrayHasKey($key, $user); $this->assertEquals($value, $user[$key]); } } }
/** * Inject links for the service services of a module * * @param Entity $halEntity * @param HalJsonModel $model * @param EventInterface $e * @return void */ private function injectServiceLinks(Entity $halEntity, HalJsonModel $model, EventInterface $e) { $entity = $halEntity->getEntity(); $links = $halEntity->getLinks(); if ($entity instanceof Model\ModuleEntity) { $this->injectModuleResourceRelationalLinks($entity, $links, $model); } if ($entity instanceof Model\RestServiceEntity || $entity instanceof Model\RpcServiceEntity) { $this->normalizeEntityControllerServiceName($entity, $links, $model); } if ($entity instanceof Model\InputFilterEntity) { $this->normalizeEntityInputFilterName($entity, $links, $model); } }