diff --git a/phpstan.neon b/phpstan.neon
index c521d5e..67a7ed6 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -7,3 +7,6 @@ parameters:
-
message: '#.* generic class Shopware\\Core\\Framework\\DataAbstractionLayer\\EntityRepository.*not specify its types: TEntityCollection#'
reportUnmatched: false
+ -
+ message: "#^Out of .* possible param types, only .* %% actually have it\\. Add more param types to get over 99 %%$#"
+ reportUnmatched: false
diff --git a/src/Command/CleanupExcludesCommand.php b/src/Command/CleanupExcludesCommand.php
new file mode 100644
index 0000000..6089e61
--- /dev/null
+++ b/src/Command/CleanupExcludesCommand.php
@@ -0,0 +1,99 @@
+getName());
+ }
+
+ protected function configure(): void
+ {
+ $this->addOption('dry-run', 'd', null, 'Dry run will not delete any entries but prints ids.');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $output->writeln('Collecting entries:');
+
+ $context = new Context(new SystemSource());
+ $criteria = (new Criteria())
+ ->setLimit(500)
+ ->addFilter(new EqualsFilter('active', false))
+ ->addAssociation('salesChannelDomain');
+
+ $repositoryIterator = new RepositoryIterator($this->tinectRedirectsRedirectRepository, $context, $criteria);
+
+ $progressBar = new ProgressBar($output, $repositoryIterator->getTotal());
+ $progressBar->start();
+
+ $deleteIds = [];
+ while (($result = $repositoryIterator->fetch()) !== null) {
+ foreach ($result->getEntities() as $redirect) {
+ $progressBar->advance();
+
+ if (!$redirect instanceof RedirectEntity) {
+ continue;
+ }
+
+ $salesChannelId = $redirect->getSalesChannelDomain()?->getSalesChannelId();
+
+ if ($this->excludedService->isExcluded($redirect->getSource(), $salesChannelId)) {
+ $deleteIds[] = $redirect->getId();
+ }
+ }
+ }
+
+ $progressBar->finish();
+ $output->writeln('');
+
+ $countDeletes = \count($deleteIds);
+
+ if ($countDeletes === 0) {
+ $output->writeln('No entries to delete.');
+
+ return Command::SUCCESS;
+ }
+
+ if ($input->getOption('dry-run')) {
+ $output->writeln('Would delete ' . $countDeletes . ' entries');
+ } else {
+ $output->writeln('Deleting ' . $countDeletes . ' entries:');
+
+ $progressBar = new ProgressBar($output, $countDeletes);
+ $progressBar->start();
+
+ $deleteIds = \array_chunk($deleteIds, 1000);
+ foreach ($deleteIds as $ids) {
+ $this->tinectRedirectsRedirectRepository->delete(\array_map(static fn ($id) => ['id' => $id], $ids), $context);
+ $progressBar->advance(\count($ids));
+ }
+
+ $progressBar->finish();
+ $output->writeln('');
+ }
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Resources/config/config.xml b/src/Resources/config/config.xml
index 6efa218..a24ce06 100644
--- a/src/Resources/config/config.xml
+++ b/src/Resources/config/config.xml
@@ -47,8 +47,8 @@
#.js.map$#i
#/wp-config#i
]]>
- Every line is managed an own regex rule. You can check them e.g. at regex101.com
- Jede Zeile wird mit einer eigenen Regex-Regel verwaltet. Sie können diese z.B. bei regex101.com nachlesen
+ Every line is managed an own regex rule. You can check them e.g. at regex101.com. Whenever you add a new line, you might want to use the command tinect-redirects:excludes-cleanup to clean up existing entries.
+ Jede Zeile wird mit einer eigenen Regex-Regel verwaltet. Sie können diese z.B. bei regex101.com nachlesen. Wenn Sie eine neue Zeile hinzufügen, möchten Sie möglicherweise den Befehl tinect-redirects:excludes-cleanup verwenden, um vorhandene Einträge zu bereinigen.
diff --git a/src/Services/ExcludedService.php b/src/Services/ExcludedService.php
new file mode 100644
index 0000000..abdc933
--- /dev/null
+++ b/src/Services/ExcludedService.php
@@ -0,0 +1,44 @@
+>
+ */
+ private array $excludes = [];
+
+ public function __construct(
+ private readonly SystemConfigService $systemConfigService,
+ ) {
+ }
+
+ public function isExcluded(string $path, ?string $salesChannelId): bool
+ {
+ if (!isset($this->excludes[$salesChannelId])) {
+ $excludes = \array_filter(\explode(PHP_EOL, $this->systemConfigService->getString('TinectRedirects.config.excludes', $salesChannelId)));
+ $this->excludes[$salesChannelId] = $excludes;
+ }
+
+ $excludes = $this->excludes[$salesChannelId];
+
+ foreach ($excludes as $exclude) {
+ try {
+ if (\preg_match($exclude, $path)) {
+ return true;
+ }
+ } catch (\Throwable) {
+ // nth, we don't care whether the regex is valid
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/Subscriber/BeforeSendResponseSubscriber.php b/src/Subscriber/BeforeSendResponseSubscriber.php
index 3d528bd..353305a 100644
--- a/src/Subscriber/BeforeSendResponseSubscriber.php
+++ b/src/Subscriber/BeforeSendResponseSubscriber.php
@@ -31,6 +31,7 @@
use Symfony\Component\Messenger\MessageBusInterface;
use Tinect\Redirects\Content\Redirect\RedirectEntity;
use Tinect\Redirects\Message\TinectRedirectUpdateMessage;
+use Tinect\Redirects\Services\ExcludedService;
readonly class BeforeSendResponseSubscriber implements EventSubscriberInterface
{
@@ -41,7 +42,8 @@ public function __construct(
private AbstractSalesChannelContextFactory $salesChannelContextFactory,
private SystemConfigService $systemConfigService,
private MessageBusInterface $messageBus,
- private RequestTransformer $requestTransformer
+ private RequestTransformer $requestTransformer,
+ private ExcludedService $excludedService
) {
}
@@ -214,23 +216,6 @@ private function canCreateRedirect(string $path, ?string $salesChannelId): bool
return false;
}
- return $this->canCreateRedirectByExcludes($path, $salesChannelId);
- }
-
- private function canCreateRedirectByExcludes(string $path, ?string $salesChannelId): bool
- {
- $excludes = \explode(PHP_EOL, $this->systemConfigService->getString('TinectRedirects.config.excludes', $salesChannelId));
-
- foreach ($excludes as $exclude) {
- try {
- if (\preg_match($exclude, $path)) {
- return false;
- }
- } catch (\Throwable) {
- // nth, we don't care whether the regex is valid
- }
- }
-
- return true;
+ return !$this->excludedService->isExcluded($path, $salesChannelId);
}
}