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(); }
/** * 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); } }
/** * @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; } } }