Example #1
0
 public function testInjectCollectionSelfLinkShouldAddSelfLinkToLinkCollection()
 {
     $linkCollection = new LinkCollection();
     $resource = new Collection([]);
     $resource->setLinks($linkCollection);
     $injector = new SelfLinkInjector();
     $injector->injectSelfLink($resource, 'foo');
     $this->assertTrue($linkCollection->has('self'));
 }
 public function halObjects()
 {
     $entity = new Entity(['foo' => 'bar'], 'identifier', 'route');
     $link = new Link('self');
     $link->setRoute('resource/route')->setRouteParams(['id' => 'identifier']);
     $entity->getLinks()->add($link);
     $collection = new Collection([$entity]);
     $collection->setCollectionRoute('collection/route');
     $collection->setEntityRoute('resource/route');
     return ['entity' => [$entity], 'collection' => [$collection]];
 }
 /**
  * @param  int $pages
  * @param  int $currentPage
  * @return Collection
  */
 private function getHalCollection($pages, $currentPage)
 {
     $items = [];
     for ($i = 0; $i < $pages; $i++) {
         $items[] = [];
     }
     $adapter = new ArrayAdapter($items);
     $collection = new Paginator($adapter);
     $halCollection = new Collection($collection);
     $halCollection->setCollectionRoute('foo');
     $halCollection->setPage($currentPage);
     $halCollection->setPageSize(1);
     return $halCollection;
 }
Example #4
0
    public function halObjects()
    {
        $entity = new Entity(array(
            'foo' => 'bar',
        ), 'identifier', 'route');
        $link = new Link('self');
        $link->setRoute('resource/route')->setRouteParams(array('id' => 'identifier'));
        $entity->getLinks()->add($link);

        $collection = new Collection(array($entity));
        $collection->setCollectionRoute('collection/route');
        $collection->setEntityRoute('resource/route');

        return array(
            'entity'     => array($entity),
            'collection' => array($collection),
        );
    }
 public function settingsDashboardAction()
 {
     $authentication = $this->authentication->fetch();
     if ($authentication) {
         $authenticationEntity = $authentication;
         $authentication = new Entity($authentication, null);
         $authentication->getLinks()->add(Link::factory(array('rel' => 'self', 'route' => $this->getRouteForEntity($authenticationEntity))));
     }
     $dbAdapters = new Collection($this->dbAdapters->fetchAll());
     $dbAdapters->setCollectionRoute('zf-apigility/api/db-adapter');
     $contentNegotiation = new Collection($this->contentNegotiation->fetchAll());
     $contentNegotiation->setCollectionRoute('zf-apigility/api/content-negotiation');
     $dashboard = array('authentication' => $authentication, 'content_negotiation' => $contentNegotiation, 'db_adapter' => $dbAdapters);
     $entity = new Entity($dashboard, 'settings-dashboard');
     $links = $entity->getLinks();
     $links->add(Link::factory(array('rel' => 'self', 'route' => array('name' => 'zf-apigility/api/settings-dashboard'))));
     return new ViewModel(array('payload' => $entity));
 }
 /**
  * @param HalCollection $halCollection
  * @return array
  */
 protected function getCollectionPayload(HalCollection $halCollection)
 {
     $collection = $halCollection->getCollection();
     $collectionName = $halCollection->getCollectionName();
     $attributes = $halCollection->getAttributes();
     $normalizationGroups = $this->getNormalizationGroups($halCollection);
     if ($collection instanceof Paginator) {
         $pageSize = (int) (isset($attributes['page_size']) ? $attributes['page_size'] : $halCollection->getPageSize());
         $collection->setItemCountPerPage($pageSize);
         $items = (array) $collection->getCurrentItems();
         /** @todo Force snake case as collection name? */
         $payload = array($collectionName => $this->getNormalizer()->normalize($items, $normalizationGroups), 'page_count' => (int) (isset($attributes['page_count']) ? $attributes['page_count'] : $collection->count()), 'page_size' => $pageSize, 'total_items' => (int) (isset($attributes['total_items']) ? $attributes['total_items'] : $collection->getTotalItemCount()));
     } else {
         $payload = array($collectionName => $this->getNormalizer()->normalize($collection, $normalizationGroups));
         if (is_array($collection) || $collection instanceof Countable) {
             $payload['total_items'] = isset($attributes['total_items']) ? $attributes['total_items'] : count($collection);
         }
     }
     $payload = array_merge($attributes, $payload);
     return $payload;
 }
