Commit e829c1e3 authored by catch's avatar catch
Browse files

Issue #2745755 by vasi, Steven Jones, smustgrave, mvc, Wim Leers,...

Issue #2745755 by vasi, Steven Jones, smustgrave, mvc, Wim Leers, james.williams, Gábor Hojtsy: AliasStorage::preloadPathAlias() incorrectly prioritizes und aliases

(cherry picked from commit 94e37fd5)
parent 635cd755
Loading
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -45,12 +45,21 @@ public function preloadPathAlias($preloaded, $langcode) {

    $this->addLanguageFallback($select, $langcode);

    // We order by ID ASC so that fetchAllKeyed() returns the most recently
    // created alias for each source. Subsequent queries using fetchField() must
    // use ID DESC to have the same effect.
    $select->orderBy('base_table.id', 'ASC');
    $select->orderBy('base_table.id', 'DESC');

    // We want the most recently created alias for each source, however that
    // will be at the start of the result-set, so fetch everything and reverse
    // it. Note that it would not be sufficient to reverse the ordering of the
    // 'base_table.id' column, as that would not guarantee other conditions
    // added to the query, such as those in ::addLanguageFallback, would be
    // reversed.
    $results = $select->execute()->fetchAll(\PDO::FETCH_ASSOC);
    $aliases = [];
    foreach (array_reverse($results) as $result) {
      $aliases[$result['path']] = $result['alias'];
    }

    return $select->execute()->fetchAllKeyed();
    return $aliases;
  }

  /**
+244 −0
Original line number Diff line number Diff line
@@ -38,6 +38,250 @@ protected function setUp(): void {
    $this->installEntitySchema('path_alias');
  }

  /**
   * @covers ::preloadPathAlias
   */
  public function testPreloadPathAlias() {
    $path_alias_repository = $this->container->get('path_alias.repository');

    // Every interesting language combination:
    // Just unspecified.
    $this->createPathAlias('/und/src', '/und/alias', LanguageInterface::LANGCODE_NOT_SPECIFIED);
    // Just a single language.
    $this->createPathAlias('/en/src', '/en/alias', 'en');
    // A single language, plus unspecified.
    $this->createPathAlias('/en-und/src', '/en-und/und', LanguageInterface::LANGCODE_NOT_SPECIFIED);
    $this->createPathAlias('/en-und/src', '/en-und/en', 'en');
    // Multiple languages.
    $this->createPathAlias('/en-xx-lolspeak/src', '/en-xx-lolspeak/en', 'en');
    $this->createPathAlias('/en-xx-lolspeak/src', '/en-xx-lolspeak/xx-lolspeak', 'xx-lolspeak');
    // A duplicate alias for the same path. This is later, so should be
    // preferred.
    $this->createPathAlias('/en-xx-lolspeak/src', '/en-xx-lolspeak/en-dup', 'en');
    // Multiple languages, plus unspecified.
    $this->createPathAlias('/en-xx-lolspeak-und/src', '/en-xx-lolspeak-und/und', LanguageInterface::LANGCODE_NOT_SPECIFIED);
    $this->createPathAlias('/en-xx-lolspeak-und/src', '/en-xx-lolspeak-und/en', 'en');
    $this->createPathAlias('/en-xx-lolspeak-und/src', '/en-xx-lolspeak-und/xx-lolspeak', 'xx-lolspeak');

    // Queries for unspecified language aliases.
    // Ask for an empty array, get all results.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-und/src' => '/en-und/und',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und',
      ],
      $path_alias_repository->preloadPathAlias([], LanguageInterface::LANGCODE_NOT_SPECIFIED)
    );
    // Ask for nonexistent source.
    $this->assertEquals(
      [],
      $path_alias_repository->preloadPathAlias(['/nonexistent'], LanguageInterface::LANGCODE_NOT_SPECIFIED));
    // Ask for each saved source, individually.
    $this->assertEquals(
      ['/und/src' => '/und/alias'],
      $path_alias_repository->preloadPathAlias(['/und/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
    );
    $this->assertEquals(
      [],
      $path_alias_repository->preloadPathAlias(['/en/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
    );
    $this->assertEquals(
      ['/en-und/src' => '/en-und/und'],
      $path_alias_repository->preloadPathAlias(['/en-und/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
    );
    $this->assertEquals(
      [],
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
    );
    $this->assertEquals(
      ['/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und'],
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak-und/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
    );
    // Ask for multiple sources, all that are known.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-und/src' => '/en-und/und',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und',
      ],
      $path_alias_repository->preloadPathAlias(
        [
          '/nonexistent',
          '/und/src',
          '/en/src',
          '/en-und/src',
          '/en-xx-lolspeak/src',
          '/en-xx-lolspeak-und/src',
        ],
        LanguageInterface::LANGCODE_NOT_SPECIFIED
      )
    );
    // Ask for multiple sources, just a subset.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und',
      ],
      $path_alias_repository->preloadPathAlias(
        [
          '/und/src',
          '/en-xx-lolspeak/src',
          '/en-xx-lolspeak-und/src',
        ],
        LanguageInterface::LANGCODE_NOT_SPECIFIED
      )
    );

    // Queries for English aliases.
    // Ask for an empty array, get all results.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en/src' => '/en/alias',
        '/en-und/src' => '/en-und/en',
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en',
      ],
      $path_alias_repository->preloadPathAlias([], 'en')
    );
    // Ask for nonexistent source.
    $this->assertEquals(
      [],
      $path_alias_repository->preloadPathAlias(['/nonexistent'], 'en'));
    // Ask for each saved source, individually.
    $this->assertEquals(
      ['/und/src' => '/und/alias'],
      $path_alias_repository->preloadPathAlias(['/und/src'], 'en')
    );
    $this->assertEquals(
      ['/en/src' => '/en/alias'],
      $path_alias_repository->preloadPathAlias(['/en/src'], 'en')
    );
    $this->assertEquals(
      ['/en-und/src' => '/en-und/en'],
      $path_alias_repository->preloadPathAlias(['/en-und/src'], 'en')
    );
    $this->assertEquals(
      ['/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup'],
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak/src'], 'en')
    );
    $this->assertEquals(
      ['/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en'],
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak-und/src'], 'en')
    );
    // Ask for multiple sources, all that are known.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en/src' => '/en/alias',
        '/en-und/src' => '/en-und/en',
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en',
      ],
      $path_alias_repository->preloadPathAlias(
        [
          '/nonexistent',
          '/und/src',
          '/en/src',
          '/en-und/src',
          '/en-xx-lolspeak/src',
          '/en-xx-lolspeak-und/src',
        ],
        'en'
      )
    );
    // Ask for multiple sources, just a subset.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en',
      ],
      $path_alias_repository->preloadPathAlias(
        [
          '/und/src',
          '/en-xx-lolspeak/src',
          '/en-xx-lolspeak-und/src',
        ],
        'en'
      )
    );

    // Queries for xx-lolspeak aliases.
    // Ask for an empty array, get all results.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-und/src' => '/en-und/und',
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak',
      ],
      $path_alias_repository->preloadPathAlias([], 'xx-lolspeak')
    );
    // Ask for nonexistent source.
    $this->assertEquals(
      [],
      $path_alias_repository->preloadPathAlias(['/nonexistent'], 'xx-lolspeak'));
    // Ask for each saved source, individually.
    $this->assertEquals(
      ['/und/src' => '/und/alias'],
      $path_alias_repository->preloadPathAlias(['/und/src'], 'xx-lolspeak')
    );
    $this->assertEquals(
      [],
      $path_alias_repository->preloadPathAlias(['/en/src'], 'xx-lolspeak')
    );
    $this->assertEquals(
      ['/en-und/src' => '/en-und/und'],
      $path_alias_repository->preloadPathAlias(['/en-und/src'], 'xx-lolspeak')
    );
    $this->assertEquals(
      ['/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak'],
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak/src'], 'xx-lolspeak')
    );
    $this->assertEquals(
      ['/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak'],
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak-und/src'], 'xx-lolspeak')
    );
    // Ask for multiple sources, all that are known.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-und/src' => '/en-und/und',
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak',
      ],
      $path_alias_repository->preloadPathAlias(
        [
          '/nonexistent',
          '/und/src',
          '/en/src',
          '/en-und/src',
          '/en-xx-lolspeak/src',
          '/en-xx-lolspeak-und/src',
        ],
        'xx-lolspeak'
      )
    );
    // Ask for multiple sources, just a subset.
    $this->assertEquals(
      [
        '/und/src' => '/und/alias',
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak',
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak',
      ],
      $path_alias_repository->preloadPathAlias(
        [
          '/und/src',
          '/en-xx-lolspeak/src',
          '/en-xx-lolspeak-und/src',
        ],
        'xx-lolspeak'
      )
    );
  }

  /**
   * @covers ::lookupBySystemPath
   */