Feature: #99491 - PSR-14 event for redirect integrity checks
See forge#99491
Description
A new PSR-14 event
\TYPO3\ has been
added. It is dispatched in
\TYPO3\
for each redirect record.
While the existing integrity check verifies only whether redirect sources
conflict with page URLs (self-reference), this event allows
extensions to validate redirects for other conflict types. For example, an
extension can check whether a t3:// link target still resolves correctly
or whether an external URL returns a valid response.
The event provides the following methods:
get: The fullRedirect () sys_record as an array.redirect get: Convenience method returning the redirectUid () uidas an integer.get: Convenience method returning the redirectPid () pidas an integer.get: Convenience method returning the redirectDeleted () deletedas a boolean.get: Convenience method returning the redirectDisabled () disabledas a boolean.get: Convenience method returning the redirectSource Host () source_as a string.host get: Convenience method returning the redirectSource Path () source_as a string.path get: Convenience method returning the redirectIs Reg Exp () is_as a boolean.regexp get: Convenience method returning the redirectProtected () protectedas a boolean.get: Convenience method returning the redirectForce Https () force_as a boolean.https get: Convenience method returning the redirectRespect Query Parameters () respect_as a boolean.query_ parameters get: Convenience method returning the redirectKeep Query Parameters () keep_as a boolean.query_ parameters get: Convenience method returning the redirectTarget () targetas a string.get: Convenience method returning the redirectTarget Status Code () target_as an integer.statuscode get: Convenience method returning the redirectCreation Type () creation_as an integer.type get: Convenience method returning the redirectOriginal Integrity Status () integrity_as a string.status get/Integrity Status () set: Read or set the integrity status. When a listener sets a non-null status, the redirect is reported as a conflict in theIntegrity Status () redirects:command output. Be aware thatcheckintegrity \TYPO3\can be set as the integrity status and will not be included in the report, even if a listener explicitly setsCMS\ Redirects\ Utility\ Redirect Conflict:: NO_ CONFLICT \TYPO3\for the redirect.CMS\ Redirects\ Utility\ Redirect Conflict:: NO_ CONFLICT
Additionally, the following new class constant has been added to allow extensions to conveniently reuse a shared conflict status in custom event listeners:
\TYPO3\CMS\ Redirects\ Utility\ Redirect Conflict:: INVALID_ TARGET
Example
An event listener that validates t3:// targets:
<?php
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Redirects\Event\RedirectIntegrityCheckEvent;
use TYPO3\CMS\Redirects\Utility\RedirectConflict;
final readonly class ValidateRedirectTarget
{
public function __construct(
private ConnectionPool $connectionPool,
) {}
#[AsEventListener('my-extension/validate-redirect-target')]
public function __invoke(RedirectIntegrityCheckEvent $event): void
{
$target = $event->getTarget();
if (!str_starts_with($target, 't3://record')) {
return;
}
// Parse t3://record?identifier=tx_news&uid=456
parse_str((string)parse_url($target, PHP_URL_QUERY), $params);
$table = $params['identifier'] ?? '';
$uid = (int)($params['uid'] ?? 0);
if ($table === '' || $uid === 0) {
$event->setIntegrityStatus(RedirectConflict::INVALID_TARGET);
return;
}
$count = $this->connectionPool
->getConnectionForTable($table)
->count('uid', $table, ['uid' => $uid]);
if ($count === 0) {
$event->setIntegrityStatus(RedirectConflict::INVALID_TARGET);
return;
}
// Set to NO_CONFLICT. This will not be reported as a conflicting
// redirect, but it clears any previously set integrity status.
$event->setIntegrityStatus(RedirectConflict::NO_CONFLICT);
}
}
Impact
Extensions can now validate redirects during the integrity check by listening
to this event. Broken or invalid redirects are reported alongside existing
self-reference conflicts in the
redirects: command
output.