Example #7
0
 /**
  * @param  object $object
  * @param  Metadata $metadata
  * @return Collection
  */
 public function createCollectionFromMetadata($object, Metadata $metadata)
 {
     $halCollection = new Collection($object);
     $halCollection->setCollectionName($metadata->getCollectionName());
     $halCollection->setCollectionRoute($metadata->getRoute());
     $halCollection->setEntityRoute($metadata->getEntityRoute());
     $halCollection->setRouteIdentifierName($metadata->getRouteIdentifierName());
     $halCollection->setEntityIdentifierName($metadata->getEntityIdentifierName());
     $links = $halCollection->getLinks();
     $this->marshalMetadataLinks($metadata, $links);
     $forceSelfLink = $metadata->getForceSelfLink();
     if ($forceSelfLink && !$links->has('self') && ($metadata->hasUrl() || $metadata->hasRoute())) {
         $link = $this->marshalLinkFromMetadata($metadata, $object);
         $links->add($link);
     }
     return $halCollection;
 }
Example #8
0
 public function testAllowsSpecifyingAlternateCallbackForReturningEntityId()
 {
     $this->plugin->getEventManager()->attach('getIdFromEntity', function ($e) {
         $entity = $e->getParam('entity');
         if (!is_array($entity)) {
             return false;
         }
         if (array_key_exists('name', $entity)) {
             return $entity['name'];
         }
         return false;
     }, 10);
     $prototype = ['foo' => 'bar'];
     $items = [];
     foreach (range(1, 100) as $id) {
         $item = $prototype;
         $item['name'] = $id;
         $items[] = $item;
     }
     $collection = new Collection($items);
     $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));
     $this->assertRelationalLinkEquals('http://localhost.localdomain/resource', 'self', $result);
     $this->assertArrayHasKey('_embedded', $result);
     $this->assertInternalType('array', $result['_embedded']);
     $this->assertArrayHasKey('items', $result['_embedded']);
     $this->assertInternalType('array', $result['_embedded']['items']);
     $this->assertEquals(100, count($result['_embedded']['items']));
     foreach ($result['_embedded']['items'] as $key => $item) {
         $id = $key + 1;
         $this->assertRelationalLinkEquals('http://localhost.localdomain/resource/' . $id, 'self', $item);
         $this->assertArrayHasKey('name', $item, var_export($item, 1));
         $this->assertEquals($id, $item['name']);
         $this->assertArrayHasKey('foo', $item);
         $this->assertEquals('bar', $item['foo']);
     }
 }
 /**
  * Inject the input filters collection, if any, as an embedded collection
  *
  * @param RestServiceEntity $service
  */
 protected function injectInputFilters(RestServiceEntity $service)
 {
     $inputFilters = $this->inputFilterModel->fetch($this->moduleName, $service->controllerServiceName);
     if (!$inputFilters instanceof InputFilterCollection || !count($inputFilters)) {
         return;
     }
     $collection = [];
     $parentName = str_replace('\\', '-', $service->controllerServiceName);
     foreach ($inputFilters as $inputFilter) {
         $inputFilter['input_filter_name'] = str_replace('\\', '-', $inputFilter['input_filter_name']);
         $entity = new HalEntity($inputFilter, $inputFilter['input_filter_name']);
         $links = $entity->getLinks();
         $links->add(Link::factory(['rel' => 'self', 'route' => ['name' => 'zf-apigility/api/module/rest-service/input-filter', 'params' => ['name' => $this->moduleName, 'controller_service_name' => $parentName, 'input_filter_name' => $inputFilter['input_filter_name']]]]));
         $collection[] = $entity;
     }
     $collection = new HalCollection($collection);
     $collection->setCollectionName('input_filter');
     $collection->setCollectionRoute('zf-apigility/module/rest-service/input-filter');
     $collection->setCollectionRouteParams(['name' => $service->module, 'controller_service_name' => $service->controllerServiceName]);
     $service->exchangeArray(['input_filters' => $collection]);
 }
 public function testAllowsSpecifyingAlternateCallbackForReturningEntityId()
 {
     $this->setUpHelpers();
     $this->helpers->get('Hal')->getEventManager()->attach('getIdFromEntity', function ($e) {
         $entity = $e->getParam('entity');
         if (!is_array($entity)) {
             return false;
         }
         if (array_key_exists('name', $entity)) {
             return $entity['name'];
         }
         return false;
     }, 10);
     $prototype = array('foo' => 'bar');
     $items = array();
     foreach (range(1, 100) as $id) {
         $item = $prototype;
         $item['name'] = $id;
         $items[] = $item;
     }
     $collection = new Collection($items);
     $collection->setCollectionRoute('resource');
     $collection->setEntityRoute('resource');
     $links = $collection->getLinks();
     $self = new Link('self');
     $self->setRoute('resource');
     $links->add($self);
     $model = new HalJsonModel(array('payload' => $collection));
     $test = $this->renderer->render($model);
     $test = json_decode($test);
     $this->assertInstanceof('stdClass', $test, var_export($test, 1));
     $this->assertRelationalLinkEquals('http://localhost.localdomain/resource', 'self', $test);
     $this->assertObjectHasAttribute('_embedded', $test);
     $this->assertInstanceof('stdClass', $test->_embedded);
     $this->assertObjectHasAttribute('items', $test->_embedded);
     $this->assertInternalType('array', $test->_embedded->items);
     $this->assertEquals(100, count($test->_embedded->items));
     foreach ($test->_embedded->items as $key => $item) {
         $id = $key + 1;
         $this->assertRelationalLinkEquals('http://localhost.localdomain/resource/' . $id, 'self', $item);
         $this->assertObjectHasAttribute('name', $item, var_export($item, 1));
         $this->assertEquals($id, $item->name);
         $this->assertObjectHasAttribute('foo', $item);
         $this->assertEquals('bar', $item->foo);
     }
 }
