Skip to content

Commit

Permalink
Check if the URL prefix is duplicated in another root page
Browse files Browse the repository at this point in the history
  • Loading branch information
aschempp committed Jul 11, 2020
1 parent 491c83b commit 681dafd
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 13 deletions.
14 changes: 14 additions & 0 deletions core-bundle/src/EventListener/DataContainer/PageUrlListener.php
Expand Up @@ -148,6 +148,20 @@ public function validateUrlPrefix(string $value, DataContainer $dc): string
return $value;
}

// First check if another root page uses the same url prefix and domain
$count = $this->connection->executeQuery(
'SELECT COUNT(*) FROM tl_page WHERE urlPrefix=:urlPrefix AND dns=:dns AND id!=:rootId',
[
'urlPrefix' => $value,
'dns' => $dc->activeRecord->dns,
'rootId' => $dc->id,
]
)->fetchColumn();

if ($count > 0) {
throw new \RuntimeException($this->translator->trans('ERR.urlPrefixExists', [$value], 'contao_default'));
}

/** @var PageModel|Adapter $pageAdapter */
$pageAdapter = $this->framework->getAdapter(PageModel::class);

Expand Down
3 changes: 3 additions & 0 deletions core-bundle/src/Resources/contao/languages/en/default.xlf
Expand Up @@ -140,6 +140,9 @@
<trans-unit id="ERR.aliasExists">
<source>The alias "%s" already exists!</source>
</trans-unit>
<trans-unit id="ERR.urlPrefixExists">
<source>The URL prefix "%s" already exists on this domain!</source>
</trans-unit>
<trans-unit id="ERR.pageUrlExists">
<source>A page with URL "%s" already exists!</source>
</trans-unit>
Expand Down
Expand Up @@ -1011,7 +1011,8 @@ public function testReturnsValueWhenValidatingUrlPrefix(): void
[['urlPrefix' => 'de', 'urlSuffix' => '.html']],
[2],
['foo'],
[[]]
[[]],
true
);

$listener = new PageUrlListener(
Expand All @@ -1027,14 +1028,61 @@ public function testReturnsValueWhenValidatingUrlPrefix(): void
DataContainer::class,
[
'id' => 1,
'activeRecord' => (object) ['type' => 'root', 'urlPrefix' => 'de', 'urlSuffix' => ''],
'activeRecord' => (object) ['type' => 'root', 'dns' => '', 'urlPrefix' => 'de', 'urlSuffix' => ''],
]
);

$listener->validateUrlPrefix('en', $dc);
}

public function testThrowsExceptionOnDuplicateUrlPrefixInDomain(): void
{
$translator = $this->mockTranslator('ERR.urlPrefixExists', 'en');

$statement = $this->createMock(Statement::class);
$statement
->expects($this->once())
->method('fetchColumn')
->willReturn(1)
;

$connection = $this->createMock(Connection::class);
$connection
->expects($this->once())
->method('executeQuery')
->with(
'SELECT COUNT(*) FROM tl_page WHERE urlPrefix=:urlPrefix AND dns=:dns AND id!=:rootId',
['urlPrefix' => 'en', 'dns' => 'www.example.com', 'rootId' => 1]
)
->willReturn($statement)
;

$listener = new PageUrlListener(
$this->mockContaoFramework(),
$this->createMock(Slug::class),
$translator,
$connection,
$this->createMock(IndexerInterface::class)
);

/** @var MockObject&DataContainer $dc */
$dc = $this->mockClassWithProperties(
DataContainer::class,
[
'id' => 1,
'activeRecord' => (object) [
'type' => 'root',
'dns' => 'www.example.com',
'urlPrefix' => 'de',
'urlSuffix' => '',
],
]
);

$listener->validateUrlPrefix('en', $dc);
}

public function testThrowsExceptionOnDuplicateUrlPrefix(): void
public function testThrowsExceptionIfUrlPrefixLeadsToDuplicatePages(): void
{
$framework = $this->mockFrameworkWithPages(
[
Expand Down Expand Up @@ -1093,7 +1141,8 @@ public function testThrowsExceptionOnDuplicateUrlPrefix(): void
[['urlPrefix' => 'de', 'urlSuffix' => '.html']],
[2, 3, 4],
['foo', 'bar', 'bar/foo'],
[[], [], [6]]
[[], [], [6]],
true
);

$listener = new PageUrlListener(
Expand All @@ -1109,7 +1158,7 @@ public function testThrowsExceptionOnDuplicateUrlPrefix(): void
DataContainer::class,
[
'id' => 1,
'activeRecord' => (object) ['type' => 'root', 'urlPrefix' => 'de', 'urlSuffix' => ''],
'activeRecord' => (object) ['type' => 'root', 'dns' => '', 'urlPrefix' => 'de', 'urlSuffix' => ''],
]
);

Expand Down Expand Up @@ -1209,6 +1258,7 @@ public function testDoesNotValidateTheUrlPrefixIfTheRootPageIsNotFound(): void
'id' => 1,
'activeRecord' => (object) [
'type' => 'root',
'dns' => '',
'urlPrefix' => 'en',
],
]
Expand Down Expand Up @@ -1444,6 +1494,7 @@ public function testDoesNotValidateTheUrlSuffixIfTheRootPageIsNotFound(): void
'id' => 1,
'activeRecord' => (object) [
'type' => 'root',
'dns' => '',
'urlPrefix' => '',
],
]
Expand All @@ -1455,18 +1506,30 @@ public function testDoesNotValidateTheUrlSuffixIfTheRootPageIsNotFound(): void
/**
* @return Connection&MockObject
*/
private function mockConnection(array $prefixAndSuffix, array $ids, array $aliases, array $aliasIds): Connection
private function mockConnection(array $prefixAndSuffix, array $ids, array $aliases, array $aliasIds, bool $prefixCheck = false): Connection
{
$args = [];
$statements = [];

if ($prefixCheck) {
$args[] = ['SELECT COUNT(*) FROM tl_page WHERE urlPrefix=:urlPrefix AND dns=:dns AND id!=:rootId'];
$statement = $this->createMock(Statement::class);
$statement
->expects($this->once())
->method('fetchColumn')
->willReturn(0)
;
$statements[] = $statement;
}

$args[] = ["SELECT urlPrefix, urlSuffix FROM tl_page WHERE type='root'"];
$statements[] = $this->createMock(Statement::class);
$statements[0]
$statement = $this->createMock(Statement::class);
$statement
->expects($this->once())
->method('fetchAll')
->willReturn($prefixAndSuffix)
;
$statements[] = $statement;

foreach ($ids as $k => $id) {
$args[] = [
Expand Down Expand Up @@ -1567,11 +1630,11 @@ static function ($key) use ($inputData) {
/**
* @return TranslatorInterface&MockObject
*/
private function mockTranslator(string $messageKey = null, string $url = null): TranslatorInterface
private function mockTranslator(string $messageKey = null, string $argument = null): TranslatorInterface
{
$translator = $this->createMock(TranslatorInterface::class);

if (null === $messageKey || null === $url) {
if (null === $messageKey || null === $argument) {
$translator
->expects($this->never())
->method('trans')
Expand All @@ -1583,12 +1646,12 @@ private function mockTranslator(string $messageKey = null, string $url = null):
$translator
->expects($this->once())
->method('trans')
->with($messageKey, [$url], 'contao_default')
->willReturn($url)
->with($messageKey, [$argument], 'contao_default')
->willReturn($argument)
;

$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage($url);
$this->expectExceptionMessage($argument);

return $translator;
}
Expand Down

0 comments on commit 681dafd

Please sign in to comment.