Commit a4d7fad2 authored by catch's avatar catch

Revert "Issue #1906810 by dawehner, damiankloip, tstoeckler, kgoel, fubhy,...

Revert "Issue #1906810 by dawehner, damiankloip, tstoeckler, kgoel, fubhy, jrglasgow, xjm, Gaelan, socketwench: Require type hints for automatic entity upcasting."

This reverts commit c9e73f7d.
parent 0616fed2
...@@ -451,14 +451,11 @@ services: ...@@ -451,14 +451,11 @@ services:
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
arguments: ['@module_handler'] arguments: ['@module_handler']
resolver_manager.entity:
class: Drupal\Core\Entity\EntityResolverManager
arguments: ['@entity.manager', '@controller_resolver', '@class_resolver']
route_subscriber.entity: route_subscriber.entity:
class: Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber class: Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
arguments: ['@resolver_manager.entity'] arguments: ['@entity.manager']
reverse_proxy_subscriber: reverse_proxy_subscriber:
class: Drupal\Core\EventSubscriber\ReverseProxySubscriber class: Drupal\Core\EventSubscriber\ReverseProxySubscriber
tags: tags:
......
<?php
/**
* @file
* Contains \Drupal\Core\Entity\EntityResolverManager.
*/
namespace Drupal\Core\Entity;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Controller\ControllerResolverInterface;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Symfony\Component\Routing\Route;
/**
* Sets the entity route parameter converter options automatically.
*
* If controllers of routes with route parameters, type-hint the parameters with
* an entity interface, upcasting is done automatically.
*/
class EntityResolverManager {
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* The controller resolver.
*
* @var \Drupal\Core\Controller\ControllerResolverInterface
*/
protected $controllerResolver;
/**
* The class resolver.
*
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface
*/
protected $classResolver;
/**
* Constructs a new EntityRouteAlterSubscriber.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
* The controller resolver.
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
* The class resolver.
*/
public function __construct(EntityManagerInterface $entity_manager, ControllerResolverInterface $controller_resolver, ClassResolverInterface $class_resolver) {
$this->entityManager = $entity_manager;
$this->controllerResolver = $controller_resolver;
$this->classResolver = $class_resolver;
}
/**
* Creates a controller instance using route defaults.
*
* By design we cannot support all possible routes, but just the ones which
* use the defaults provided by core, which are _content, _controller
* and _form.
*
* @param array $defaults
* The default values provided by the route.
*
* @return array|null
* Returns the controller instance if it is possible to instantiate it, NULL
*/
protected function getController(array $defaults) {
$controller = NULL;
if (isset($defaults['_content'])) {
$controller = $this->controllerResolver->getControllerFromDefinition($defaults['_content']);
}
if (isset($defaults['_controller'])) {
$controller = $this->controllerResolver->getControllerFromDefinition($defaults['_controller']);
}
if (isset($defaults['_form'])) {
$form_arg = $defaults['_form'];
// Check if the class exists first as the class resolver will throw an
// exception if it doesn't. This also means a service cannot be used here.
if (class_exists($form_arg)) {
$controller = array($this->classResolver->getInstanceFromDefinition($form_arg), 'buildForm');
}
}
return $controller;
}
/**
* Sets the upcasting information using reflection.
*
* @param array $controller
* An array of class instance and method name.
* @param \Symfony\Component\Routing\Route $route
* The route object to populate without upcasting information.
*
* @return bool
* Returns TRUE if the upcasting parameters could be set, FALSE otherwise.
*/
protected function setParametersFromReflection(array $controller, Route $route) {
$entity_types = $this->getEntityTypes();
$parameter_definitions = $route->getOption('parameters') ?: array();
$result = FALSE;
list($instance, $method) = $controller;
$reflection = new \ReflectionMethod($instance, $method);
$parameters = $reflection->getParameters();
foreach ($parameters as $parameter) {
$parameter_name = $parameter->getName();
// If the parameter name matches with an entity type try to set the
// upcasting information automatically. Therefore take into account that
// the user has specified some interface, so the upasting is intended.
if (isset($entity_types[$parameter_name])) {
$entity_type = $entity_types[$parameter_name];
$entity_class = $entity_type->getClass();
if (($reflection_class = $parameter->getClass()) && (is_subclass_of($entity_class, $reflection_class->name) || $entity_class == $reflection_class->name)) {
$parameter_definitions += array($parameter_name => array());
$parameter_definitions[$parameter_name] += array(
'type' => 'entity:' . $parameter_name,
);
$result = TRUE;
}
}
}
if (!empty($parameter_definitions)) {
$route->setOption('parameters', $parameter_definitions);
}
return $result;
}
/**
* Sets the upcasting information using the _entity_* route defaults.
*
* Supported are the '_entity_view', '_entity_list' and '_entity_form' route
* defaults.
*
* @param \Symfony\Component\Routing\Route $route
* The route object.
*/
protected function setParametersFromEntityInformation(Route $route) {
if ($entity_view = $route->getDefault('_entity_view')) {
list($entity_type) = explode('.', $entity_view, 2);
}
elseif ($entity_list = $route->getDefault('_entity_list')) {
$entity_type = $entity_list;
}
elseif ($entity_form = $route->getDefault('_entity_form')) {
list($entity_type) = explode('.', $entity_form, 2);
}
if (isset($entity_type) && isset($this->getEntityTypes()[$entity_type])) {
$parameter_definitions = $route->getOption('parameters') ?: array();
// First try to figure out whether there is already a parameter upcasting
// the same entity type already.
foreach ($parameter_definitions as $info) {
if (isset($info['type'])) {
// The parameter types are in the form 'entity:$entity_type'.
list(, $parameter_entity_type) = explode(':', $info['type'], 2);
if ($parameter_entity_type == $entity_type) {
return;
}
}
}
if (!isset($parameter_definitions[$entity_type])) {
$parameter_definitions[$entity_type] = array();
}
$parameter_definitions[$entity_type] += array(
'type' => 'entity:' . $entity_type,
);
if (!empty($parameter_definitions)) {
$route->setOption('parameters', $parameter_definitions);
}
}
}
/**
* Set the upcasting route objects.
*
* @param \Symfony\Component\Routing\Route $route
* The route object to add the upcasting information onto.
*/
public function setRouteOptions(Route $route) {
if ($controller = $this->getController($route->getDefaults())) {
// Try to use reflection.
if ($this->setParametersFromReflection($controller, $route)) {
return;
}
}
// Try to use _entity_view, _entity_list information on the route.
$this->setParametersFromEntityInformation($route);
}
/**
* Returns a list of all entity types.
*
* @return \Drupal\Core\Entity\EntityTypeInterface[]
*/
protected function getEntityTypes() {
if (!isset($this->entityTypes)) {
$this->entityTypes = $this->entityManager->getDefinitions();
}
return $this->entityTypes;
}
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
namespace Drupal\Core\EventSubscriber; namespace Drupal\Core\EventSubscriber;
use Drupal\Core\Entity\EntityResolverManager; use Drupal\Core\Entity\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Routing\RoutingEvents; use Drupal\Core\Routing\RoutingEvents;
use Drupal\Core\Routing\RouteBuildEvent; use Drupal\Core\Routing\RouteBuildEvent;
...@@ -26,20 +26,20 @@ ...@@ -26,20 +26,20 @@
class EntityRouteAlterSubscriber implements EventSubscriberInterface { class EntityRouteAlterSubscriber implements EventSubscriberInterface {
/** /**
* The entity resolver manager. * Entity manager.
* *
* @var \Drupal\Core\Entity\EntityResolverManager * @var \Drupal\Core\Entity\EntityManagerInterface
*/ */
protected $resolverManager; protected $entityManager;
/** /**
* Constructs an EntityRouteAlterSubscriber instance. * Constructs a new EntityRouteAlterSubscriber.
* *
* @param \Drupal\Core\Entity\EntityResolverManager * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity resolver manager. * The entity manager.
*/ */
public function __construct(EntityResolverManager $entity_resolver_manager) { public function __construct(EntityManagerInterface $entity_manager) {
$this->resolverManager = $entity_resolver_manager; $this->entityManager = $entity_manager;
} }
/** /**
...@@ -49,8 +49,22 @@ public function __construct(EntityResolverManager $entity_resolver_manager) { ...@@ -49,8 +49,22 @@ public function __construct(EntityResolverManager $entity_resolver_manager) {
* The event to process. * The event to process.
*/ */
public function onRoutingRouteAlterSetType(RouteBuildEvent $event) { public function onRoutingRouteAlterSetType(RouteBuildEvent $event) {
$entity_types = array_keys($this->entityManager->getDefinitions());
foreach ($event->getRouteCollection() as $route) { foreach ($event->getRouteCollection() as $route) {
$this->resolverManager->setRouteOptions($route); $parameter_definitions = $route->getOption('parameters') ?: array();
// For all route parameter names that match an entity type, add the 'type'
// to the parameter definition if it's not already explicitly provided.
foreach (array_intersect($route->compile()->getVariables(), $entity_types) as $parameter_name) {
if (!isset($parameter_definitions[$parameter_name])) {
$parameter_definitions[$parameter_name] = array();
}
$parameter_definitions[$parameter_name] += array(
'type' => 'entity:' . $parameter_name,
);
}
if (!empty($parameter_definitions)) {
$route->setOption('parameters', $parameter_definitions);
}
} }
} }
......
...@@ -56,7 +56,8 @@ function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $l ...@@ -56,7 +56,8 @@ function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $l
$this->cache = $cache; $this->cache = $cache;
$this->lock = $lock; $this->lock = $lock;
$this->tags = $tags; $this->tags = $tags;
$this->persistable = $modules_loaded && \Drupal::hasRequest() && \Drupal::request()->isMethod('GET'); $request = \Drupal::request();
$this->persistable = $modules_loaded && $request->isMethod('GET');
// @todo: Implement lazyload. // @todo: Implement lazyload.
$this->cacheLoaded = TRUE; $this->cacheLoaded = TRUE;
......
...@@ -21,7 +21,7 @@ class CommentDefaultFormatterCacheTagsTest extends EntityUnitTestBase { ...@@ -21,7 +21,7 @@ class CommentDefaultFormatterCacheTagsTest extends EntityUnitTestBase {
* *
* @var array * @var array
*/ */
public static $modules = array('entity_test', 'comment', 'menu_link'); public static $modules = array('entity_test', 'comment');
/** /**
* {@inheritdoc} * {@inheritdoc}
......
...@@ -7,7 +7,7 @@ config_translation.mapper_list: ...@@ -7,7 +7,7 @@ config_translation.mapper_list:
_permission: 'translate configuration' _permission: 'translate configuration'
config_translation.entity_list: config_translation.entity_list:
path: '/admin/config/regional/config-translation/{mapper_id}' path: '/admin/config/regional/config-translation/{config_translation_mapper}'
defaults: defaults:
_content: '\Drupal\config_translation\Controller\ConfigTranslationListController::listing' _content: '\Drupal\config_translation\Controller\ConfigTranslationListController::listing'
requirements: requirements:
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
use Drupal\locale\LocaleConfigManager; use Drupal\locale\LocaleConfigManager;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/** /**
* Configuration mapper for configuration entities. * Configuration mapper for configuration entities.
...@@ -234,18 +233,4 @@ public function getContextualLinkGroup() { ...@@ -234,18 +233,4 @@ public function getContextualLinkGroup() {
} }
} }
/**
* {@inheritdoc}
*/
protected function processRoute(Route $route) {
// Add entity upcasting information.
$parameters = $route->getOption('parameters') ?: array();
$parameters += array(
$this->entityType => array(
'type' => 'entity:' . $this->entityType,
)
);
$route->setOption('parameters', $parameters);
}
} }
...@@ -46,13 +46,6 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con ...@@ -46,13 +46,6 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con
*/ */
protected $configMapperManager; protected $configMapperManager;
/**
* The route provider.
*
* @var \Drupal\Core\Routing\RouteProviderInterface
*/
protected $routeProvider;
/** /**
* The base route object that the mapper is attached to. * The base route object that the mapper is attached to.
* *
...@@ -175,15 +168,6 @@ public function getBaseRoute() { ...@@ -175,15 +168,6 @@ public function getBaseRoute() {
} }
} }
/**
* Allows to process all config translation routes.
*
* @param \Symfony\Component\Routing\Route $route
* The route object to process.
*/
protected function processRoute(Route $route) {
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -209,7 +193,7 @@ public function getOverviewRouteParameters() { ...@@ -209,7 +193,7 @@ public function getOverviewRouteParameters() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getOverviewRoute() { public function getOverviewRoute() {
$route = new Route( return new Route(
$this->getBaseRoute()->getPath() . '/translate', $this->getBaseRoute()->getPath() . '/translate',
array( array(
'_content' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage', '_content' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage',
...@@ -217,8 +201,6 @@ public function getOverviewRoute() { ...@@ -217,8 +201,6 @@ public function getOverviewRoute() {
), ),
array('_config_translation_overview_access' => 'TRUE') array('_config_translation_overview_access' => 'TRUE')
); );
$this->processRoute($route);
return $route;
} }
/** /**
...@@ -250,7 +232,7 @@ public function getAddRouteParameters() { ...@@ -250,7 +232,7 @@ public function getAddRouteParameters() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getAddRoute() { public function getAddRoute() {
$route = new Route( return new Route(
$this->getBaseRoute()->getPath() . '/translate/{langcode}/add', $this->getBaseRoute()->getPath() . '/translate/{langcode}/add',
array( array(
'_form' => '\Drupal\config_translation\Form\ConfigTranslationAddForm', '_form' => '\Drupal\config_translation\Form\ConfigTranslationAddForm',
...@@ -258,8 +240,6 @@ public function getAddRoute() { ...@@ -258,8 +240,6 @@ public function getAddRoute() {
), ),
array('_config_translation_form_access' => 'TRUE') array('_config_translation_form_access' => 'TRUE')
); );
$this->processRoute($route);
return $route;
} }
/** /**
...@@ -280,7 +260,7 @@ public function getEditRouteParameters() { ...@@ -280,7 +260,7 @@ public function getEditRouteParameters() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getEditRoute() { public function getEditRoute() {
$route = new Route( return new Route(
$this->getBaseRoute()->getPath() . '/translate/{langcode}/edit', $this->getBaseRoute()->getPath() . '/translate/{langcode}/edit',
array( array(
'_form' => '\Drupal\config_translation\Form\ConfigTranslationEditForm', '_form' => '\Drupal\config_translation\Form\ConfigTranslationEditForm',
...@@ -288,8 +268,6 @@ public function getEditRoute() { ...@@ -288,8 +268,6 @@ public function getEditRoute() {
), ),
array('_config_translation_form_access' => 'TRUE') array('_config_translation_form_access' => 'TRUE')
); );
$this->processRoute($route);
return $route;
} }
/** /**
...@@ -310,7 +288,7 @@ public function getDeleteRouteParameters() { ...@@ -310,7 +288,7 @@ public function getDeleteRouteParameters() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getDeleteRoute() { public function getDeleteRoute() {
$route = new Route( return new Route(
$this->getBaseRoute()->getPath() . '/translate/{langcode}/delete', $this->getBaseRoute()->getPath() . '/translate/{langcode}/delete',
array( array(
'_form' => '\Drupal\config_translation\Form\ConfigTranslationDeleteForm', '_form' => '\Drupal\config_translation\Form\ConfigTranslationDeleteForm',
...@@ -318,8 +296,6 @@ public function getDeleteRoute() { ...@@ -318,8 +296,6 @@ public function getDeleteRoute() {
), ),
array('_config_translation_form_access' => 'TRUE') array('_config_translation_form_access' => 'TRUE')
); );
$this->processRoute($route);
return $route;
} }
/** /**
......
...@@ -18,20 +18,30 @@ ...@@ -18,20 +18,30 @@
class ConfigTranslationListController extends ControllerBase { class ConfigTranslationListController extends ControllerBase {
/** /**
* The mapper manager. * The definition of the config mapper.
* *
* @var \Drupal\config_translation\ConfigMapperManagerInterface * @var array
*/ */
protected $mapperManager; protected $mapperDefinition;
/**
* The config mapper.
*
* @var \Drupal\config_translation\ConfigEntityMapper
*/
protected $mapper;
/** /**
* Constructs a new ConfigTranslationListController object. * Constructs a new ConfigTranslationListController object.
* *
* @param \Drupal\config_translation\ConfigMapperManagerInterface $mapper_manager * @param \Drupal\config_translation\ConfigMapperManagerInterface $mapper_manager
* The config mapper manager. * The config mapper manager.
* @param string $config_translation_mapper
* The config mapper id.
*/ */
public function __construct(ConfigMapperManagerInterface $mapper_manager) { public function __construct(ConfigMapperManagerInterface $mapper_manager, $config_translation_mapper) {
$this->mapperManager = $mapper_manager; $this->mapperDefinition = $mapper_manager->getDefinition($config_translation_mapper);
$this->mapper = $mapper_manager->createInstance($config_translation_mapper, $this->mapperDefinition);
} }
/** /**
...@@ -39,16 +49,14 @@ public function __construct(ConfigMapperManagerInterface $mapper_manager) { ...@@ -39,16 +49,14 @@ public function __construct(ConfigMapperManagerInterface $mapper_manager) {
*/ */
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
return new static( return new static(
$container->get('plugin.manager.config_translation.mapper') $container->get('plugin.manager.config_translation.mapper'),
$container->get('request')->attributes->get('_raw_variables')->get('config_translation_mapper')
); );
} }
/** /**
* Provides the listing page for any entity type. * Provides the listing page for any entity type.
* *
* @param string $mapper_id
* The name of the mapper.
*
* @return array * @return array
* A render array as expected by drupal_render(). * A render array as expected by drupal_render().
* *
...@@ -56,22 +64,20 @@ public static function create(ContainerInterface $container) { ...@@ -56,22 +64,20 @@ public static function create(ContainerInterface $container) {
* Throws an exception if a mapper plugin could not be instantiated from the * Throws an exception if a mapper plugin could not be instantiated from the
* mapper definition in the constructor. * mapper definition in the constructor.
*/ */
public function listing($mapper_id) { public function listing() {
$mapper_definition = $this->mapperManager->getDefinition($mapper_id); if (!$this->mapper) {
$mapper = $this->mapperManager->createInstance($mapper_id, $mapper_definition);
if (!$mapper) {
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }
$entity_type = $mapper->getType(); $entity_type = $this->mapper->getType();
// If the mapper, for example the mapper for field instances, has a custom // If the mapper, for example the mapper for field instances, has a custom
// list controller defined, use it. Other mappers, for examples the ones for // list controller defined, use it. Other mappers, for examples the ones for
// node_type and block, fallback to the generic configuration translation // node_type and block, fallback to the generic configuration translation
// list controller. // list controller.
$build = $this->entityManager() $build = $this->entityManager()
->getController($entity_type, 'config_translation_list') ->getController($entity_type, 'config_translation_list')
->setMapperDefinition($mapper_definition) ->setMapperDefinition($this->mapperDefinition)
->render(); ->render();
$build['#title'] = $mapper->getTypeLabel(); $build['#title'] = $this->mapper->getTypeLabel();
return $build; return $build;
} }