public function setUp()
 {
     $this->resource = $resource = new Resource();
     $this->controller = $controller = new RestController();
     $controller->setResource($resource);
     $this->matches = $matches = new RouteMatch([]);
     $this->query = $query = new Parameters();
     $this->request = $request = new Request();
     $request->setQuery($query);
     $this->event = new MvcEvent();
     $this->event->setTarget($controller);
     $this->event->setRouteMatch($matches);
     $this->event->setRequest($request);
     $this->listener = new RestParametersListener();
 }
Example #2
0
 /**
  * Handle the dispatch event
  *
  * Does several "pre-flight" checks:
  * - Raises an exception if no resource is composed.
  * - Raises an exception if no route is composed.
  * - Returns a 405 response if the current HTTP request method is not in
  *   $options
  *
  * When the dispatch is complete, it will check to see if an array was
  * returned; if so, it will cast it to a view model using the
  * AcceptableViewModelSelector plugin, and the $acceptCriteria property.
  *
  * @param  MvcEvent $e
  * @return mixed
  * @throws DomainException
  */
 public function onDispatch(MvcEvent $e)
 {
     if (!$this->getResource()) {
         throw new DomainException(sprintf('%s requires that a %s\\ResourceInterface object is composed; none provided', __CLASS__, __NAMESPACE__));
     }
     if (!$this->route) {
         throw new DomainException(sprintf('%s requires that a route name for the resource is composed; none provided', __CLASS__));
     }
     // Check for an API-Problem in the event
     $return = $e->getParam('api-problem', false);
     // If no return value dispatch the parent event
     if (!$return) {
         $return = parent::onDispatch($e);
     }
     if (!$return instanceof ApiProblem && !$return instanceof JsonLDEntity && !$return instanceof JsonLDCollection) {
         return $return;
     }
     if ($return instanceof ApiProblem) {
         return new ApiProblemResponse($return);
     }
     // Set the fallback content negotiation to use HalJson.
     $e->setParam('ZFContentNegotiationFallback', 'JsonLD');
     // Use content negotiation for creating the view model
     $viewModel = new ContentNegotiationViewModel(['payload' => $return]);
     $e->setResult($viewModel);
     return $viewModel;
 }
 public function onDispatch(MvcEvent $event)
 {
     $routeMatch = $event->getRouteMatch();
     /** @var \Zend\Http\Request $request */
     $request = $event->getRequest();
     $method = strtolower($request->getMethod());
     if ($routeMatch && $method === 'patch') {
         $id = $this->getIdentifier($routeMatch, $request);
         $data = $this->processBodyContent($request);
         // We assume we have to patch multiple resources when
         // there's a comma (the separator) in the ID.
         if ($id !== false && strpos($id, ',') !== false) {
             $ids = explode(',', $id);
             $return = $this->patchMultiple($ids, $data);
             $routeMatch->setParam('action', 'patchMultiple');
             $event->setResult($return);
             return $this->processResult($event, $return);
         }
     }
     return parent::onDispatch($event);
 }
 public function testChildResourceObjectIdentifierMappingInCollectionsViaControllerReturn()
 {
     $this->setUpAlternateRouter();
     $resource = new Resource();
     $resource->getEventManager()->attach('fetchAll', function ($e) {
         return array((object) array('id' => 'luke', 'name' => 'Luke Skywalker'), (object) array('id' => 'leia', 'name' => 'Leia Organa'));
     });
     $controller = new RestController();
     $controller->setPluginManager($this->plugins);
     $controller->setResource($resource);
     $controller->setRoute('parent/child');
     $controller->setIdentifierName('child_id');
     $controller->setCollectionName('children');
     $r = new ReflectionObject($controller);
     $m = $r->getMethod('getIdentifier');
     $m->setAccessible(true);
     $uri = 'http://localhost.localdomain/api/parent/anakin/child';
     $request = new Request();
     $request->setUri($uri);
     $matches = $this->router->match($request);
     $this->assertInstanceOf('Zend\\Mvc\\Router\\RouteMatch', $matches);
     $this->assertEquals('anakin', $matches->getParam('id'));
     $this->assertNull($matches->getParam('child_id'));
     $this->assertEquals('parent/child', $matches->getMatchedRouteName());
     // Emulate url helper factory and inject route matches
     $this->helpers->get('url')->setRouteMatch($matches);
     $result = $controller->getList();
     $this->assertInstanceOf('ZF\\Hal\\Collection', $result);
     // Now, what happens if we render this?
     $model = new HalJsonModel();
     $model->setPayload($result);
     $json = $this->renderer->render($model);
     $test = json_decode($json);
     $this->assertObjectHasAttribute('_links', $test);
     $this->assertObjectHasAttribute('self', $test->_links);
     $this->assertObjectHasAttribute('href', $test->_links->self);
     $this->assertEquals('http://localhost.localdomain/api/parent/anakin/child', $test->_links->self->href);
     $this->assertObjectHasAttribute('_embedded', $test);
     $this->assertObjectHasAttribute('children', $test->_embedded);
     $this->assertInternalType('array', $test->_embedded->children);
     foreach ($test->_embedded->children as $child) {
         $this->assertObjectHasAttribute('_links', $child);
         $this->assertObjectHasAttribute('self', $child->_links);
         $this->assertObjectHasAttribute('href', $child->_links->self);
         $this->assertRegexp('#^http://localhost.localdomain/api/parent/anakin/child/[^/]+$#', $child->_links->self->href);
     }
 }
