From 55a2b4076f437219990517b806c65b88920a1064 Mon Sep 17 00:00:00 2001 From: Francesco Placella <plach@183211.no-reply.drupal.org> Date: Fri, 11 Oct 2019 22:04:15 +0200 Subject: [PATCH] Issue #3011807 by amateescu, Berdir: Convert the path alias admin overview to a list builder --- .../lib/Drupal/Core/Path/Entity/PathAlias.php | 14 +- core/modules/path/path.module | 2 + core/modules/path/path.routing.yml | 16 -- .../path/src/Controller/PathController.php | 135 ------------ core/modules/path/src/Form/PathFilterForm.php | 2 +- .../modules/path/src/PathAliasListBuilder.php | 195 ++++++++++++++++++ .../path/src/Routing/RouteProcessor.php | 1 + .../path/src/Routing/RouteSubscriber.php | 1 + .../tests/src/Functional/PathAliasTest.php | 2 +- .../src/Kernel/PathLegacyRoutesKernelTest.php | 7 + 10 files changed, 215 insertions(+), 160 deletions(-) delete mode 100644 core/modules/path/path.routing.yml delete mode 100644 core/modules/path/src/Controller/PathController.php create mode 100644 core/modules/path/src/PathAliasListBuilder.php diff --git a/core/lib/Drupal/Core/Path/Entity/PathAlias.php b/core/lib/Drupal/Core/Path/Entity/PathAlias.php index 60ec286c6347..4e29120f7a44 100644 --- a/core/lib/Drupal/Core/Path/Entity/PathAlias.php +++ b/core/lib/Drupal/Core/Path/Entity/PathAlias.php @@ -16,13 +16,13 @@ * * @ContentEntityType( * id = "path_alias", - * label = @Translation("Path alias"), - * label_collection = @Translation("Path aliases"), - * label_singular = @Translation("path alias"), - * label_plural = @Translation("path aliases"), + * label = @Translation("URL alias"), + * label_collection = @Translation("URL aliases"), + * label_singular = @Translation("URL alias"), + * label_plural = @Translation("URL aliases"), * label_count = @PluralTranslation( - * singular = "@count path alias", - * plural = "@count path aliases" + * singular = "@count URL alias", + * plural = "@count URL aliases" * ), * handlers = { * "storage" = "Drupal\Core\Path\PathAliasStorage", @@ -68,7 +68,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->addPropertyConstraints('value', ['ValidPath' => []]); $fields['alias'] = BaseFieldDefinition::create('string') - ->setLabel(new TranslatableMarkup('Path alias')) + ->setLabel(new TranslatableMarkup('URL alias')) ->setDescription(new TranslatableMarkup('An alias used with this path.')) ->setRequired(TRUE) ->setRevisionable(TRUE) diff --git a/core/modules/path/path.module b/core/modules/path/path.module index 24d3f7304bd1..0e7ce166a3a8 100644 --- a/core/modules/path/path.module +++ b/core/modules/path/path.module @@ -15,6 +15,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\path\PathAliasForm; +use Drupal\path\PathAliasListBuilder; /** * Implements hook_help(). @@ -50,6 +51,7 @@ function path_entity_type_alter(array &$entity_types) { $entity_types['path_alias']->setFormClass('default', PathAliasForm::class); $entity_types['path_alias']->setFormClass('delete', ContentEntityDeleteForm::class); $entity_types['path_alias']->setHandlerClass('route_provider', ['html' => AdminHtmlRouteProvider::class]); + $entity_types['path_alias']->setListBuilderClass(PathAliasListBuilder::class); $entity_types['path_alias']->setLinkTemplate('collection', '/admin/config/search/path'); $entity_types['path_alias']->setLinkTemplate('add-form', '/admin/config/search/path/add'); $entity_types['path_alias']->setLinkTemplate('edit-form', '/admin/config/search/path/edit/{path_alias}'); diff --git a/core/modules/path/path.routing.yml b/core/modules/path/path.routing.yml deleted file mode 100644 index a4005ce231d3..000000000000 --- a/core/modules/path/path.routing.yml +++ /dev/null @@ -1,16 +0,0 @@ -entity.path_alias.collection: - path: '/admin/config/search/path' - defaults: - _title: 'URL aliases' - _controller: '\Drupal\path\Controller\PathController::adminOverview' - keys: NULL - requirements: - _permission: 'administer url aliases' - -path.admin_overview_filter: - path: '/admin/config/search/path/filter' - defaults: - _title: 'URL aliases' - _controller: '\Drupal\path\Controller\PathController::adminOverview' - requirements: - _permission: 'administer url aliases' diff --git a/core/modules/path/src/Controller/PathController.php b/core/modules/path/src/Controller/PathController.php deleted file mode 100644 index b583152e9475..000000000000 --- a/core/modules/path/src/Controller/PathController.php +++ /dev/null @@ -1,135 +0,0 @@ -<?php - -namespace Drupal\path\Controller; - -use Drupal\Component\Utility\Unicode; -use Drupal\Core\Controller\ControllerBase; -use Drupal\Core\Link; -use Drupal\Core\Path\AliasStorageInterface; -use Drupal\Core\Path\AliasManagerInterface; -use Drupal\Core\Url; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpFoundation\Request; - -/** - * Controller routines for path routes. - */ -class PathController extends ControllerBase { - - /** - * The path alias storage. - * - * @var \Drupal\Core\Path\AliasStorageInterface - */ - protected $aliasStorage; - - /** - * The path alias manager. - * - * @var \Drupal\Core\Path\AliasManagerInterface - */ - protected $aliasManager; - - /** - * Constructs a new PathController. - * - * @param \Drupal\Core\Path\AliasStorageInterface $alias_storage - * The path alias storage. - * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager - * The path alias manager. - */ - public function __construct(AliasStorageInterface $alias_storage, AliasManagerInterface $alias_manager) { - $this->aliasStorage = $alias_storage; - $this->aliasManager = $alias_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('path.alias_storage'), - $container->get('path.alias_manager') - ); - } - - /** - * Displays the path administration overview page. - * - * @param \Symfony\Component\HttpFoundation\Request $request - * The request object. - * - * @return array - * A render array as expected by - * \Drupal\Core\Render\RendererInterface::render(). - */ - public function adminOverview(Request $request) { - $keys = $request->query->get('search'); - // Add the filter form above the overview table. - $build['path_admin_filter_form'] = $this->formBuilder()->getForm('Drupal\path\Form\PathFilterForm', $keys); - // Enable language column if language.module is enabled or if we have any - // alias with a language. - $multilanguage = ($this->moduleHandler()->moduleExists('language') || $this->aliasStorage->languageAliasExists()); - - $header = []; - $header[] = ['data' => $this->t('Alias'), 'field' => 'alias', 'sort' => 'asc']; - $header[] = ['data' => $this->t('System'), 'field' => 'source']; - if ($multilanguage) { - $header[] = ['data' => $this->t('Language'), 'field' => 'langcode']; - } - $header[] = $this->t('Operations'); - - $rows = []; - $destination = $this->getDestinationArray(); - foreach ($this->aliasStorage->getAliasesForAdminListing($header, $keys) as $data) { - $row = []; - // @todo Should Path module store leading slashes? See - // https://www.drupal.org/node/2430593. - $row['data']['alias'] = Link::fromTextAndUrl(Unicode::truncate($data->alias, 50, FALSE, TRUE), Url::fromUserInput($data->source, [ - 'attributes' => ['title' => $data->alias], - ]))->toString(); - $row['data']['source'] = Link::fromTextAndUrl(Unicode::truncate($data->source, 50, FALSE, TRUE), Url::fromUserInput($data->source, [ - 'alias' => TRUE, - 'attributes' => ['title' => $data->source], - ]))->toString(); - if ($multilanguage) { - $row['data']['language_name'] = $this->languageManager()->getLanguageName($data->langcode); - } - - $operations = []; - $operations['edit'] = [ - 'title' => $this->t('Edit'), - 'url' => Url::fromRoute('entity.path_alias.edit_form', ['path_alias' => $data->pid], ['query' => $destination]), - ]; - $operations['delete'] = [ - 'title' => $this->t('Delete'), - 'url' => Url::fromRoute('entity.path_alias.delete_form', ['path_alias' => $data->pid], ['query' => $destination]), - ]; - $row['data']['operations'] = [ - 'data' => [ - '#type' => 'operations', - '#links' => $operations, - ], - ]; - - // If the system path maps to a different URL alias, highlight this table - // row to let the user know of old aliases. - if ($data->alias != $this->aliasManager->getAliasByPath($data->source, $data->langcode)) { - $row['class'] = ['warning']; - } - - $rows[] = $row; - } - - $build['path_table'] = [ - '#type' => 'table', - '#header' => $header, - '#rows' => $rows, - '#empty' => $this->t('No URL aliases available. <a href=":link">Add URL alias</a>.', [':link' => Url::fromRoute('entity.path_alias.add_form')->toString()]), - ]; - $build['path_pager'] = ['#type' => 'pager']; - - return $build; - } - -} diff --git a/core/modules/path/src/Form/PathFilterForm.php b/core/modules/path/src/Form/PathFilterForm.php index 93b5af816339..9ff0c34f21a8 100644 --- a/core/modules/path/src/Form/PathFilterForm.php +++ b/core/modules/path/src/Form/PathFilterForm.php @@ -56,7 +56,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $keys = N * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { - $form_state->setRedirect('path.admin_overview_filter', [], [ + $form_state->setRedirect('entity.path_alias.collection', [], [ 'query' => ['search' => trim($form_state->getValue('filter'))], ]); } diff --git a/core/modules/path/src/PathAliasListBuilder.php b/core/modules/path/src/PathAliasListBuilder.php new file mode 100644 index 000000000000..0d6dc539e7e9 --- /dev/null +++ b/core/modules/path/src/PathAliasListBuilder.php @@ -0,0 +1,195 @@ +<?php + +namespace Drupal\path; + +use Drupal\Component\Utility\Unicode; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityListBuilder; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Path\AliasManagerInterface; +use Drupal\Core\Url; +use Drupal\path\Form\PathFilterForm; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; + +/** + * Defines a class to build a listing of path_alias entities. + * + * @see \Drupal\Core\Path\Entity\PathAlias + */ +class PathAliasListBuilder extends EntityListBuilder { + + /** + * The current request. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $currentRequest; + + /** + * The form builder. + * + * @var \Drupal\Core\Form\FormBuilderInterface + */ + protected $formBuilder; + + /** + * The language manager. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + + /** + * The path alias manager. + * + * @var \Drupal\Core\Path\AliasManagerInterface + */ + protected $aliasManager; + + /** + * Constructs a new PathAliasListBuilder object. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param \Drupal\Core\Entity\EntityStorageInterface $storage + * The entity storage class. + * @param \Symfony\Component\HttpFoundation\Request $current_request + * The current request. + * @param \Drupal\Core\Form\FormBuilderInterface $form_builder + * The form builder. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager. + * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager + * The path alias manager. + */ + public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, Request $current_request, FormBuilderInterface $form_builder, LanguageManagerInterface $language_manager, AliasManagerInterface $alias_manager) { + parent::__construct($entity_type, $storage); + + $this->currentRequest = $current_request; + $this->formBuilder = $form_builder; + $this->languageManager = $language_manager; + $this->aliasManager = $alias_manager; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity_type.manager')->getStorage($entity_type->id()), + $container->get('request_stack')->getCurrentRequest(), + $container->get('form_builder'), + $container->get('language_manager'), + $container->get('path.alias_manager') + ); + } + + /** + * {@inheritdoc} + */ + protected function getEntityIds() { + $query = $this->getStorage()->getQuery(); + + $search = $this->currentRequest->query->get('search'); + if ($search) { + $query->condition('alias', $search, 'CONTAINS'); + } + + // Only add the pager if a limit is specified. + if ($this->limit) { + $query->pager($this->limit); + } + + // Allow the entity query to sort using the table header. + $header = $this->buildHeader(); + $query->tableSort($header); + + return $query->execute(); + } + + /** + * {@inheritdoc} + */ + public function render() { + $keys = $this->currentRequest->query->get('search'); + $build['path_admin_filter_form'] = $this->formBuilder->getForm(PathFilterForm::class, $keys); + $build += parent::render(); + + $build['table']['#empty'] = $this->t('No path aliases available. <a href=":link">Add URL alias</a>.', [':link' => Url::fromRoute('entity.path_alias.add_form')->toString()]); + + return $build; + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header = [ + 'alias' => [ + 'data' => $this->t('Alias'), + 'field' => 'alias', + 'specifier' => 'alias', + 'sort' => 'asc', + ], + 'path' => [ + 'data' => $this->t('System path'), + 'field' => 'path', + 'specifier' => 'path', + ], + ]; + + // Enable language column and filter if multiple languages are added. + if ($this->languageManager->isMultilingual()) { + $header['language_name'] = [ + 'data' => $this->t('Language'), + 'field' => 'langcode', + 'specifier' => 'langcode', + 'class' => [RESPONSIVE_PRIORITY_MEDIUM], + ]; + } + + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + /** @var \Drupal\Core\Path\Entity\PathAlias $entity */ + $langcode = $entity->language()->getId(); + $alias = $entity->getAlias(); + $path = $entity->getPath(); + $url = Url::fromUserInput($path); + + $row['data']['alias']['data'] = [ + '#type' => 'link', + '#title' => Unicode::truncate($alias, 50, FALSE, TRUE), + '#url' => $url->setOption('attributes', ['title' => $alias]), + ]; + $row['data']['path']['data'] = [ + '#type' => 'link', + '#title' => Unicode::truncate($path, 50, FALSE, TRUE), + '#url' => $url->setOption('attributes', ['title' => $path]), + ]; + + if ($this->languageManager->isMultilingual()) { + $row['data']['language_name'] = $this->languageManager->getLanguageName($langcode); + } + + $row['data']['operations']['data'] = $this->buildOperations($entity); + + // If the system path maps to a different URL alias, highlight this table + // row to let the user know of old aliases. + if ($alias != $this->aliasManager->getAliasByPath($path, $langcode)) { + $row['class'] = ['warning']; + } + + return $row; + } + +} diff --git a/core/modules/path/src/Routing/RouteProcessor.php b/core/modules/path/src/Routing/RouteProcessor.php index 90dfa40f08af..aacd537f5456 100644 --- a/core/modules/path/src/Routing/RouteProcessor.php +++ b/core/modules/path/src/Routing/RouteProcessor.php @@ -38,6 +38,7 @@ public function processOutbound($route_name, Route $route, array &$parameters, B 'path.admin_edit' => 'entity.path_alias.edit_form', 'path.delete' => 'entity.path_alias.delete_form', 'path.admin_overview' => 'entity.path_alias.collection', + 'path.admin_overview_filter' => 'entity.path_alias.collection', ]; if (in_array($route_name, array_keys($redirected_route_names), TRUE)) { diff --git a/core/modules/path/src/Routing/RouteSubscriber.php b/core/modules/path/src/Routing/RouteSubscriber.php index e4cec9be52ea..077539523b1e 100644 --- a/core/modules/path/src/Routing/RouteSubscriber.php +++ b/core/modules/path/src/Routing/RouteSubscriber.php @@ -25,6 +25,7 @@ public function onDynamicRouteEvent(RouteBuildEvent $event) { $route_collection->add('path.admin_edit', new BcRoute()); $route_collection->add('path.delete', new BcRoute()); $route_collection->add('path.admin_overview', new BcRoute()); + $route_collection->add('path.admin_overview_filter', new BcRoute()); } /** diff --git a/core/modules/path/tests/src/Functional/PathAliasTest.php b/core/modules/path/tests/src/Functional/PathAliasTest.php index 13b52680d14c..80ce4c385bfe 100644 --- a/core/modules/path/tests/src/Functional/PathAliasTest.php +++ b/core/modules/path/tests/src/Functional/PathAliasTest.php @@ -143,7 +143,7 @@ public function testAdminAlias() { // Delete alias. $this->drupalGet('admin/config/search/path/edit/' . $pid); $this->clickLink(t('Delete')); - $this->assertRaw(t('Are you sure you want to delete the path alias %name?', ['%name' => $edit['alias[0][value]']])); + $this->assertRaw(t('Are you sure you want to delete the URL alias %name?', ['%name' => $edit['alias[0][value]']])); $this->drupalPostForm(NULL, [], t('Delete')); // Confirm that the alias no longer works. diff --git a/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php b/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php index e21d5e37b56a..f83ad0bcb49a 100644 --- a/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php +++ b/core/modules/path/tests/src/Kernel/PathLegacyRoutesKernelTest.php @@ -46,4 +46,11 @@ public function testLegacyCollectionRoute() { $this->assertNotEmpty(Url::fromRoute('path.admin_overview')->toString()); } + /** + * @expectedDeprecation The 'path.admin_overview_filter' route is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the 'entity.path_alias.collection' route instead. See https://www.drupal.org/node/3013865 + */ + public function testLegacyCollectionFilterRoute() { + $this->assertNotEmpty(Url::fromRoute('path.admin_overview_filter')->toString()); + } + } -- GitLab