Example #11
0
    /**
     * @group 14
     */
    public function testRenderingNonPaginatorCollectionRendersCountOfTotalItems()
    {
        $embedded = new Entity((object) array('id' => 'foo', 'name' => 'foo'), 'foo');
        $links = $embedded->getLinks();
        $self = new Link('self');
        $self->setRoute('hostname/users', array('id' => 'foo'));
        $links->add($self);

        $collection = new Collection(array($embedded));
        $collection->setCollectionName('users');
        $self = new Link('self');
        $self->setRoute('hostname/users');
        $collection->getLinks()->add($self);

        $rendered = $this->plugin->renderCollection($collection);

        $expectedKeys = array('_links', '_embedded', 'total_items');
        $this->assertEquals($expectedKeys, array_keys($rendered));
    }
 private function createPaginationLink($relation, Collection $halCollection, $page = null)
 {
     $options = ArrayUtils::merge($halCollection->getCollectionRouteOptions(), ['query' => ['page' => $page]]);
     return Link::factory(['rel' => $relation, 'route' => ['name' => $halCollection->getCollectionRoute(), 'params' => $halCollection->getCollectionRouteParams(), 'options' => $options]]);
 }
Example #13
0
    /**
     * Extract a collection as an array
     *
     * @todo   Remove 'resource' from event parameters for 1.0.0
     * @todo   Remove trigger of 'renderCollection.resource' for 1.0.0
     * @param  Collection $halCollection
     * @param  int $depth                   depth of the current rendering recursion
     * @param  int $maxDepth                maximum rendering depth for the current metadata
     * @return array
     */
    protected function extractCollection(Collection $halCollection, $depth = 0, $maxDepth = null)
    {
        $collection           = array();
        $events               = $this->getEventManager();
        $routeIdentifierName  = $halCollection->getRouteIdentifierName();
        $entityRoute          = $halCollection->getEntityRoute();
        $entityRouteParams    = $halCollection->getEntityRouteParams();
        $entityRouteOptions   = $halCollection->getEntityRouteOptions();
        $metadataMap          = $this->getMetadataMap();

        foreach ($halCollection->getCollection() as $entity) {
            $eventParams = new ArrayObject(array(
                'collection'   => $halCollection,
                'entity'       => $entity,
                'resource'     => $entity,
                'route'        => $entityRoute,
                'routeParams'  => $entityRouteParams,
                'routeOptions' => $entityRouteOptions,
            ));
            $events->trigger('renderCollection.resource', $this, $eventParams);
            $events->trigger('renderCollection.entity', $this, $eventParams);

            $entity = $eventParams['entity'];

            if (is_object($entity) && $metadataMap->has($entity)) {
                $entity = $this->createEntityFromMetadata($entity, $metadataMap->get($entity));
            }

            if ($entity instanceof Entity) {
                // Depth does not increment at this level
                $collection[] = $this->renderEntity($entity, $this->getRenderCollections(), $depth, $maxDepth);
                continue;
            }

            if (!is_array($entity)) {
                $entity = $this->convertEntityToArray($entity);
            }

            foreach ($entity as $key => $value) {
                if (is_object($value) && $metadataMap->has($value)) {
                    $value = $this->createEntityFromMetadata($value, $metadataMap->get($value));
                }

                if ($value instanceof Entity) {
                    $this->extractEmbeddedEntity($entity, $key, $value, $depth + 1, $maxDepth);
                }

                if ($value instanceof Collection) {
                    $this->extractEmbeddedCollection($entity, $key, $value, $depth + 1, $maxDepth);
                }
            }

            $id = $this->getIdFromEntity($entity);

            if ($id === false) {
                // Cannot handle entities without an identifier
                // Return as-is
                $collection[] = $entity;
                continue;
            }

            if ($eventParams['entity'] instanceof LinkCollectionAwareInterface) {
                $links = $eventParams['entity']->getLinks();
            } else {
                $links = new LinkCollection();
            }

            if (isset($entity['links']) && $entity['links'] instanceof LinkCollection) {
                $links = $entity['links'];
            }

            $selfLink = new Link('self');
            $selfLink->setRoute(
                $eventParams['route'],
                array_merge($eventParams['routeParams'], array($routeIdentifierName => $id)),
                $eventParams['routeOptions']
            );
            $links->add($selfLink);

            $entity['_links'] = $this->fromLinkCollection($links);

            $collection[] = $entity;
        }

        return $collection;
    }
 public function indexAction()
 {
     $event = $this->getEvent();
     $routeMatch = $event->getRouteMatch();
     $route = $this->deriveRouteName($routeMatch->getMatchedRouteName());
     $request = $this->getRequest();
     $module = $this->params()->fromRoute('name', false);
     $controller = $this->params()->fromRoute('controller_service_name', false);
     $inputFilterName = $this->params()->fromRoute('input_filter_name', false);
     if (!$module || !$this->model->moduleExists($module)) {
         return new ApiProblemResponse(new ApiProblem(404, 'The module specified does not exist'));
     }
     if (!$controller || !$this->model->controllerExists($module, $controller)) {
         return new ApiProblemResponse(new ApiProblem(404, 'The controller specified does not exist'));
     }
     switch ($request->getMethod()) {
         case $request::METHOD_GET:
             $result = $this->model->fetch($module, $controller, $inputFilterName);
             if (false === $result) {
                 return new ApiProblemResponse(new ApiProblem(404, 'The input filter specified does not exist'));
             }
             if ($result instanceof InputFilterCollection) {
                 $result = new HalCollection($result);
                 $result->setCollectionName('input_filter');
                 $result->getLinks()->add(Link::factory(array('rel' => 'self', 'route' => array('name' => $route, 'params' => array('name' => $module, 'controller_service_name' => str_replace('\\', '-', $controller))))));
                 $result->setEntityRoute($route);
                 break;
             }
             $name = $result['input_filter_name'];
             $result = new HalEntity($result, $name);
             $this->injectEntitySelfLink($result->getLinks(), $route, $module, $controller, $name);
             break;
         case $request::METHOD_POST:
             if ($inputFilterName) {
                 return new ApiProblemResponse(new ApiProblem(400, 'POST requests are not allowed to individual input filters'));
             }
             // Intentionally not breaking, as remainder of logic remains the same as PUT
         // Intentionally not breaking, as remainder of logic remains the same as PUT
         case $request::METHOD_PUT:
             $inputFilter = $this->bodyParams();
             $result = $this->model->update($module, $controller, $inputFilter);
             if (!$result) {
                 return new ApiProblemResponse(new ApiProblem(500, 'There was an unexpected error updating the input filter; please verify the module and controller specified are valid'));
             }
             $name = $result['input_filter_name'];
             $result = new HalEntity($result, $name);
             $this->injectEntitySelfLink($result->getLinks(), $route, $module, $controller, $name);
             break;
         case $request::METHOD_DELETE:
             if (empty($inputFilterName)) {
                 return new ApiProblemResponse(new ApiProblem(400, 'The input filter name has not been specified'));
             }
             $result = $this->model->remove($module, $controller, $inputFilterName);
             if (!$result) {
                 return new ApiProblemResponse(new ApiProblem(404, 'The input filter specified does not exist'));
             }
             return $this->getResponse()->setStatusCode(204);
     }
     $e = $this->getEvent();
     $e->setParam('ZFContentNegotiationFallback', 'HalJson');
     return new ViewModel(array('payload' => $result));
 }
