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); } }