From ce889f8b794a55fb4c5a91877a8e27b64ccf9f15 Mon Sep 17 00:00:00 2001 From: Kristiaan Van den Eynde Date: Fri, 21 Sep 2018 12:07:33 +0200 Subject: [PATCH] Issue #2651974 by kristiaanvandeneynde: field_ui_entity_operation() cannot respect route parameters because of incorrectly named routes --- core/lib/Drupal/Core/Entity/Entity.php | 2 +- core/lib/Drupal/Core/Entity/EntityType.php | 17 +++++- core/modules/field_ui/field_ui.module | 39 +++++++++---- core/modules/field_ui/field_ui.services.yml | 4 ++ .../src/Routing/DeprecatedRouteMatcher.php | 55 +++++++++++++++++++ .../field_ui/src/Routing/RouteSubscriber.php | 15 ++++- 6 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 core/modules/field_ui/src/Routing/DeprecatedRouteMatcher.php diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 84991bc609..7e4592a5db 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -318,7 +318,7 @@ protected function urlRouteParameters($rel) { // The entity ID is needed as a route parameter. $uri_route_parameters[$this->getEntityTypeId()] = $this->id(); } - if ($rel === 'add-form' && ($this->getEntityType()->hasKey('bundle'))) { + if (($rel === 'add-form' || strpos('drupal:field-ui-', $rel) === 0) && ($this->getEntityType()->hasKey('bundle'))) { $parameter_name = $this->getEntityType()->getBundleEntityType() ?: $this->getEntityType()->getKey('bundle'); $uri_route_parameters[$parameter_name] = $this->bundle(); } diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index c6f320fd6e..fc3edcbfaa 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -241,7 +241,22 @@ class EntityType extends PluginDefinition implements EntityTypeInterface { protected $group_label; /** - * The route name used by field UI to attach its management pages. + * The path used by field UI to create its management pages routes with. + * + * @todo From Drupal 9.0.0 onwards, this should be used to detect whether an + * entity type supports Field UI. + * + * @var string + */ + protected $field_ui_base_path; + + /** + * The route name used by field UI to attach its management pages local tasks. + * + * The path for this route should be the field_ui_base_path value. + * + * @todo From Drupal 9.0.0 onwards, this should only be used to detect whether + * an entity type supports Field UI local tasks (tabs). * * @var string */ diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index 79b3f151a5..bff5a821ce 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -10,7 +10,7 @@ use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Entity\EntityViewModeInterface; use Drupal\Core\Entity\EntityFormModeInterface; -use Drupal\Core\Url; +use Drupal\Core\Routing\RouteProviderLazyBuilder; use Drupal\field_ui\FieldUI; use Drupal\field_ui\Plugin\Derivative\FieldUiLocalTask; @@ -105,6 +105,31 @@ function field_ui_entity_type_build(array &$entity_types) { $view_mode->setLinkTemplate('collection', '/admin/structure/display-modes/view'); } +/** + * Implements hook_entity_type_alter(). + */ +function field_ui_entity_type_alter(array &$entity_types) { + /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ + foreach ($entity_types as $entity_type) { + // Add manage fields and display link relations and templates if this entity + // type has field UI enabled. + $base_path = $entity_type->get('field_ui_base_path'); + if (!$base_path) { + continue; + } + + // If the entity type uses another entity type as its bundle, we need to + // set the Field UI link templates on the bundle entity type instead. + $target_entity_type = ($bundle_entity = $entity_type->getBundleEntityType()) + ? $entity_types[$bundle_entity] + : $entity_type; + + $target_entity_type->setLinkTemplate('drupal:field-ui-fields', $base_path . '/fields'); + $target_entity_type->setLinkTemplate('drupal:field-ui-form-display', $base_path . '/form-display'); + $target_entity_type->setLinkTemplate('drupal:field-ui-display', $base_path . '/display'); + } +} + /** * Implements hook_entity_bundle_create(). */ @@ -148,27 +173,21 @@ function field_ui_entity_operation(EntityInterface $entity) { $operations['manage-fields'] = [ 'title' => t('Manage fields'), 'weight' => 15, - 'url' => Url::fromRoute("entity.{$bundle_of}.field_ui_fields", [ - $entity->getEntityTypeId() => $entity->id(), - ]), + 'url' => $entity->toUrl('drupal:field-ui-fields'), ]; } if ($account->hasPermission('administer ' . $bundle_of . ' form display')) { $operations['manage-form-display'] = [ 'title' => t('Manage form display'), 'weight' => 20, - 'url' => Url::fromRoute("entity.entity_form_display.{$bundle_of}.default", [ - $entity->getEntityTypeId() => $entity->id(), - ]), + 'url' => $entity->toUrl('drupal:field-ui-form-display'), ]; } if ($account->hasPermission('administer ' . $bundle_of . ' display')) { $operations['manage-display'] = [ 'title' => t('Manage display'), 'weight' => 25, - 'url' => Url::fromRoute("entity.entity_view_display.{$bundle_of}.default", [ - $entity->getEntityTypeId() => $entity->id(), - ]), + 'url' => $entity->toUrl('drupal:field-ui-display'), ]; } } diff --git a/core/modules/field_ui/field_ui.services.yml b/core/modules/field_ui/field_ui.services.yml index f6744eb1ba..ab62ed7a72 100644 --- a/core/modules/field_ui/field_ui.services.yml +++ b/core/modules/field_ui/field_ui.services.yml @@ -19,3 +19,7 @@ services: arguments: ['@entity.manager'] tags: - { name: access_check, applies_to: _field_ui_form_mode_access } + field_ui.deprecated_route_matcher: + class: Drupal\field_ui\Routing\DeprecatedRouteMatcher + tags: + - { name: route_filter } diff --git a/core/modules/field_ui/src/Routing/DeprecatedRouteMatcher.php b/core/modules/field_ui/src/Routing/DeprecatedRouteMatcher.php new file mode 100644 index 0000000000..9310783dbf --- /dev/null +++ b/core/modules/field_ui/src/Routing/DeprecatedRouteMatcher.php @@ -0,0 +1,55 @@ + $route) { + if ($entity_type_id = $route->getDefault('entity_type_id')) { + if ($this->isBackwardsIncompatibleRouteName($route_name, $entity_type_id)) { + $collection->remove($route_name); + } + } + } + if (count($collection)) { + return $collection; + } + throw new NotAcceptableHttpException('No route remaining after filtering out backwards incompatible Field UI routes.'); + } + + /** + * Checks whether a route name is a newer, backwards incompatible version. + * + * @param string $route_name + * The route name to check. + * @param string $entity_type_id + * The entity type ID used by the route. + * + * @return bool + * Whether the route name is the newer version. + */ + protected function isBackwardsIncompatibleRouteName($route_name, $entity_type_id) { + $backwards_incompatible = [ + "entity.{$entity_type_id}.field_ui_form_display", + "entity.{$entity_type_id}.field_ui_display", + ]; + return in_array($route_name, $backwards_incompatible, TRUE); + } + +} diff --git a/core/modules/field_ui/src/Routing/RouteSubscriber.php b/core/modules/field_ui/src/Routing/RouteSubscriber.php index b08e7f8fe5..576b414577 100644 --- a/core/modules/field_ui/src/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php @@ -40,7 +40,10 @@ protected function alterRoutes(RouteCollection $collection) { if (!$entity_route = $collection->get($route_name)) { continue; } - $path = $entity_route->getPath(); + // @deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. + // Should consistently check for the field_ui_base_path entity type key + // instead of the base route starting from Drupal 9.0.0 onwards. + $path = $entity_type->get('field_ui_base_path') ?: $entity_route->getPath(); $options = $entity_route->getOptions(); if ($bundle_entity_type = $entity_type->getBundleEntityType()) { @@ -119,7 +122,12 @@ protected function alterRoutes(RouteCollection $collection) { ['_field_ui_form_mode_access' => 'administer ' . $entity_type_id . ' form display'], $options ); + // @deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. + // Use entity.{$entity_type_id}.field_ui_form_display instead. The old + // name is kept to maintain backwards compatibility and will be selected + // over the newer one in Drupal\field_ui\Routing\DeprecatedRouteMatcher. $collection->add("entity.entity_form_display.{$entity_type_id}.default", $route); + $collection->add("entity.{$entity_type_id}.field_ui_form_display", $route); $route = new Route( "$path/form-display/{form_mode_name}", @@ -142,7 +150,12 @@ protected function alterRoutes(RouteCollection $collection) { ['_field_ui_view_mode_access' => 'administer ' . $entity_type_id . ' display'], $options ); + // @deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. + // Use entity.{$entity_type_id}.field_ui_display instead. The old route + // name is kept to maintain backwards compatibility and will be selected + // over the newer one in Drupal\field_ui\Routing\DeprecatedRouteMatcher. $collection->add("entity.entity_view_display.{$entity_type_id}.default", $route); + $collection->add("entity.{$entity_type_id}.field_ui_display", $route); $route = new Route( "$path/display/{view_mode_name}", -- 2.17.1