Example #15
0
 /**
  * Prepare a HAL collection with the metadata for the current instance.
  *
  * @param HalCollection $collection
  * @return HalCollection|ApiProblem
  */
 protected function prepareHalCollection(HalCollection $collection)
 {
     if (!$collection->getLinks()->has('self')) {
         $plugin = $this->plugin('Hal');
         $plugin->injectSelfLink($collection, $this->route);
     }
     $collection->setCollectionRoute($this->route);
     $collection->setRouteIdentifierName($this->getRouteIdentifierName());
     $collection->setEntityRoute($this->route);
     $collection->setCollectionName($this->collectionName);
     $collection->setPageSize($this->getPageSize());
     try {
         $collection->setPage($this->getRequest()->getQuery('page', 1));
     } catch (HalInvalidArgumentException $e) {
         return new ApiProblem(400, $e->getMessage());
     }
     return $collection;
 }
 public function setUpChildCollection()
 {
     $children = array(array('luke', 'Luke Skywalker'), array('leia', 'Leia Organa'));
     $this->collection = array();
     foreach ($children as $info) {
         $collection[] = call_user_func_array(array($this, 'setUpChildResource'), $info);
     }
     $collection = new HalCollection($this->collection);
     $collection->setCollectionRoute('parent/child');
     $collection->setEntityRoute('parent/child');
     $collection->setPage(1);
     $collection->setPageSize(10);
     $collection->setCollectionName('child');
     $link = new Link('self');
     $link->setRoute('parent/child');
     $collection->getLinks()->add($link);
     return $collection;
 }
