From 7d8c6a885293ab0099f070f922bc69497b1db2f1 Mon Sep 17 00:00:00 2001 From: Kristiaan Van den Eynde Date: Thu, 16 Nov 2017 12:36:54 +0100 Subject: [PATCH] Issue #2651974 by kristiaanvandeneynde: field_ui_entity_operation() cannot respect route parameters because of incorrectly named routes. --- core/modules/field_ui/field_ui.module | 52 ++++++++++++++++---- core/modules/field_ui/field_ui.services.yml | 4 ++ .../src/Routing/DeprecatedRouteMatcher.php | 55 ++++++++++++++++++++++ .../field_ui/src/Routing/RouteSubscriber.php | 10 ++++ 4 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 core/modules/field_ui/src/Routing/DeprecatedRouteMatcher.php diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index 79b3f15..c90fa60 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; @@ -106,6 +106,44 @@ function field_ui_entity_type_build(array &$entity_types) { } /** + * Implements hook_entity_type_alter(). + */ +function field_ui_entity_type_alter(array &$entity_types) { + // Because we are in the middle of building entity type definitions and we + // need information from another "build system" (routes), we need to build in + // an eternal loop prevention. Otherwise, if the route builder needs info + // about entity types, it will trigger yet another entity type build and we + // will keep looping back and forth between the two systems. + // + // Something like this is currently possible because Views' route subscriber. + // @see https://www.drupal.org/project/drupal/issues/2924075 + // + // @todo Remove when the above issue has a fix. + $building = &drupal_static(__FUNCTION__, FALSE); + if ($building) { + return; + } + $building = TRUE; + + /** @var \Drupal\Core\Routing\RouteProvider $route_provider */ + $route_provider = \Drupal::service('router.route_provider'); + + /** @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 is the bundle of another and that type has field UI enabled. + if (($bundle_of = $entity_type->getBundleOf()) && ($base_route = $entity_types[$bundle_of]->get('field_ui_base_route'))) { + $field_ui_path = $route_provider->getRouteByName($base_route)->getPath(); + $entity_type->setLinkTemplate('drupal:field-ui-fields', $field_ui_path . '/fields'); + $entity_type->setLinkTemplate('drupal:field-ui-form-display', $field_ui_path . '/form-display'); + $entity_type->setLinkTemplate('drupal:field-ui-display', $field_ui_path . '/display'); + } + } + + $building = FALSE; +} + +/** * Implements hook_entity_bundle_create(). */ function field_ui_entity_bundle_create($entity_type, $bundle) { @@ -148,27 +186,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 f6744eb..ab62ed7 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 0000000..9310783 --- /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 b08e7f8..8b4c8e5 100644 --- a/core/modules/field_ui/src/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php @@ -119,7 +119,12 @@ protected function alterRoutes(RouteCollection $collection) { ['_field_ui_form_mode_access' => 'administer ' . $entity_type_id . ' form display'], $options ); + // @deprecated in Drupal 8.5.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 +147,12 @@ protected function alterRoutes(RouteCollection $collection) { ['_field_ui_view_mode_access' => 'administer ' . $entity_type_id . ' display'], $options ); + // @deprecated in Drupal 8.5.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.8.1