/** * {@inheritdoc} */ public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) { $parameters = $route_match->getParameters()->all(); $entity_type_id = $parameters['entity_type_id']; // Attempt to load the content entity. if (isset($parameters[$entity_type_id]) && $parameters[$entity_type_id] instanceof ContentEntityInterface) { $this->contentEntity = $parameters[$entity_type_id]; } return $this->entityLayoutManager->getFromRouteMatch($route_match); }
/** * Wizards are not instantiated as simply as forms, so this method is unused. */ protected function getFormObject(RouteMatchInterface $route_match, $form_arg) { if (!is_subclass_of($form_arg, '\\Drupal\\ctools\\Wizard\\FormWizardInterface')) { throw new \Exception("The _wizard default must reference a class instance of \\Drupal\\ctools\\Wizard\\FormWizardInterface."); } $parameters = $route_match->getParameters()->all(); $parameters += $form_arg::getParameters(); $parameters['route_match'] = $route_match; return $this->wizardFactory->createWizard($form_arg, $parameters); }
/** * Loads the default revision of the entity this route is for. * * @param \Symfony\Component\Routing\Route $route * The route to check against. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The parametrized route * * @return ContentEntityInterface|null * returns the Entity in question, or NULL if for some reason no entity * is available. */ protected function loadEntity(Route $route, RouteMatchInterface $route_match) { // Split the entity type and the operation. $requirement = $route->getRequirement('_entity_access'); list($entity_type, $operation) = explode('.', $requirement); // If there is valid entity of the given entity type, check its access. $parameters = $route_match->getParameters(); if ($parameters->has($entity_type)) { $entity = $parameters->get($entity_type); if ($entity instanceof EntityInterface) { return $entity; } } return NULL; }
/** * Checks whether the embed button is enabled for the given text editor. * * Returns allowed if the editor toolbar contains the embed button or neutral * otherwise. * * @code * pattern: '/foo/{editor}/{embed_button}' * requirements: * _embed_button_filter_access: 'TRUE' * @endcode * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The current route match. * @param \Drupal\Core\Session\AccountInterface $account * The currently logged in account. * * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ public function access(RouteMatchInterface $route_match, AccountInterface $account) { $parameters = $route_match->getParameters(); $access_result = AccessResult::allowedIf($parameters->has('editor') && $parameters->has('embed_button'))->addCacheContexts(['route']); if ($access_result->isAllowed()) { $editor = $parameters->get('editor'); $embed_button = $parameters->get('embed_button'); if ($editor instanceof EditorInterface && $embed_button instanceof EmbedButtonInterface) { return $access_result->andIf($editor->getFilterFormat()->access('use', $account, TRUE))->andIf($this->checkButtonEditorAccess($embed_button, $editor)); } } // No opinion, so other access checks should decide if access should be // allowed or not. return $access_result; }
/** * {@inheritdoc} */ public function getRuntimeContexts(array $unqualified_context_ids) { $result = []; $value = NULL; if (($route_object = $this->routeMatch->getRouteObject()) && ($route_contexts = $route_object->getOption('parameters')) && isset($route_contexts['rdf_entity'])) { /** @var \Drupal\rdf_entity\RdfInterface $collection */ if ($collection = $this->routeMatch->getParameter('rdf_entity')) { if ($collection->bundle() == 'collection') { $value = $collection; } } } elseif (($route_parameters = $this->routeMatch->getParameters()) && in_array($this->routeMatch->getRouteName(), $this->getSupportedRoutes())) { foreach ($route_parameters as $route_parameter) { if ($route_parameter instanceof ContentEntityInterface) { $bundle = $route_parameter->bundle(); $entity_type = $route_parameter->getEntityTypeId(); // Check if the object is a og content entity. if (Og::isGroupContent($entity_type, $bundle) && ($groups = $this->membershipManager->getGroupIds($route_parameter, 'rdf_entity', 'collection'))) { // A content can belong to only one rdf_entity. // Check that the content is not an orphaned one. if ($collection_id = reset($groups['rdf_entity'])) { $collection = Rdf::load($collection_id); $value = $collection; } } } } } $cacheability = new CacheableMetadata(); $cacheability->setCacheContexts(['route']); $collection_context_definition = new ContextDefinition('entity', $this->t('Organic group provided by collection'), FALSE); $context = new Context($collection_context_definition, $value); $context->addCacheableDependency($cacheability); $result['og'] = $context; return $result; }
/** * Determines whether the route of a certain local task is currently active. * * @param string $current_route_name * The route name of the current main request. * @param string $route_name * The route name of the local task to determine the active status. * @param array $route_parameters * * @return bool * Returns TRUE if the passed route_name and route_parameters is considered * as the same as the one from the request, otherwise FALSE. */ protected function isRouteActive($current_route_name, $route_name, $route_parameters) { // Flag the list element as active if this tab's route and parameters match // the current request's route and route variables. $active = $current_route_name == $route_name; if ($active) { // The request is injected, so we need to verify that we have the expected // _raw_variables attribute. $raw_variables_bag = $this->routeMatch->getRawParameters(); // If we don't have _raw_variables, we assume the attributes are still the // original values. $raw_variables = $raw_variables_bag ? $raw_variables_bag->all() : $this->routeMatch->getParameters()->all(); $active = array_intersect_assoc($route_parameters, $raw_variables) == $route_parameters; } return $active; }
/** * Checks access to the entity operation on the given route. * * The value of the '_entity_access' key must be in the pattern * 'entity_type.operation.' The entity type must match the {entity_type} * parameter in the route pattern. This will check a node for 'update' access: * @code * pattern: '/foo/{node}/bar' * requirements: * _entity_access: 'node.update' * @endcode * Available operations are 'view', 'update', 'create', and 'delete'. * * @param \Symfony\Component\Routing\Route $route * The route to check against. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The parametrized route * @param \Drupal\Core\Session\AccountInterface $account * The currently logged in account. * * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account) { // Split the entity type and the operation. $requirement = $route->getRequirement('_entity_access'); list($entity_type, $operation) = explode('.', $requirement); // If there is valid entity of the given entity type, check its access. $parameters = $route_match->getParameters(); if ($parameters->has($entity_type)) { $entity = $parameters->get($entity_type); if ($entity instanceof EntityInterface) { return $entity->access($operation, $account, TRUE); } } // No opinion, so other access checks should decide if access should be // allowed or not. return AccessResult::neutral(); }
/** * {@inheritdoc} */ public function getArgumentsResolver(RouteMatchInterface $route_match, AccountInterface $account, Request $request = NULL) { $route = $route_match->getRouteObject(); // Defaults for the parameters defined on the route object need to be added // to the raw arguments. $raw_route_arguments = $route_match->getRawParameters()->all() + $route->getDefaults(); $upcasted_route_arguments = $route_match->getParameters()->all(); // Parameters which are not defined on the route object, but still are // essential for access checking are passed as wildcards to the argument // resolver. An access-check method with a parameter of type Route, // RouteMatchInterface, AccountInterface or Request will receive those // arguments regardless of the parameter name. $wildcard_arguments = [$route, $route_match, $account]; if (isset($request)) { $wildcard_arguments[] = $request; } return new ArgumentsResolver($raw_route_arguments, $upcasted_route_arguments, $wildcard_arguments); }
/** * Attempt to load an entity layout from the route match. * * @param RouteMatchInterface $route_match * The route match object. * * @return \Drupal\entity_layout\EntityLayoutInterface|null * The entity layout object if found. */ public function getFromRouteMatch(RouteMatchInterface $route_match) { $parameters = $route_match->getParameters()->all(); if (!isset($parameters['entity_type_id']) || !isset($parameters['bundle'])) { return NULL; } $entity_type_id = $parameters['entity_type_id']; $bundle = $parameters['bundle']; // If the page being loaded is for a content entity then we need to use // the bundle from the content entity instead as the bundle name since // the one supplied in the route parameters is the key for where the // bundle is stored in the database only. if (isset($parameters[$entity_type_id]) && $parameters[$entity_type_id] instanceof ContentEntityInterface) { /** @var ContentEntityInterface $content_entity */ $content_entity = $parameters[$entity_type_id]; $bundle = $content_entity->bundle(); } return $this->getEntityLayout($entity_type_id, $bundle); }
/** * Determines the entity. * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. * @param \Drupal\Core\Entity\EntityInterface $_entity * (optional) The entity, set in * \Drupal\Core\Entity\Enhancer\EntityRouteEnhancer. * * @return \Drupal\Core\Entity\EntityInterface|NULL * The entity, if it is passed in directly or if the first parameter of the * active route is an entity; otherwise, NULL. */ protected function doGetEntity(RouteMatchInterface $route_match, EntityInterface $_entity = NULL) { if ($_entity) { $entity = $_entity; } else { // Let's look up in the route object for the name of upcasted values. foreach ($route_match->getParameters() as $parameter) { if ($parameter instanceof EntityInterface) { $entity = $parameter; break; } } } if ($entity) { return $this->entityManager->getTranslationFromContext($entity); } }
/** * @covers ::getParameters * @covers \Drupal\Core\Routing\RouteMatch::getParameterNames * @dataProvider routeMatchProvider */ public function testGetParameters(RouteMatchInterface $route_match, Route $route, $parameters, $expected_filtered_parameters) { $this->assertSame($expected_filtered_parameters, $route_match->getParameters()->all()); }
/** * {@inheritdoc} */ public function applies(RouteMatchInterface $route_match) { // This breadcrumb apply only for all articles. $parameters = $route_match->getParameters()->all(); if (isset($parameters['node']) && is_object($parameters['node'])) { return $parameters['node']->getType() == 'article'; } return FALSE; }
/** * Handles a web API request. * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. * @param \Symfony\Component\HttpFoundation\Request $request * The HTTP request object. * * @return \Symfony\Component\HttpFoundation\Response * The response object. */ public function handle(RouteMatchInterface $route_match, Request $request) { $plugin = $route_match->getRouteObject()->getDefault('_plugin'); $method = strtolower($request->getMethod()); $resource = $this->container->get('plugin.manager.rest')->getInstance(array('id' => $plugin)); // Deserialize incoming data if available. $serializer = $this->container->get('serializer'); $received = $request->getContent(); $unserialized = NULL; if (!empty($received)) { $format = $request->getContentType(); // Only allow serialization formats that are explicitly configured. If no // formats are configured allow all and hope that the serializer knows the // format. If the serializer cannot handle it an exception will be thrown // that bubbles up to the client. $config = $this->container->get('config.factory')->get('rest.settings')->get('resources'); $method_settings = $config[$plugin][$request->getMethod()]; if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) { $definition = $resource->getPluginDefinition(); $class = $definition['serialization_class']; try { $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method)); } catch (UnexpectedValueException $e) { $error['error'] = $e->getMessage(); $content = $serializer->serialize($error, $format); return new Response($content, 400, array('Content-Type' => $request->getMimeType($format))); } } else { throw new UnsupportedMediaTypeHttpException(); } } // Determine the request parameters that should be passed to the resource // plugin. $route_parameters = $route_match->getParameters(); $parameters = array(); // Filter out all internal parameters starting with "_". foreach ($route_parameters as $key => $parameter) { if ($key[0] !== '_') { $parameters[] = $parameter; } } // Invoke the operation on the resource plugin. // All REST routes are restricted to exactly one format, so instead of // parsing it out of the Accept headers again, we can simply retrieve the // format requirement. If there is no format associated, just pick JSON. $format = $route_match->getRouteObject()->getRequirement('_format') ?: 'json'; try { $response = call_user_func_array(array($resource, $method), array_merge($parameters, array($unserialized, $request))); } catch (HttpException $e) { $error['error'] = $e->getMessage(); $content = $serializer->serialize($error, $format); // Add the default content type, but only if the headers from the // exception have not specified it already. $headers = $e->getHeaders() + array('Content-Type' => $request->getMimeType($format)); return new Response($content, $e->getStatusCode(), $headers); } // Serialize the outgoing data for the response, if available. $data = $response->getResponseData(); if ($data != NULL) { $output = $serializer->serialize($data, $format); $response->setContent($output); $response->headers->set('Content-Type', $request->getMimeType($format)); // Add rest settings config's cache tags. $response->addCacheableDependency($this->container->get('config.factory')->get('rest.settings')); } return $response; }
/** * Gets the bundle object from the route match. * * @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch * The route match. * * @return \Drupal\Core\Entity\EntityInterface * The bundle object as determined from the passed-in route match. */ protected function getBundleFromRouteMatch(RouteMatchInterface $routeMatch) { // Assume that the bundle is the last route parameter. $parameters = $routeMatch->getParameters()->all(); $bundle = end($parameters); return $bundle; }
/** * {@inheritdoc} */ public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) { $route_parameters = $route_match->getParameters()->all(); return $this->getEntityDisplay($route_parameters['entity_type_id'], $route_parameters['bundle'], $route_parameters[$this->displayContext . '_mode_name']); }
/** * Handles a web API request. * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. * @param \Symfony\Component\HttpFoundation\Request $request * The HTTP request object. * * @return \Symfony\Component\HttpFoundation\Response * The response object. */ public function handle(RouteMatchInterface $route_match, Request $request) { $plugin = $route_match->getRouteObject()->getDefault('_plugin'); $method = strtolower($request->getMethod()); // Symfony is built to transparently map HEAD requests to a GET request. In // the case of the REST module's RequestHandler though, we essentially have // our own light-weight routing system on top of the Drupal/symfony routing // system. So, we have to do the same as what the UrlMatcher does: map HEAD // requests to the logic for GET. This also guarantees response headers for // HEAD requests are identical to those for GET requests, because we just // return a GET response. Response::prepare() will transform it to a HEAD // response at the very last moment. // @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4 // @see \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection() // @see \Symfony\Component\HttpFoundation\Response::prepare() if ($method === 'head') { $method = 'get'; } $resource = $this->container->get('plugin.manager.rest')->getInstance(array('id' => $plugin)); // Deserialize incoming data if available. $serializer = $this->container->get('serializer'); $received = $request->getContent(); $unserialized = NULL; if (!empty($received)) { $format = $request->getContentType(); // Only allow serialization formats that are explicitly configured. If no // formats are configured allow all and hope that the serializer knows the // format. If the serializer cannot handle it an exception will be thrown // that bubbles up to the client. $config = $this->container->get('config.factory')->get('rest.settings')->get('resources'); $method_settings = $config[$plugin][$request->getMethod()]; if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) { $definition = $resource->getPluginDefinition(); $class = $definition['serialization_class']; try { $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method)); } catch (UnexpectedValueException $e) { $error['error'] = $e->getMessage(); $content = $serializer->serialize($error, $format); return new Response($content, 400, array('Content-Type' => $request->getMimeType($format))); } } else { throw new UnsupportedMediaTypeHttpException(); } } // Determine the request parameters that should be passed to the resource // plugin. $route_parameters = $route_match->getParameters(); $parameters = array(); // Filter out all internal parameters starting with "_". foreach ($route_parameters as $key => $parameter) { if ($key[0] !== '_') { $parameters[] = $parameter; } } // Invoke the operation on the resource plugin. // All REST routes are restricted to exactly one format, so instead of // parsing it out of the Accept headers again, we can simply retrieve the // format requirement. If there is no format associated, just pick JSON. $format = $route_match->getRouteObject()->getRequirement('_format') ?: 'json'; try { $response = call_user_func_array(array($resource, $method), array_merge($parameters, array($unserialized, $request))); } catch (HttpException $e) { $error['error'] = $e->getMessage(); $content = $serializer->serialize($error, $format); // Add the default content type, but only if the headers from the // exception have not specified it already. $headers = $e->getHeaders() + array('Content-Type' => $request->getMimeType($format)); return new Response($content, $e->getStatusCode(), $headers); } if ($response instanceof ResourceResponse) { $data = $response->getResponseData(); // Serialization can invoke rendering (e.g., generating URLs), but the // serialization API does not provide a mechanism to collect the // bubbleable metadata associated with that (e.g., language and other // contexts), so instead, allow those to "leak" and collect them here in // a render context. // @todo Add test coverage for language negotiation contexts in // https://www.drupal.org/node/2135829. $context = new RenderContext(); $output = $this->container->get('renderer')->executeInRenderContext($context, function () use($serializer, $data, $format) { return $serializer->serialize($data, $format); }); $response->setContent($output); if (!$context->isEmpty()) { $response->addCacheableDependency($context->pop()); } $response->headers->set('Content-Type', $request->getMimeType($format)); // Add rest settings config's cache tags. $response->addCacheableDependency($this->container->get('config.factory')->get('rest.settings')); } return $response; }
/** * Handles a web API request. * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. * @param \Symfony\Component\HttpFoundation\Request $request * The HTTP request object. * * @return \Symfony\Component\HttpFoundation\Response * The response object. */ public function handle(RouteMatchInterface $route_match, Request $request) { $method = strtolower($request->getMethod()); // Symfony is built to transparently map HEAD requests to a GET request. In // the case of the REST module's RequestHandler though, we essentially have // our own light-weight routing system on top of the Drupal/symfony routing // system. So, we have to do the same as what the UrlMatcher does: map HEAD // requests to the logic for GET. This also guarantees response headers for // HEAD requests are identical to those for GET requests, because we just // return a GET response. Response::prepare() will transform it to a HEAD // response at the very last moment. // @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4 // @see \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection() // @see \Symfony\Component\HttpFoundation\Response::prepare() if ($method === 'head') { $method = 'get'; } $resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config'); /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */ $resource_config = $this->resourceStorage->load($resource_config_id); $resource = $resource_config->getResourcePlugin(); // Deserialize incoming data if available. /** @var \Symfony\Component\Serializer\SerializerInterface $serializer */ $serializer = $this->container->get('serializer'); $received = $request->getContent(); $unserialized = NULL; if (!empty($received)) { $format = $request->getContentType(); // Only allow serialization formats that are explicitly configured. If no // formats are configured allow all and hope that the serializer knows the // format. If the serializer cannot handle it an exception will be thrown // that bubbles up to the client. $request_method = $request->getMethod(); if (in_array($format, $resource_config->getFormats($request_method))) { $definition = $resource->getPluginDefinition(); try { if (!empty($definition['serialization_class'])) { $unserialized = $serializer->deserialize($received, $definition['serialization_class'], $format, array('request_method' => $method)); } else { $unserialized = $serializer->decode($received, $format, array('request_method' => $method)); } } catch (UnexpectedValueException $e) { $error['error'] = $e->getMessage(); $content = $serializer->serialize($error, $format); return new Response($content, 400, array('Content-Type' => $request->getMimeType($format))); } } else { throw new UnsupportedMediaTypeHttpException(); } } // Determine the request parameters that should be passed to the resource // plugin. $route_parameters = $route_match->getParameters(); $parameters = array(); // Filter out all internal parameters starting with "_". foreach ($route_parameters as $key => $parameter) { if ($key[0] !== '_') { $parameters[] = $parameter; } } // Invoke the operation on the resource plugin. $format = $this->getResponseFormat($route_match, $request); $response = call_user_func_array(array($resource, $method), array_merge($parameters, array($unserialized, $request))); return $response instanceof ResourceResponseInterface ? $this->renderResponse($request, $response, $serializer, $format, $resource_config) : $response; }