class EntityResolverManager in Zircon Profile 8
Same name and namespace in other branches
- 8.0 core/lib/Drupal/Core/Entity/EntityResolverManager.php \Drupal\Core\Entity\EntityResolverManager
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.
Hierarchy
- class \Drupal\Core\Entity\EntityResolverManager
Expanded class hierarchy of EntityResolverManager
2 files declare their use of EntityResolverManager
- EntityResolverManagerTest.php in core/
tests/ Drupal/ Tests/ Core/ Entity/ EntityResolverManagerTest.php - Contains \Drupal\Tests\Core\Entity\EntityResolverManagerTest.
- EntityRouteAlterSubscriber.php in core/
lib/ Drupal/ Core/ EventSubscriber/ EntityRouteAlterSubscriber.php - Contains \Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber.
1 string reference to 'EntityResolverManager'
- core.services.yml in core/
core.services.yml - core/core.services.yml
1 service uses EntityResolverManager
File
- core/
lib/ Drupal/ Core/ Entity/ EntityResolverManager.php, line 19 - Contains \Drupal\Core\Entity\EntityResolverManager.
Namespace
Drupal\Core\EntityView source
class EntityResolverManager {
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* 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\DependencyInjection\ClassResolverInterface $class_resolver
* The class resolver.
*/
public function __construct(EntityManagerInterface $entity_manager, ClassResolverInterface $class_resolver) {
$this->entityManager = $entity_manager;
$this->classResolver = $class_resolver;
}
/**
* Gets the controller class using route defaults.
*
* By design we cannot support all possible routes, but just the ones which
* use the defaults provided by core, which are _controller and _form.
*
* Rather than creating an instance of every controller determine the class
* and method that would be used. This is not possible for the service:method
* notation as the runtime container does not allow static introspection.
*
* @see \Drupal\Core\Controller\ControllerResolver::getControllerFromDefinition()
* @see \Drupal\Core\Controller\ClassResolver::getInstanceFromDefinition()
*
* @param array $defaults
* The default values provided by the route.
*
* @return string|null
* Returns the controller class, otherwise NULL.
*/
protected function getControllerClass(array $defaults) {
$controller = NULL;
if (isset($defaults['_controller'])) {
$controller = $defaults['_controller'];
}
if (isset($defaults['_form'])) {
$controller = $defaults['_form'];
// Check if the class exists and if so use the buildForm() method from the
// interface.
if (class_exists($controller)) {
return array(
$controller,
'buildForm',
);
}
}
if (strpos($controller, ':') === FALSE) {
if (method_exists($controller, '__invoke')) {
return array(
$controller,
'__invoke',
);
}
if (function_exists($controller)) {
return $controller;
}
return NULL;
}
$count = substr_count($controller, ':');
if ($count == 1) {
// Controller in the service:method notation. Get the information from the
// service. This is dangerous as the controller could depend on services
// that could not exist at this point. There is however no other way to
// do it, as the container does not allow static introspection.
list($class_or_service, $method) = explode(':', $controller, 2);
return array(
$this->classResolver
->getInstanceFromDefinition($class_or_service),
$method,
);
}
elseif (strpos($controller, '::') !== FALSE) {
// Controller in the class::method notation.
return explode('::', $controller, 2);
}
return NULL;
}
/**
* Sets the upcasting information using reflection.
*
* @param string|array $controller
* A PHP callable representing the controller.
* @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($controller, Route $route) {
$entity_types = $this
->getEntityTypes();
$parameter_definitions = $route
->getOption('parameters') ?: array();
$result = FALSE;
if (is_array($controller)) {
list($instance, $method) = $controller;
$reflection = new \ReflectionMethod($instance, $method);
}
else {
$reflection = new \ReflectionFunction($controller);
}
$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 upcasting 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.
*
* Supports the '_entity_view' 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_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
->getControllerClass($route
->getDefaults())) {
// Try to use reflection.
if ($this
->setParametersFromReflection($controller, $route)) {
return;
}
}
// Try to use _entity_* information on the route.
$this
->setParametersFromEntityInformation($route);
}
/**
* Gets the 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;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EntityResolverManager:: |
protected | property | The class resolver. | |
EntityResolverManager:: |
protected | property | The entity manager. | |
EntityResolverManager:: |
protected | function | Gets the controller class using route defaults. | |
EntityResolverManager:: |
protected | function | Gets the list of all entity types. | |
EntityResolverManager:: |
protected | function | Sets the upcasting information using the _entity_* route defaults. | |
EntityResolverManager:: |
protected | function | Sets the upcasting information using reflection. | |
EntityResolverManager:: |
public | function | Set the upcasting route objects. | |
EntityResolverManager:: |
public | function | Constructs a new EntityRouteAlterSubscriber. |