diff --git a/pathauto.services.yml b/pathauto.services.yml index 748de19..3d3a760 100644 --- a/pathauto.services.yml +++ b/pathauto.services.yml @@ -10,7 +10,7 @@ services: arguments: ['@config.factory', '@path.alias_storage', '@database','@pathauto.verbose_messenger', '@string_translation'] pathauto.alias_uniquifier: class: Drupal\pathauto\AliasUniquifier - arguments: ['@config.factory', '@pathauto.alias_storage_helper','@module_handler', '@router.no_access_checks', '@path.alias_manager'] + arguments: ['@config.factory', '@pathauto.alias_storage_helper','@module_handler', '@router.route_provider', '@path.alias_manager'] pathauto.verbose_messenger: class: Drupal\pathauto\VerboseMessenger arguments: ['@config.factory', '@current_user'] diff --git a/src/AliasUniquifier.php b/src/AliasUniquifier.php index 902a03e..98ac166 100644 --- a/src/AliasUniquifier.php +++ b/src/AliasUniquifier.php @@ -12,9 +12,7 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Path\AliasManagerInterface; -use Drupal\Core\Path\AliasStorageInterface; -use Symfony\Component\Routing\Exception\ResourceNotFoundException; -use Symfony\Component\Routing\Matcher\UrlMatcherInterface; +use Drupal\Core\Routing\RouteProviderInterface; /** * Provides a utility for creating a unique path alias. @@ -43,11 +41,11 @@ class AliasUniquifier implements AliasUniquifierInterface { protected $moduleHandler; /** - * The url matcher service. + * The route provider service. * - * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface + * @var \Drupal\Core\Routing\RouteProviderInterface. */ - protected $urlMatcher; + protected $routeProvider; /** * The alias manager. @@ -57,15 +55,6 @@ class AliasUniquifier implements AliasUniquifierInterface { protected $aliasManager; /** - * Stores the last matching route name. - * - * Used to prevent a loop if the same route matches a given pattern. - * - * @var - */ - protected $lastRouteName; - - /** * Creates a new AliasUniquifier. * * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory @@ -74,14 +63,14 @@ class AliasUniquifier implements AliasUniquifierInterface { * The alias storage helper. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. - * @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $url_matcher - * The url matcher service. + * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider + * The route provider service. */ - public function __construct(ConfigFactoryInterface $config_factory, AliasStorageHelperInterface $alias_storage_helper, ModuleHandlerInterface $module_handler, UrlMatcherInterface $url_matcher, AliasManagerInterface $alias_manager) { + public function __construct(ConfigFactoryInterface $config_factory, AliasStorageHelperInterface $alias_storage_helper, ModuleHandlerInterface $module_handler, RouteProviderInterface $route_provider, AliasManagerInterface $alias_manager) { $this->configFactory = $config_factory; $this->aliasStorageHelper = $alias_storage_helper; $this->moduleHandler = $module_handler; - $this->urlMatcher = $url_matcher; + $this->routeProvider = $route_provider; $this->aliasManager = $alias_manager; } @@ -167,20 +156,17 @@ class AliasUniquifier implements AliasUniquifierInterface { return TRUE; } - try { - $route = $this->urlMatcher->match($path); + $routes = $this->routeProvider->getRoutesByPattern($path); - if ($route['_route'] == $this->lastRouteName) { - throw new \InvalidArgumentException('The path "' . $path . '" collides with the route with identifier ' . $this->lastRouteName . ', whose path is ' . $route['_route_object']->getPath()); + // Only return true for an exact match, ignore placeholders. + foreach ($routes as $route) { + if ($route->getPath() == $path) { + return TRUE; } - - $this->lastRouteName = $route['_route']; - return TRUE; - } - catch (ResourceNotFoundException $e) { - $this->lastRouteName = NULL; - return FALSE; } + + return FALSE; + } } diff --git a/src/Tests/PathautoNodeWebTest.php b/src/Tests/PathautoNodeWebTest.php index 825b679..8d1be1d 100644 --- a/src/Tests/PathautoNodeWebTest.php +++ b/src/Tests/PathautoNodeWebTest.php @@ -6,6 +6,7 @@ */ namespace Drupal\pathauto\Tests; +use Drupal\language\Entity\ConfigurableLanguage; use Drupal\pathauto\Entity\PathautoPattern; use Drupal\node\Entity\Node; use Drupal\pathauto\PathautoState; @@ -25,7 +26,7 @@ class PathautoNodeWebTest extends WebTestBase { * * @var array */ - public static $modules = array('node', 'pathauto', 'views', 'taxonomy', 'pathauto_views_test'); + public static $modules = array('node', 'locale', 'pathauto', 'views', 'taxonomy', 'pathauto_views_test'); /** * Admin user. @@ -146,6 +147,38 @@ class PathautoNodeWebTest extends WebTestBase { } /** + * Tests that nodes with the same title but different languages are properly + * handled. + */ + public function testNodeDifferentLanguages() { + $this->drupalLogin($this->rootUser); + + // Create a title-based node pattern. + $this->createPattern('node', '/prefix/[node:title]', -1); + + // Add predefined French language. + ConfigurableLanguage::createFromLangcode('fr')->save(); + + // Create two English articles with the same title. + $edit = [ + 'title' => 'Sample article', + 'type' => 'article', + 'langcode' => 'en', + ]; + $node1 = $this->drupalCreateNode($edit); + $this->assertEntityAlias($node1, '/prefix/sample-article', 'en'); + + $node2 = $this->drupalCreateNode($edit); + $this->assertEntityAlias($node2, '/prefix/sample-article-0', 'en'); + + // Now, create a French article with the same title, and verify that it gets + // the basic alias with the correct langcode. + $edit['langcode'] = 'fr'; + $node3 = $this->drupalCreateNode($edit); + $this->assertEntityAlias($node3, '/prefix/sample-article', 'fr'); + } + + /** * Test node operations. */ function testNodeOperations() { @@ -285,28 +318,4 @@ class PathautoNodeWebTest extends WebTestBase { $this->assertResponse(200); } - /** - * Tests that patterns can coexist with routes with arguments. - * - * A common case is to have a view with a term name as a contextual filter, - * and a pattern that matches the view's path. - */ - public function testPatternMatchingDynamicRoute() { - $this->drupalLogin($this->rootUser); - - // Create a pattern for nodes that matches with a view path defined at - // pathauto_views_test module. - $this->createPattern('node', '/articles/[node:title]', -1); - - // Create an article. - $edit = array( - 'title[0][value]' => 'Sample article', - ); - $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); - - // Check that the alias was not created and an alert was shown. - $this->assertText('collides with the route with identifier'); - $this->assertNoAliasExists(array('alias' => '/articles/sample-article')); - } - }