TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:33 +02:00
commit 1a6eae9988
124 changed files with 11393 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Redirects\RedirectUpdate;
final readonly class PageTypeSource implements RedirectSourceInterface
{
public function __construct(
private string $host,
private string $path,
private int $pageType,
private array $targetLinkParameters,
) {}
public function getHost(): string
{
return $this->host;
}
public function getPath(): string
{
return $this->path;
}
public function getPageType(): int
{
return $this->pageType;
}
public function getTargetLinkParameters(): array
{
return $this->targetLinkParameters;
}
}
@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Redirects\RedirectUpdate;
/**
* @internal This is a concrete implementation and solely used for EXT:redirects and not part of TYPO3's Core API. It
* may vanish any time.
*/
final readonly class PlainSlugReplacementRedirectSource implements RedirectSourceInterface
{
public function __construct(
private string $host,
private string $path,
private array $targetLinkParameters,
) {}
public function getHost(): string
{
return $this->host;
}
public function getPath(): string
{
return $this->path;
}
public function getTargetLinkParameters(): array
{
return $this->targetLinkParameters;
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Redirects\RedirectUpdate;
/**
* @internal This is a concrete collection implementation and solely used for EXT:redirects and not part of TYPO3's Core API.
*/
final class RedirectSourceCollection implements \Countable
{
/**
* @var list<RedirectSourceInterface>
*/
private array $sources;
private int $count;
public function __construct(RedirectSourceInterface ...$sources)
{
// Ensure to strip out eventually containing associative keys
$this->sources = array_values($sources);
$this->count = count($this->sources);
}
/**
* @return list<RedirectSourceInterface>
*/
public function all(): array
{
return $this->sources;
}
public function count(): int
{
return $this->count;
}
}
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Redirects\RedirectUpdate;
/**
* This is a contract containing the base information on an original redirect that should
* be transformed or replaced.
*/
interface RedirectSourceInterface
{
public function getHost(): string;
public function getPath(): string;
public function getTargetLinkParameters(): array;
}
@@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Redirects\RedirectUpdate;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
/**
* This class contains data on the journey through the auto-create-redirects
* path. It may be also included as information in a PSR-14 event, if needed.
*
* @internal This class is a specific data container for slug service handling and is not part of the public TYPO3 API.
*/
final readonly class SlugRedirectChangeItem
{
public function __construct(
private int $defaultLanguagePageId,
private int $pageId,
private Site $site,
private SiteLanguage $siteLanguage,
private array $original,
private RedirectSourceCollection $sourcesCollection,
private ?array $changed = null,
) {}
public function getDefaultLanguagePageId(): int
{
return $this->defaultLanguagePageId;
}
public function getPageId(): int
{
return $this->pageId;
}
public function getOriginal(): array
{
return $this->original;
}
public function getChanged(): ?array
{
return $this->changed;
}
public function getSite(): Site
{
return $this->site;
}
public function getSiteLanguage(): SiteLanguage
{
return $this->siteLanguage;
}
public function getSourcesCollection(): RedirectSourceCollection
{
return $this->sourcesCollection;
}
public function withChanged(array $changed): self
{
return new self(
defaultLanguagePageId: $this->defaultLanguagePageId,
pageId: $this->pageId,
site: $this->site,
siteLanguage: $this->siteLanguage,
original: $this->original,
sourcesCollection: $this->sourcesCollection,
changed: $changed,
);
}
public function withSourcesCollection(RedirectSourceCollection $sourcesCollection): self
{
return new self(
defaultLanguagePageId: $this->defaultLanguagePageId,
pageId: $this->pageId,
site: $this->site,
siteLanguage: $this->siteLanguage,
original: $this->original,
sourcesCollection: $sourcesCollection,
changed: $this->changed,
);
}
}
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Redirects\RedirectUpdate;
use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
/**
* @internal This factory class is a specific implementation for creating SlugRedirectChangeItems
* and is not part of the public TYPO3 API.
*/
final readonly class SlugRedirectChangeItemFactory
{
public function __construct(
private SiteFinder $siteFinder,
private EventDispatcherInterface $eventDispatcher,
) {}
public function create(int $pageId, ?array $original = null, ?array $changed = null): ?SlugRedirectChangeItem
{
// @todo Consider to omit hidden or scheduled records completly, eventually based on configuration.
$original ??= BackendUtility::getRecordWSOL('pages', $pageId);
if (!$original) {
return null;
}
$languageId = (int)$original['language_tag'];
$defaultLanguagePageId = (int)$original['language_tag'] > 0 ? (int)$original['l10n_parent'] : $pageId;
try {
$site = $this->siteFinder->getSiteByPageId($defaultLanguagePageId);
} catch (SiteNotFoundException) {
// "autoCreateRedirects" and "autoUpdateSlugs" are site configuration settings. Not finding one
// means that we should not handle the creation of them, thus no need to create a change item.
return null;
}
$siteLanguage = $site->getLanguageById($languageId);
// Verify we should process auto redirect creation or slug updating. If not return early avoiding to create
// a change item which is superflous at all.
$settings = $site->getSettings();
$autoUpdateSlugs = (bool)$settings->get('redirects.autoUpdateSlugs', true);
$autoCreateRedirects = (bool)$settings->get('redirects.autoCreateRedirects', true);
if (!($autoUpdateSlugs || $autoCreateRedirects)) {
return null;
}
$changeItem = new SlugRedirectChangeItem(
defaultLanguagePageId: $defaultLanguagePageId,
pageId: $pageId,
site: $site,
siteLanguage: $siteLanguage,
original: $original,
sourcesCollection: new RedirectSourceCollection(),
changed: $changed
);
return $this->eventDispatcher->dispatch(new SlugRedirectChangeItemCreatedEvent($changeItem))
->getSlugRedirectChangeItem();
}
}