Example #17
0
 public function testAllowsSettingAdditionalEntityLinks()
 {
     $links = new LinkCollection();
     $links->add(new Link('describedby'));
     $links->add(new Link('orders'));
     $hal   = new Collection(array(), 'item/route');
     $hal->setEntityLinks($links);
     $this->assertSame($links, $hal->getEntityLinks());
 }
Example #18
0
 /**
  * Extract a collection as an array
  *
  * @todo   Remove 'resource' from event parameters for 1.0.0
  * @todo   Remove trigger of 'renderCollection.resource' for 1.0.0
  * @param  Collection $halCollection
  * @param  int $depth                   depth of the current rendering recursion
  * @param  int $maxDepth                maximum rendering depth for the current metadata
  * @return array
  */
 protected function extractCollection(Collection $halCollection, $depth = 0, $maxDepth = null)
 {
     $collection = [];
     $events = $this->getEventManager();
     $routeIdentifierName = $halCollection->getRouteIdentifierName();
     $entityRoute = $halCollection->getEntityRoute();
     $entityRouteParams = $halCollection->getEntityRouteParams();
     $entityRouteOptions = $halCollection->getEntityRouteOptions();
     $metadataMap = $this->getMetadataMap();
     foreach ($halCollection->getCollection() as $entity) {
         $eventParams = new ArrayObject(['collection' => $halCollection, 'entity' => $entity, 'resource' => $entity, 'route' => $entityRoute, 'routeParams' => $entityRouteParams, 'routeOptions' => $entityRouteOptions]);
         $events->trigger('renderCollection.resource', $this, $eventParams);
         $events->trigger('renderCollection.entity', $this, $eventParams);
         $entity = $eventParams['entity'];
         if (is_object($entity) && $metadataMap->has($entity)) {
             $entity = $this->getResourceFactory()->createEntityFromMetadata($entity, $metadataMap->get($entity));
         }
         if ($entity instanceof Entity) {
             // Depth does not increment at this level
             $collection[] = $this->renderEntity($entity, $this->getRenderCollections(), $depth, $maxDepth);
             continue;
         }
         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));
             }
             if ($value instanceof Entity) {
                 $this->extractEmbeddedEntity($entity, $key, $value, $depth + 1, $maxDepth);
             }
             if ($value instanceof Collection) {
                 $this->extractEmbeddedCollection($entity, $key, $value, $depth + 1, $maxDepth);
             }
         }
         $id = $this->getIdFromEntity($entity);
         if ($id === false) {
             // Cannot handle entities without an identifier
             // Return as-is
             $collection[] = $entity;
             continue;
         }
         if ($eventParams['entity'] instanceof LinkCollectionAwareInterface) {
             $links = $eventParams['entity']->getLinks();
         } else {
             $links = new LinkCollection();
         }
         if (isset($entity['links']) && $entity['links'] instanceof LinkCollection) {
             $links = $entity['links'];
         }
         /* $entity is always an array here. We don't have metadata config for arrays so the self link is forced
            by default (at the moment) and should be removed manually if not required. But at some point it should
            be discussed if it makes sense to force self links in this particular use-case.  */
         $selfLink = new Link('self');
         $selfLink->setRoute($eventParams['route'], array_merge($eventParams['routeParams'], [$routeIdentifierName => $id]), $eventParams['routeOptions']);
         $links->add($selfLink);
         $entity['_links'] = $this->fromLinkCollection($links);
         $collection[] = $entity;
     }
     return $collection;
 }
 /**
  * Inject the input filters collection, if any, as an embedded collection
  *
  * @param DoctrineRpcServiceEntity $service
  */
 protected function injectInputFilters(DoctrineRpcServiceEntity $service)
 {
     $inputFilters = $this->inputFilterModel->fetch($this->moduleName, $service->controllerServiceName);
     if (!$inputFilters instanceof InputFilterCollection || !count($inputFilters)) {
         return;
     }
     // @codeCoverageIgnoreStart
     $collection = array();
     foreach ($inputFilters as $inputFilter) {
         $resource = new HalResource($inputFilter, $inputFilter['input_filter_name']);
         $links = $resource->getLinks();
         $links->add(Link::factory(array('rel' => 'self', 'route' => array('name' => 'zf-apigility-admin/api/module/rpc-service/rpc_input_filter', 'params' => array('name' => $this->moduleName, 'controller_service_name' => $service->controllerServiceName, 'input_filter_name' => $inputFilter['input_filter_name'])))));
         $collection[] = $resource;
     }
     $collection = new HalCollection($collection);
     $collection->setCollectionName('input_filter');
     $collection->setCollectionRoute('zf-apigility-admin/module/rpc-service/inputfilter');
     $collection->setCollectionRouteParams(array('name' => $this->moduleName, 'controller_service_name' => $service->controllerServiceName));
     $service->exchangeArray(array('input_filters' => $collection));
 }