"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.10/core/modules/rest/src/Plugin/ResourceBase.php" (26 Nov 2020, 8134 Bytes) of package /linux/www/drupal-8.9.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ResourceBase.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Drupal\rest\Plugin;
    4 
    5 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
    6 use Drupal\Core\Plugin\PluginBase;
    7 use Drupal\Core\Routing\BcRoute;
    8 use Psr\Log\LoggerInterface;
    9 use Symfony\Component\DependencyInjection\ContainerInterface;
   10 use Symfony\Component\Routing\Route;
   11 use Symfony\Component\Routing\RouteCollection;
   12 
   13 /**
   14  * Common base class for resource plugins.
   15  *
   16  * Note that this base class' implementation of the permissions() method
   17  * generates a permission for every method for a resource. If your resource
   18  * already has its own access control mechanism, you should opt out from this
   19  * default permissions() method by overriding it.
   20  *
   21  * @see \Drupal\rest\Annotation\RestResource
   22  * @see \Drupal\rest\Plugin\Type\ResourcePluginManager
   23  * @see \Drupal\rest\Plugin\ResourceInterface
   24  * @see plugin_api
   25  *
   26  * @ingroup third_party
   27  */
   28 abstract class ResourceBase extends PluginBase implements ContainerFactoryPluginInterface, ResourceInterface {
   29 
   30   /**
   31    * The available serialization formats.
   32    *
   33    * @var array
   34    */
   35   protected $serializerFormats = [];
   36 
   37   /**
   38    * A logger instance.
   39    *
   40    * @var \Psr\Log\LoggerInterface
   41    */
   42   protected $logger;
   43 
   44   /**
   45    * Constructs a Drupal\rest\Plugin\ResourceBase object.
   46    *
   47    * @param array $configuration
   48    *   A configuration array containing information about the plugin instance.
   49    * @param string $plugin_id
   50    *   The plugin_id for the plugin instance.
   51    * @param mixed $plugin_definition
   52    *   The plugin implementation definition.
   53    * @param array $serializer_formats
   54    *   The available serialization formats.
   55    * @param \Psr\Log\LoggerInterface $logger
   56    *   A logger instance.
   57    */
   58   public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger) {
   59     parent::__construct($configuration, $plugin_id, $plugin_definition);
   60     $this->serializerFormats = $serializer_formats;
   61     $this->logger = $logger;
   62   }
   63 
   64   /**
   65    * {@inheritdoc}
   66    */
   67   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
   68     return new static(
   69       $configuration,
   70       $plugin_id,
   71       $plugin_definition,
   72       $container->getParameter('serializer.formats'),
   73       $container->get('logger.factory')->get('rest')
   74     );
   75   }
   76 
   77   /**
   78    * Implements ResourceInterface::permissions().
   79    *
   80    * Every plugin operation method gets its own user permission. Example:
   81    * "restful delete entity:node" with the title "Access DELETE on Node
   82    * resource".
   83    */
   84   public function permissions() {
   85     $permissions = [];
   86     $definition = $this->getPluginDefinition();
   87     foreach ($this->availableMethods() as $method) {
   88       $lowered_method = strtolower($method);
   89       $permissions["restful $lowered_method $this->pluginId"] = [
   90         'title' => $this->t('Access @method on %label resource', ['@method' => $method, '%label' => $definition['label']]),
   91       ];
   92     }
   93     return $permissions;
   94   }
   95 
   96   /**
   97    * {@inheritdoc}
   98    */
   99   public function routes() {
  100     $collection = new RouteCollection();
  101 
  102     $definition = $this->getPluginDefinition();
  103     $canonical_path = isset($definition['uri_paths']['canonical']) ? $definition['uri_paths']['canonical'] : '/' . strtr($this->pluginId, ':', '/') . '/{id}';
  104     $create_path = isset($definition['uri_paths']['create']) ? $definition['uri_paths']['create'] : '/' . strtr($this->pluginId, ':', '/');
  105     // BC: the REST module originally created the POST URL for a resource by
  106     // reading the 'https://www.drupal.org/link-relations/create' URI path from
  107     // the plugin annotation. For consistency with entity type definitions, that
  108     // then changed to reading the 'create' URI path. For any REST Resource
  109     // plugins that were using the old mechanism, we continue to support that.
  110     if (!isset($definition['uri_paths']['create']) && isset($definition['uri_paths']['https://www.drupal.org/link-relations/create'])) {
  111       @trigger_error('The "https://www.drupal.org/link-relations/create" string as a RestResource plugin annotation URI path key is deprecated in Drupal 8.4.0, now a valid link relation type name must be specified, so "create" must be specified instead before Drupal 9.0.0. See https://www.drupal.org/node/2737401.', E_USER_DEPRECATED);
  112       $create_path = $definition['uri_paths']['https://www.drupal.org/link-relations/create'];
  113     }
  114 
  115     $route_name = strtr($this->pluginId, ':', '.');
  116 
  117     $methods = $this->availableMethods();
  118     foreach ($methods as $method) {
  119       $path = $method === 'POST'
  120         ? $create_path
  121         : $canonical_path;
  122       $route = $this->getBaseRoute($path, $method);
  123 
  124       // Note that '_format' and '_content_type_format' route requirements are
  125       // added in ResourceRoutes::getRoutesForResourceConfig().
  126       $collection->add("$route_name.$method", $route);
  127 
  128       // BC: the REST module originally created per-format GET routes, instead
  129       // of a single route. To minimize the surface of this BC layer, this uses
  130       // route definitions that are as empty as possible, plus an outbound route
  131       // processor.
  132       // @see \Drupal\rest\RouteProcessor\RestResourceGetRouteProcessorBC
  133       if ($method === 'GET' || $method === 'HEAD') {
  134         foreach ($this->serializerFormats as $format_name) {
  135           $collection->add("$route_name.$method.$format_name", (new BcRoute())->setRequirement('_format', $format_name));
  136         }
  137       }
  138     }
  139 
  140     return $collection;
  141   }
  142 
  143   /**
  144    * Provides predefined HTTP request methods.
  145    *
  146    * Plugins can override this method to provide additional custom request
  147    * methods.
  148    *
  149    * @return array
  150    *   The list of allowed HTTP request method strings.
  151    */
  152   protected function requestMethods() {
  153     return [
  154       'HEAD',
  155       'GET',
  156       'POST',
  157       'PUT',
  158       'DELETE',
  159       'TRACE',
  160       'OPTIONS',
  161       'CONNECT',
  162       'PATCH',
  163     ];
  164   }
  165 
  166   /**
  167    * {@inheritdoc}
  168    */
  169   public function availableMethods() {
  170     $methods = $this->requestMethods();
  171     $available = [];
  172     foreach ($methods as $method) {
  173       // Only expose methods where the HTTP request method exists on the plugin.
  174       if (method_exists($this, strtolower($method))) {
  175         $available[] = $method;
  176       }
  177     }
  178     return $available;
  179   }
  180 
  181   /**
  182    * Gets the base route for a particular method.
  183    *
  184    * @param string $canonical_path
  185    *   The canonical path for the resource.
  186    * @param string $method
  187    *   The HTTP method to be used for the route.
  188    *
  189    * @return \Symfony\Component\Routing\Route
  190    *   The created base route.
  191    */
  192   protected function getBaseRoute($canonical_path, $method) {
  193     return new Route($canonical_path, [
  194       '_controller' => 'Drupal\rest\RequestHandler::handle',
  195     ],
  196       $this->getBaseRouteRequirements($method),
  197       [],
  198       '',
  199       [],
  200       // The HTTP method is a requirement for this route.
  201       [$method]
  202     );
  203   }
  204 
  205   /**
  206    * Gets the base route requirements for a particular method.
  207    *
  208    * @param $method
  209    *   The HTTP method to be used for the route.
  210    *
  211    * @return array
  212    *   An array of requirements for parameters.
  213    */
  214   protected function getBaseRouteRequirements($method) {
  215     $lower_method = strtolower($method);
  216     // Every route MUST have requirements that result in the access manager
  217     // having access checks to check. If it does not, the route is made
  218     // inaccessible. So, we default to granting access to everyone. If a
  219     // permission exists, then we add that below. The access manager requires
  220     // that ALL access checks must grant access, so this still results in
  221     // correct behavior.
  222     $requirements = [
  223       '_access' => 'TRUE',
  224     ];
  225 
  226     // Only specify route requirements if the default permission exists. For any
  227     // more advanced route definition, resource plugins extending this base
  228     // class must override this method.
  229     $permission = "restful $lower_method $this->pluginId";
  230     if (isset($this->permissions()[$permission])) {
  231       $requirements['_permission'] = $permission;
  232     }
  233 
  234     return $requirements;
  235   }
  236 
  237 }