Example #5
0
 /**
  * @expectedException \ZF\ApiProblem\Exception\DomainException
  */
 public function testGetResourceThrowsExceptionOnMissingResource()
 {
     $controller = new RestController();
     $controller->getResource();
 }
 /**
  * Loop through configuration to discover and set controller options.
  *
  * @param  array $config
  * @param  RestController $controller
  */
 protected function setControllerOptions(array $config, RestController $controller)
 {
     foreach ($config as $option => $value) {
         switch ($option) {
             case 'collection_http_methods':
                 $controller->setCollectionHttpMethods($value);
                 break;
             case 'collection_name':
                 $controller->setCollectionName($value);
                 break;
             case 'collection_query_whitelist':
                 if (is_string($value)) {
                     $value = (array) $value;
                 }
                 if (!is_array($value)) {
                     break;
                 }
                 // Create a listener that checks the query string against
                 // the whitelisted query parameters in order to seed the
                 // collection route options.
                 $whitelist = $value;
                 $controller->getEventManager()->attach('getList.pre', function (Event $e) use($whitelist) {
                     $controller = $e->getTarget();
                     $resource = $controller->getResource();
                     if (!$resource instanceof Resource) {
                         // ResourceInterface does not define setQueryParams, so we need
                         // specifically a Resource instance
                         return;
                     }
                     $request = $controller->getRequest();
                     if (!method_exists($request, 'getQuery')) {
                         return;
                     }
                     $query = $request->getQuery();
                     $params = new Parameters(array());
                     foreach ($query as $key => $value) {
                         if (!in_array($key, $whitelist)) {
                             continue;
                         }
                         $params->set($key, $value);
                     }
                     $resource->setQueryParams($params);
                 });
                 $controller->getEventManager()->attach('getList.post', function (Event $e) use($whitelist) {
                     $controller = $e->getTarget();
                     $resource = $controller->getResource();
                     if (!$resource instanceof Resource) {
                         // ResourceInterface does not define setQueryParams, so we need
                         // specifically a Resource instance
                         return;
                     }
                     $collection = $e->getParam('collection');
                     if (!$collection instanceof Collection) {
                         return;
                     }
                     $params = $resource->getQueryParams()->getArrayCopy();
                     // Set collection route options with the captured query whitelist, to
                     // ensure paginated links are generated correctly
                     $collection->setCollectionRouteOptions(array('query' => $params));
                     // If no self link defined, set the options in the collection and return
                     $links = $collection->getLinks();
                     if (!$links->has('self')) {
                         return;
                     }
                     // If self link is defined, but is not route-based, return
                     $self = $links->get('self');
                     if (!$self->hasRoute()) {
                         return;
                     }
                     // Otherwise, merge the query string parameters with
                     // the self link's route options
                     $self = $links->get('self');
                     $options = $self->getRouteOptions();
                     $self->setRouteOptions(array_merge($options, array('query' => $params)));
                 });
                 break;
             case 'entity_http_methods':
                 $controller->setEntityHttpMethods($value);
                 break;
                 /**
                  * The identifierName is a property of the ancestor
                  * and is described by Apigility as route_identifier_name
                  */
             /**
              * The identifierName is a property of the ancestor
              * and is described by Apigility as route_identifier_name
              */
             case 'route_identifier_name':
                 $controller->setIdentifierName($value);
                 break;
             case 'page_size':
                 $controller->setPageSize($value);
                 break;
             case 'page_size_param':
                 $controller->setPageSizeParam($value);
                 break;
                 /**
                  * @todo Remove this by 1.0; BC only, starting in 0.9.0
                  */
             /**
              * @todo Remove this by 1.0; BC only, starting in 0.9.0
              */
             case 'resource_http_methods':
                 $controller->setEntityHttpMethods($value);
                 break;
             case 'route_name':
                 $controller->setRoute($value);
                 break;
         }
     }
 }