diff --git a/core/lib/Drupal/Core/Path/AliasStorage.php b/core/lib/Drupal/Core/Path/AliasStorage.php index e702f55..657f928 100644 --- a/core/lib/Drupal/Core/Path/AliasStorage.php +++ b/core/lib/Drupal/Core/Path/AliasStorage.php @@ -14,6 +14,9 @@ /** * Provides a class for CRUD operations on path aliases. + * + * All queries use case-insensitive implementations, so '/test-alias' and + * '/test-Alias' is treated as equal. */ class AliasStorage implements AliasStorageInterface { /** diff --git a/core/lib/Drupal/Core/Path/AliasStorageInterface.php b/core/lib/Drupal/Core/Path/AliasStorageInterface.php index 7717aef..a416fec 100644 --- a/core/lib/Drupal/Core/Path/AliasStorageInterface.php +++ b/core/lib/Drupal/Core/Path/AliasStorageInterface.php @@ -44,6 +44,8 @@ public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NO /** * Fetches a specific URL alias from the database. * + * The default implementation provides a case-insensitive implementation. + * * @param array $conditions * An array of query conditions. * @@ -60,6 +62,8 @@ public function load($conditions); /** * Deletes a URL alias. * + * The default implementation provides a case-insensitive implementation. + * * @param array $conditions * An array of criteria. */ @@ -82,6 +86,8 @@ public function preloadPathAlias($preloaded, $langcode); /** * Returns an alias of Drupal system URL. * + * The default implementation provides a case-insensitive implementation. + * * @param string $path * The path to investigate for corresponding path aliases. * @param string $langcode @@ -96,6 +102,8 @@ public function lookupPathAlias($path, $langcode); /** * Returns Drupal system URL of an alias. * + * The default implementation provides a case-insensitive implementation. + * * @param string $path * The path to investigate for corresponding system URLs. * @param string $langcode @@ -110,6 +118,8 @@ public function lookupPathSource($path, $langcode); /** * Checks if alias already exists. * + * The default implementation provides a case-insensitive implementation. + * * @param string $alias * Alias to check against. * @param string $langcode diff --git a/core/modules/path/src/Form/PathFormBase.php b/core/modules/path/src/Form/PathFormBase.php index 8c84841..eac4e71 100644 --- a/core/modules/path/src/Form/PathFormBase.php +++ b/core/modules/path/src/Form/PathFormBase.php @@ -180,8 +180,16 @@ public function validateForm(array &$form, FormStateInterface $form_state) { $langcode = $form_state->getValue('langcode', LanguageInterface::LANGCODE_NOT_SPECIFIED); if ($this->aliasStorage->aliasExists($alias, $langcode, $this->path['source'])) { - $form_state->setErrorByName('alias', t('The alias %alias is already in use in this language.', array('%alias' => $alias))); + $stored_alias = $this->aliasStorage->load(['alias' => $alias, 'langocde' => $langcode]); + if ($stored_alias['alias'] !== $alias) { + $form_state->setErrorByName('alias', t('There is an alias with other case-sensitivity: %actual_alias is already in use in this language.', ['%actual_alias' => $stored_alias['alias']])); + } + else { + $form_state->setErrorByName('alias', t('The alias %alias is already in use in this language.', array('%alias' => $alias))); + } } + + if (!$this->pathValidator->isValid(trim($source, '/'))) { $form_state->setErrorByName('source', t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $source))); } diff --git a/core/tests/Drupal/KernelTests/Core/Path/AliasStorageTest.php b/core/tests/Drupal/KernelTests/Core/Path/AliasStorageTest.php new file mode 100644 index 0000000..98180e3 --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Path/AliasStorageTest.php @@ -0,0 +1,86 @@ +installSchema('system', 'url_alias'); + $this->storage = $this->container->get('path.alias_storage'); + } + + /** + * @covers ::load + */ + public function testLoad() { + $this->storage->save('/test-source-Case', '/test-alias-Case'); + + $expected = [ + 'pid' => 1, + 'alias' => '/test-alias-Case', + 'source' => '/test-source-Case', + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]; + + $this->assertEquals($expected, $this->storage->load(['alias' => '/test-alias-Case'])); + $this->assertEquals($expected, $this->storage->load(['alias' => '/test-alias-case'])); + $this->assertEquals($expected, $this->storage->load(['source' => '/test-source-Case'])); + $this->assertEquals($expected, $this->storage->load(['source' => '/test-source-case'])); + } + + /** + * @covers ::lookupPathAlias + */ + public function testLookupPathAlias() { + $this->storage->save('/test-source-Case', '/test-alias'); + + $this->assertEquals('/test-alias', $this->storage->lookupPathAlias('/test-source-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)); + $this->assertEquals('/test-alias', $this->storage->lookupPathAlias('/test-source-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)); + } + + /** + * @covers ::lookupPathSource + */ + public function testLookupPathSource() { + $this->storage->save('/test-source', '/test-alias-Case'); + + $this->assertEquals('/test-source', $this->storage->lookupPathSource('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)); + $this->assertEquals('/test-source', $this->storage->lookupPathSource('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)); + } + + /** + * @covers ::aliasExists + */ + public function testAliasExists() { + $this->storage->save('/test-source-Case', '/test-alias-Case'); + + $this->assertTrue($this->storage->aliasExists('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)); + $this->assertTrue($this->storage->aliasExists('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)); + } + +}