Skip to content

Commit

Permalink
feat: add command to delete excluded paths afterward
Browse files Browse the repository at this point in the history
  • Loading branch information
tinect committed Jul 7, 2024
1 parent 29d974d commit f6ec01f
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 21 deletions.
3 changes: 3 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -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
99 changes: 99 additions & 0 deletions src/Command/CleanupExcludesCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

namespace Tinect\Redirects\Command;

use Shopware\Core\Framework\Api\Context\SystemSource;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Dbal\Common\RepositoryIterator;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Tinect\Redirects\Content\Redirect\RedirectEntity;
use Tinect\Redirects\Services\ExcludedService;

#[AsCommand(name: 'tinect-redirects:excludes-cleanup', description: 'Cleanup existing entries by re-checking them for the exclude patterns.')]
class CleanupExcludesCommand extends Command
{
public function __construct(
private readonly EntityRepository $tinectRedirectsRedirectRepository,
private readonly ExcludedService $excludedService
) {
parent::__construct($this->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;
}
}
4 changes: 2 additions & 2 deletions src/Resources/config/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
#.js.map$#i
#/wp-config#i
]]></defaultValue>
<helpText>Every line is managed an own regex rule. You can check them e.g. at regex101.com</helpText>
<helpText lang="de-DE">Jede Zeile wird mit einer eigenen Regex-Regel verwaltet. Sie können diese z.B. bei regex101.com nachlesen</helpText>
<helpText>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.</helpText>
<helpText lang="de-DE">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.</helpText>
</input-field>
</card>
</config>
44 changes: 44 additions & 0 deletions src/Services/ExcludedService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Tinect\Redirects\Services;

use Shopware\Core\System\SystemConfig\SystemConfigService;

class ExcludedService
{
/**
* Key is sales channel id, value is an array of exclude patterns.
*
* @var array<string, array<string>>
*/
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;
}
}
23 changes: 4 additions & 19 deletions src/Subscriber/BeforeSendResponseSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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
) {
}

Expand Down Expand Up @@ -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);
}
}

0 comments on commit f6ec01f

Please sign in to comment.