core/modules/rest/src/RequestHandler.php | 77 ++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php index e5437cc..e277893 100644 --- a/core/modules/rest/src/RequestHandler.php +++ b/core/modules/rest/src/RequestHandler.php @@ -2,6 +2,7 @@ namespace Drupal\rest; +use Drupal\Component\Utility\ArgumentsResolver; use Drupal\Core\Cache\CacheableResponseInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityStorageInterface; @@ -119,17 +120,16 @@ public function handle(RouteMatchInterface $route_match, Request $request) { // Determine the request parameters that should be passed to the resource // plugin. - $route_parameters = $route_match->getParameters(); - $parameters = []; - // Filter out all internal parameters starting with "_". - foreach ($route_parameters as $key => $parameter) { - if ($key{0} !== '_') { - $parameters[] = $parameter; - } + $argument_resolver = $this->getArgumentResolver($route_match); + try { + $arguments = $argument_resolver->getArguments([$resource, $method]); + } + catch (\RuntimeException $exception) { + $arguments = $this->getLegacyParameters($route_match, $unserialized, $request); } // Invoke the operation on the resource plugin. - $response = call_user_func_array([$resource, $method], array_merge($parameters, [$unserialized, $request])); + $response = $response = call_user_func_array([$resource, $method], $arguments); if ($response instanceof CacheableResponseInterface) { // Add rest config's cache tags. @@ -139,4 +139,65 @@ public function handle(RouteMatchInterface $route_match, Request $request) { return $response; } + /** + * Creates an argument resolver, which can pass along the REST parameters. + * + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match + * @param mixed $unserialized + * The unserialized data. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * + * @return \Drupal\Component\Utility\ArgumentsResolver + */ + protected function getArgumentResolver(RouteMatchInterface $route_match, $unserialized, Request $request) { + $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(); + $upcasted_route_arguments['entity'] = $unserialized; + $upcasted_route_arguments['data'] = $unserialized; + $upcasted_route_arguments['unserialized'] = $unserialized; + + // Parameters which are not defined on the route object, but still are + // essential for access checking are passed as wildcards to the argument + // resolver. + $wildcard_arguments = [$route, $route_match]; + if (isset($request)) { + $wildcard_arguments[] = $request; + } + $wildcard_arguments[] = $unserialized; + + return new ArgumentsResolver($raw_route_arguments, $upcasted_route_arguments, $wildcard_arguments); + } + + /** + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match + * @param mixed $unserialized + * The unserialized data. + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * + * @return array + */ + protected function getLegacyParameters(RouteMatchInterface $route_match, $unserialized, Request $request) { + $route_parameters = $route_match->getParameters(); + $parameters = []; + // Filter out all internal parameters starting with "_". + foreach ($route_parameters as $key => $parameter) { + if ($key{0} !== '_') { + $parameters[] = $parameter; + } + } + + array_merge($parameters, array($unserialized, $request)); + + return $parameters; + } + }