FormModesSubscriber.php in Form mode manager 8.2
Same filename and directory in other branches
File
src/Routing/EventSubscriber/FormModesSubscriber.phpView source
<?php
namespace Drupal\form_mode_manager\Routing\EventSubscriber;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteSubscriberBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\form_mode_manager\FormModeManagerInterface;
use Drupal\form_mode_manager\EntityRoutingMapManager;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Listens to the dynamic route event and add routes using form modes.
*/
class FormModesSubscriber extends RouteSubscriberBase {
use StringTranslationTrait;
/**
* Namespace of transverse entity controller.
*
* @var string
*/
const FORM_MODE_DEFAULT_CONTROLLER = '\\Drupal\\form_mode_manager\\Controller\\FormModeManagerEntityController';
/**
* The Regex pattern to contextualize process by route path.
*
* @var string
*/
const ROUTE_PATH_CONTEXT_REGEX = '/(^.*?\\/edit)|(^.*?\\/{block_content})/';
/**
* The entity type plugin definition.
*
* @var \Drupal\Core\Entity\EntityTypeInterface
*/
protected $entityDefinition;
/**
* The entity display repository.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected $entityDisplayRepository;
/**
* The current instance of Routing Map plugin for a specific entity type.
*
* @var \Drupal\form_mode_manager\EntityRoutingMapBase
*/
protected $entityRoutingDefinition;
/**
* The Routing Map Plugin service.
*
* @var \Drupal\form_mode_manager\EntityRoutingMapManager
*/
protected $entityRoutingMap;
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity Form Mode manager service.
*
* @var \Drupal\form_mode_manager\FormModeManagerInterface
*/
protected $formModeManager;
/**
* The route collection for adding routes.
*
* @var \Symfony\Component\Routing\RouteCollection
*/
protected $routeCollection;
/**
* Constructs a new RouteSubscriber object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* The entity display repository.
* @param \Drupal\form_mode_manager\FormModeManagerInterface $form_mode_manager
* The form mode manager.
* @param \Drupal\form_mode_manager\EntityRoutingMapManager $plugin_routes_manager
* Plugin EntityRoutingMap to retrieve entity form operation routes.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, FormModeManagerInterface $form_mode_manager, EntityRoutingMapManager $plugin_routes_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->entityDisplayRepository = $entity_display_repository;
$this->formModeManager = $form_mode_manager;
$this->entityRoutingMap = $plugin_routes_manager;
}
/**
* Add one route collection per entity using form modes.
*
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection) {
$this->routeCollection = $collection;
foreach ($this->formModeManager
->getAllFormModesDefinitions() as $entity_type_id => $form_modes) {
$this->entityDefinition = $this->entityTypeManager
->getDefinition($entity_type_id);
$this->entityRoutingDefinition = $this->entityRoutingMap
->createInstance($entity_type_id, [
'entityTypeId' => $entity_type_id,
]);
$this
->addFormModesRoutes($form_modes);
}
}
/**
* Add a collection of route per form mode for current entity.
*
* Each entity need to define a collection of routes to be used by Drupal.
* Each `entity operation` is a form handler present for all,
* ContentEntityType plugins. Each operation represent a Form to be,
* displayed by formBuilder service in routes controllers.
* To respect core logic implemented by Drupal we need to add,
* a route for each operations (add/edit/add_page/admin_add) dynamically and,
* a transverse controller compatible to use form modes.
*
* Each routes generated by `setFormModeCollection` and,
* `setAddPageCollection` respect the following naming,
* `ENTITY_ROUTES_BASIS.FORM_MODE_NAME` eg for Node entity :
*
* @code
* $routes = [
* 'add_form' => 'node.add.FORM_MODE_NAME',
* 'edit_form' => 'entity.node.edit_form.FORM_MODE_NAME',
* 'add_page' => 'form_mode_manager.node.add_page.FORM_MODE_NAME',
* 'admin_add' => 'node.add.FORM_MODE_NAME',
* ];
* @endcode
*
* @param array $form_modes
* All form-modes available for specified entity_type_id.
*/
protected function addFormModesRoutes(array $form_modes) {
foreach ($form_modes as $form_mode_infos) {
$this
->setFormModeCollection($form_mode_infos, 'add_form');
$this
->setFormModeCollection($form_mode_infos, 'edit_form');
$this
->setFormModeCollection($form_mode_infos, 'admin_add');
if (!empty($this->entityDefinition
->getKey('bundle'))) {
$this
->setAddPageCollection($form_mode_infos);
}
}
}
/**
* Create a route for given form mode and operation form handler.
*
* This method add a route for given form mode and respect the standard,
* of parent entity routing naming. All routes added in collection are,
* based on parrent route parameters and only add only,
* the minimum to use form modes. The route add only if parent entity,
* declare to use this operation in `entityRoutingMap` plugin.
*
* @param array $form_mode_infos
* A form-mode for specified entity_type_id.
* @param string $operation_name
* The entity operation name.
*/
public function setFormModeCollection(array $form_mode_infos, $operation_name) {
if ($this->entityRoutingDefinition
->getOperation($operation_name) && ($route = $this
->getFormModeRoute($form_mode_infos, $operation_name))) {
$form_mode_name = $this->formModeManager
->getFormModeMachineName($form_mode_infos['id']);
$form_mode_route_name = "{$this->entityRoutingDefinition->getOperation($operation_name)}.{$form_mode_name}";
$this->routeCollection
->add($form_mode_route_name, $route);
}
}
/**
* Get the Form Mode Manager route for given operation.
*
* @param array $form_mode_infos
* The form mode info.
* @param string $operation_name
* The entity operation name.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
public function getFormModeRoute(array $form_mode_infos, $operation_name) {
$route_name = $this->entityRoutingDefinition
->getOperation($operation_name);
$form_mode_machine_name = $this->formModeManager
->getFormModeMachineName($form_mode_infos['id']);
$entity_type_id = $this->entityDefinition
->id();
if ($this->formModeManager
->hasActiveFormMode($entity_type_id, $form_mode_machine_name) && ($entity_edit_route = $this->routeCollection
->get($route_name))) {
return $this
->setRoutes($entity_edit_route, $form_mode_infos);
}
return NULL;
}
/**
* Generate a routes based on top of given parent routes.
*
* @param \Symfony\Component\Routing\Route $parent_route
* The route object of entity.
* @param array $form_mode_infos
* The form mode info.
*
* @return \Symfony\Component\Routing\Route
* Form Mode Manager route to be added on entity collection.
*/
protected function setRoutes(Route $parent_route, array $form_mode_infos) {
$route_path = implode('/', [
$parent_route
->getPath(),
$this->formModeManager
->getFormModeMachineName($form_mode_infos['id']),
]);
$route_defaults = NestedArray::mergeDeep($parent_route
->getDefaults(), $this
->getFormModeRouteDefaults($parent_route, $form_mode_infos));
$route_options = NestedArray::mergeDeep($parent_route
->getOptions(), $this
->getFormModeRouteOptions($form_mode_infos));
$route_requirements = NestedArray::mergeDeep($parent_route
->getRequirements(), $this
->getFormModeRouteRequirements($form_mode_infos));
return new Route($route_path, $route_defaults, $route_requirements, $route_options);
}
/**
* Get defaults parameters needed to build Form Mode Manager routes.
*
* @param \Symfony\Component\Routing\Route $route
* The route object of entity.
* @param array $form_mode_infos
* The form mode info.
*
* @return array
* Array contain defaults routes parameters.
*/
protected function getFormModeRouteDefaults(Route $route, array $form_mode_infos) {
$route_parameters = [
'_entity_form' => $form_mode_infos['id'],
'_controller' => static::FORM_MODE_DEFAULT_CONTROLLER . '::entityAdd',
'_title_callback' => static::FORM_MODE_DEFAULT_CONTROLLER . '::addPageTitle',
];
if (static::isEditRoute($route)) {
$route_parameters['_title_callback'] = static::FORM_MODE_DEFAULT_CONTROLLER . '::editPageTitle';
$route_parameters['_controller'] = static::FORM_MODE_DEFAULT_CONTROLLER . '::entityEdit';
}
return $route_parameters;
}
/**
* Evaluate if current context is edit.
*
* @param \Symfony\Component\Routing\Route $route
* The route object of entity.
*
* @return bool
* True if current route context is edit or False if not.
*/
public static function isEditRoute(Route $route) {
return (bool) preg_match_all(self::ROUTE_PATH_CONTEXT_REGEX, $route
->getPath(), $matches, PREG_SET_ORDER, 0);
}
/**
* Get options parameters nedeed to build Form Mode Manager routes.
*
* @param array $form_mode_infos
* The form mode info.
*
* @return array
* Array contain options routes parameters.
*/
protected function getFormModeRouteOptions(array $form_mode_infos) {
$entity_definition = $this->entityDefinition;
$entity_type_id = $entity_definition
->id();
$route_definition = [
'_form_mode_manager_entity_type_id' => $entity_type_id,
'form_mode_theme' => NULL,
'parameters' => [
$entity_type_id => [
'type' => "entity:{$entity_type_id}",
],
'form_mode' => $form_mode_infos + [
'type' => NULL,
],
],
];
if (!empty($entity_definition
->getKey('bundle'))) {
$route_definition['_form_mode_manager_bundle_entity_type_id'] = $entity_definition
->getBundleEntityType();
}
return $route_definition;
}
/**
* Get options requirements nedeed to build Form Mode Manager routes.
*
* @param array $form_mode_infos
* The form mode info.
*
* @return array
* Array contain requirements routes parameters.
*/
protected function getFormModeRouteRequirements(array $form_mode_infos) {
return [
'_permission' => "use {$form_mode_infos['id']} form mode",
'_custom_access' => static::FORM_MODE_DEFAULT_CONTROLLER . '::checkAccess',
];
}
/**
* Add one route for `add_page` entity operation per form_mode.
*
* This page concern only bundled entities using a route for listing all,
* bundles using by this entity. Form mode manager add more granularity ,
* permit to choose what bundle is compatible with a specific form mode.
* This method add one listing route by form mode to provide,
* these granularity. Not all entities declare a `add_page` operation,
* because this isn't needed for all usecases but Form mode manager need,
* to add this possibility as a standard.
* All routes key are named with to follow these standard,
* `form_mode_manager.ENTITY_TYPE_ID.add_page.FORM_MODE_NAME`
*
* @param array $form_mode_infos
* A form-mode for specified entity_type_id.
*/
public function setAddPageCollection(array $form_mode_infos) {
$form_mode_name = $this->formModeManager
->getFormModeMachineName($form_mode_infos['id']);
if ($route = $this
->getFormModeListPageRoute($form_mode_infos)) {
$form_mode_route_name = "form_mode_manager.{$this->entityDefinition->id()}.add_page.{$form_mode_name}";
$this->routeCollection
->add($form_mode_route_name, $route);
}
}
/**
* Generate routes to use `add-list` entity operation per form modes.
*
* @param array $form_mode_infos
* An associative array represent a DisplayForm entity.
*
* @return \Symfony\Component\Routing\Route|null
* The generated route, if available.
*/
public function getFormModeListPageRoute(array $form_mode_infos) {
$form_mode_machine_name = $this->formModeManager
->getFormModeMachineName($form_mode_infos['id']);
$entity_type_id = $this->entityDefinition
->id();
$route = NULL;
if ($this->formModeManager
->hasActiveFormMode($entity_type_id, $form_mode_machine_name)) {
$route_path = implode('/', [
$entity_type_id,
'add-list',
$this->formModeManager
->getFormModeMachineName($form_mode_infos['id']),
]);
$route_defaults = [
'_controller' => static::FORM_MODE_DEFAULT_CONTROLLER . '::addPage',
'_title' => $this
->getListRouteTitle($form_mode_infos['label']),
'form_mode_name' => $this->formModeManager
->getFormModeMachineName($form_mode_infos['id']),
];
$route_requirements = [
'_permission' => "use {$form_mode_infos['id']} form mode",
];
$route_options = [
'_form_mode_manager_entity_type_id' => $entity_type_id,
'_form_mode_manager_bundle_entity_type_id' => $this->entityDefinition
->getBundleEntityType(),
'_admin_route' => TRUE,
];
$route = new Route("/{$route_path}", $route_defaults, $route_requirements, $route_options);
}
return $route;
}
/**
* Format the title for `add_list` routes.
*
* @param string $form_mode_label
* The label of current DisplayForm entity.
*
* @return string
* The translated title string of `add_list` operation routes.
*/
public function getListRouteTitle($form_mode_label) {
$translatable_markup = $this
->t('Add @entity_type as @form_mode_label', [
'@entity_type' => $this->entityDefinition
->getLabel(),
'@form_mode_label' => $form_mode_label,
]);
return $translatable_markup
->render();
}
}
Classes
Name | Description |
---|---|
FormModesSubscriber | Listens to the dynamic route event and add routes using form modes. |