-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TASK: render links to nodes with trailing slash
- Loading branch information
Showing
14 changed files
with
623 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Flowpack\SeoRouting\Helper; | ||
|
||
use Neos\Flow\Annotations as Flow; | ||
use Psr\Http\Message\UriInterface; | ||
|
||
#[Flow\Scope('singleton')] | ||
class BlocklistHelper | ||
{ | ||
#[Flow\Inject] | ||
protected ConfigurationHelper $configurationHelper; | ||
|
||
public function isUriInBlocklist(UriInterface $uri): bool | ||
{ | ||
$path = $uri->getPath(); | ||
foreach ($this->configurationHelper->getBlocklist() as $rawPattern => $active) { | ||
$pattern = '/' . str_replace('/', '\/', $rawPattern) . '/'; | ||
|
||
if (! $active) { | ||
continue; | ||
} | ||
|
||
if (preg_match($pattern, $path) === 1) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Flowpack\SeoRouting\Helper; | ||
|
||
use Neos\Flow\Annotations as Flow; | ||
|
||
#[Flow\Scope('singleton')] | ||
class ConfigurationHelper | ||
{ | ||
/** @var array{enable: array{trailingSlash: bool, toLowerCase: bool}, statusCode?: int} */ | ||
#[Flow\InjectConfiguration(path: 'redirect')] | ||
protected array $configuration; | ||
|
||
/** @var array{string: bool} */ | ||
#[Flow\InjectConfiguration(path: 'blocklist')] | ||
protected array $blocklist; | ||
|
||
public function isTrailingSlashEnabled(): bool | ||
{ | ||
return $this->configuration['enable']['trailingSlash'] ?? false; | ||
} | ||
|
||
public function isToLowerCaseEnabled(): bool | ||
{ | ||
return $this->configuration['enable']['toLowerCase'] ?? false; | ||
} | ||
|
||
public function getStatusCode(): int | ||
{ | ||
return $this->configuration['statusCode'] ?? 301; | ||
} | ||
|
||
/** | ||
* @return array{string: bool} | ||
*/ | ||
public function getBlocklist(): array | ||
{ | ||
return $this->blocklist; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Flowpack\SeoRouting\Helper; | ||
|
||
use Neos\Flow\Annotations\Scope; | ||
use Psr\Http\Message\UriInterface; | ||
|
||
#[Scope('singleton')] | ||
class LowerCaseHelper | ||
{ | ||
public function convertPathToLowerCase(UriInterface $uri): UriInterface | ||
{ | ||
$loweredPath = strtolower($uri->getPath()); | ||
|
||
if ($uri->getPath() === $loweredPath) { | ||
return $uri; | ||
} | ||
|
||
// bypass links to files | ||
if (array_key_exists('extension', pathinfo($uri->getPath()))) { | ||
return $uri; | ||
} | ||
|
||
return $uri->withPath($loweredPath); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Flowpack\SeoRouting\Helper; | ||
|
||
use Neos\Flow\Annotations\Scope; | ||
use Psr\Http\Message\UriInterface; | ||
|
||
#[Scope('singleton')] | ||
class TrailingSlashHelper | ||
{ | ||
public function appendTrailingSlash(UriInterface $uri): UriInterface | ||
{ | ||
// bypass links without path | ||
if (strlen($uri->getPath()) === 0) { | ||
return $uri; | ||
} | ||
|
||
// bypass links to files | ||
if (array_key_exists('extension', pathinfo($uri->getPath()))) { | ||
return $uri; | ||
} | ||
|
||
// bypass mailto and tel links | ||
if (in_array($uri->getScheme(), ['mailto', 'tel'], true)) { | ||
return $uri; | ||
} | ||
|
||
return $uri->withPath(rtrim($uri->getPath(), '/') . '/'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Flowpack\SeoRouting; | ||
|
||
use Flowpack\SeoRouting\Helper\BlocklistHelper; | ||
use Flowpack\SeoRouting\Helper\ConfigurationHelper; | ||
use Flowpack\SeoRouting\Helper\TrailingSlashHelper; | ||
use GuzzleHttp\Psr7\Exception\MalformedUriException; | ||
use GuzzleHttp\Psr7\Uri; | ||
use Neos\Flow\Annotations as Flow; | ||
use Neos\Flow\Aop\JoinPointInterface; | ||
use Neos\Neos\Service\LinkingService; | ||
|
||
#[Flow\Aspect] | ||
class LinkingServiceAspect | ||
{ | ||
#[Flow\Inject] | ||
protected TrailingSlashHelper $trailingSlashHelper; | ||
|
||
#[Flow\Inject] | ||
protected ConfigurationHelper $configurationHelper; | ||
|
||
#[Flow\Inject] | ||
protected BlocklistHelper $blocklistHelper; | ||
|
||
/** | ||
* This ensures that all internal links are rendered with a trailing slash. | ||
*/ | ||
#[Flow\Around('method(' . LinkingService::class . '->createNodeUri())')] | ||
public function appendTrailingSlashToNodeUri(JoinPointInterface $joinPoint): string | ||
{ | ||
/** @var string $result */ | ||
$result = $joinPoint->getAdviceChain()->proceed($joinPoint); | ||
|
||
if (! $this->configurationHelper->isTrailingSlashEnabled()) { | ||
return $result; | ||
} | ||
|
||
try { | ||
$uri = new Uri($result); | ||
} catch (MalformedUriException) { | ||
return $result; | ||
} | ||
|
||
if ($this->blocklistHelper->isUriInBlocklist($uri)) { | ||
return $result; | ||
} | ||
|
||
return (string)$this->trailingSlashHelper->appendTrailingSlash($uri); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Flowpack\SeoRouting\Tests\Unit\Helper; | ||
|
||
use Flowpack\SeoRouting\Helper\BlocklistHelper; | ||
use Flowpack\SeoRouting\Helper\ConfigurationHelper; | ||
use GuzzleHttp\Psr7\Uri; | ||
use PHPUnit\Framework\Attributes\CoversClass; | ||
use PHPUnit\Framework\Attributes\DataProvider; | ||
use PHPUnit\Framework\TestCase; | ||
use ReflectionClass; | ||
|
||
#[CoversClass(BlocklistHelper::class)] | ||
class BlocklistHelperTest extends TestCase | ||
{ | ||
#[DataProvider('urlDataProvider')] | ||
public function testIsUriInBlocklist(string $input, bool $expected): void | ||
{ | ||
$blocklistHelper = new BlocklistHelper(); | ||
$configurationHelperMock = $this->createMock(ConfigurationHelper::class); | ||
|
||
$configurationHelperMock->expects($this->once())->method('getBlocklist')->willReturn( | ||
['/neos.*' => false, '.*test.*' => true] | ||
); | ||
|
||
$reflection = new ReflectionClass($blocklistHelper); | ||
$property = $reflection->getProperty('configurationHelper'); | ||
$property->setValue($blocklistHelper, $configurationHelperMock); | ||
|
||
$uri = new Uri($input); | ||
|
||
self::assertSame($expected, $blocklistHelper->isUriInBlocklist($uri)); | ||
} | ||
|
||
/** | ||
* @return array{array{string, bool}} | ||
*/ | ||
public static function urlDataProvider(): array | ||
{ | ||
return [ | ||
['https://test.de/neos', false], | ||
['https://test.de/neos/test', true], | ||
['https://neos.de/foo', false], | ||
]; | ||
} | ||
} |
Oops, something went wrong.