diff --git a/.editorconfig b/.editorconfig index 178a650..bf6bec0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,9 +15,6 @@ indent_size = 2 [*.md] trim_trailing_whitespace = false -[*.sh] -indent_style = tab - [*.{yaml,yml}] trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes index 15d357c..53f8a7c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,8 @@ +/.github export-ignore +/etc export-ignore +/docs export-ignore /.editorconfig export-ignore /.gitattributes export-ignore -/.github export-ignore /.gitignore export-ignore /README.md export-ignore /behat.yml.dist export-ignore @@ -12,3 +14,5 @@ /psalm-baseline.xml export-ignore /psalm.xml export-ignore /tests export-ignore +/CHANGELOG.md export-ignore +/UPGRADE.md export-ignore diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 31eead5..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,17 +0,0 @@ -# https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 - -updates: - - commit-message: - include: "scope" - prefix: "composer" - directory: "/" - ignore: - - dependency-name: "symfony/*" - - dependency-name: "sylius/*" - open-pull-requests-limit: 10 - package-ecosystem: "composer" - schedule: - interval: "weekly" - versioning-strategy: "increase-if-necessary" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5fc0138..7b5b1c1 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -13,14 +13,14 @@ env: jobs: coding-standards: - name: "Coding Standards" + name: "Coding Standards (PHP${{ matrix.php-version }} | Deps: ${{ matrix.dependencies }})" runs-on: "ubuntu-latest" strategy: matrix: php-version: - - "7.4" + - "7.4" # Always use the lowest version of PHP since a higher version could create actual syntax errors in lower versions dependencies: - "highest" @@ -50,6 +50,9 @@ jobs: - name: "Check style" run: "composer check-style" + - name: "Rector" + run: "vendor/bin/rector process --dry-run" + - name: "Lint yaml files" run: "(cd tests/Application && bin/console lint:yaml ../../src/Resources)" @@ -57,7 +60,7 @@ jobs: run: "(cd tests/Application && bin/console lint:twig ../../src/Resources)" dependency-analysis: - name: "Dependency Analysis" + name: "Dependency Analysis (PHP${{ matrix.php-version }} | Deps: ${{ matrix.dependencies }} | SF${{ matrix.symfony }})" runs-on: "ubuntu-latest" @@ -65,10 +68,22 @@ jobs: matrix: php-version: - "7.4" + - "8.0" + - "8.1" + - "8.2" dependencies: + - "lowest" - "highest" + symfony: + - "^5.4" + - "^6.0" + + exclude: + - php-version: "7.4" + symfony: "^6.0" + steps: - name: "Checkout" uses: "actions/checkout@v3" @@ -79,21 +94,26 @@ jobs: coverage: "none" extensions: "${{ env.PHP_EXTENSIONS }}" php-version: "${{ matrix.php-version }}" - tools: "composer-require-checker, composer-unused" + tools: "composer-require-checker, composer-unused, flex" + + - name: "Remove require-dev section in composer.json" + run: "composer config --unset require-dev" - name: "Install composer dependencies" uses: "ramsey/composer-install@v2" + env: + SYMFONY_REQUIRE: "${{ matrix.symfony }}" with: dependency-versions: "${{ matrix.dependencies }}" - name: "Run maglnet/composer-require-checker" - run: "composer-require-checker check --config-file=$(pwd)/composer-require-checker.json" + run: "composer-require-checker check" - name: "Run composer-unused/composer-unused" run: "composer-unused" static-code-analysis: - name: "Static Code Analysis" + name: "Static Code Analysis (PHP${{ matrix.php-version }} | Deps: ${{ matrix.dependencies }} | SF${{ matrix.symfony }})" runs-on: "ubuntu-latest" @@ -101,10 +121,22 @@ jobs: matrix: php-version: - "7.4" + - "8.0" + - "8.1" + - "8.2" dependencies: + - "lowest" - "highest" + symfony: + - "^5.4" + - "^6.0" + + exclude: + - php-version: "7.4" + symfony: "^6.0" + steps: - name: "Checkout" uses: "actions/checkout@v3" @@ -112,20 +144,26 @@ jobs: - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.PHP_EXTENSIONS }}" coverage: "none" + extensions: "${{ env.PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" + tools: "flex" + + - name: "Remove sylius/sylius from composer.json" + run: "composer remove --dev sylius/sylius --no-update --no-install" - name: "Install composer dependencies" uses: "ramsey/composer-install@v2" + env: + SYMFONY_REQUIRE: "${{ matrix.symfony }}" with: dependency-versions: "${{ matrix.dependencies }}" - name: "Static analysis" - run: "composer analyse" + run: "vendor/bin/psalm --php-version=${{ matrix.php-version }}" unit-tests: - name: "Unit tests" + name: "Unit tests (PHP${{ matrix.php-version }} | Deps: ${{ matrix.dependencies }} | SF${{ matrix.symfony }})" runs-on: "ubuntu-latest" @@ -133,11 +171,21 @@ jobs: matrix: php-version: - "7.4" + - "8.0" + - "8.1" + - "8.2" dependencies: - - "lowest" - "highest" + symfony: + - "^5.4" + - "^6.0" + + exclude: + - php-version: "7.4" + symfony: "^6.0" + steps: - name: "Checkout" uses: "actions/checkout@v3" @@ -145,20 +193,26 @@ jobs: - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.PHP_EXTENSIONS }}" coverage: "none" + extensions: "${{ env.PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" + tools: "flex" + + - name: "Remove sylius/sylius from composer.json" + run: "composer remove --dev sylius/sylius --no-update --no-install" - name: "Install composer dependencies" uses: "ramsey/composer-install@v2" + env: + SYMFONY_REQUIRE: "${{ matrix.symfony }}" with: dependency-versions: "${{ matrix.dependencies }}" - - name: "Run phpspec" - run: "composer phpspec" - - name: "Run phpunit" run: "composer phpunit" + + - name: "Run phpspec" + run: "composer phpspec" integration-tests: name: "Integration tests" @@ -241,14 +295,14 @@ jobs: if-no-files-found: "ignore" code-coverage: - name: "Code Coverage" + name: "Code Coverage (PHP${{ matrix.php-version }} | Deps: ${{ matrix.dependencies }})" runs-on: "ubuntu-latest" strategy: matrix: php-version: - - "7.4" + - "8.2" dependencies: - "highest" diff --git a/composer-require-checker.json b/composer-require-checker.json deleted file mode 100644 index 63066a0..0000000 --- a/composer-require-checker.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "symbol-whitelist": [ - "array", - "bool", - "callable", - "false", - "float", - "int", - "iterable", - "null", - "object", - "parent", - "self", - "static", - "string", - "true", - "void", - "Sylius\\Bundle\\CoreBundle\\Application\\SyliusPluginTrait", - "Sylius\\Bundle\\ChannelBundle\\Form\\Type\\ChannelChoiceType", - "Sylius\\Bundle\\ProductBundle\\Form\\Type\\ProductTranslationType", - "Sylius\\Bundle\\TaxonomyBundle\\Form\\Type\\TaxonTranslationType", - "Sylius\\Bundle\\UiBundle\\Menu\\Event\\MenuBuilderEvent", - "Sylius\\Component\\Channel\\Context\\ChannelContextInterface", - "Sylius\\Component\\Channel\\Context\\ChannelNotFoundException", - "Sylius\\Component\\Channel\\Model\\ChannelAwareInterface", - "Sylius\\Component\\Channel\\Model\\ChannelInterface", - "Sylius\\Component\\Channel\\Model\\ChannelsAwareInterface", - "Sylius\\Component\\Channel\\Repository\\ChannelRepositoryInterface" - ] -} diff --git a/composer.json b/composer.json index afe623c..21553ce 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,13 @@ "doctrine/persistence": "^1.3 || ^2.1", "league/uri": "^6.0", "league/uri-components": "^2.3", - "setono/symfony-main-request-trait": "^1.0", + "sylius/channel": "^1.0", + "sylius/channel-bundle": "^1.0", + "sylius/core-bundle": "^1.0", + "sylius/product-bundle": "^1.0", "sylius/resource-bundle": "^1.6", + "sylius/taxonomy-bundle": "^1.0", + "sylius/ui-bundle": "^1.0", "symfony/config": "^5.4 || ^6.0", "symfony/console": "^5.4 || ^6.0", "symfony/dependency-injection": "^5.4 || ^6.0", @@ -32,6 +37,7 @@ "require-dev": { "api-platform/core": "^2.7", "lexik/jwt-authentication-bundle": "^2.16", + "php-http/message-factory": "^1.1", "phpspec/phpspec": "^7.3", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.6", @@ -44,8 +50,7 @@ "symfony/dotenv": "^5.4 || ^6.0", "symfony/intl": "^5.4 || ^6.0", "symfony/web-profiler-bundle": "^5.4 || ^6.0", - "symfony/webpack-encore-bundle": "^1.16", - "weirdan/doctrine-psalm-plugin": "^2.8" + "symfony/webpack-encore-bundle": "^1.16" }, "prefer-stable": true, "autoload": { @@ -65,17 +70,14 @@ "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": false, "ergebnis/composer-normalize": true, + "ocramius/package-versions": true, "symfony/thanks": false }, "sort-packages": true }, "scripts": { - "analyse": [ - "@ensure-test-container-exists", - "psalm" - ], + "analyse": "psalm", "check-style": "ecs check", - "ensure-test-container-exists": "[[ -f tests/Application/var/cache/test/ApplicationTests_Setono_SyliusRedirectPlugin_Application_KernelTestDebugContainer.xml ]] || tests/Application/bin/console cache:warmup --env=test", "fix-style": "ecs check --fix", "phpspec": "phpspec run", "phpunit": "phpunit", diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2339dbd..7e41f9e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,169 +1,14 @@ - - - - addDefaultsIfNotSet - cannotBeEmpty - cannotBeEmpty - cannotBeEmpty - cannotBeEmpty - children - defaultValue - defaultValue - defaultValue - defaultValue - defaultValue - defaultValue - end - end - end - end - end - end - end - end - end - end - end - end - end - end - info - scalarNode - scalarNode - scalarNode - scalarNode - scalarNode - - - arrayNode - integerNode - - - arrayNode - integerNode - - - ArrayNodeDefinition - - - - - $config['driver'] - $config['remove_after'] - $config['resources'] - - - getConfiguration([], $container)]]> - - - - - getDestination()]]> - - - - - isMasterRequest - - - getDestination()]]> - - - - - $channel - - - $channel - - + - first()]]> - first()]]> - first()]]> - first()]]> + $firstRedirect + $firstRedirect - - - Collection|RedirectInterface[] - - - - - AutomaticRedirectTypeExtension - - - - - channels]]> - - - Collection - - - add - contains - removeElement - - - $id - - - - - seen]]> - - - - - $dateTimeThreshold - - - - getSource - hasCycle()]]> - - - $removableRedirect - - - validationGroups]]> - - - $removableRedirect - - - - - $redirect - - - getSource()]]> - getSource()]]> - - - - - SourceRegex - - - - - $redirect - - - getSource()]]> - getSource()]]> - getSource()]]> - getSource()]]> - - diff --git a/psalm.xml b/psalm.xml index 013c539..9b1fc85 100644 --- a/psalm.xml +++ b/psalm.xml @@ -5,6 +5,10 @@ xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" errorLevel="1" errorBaseline="psalm-baseline.xml" + findUnusedBaselineEntry="true" + findUnusedPsalmSuppress="false" + findUnusedCode="false" + findUnusedVariablesAndParams="true" > @@ -16,14 +20,28 @@ - - tests/Application/var/cache/test/Tests_Setono_SyliusRedirectPlugin_Application_KernelTestDebugContainer.xml - + - + + + + + + + + + + + + + + + + + diff --git a/src/Command/RemoveRedirectsCommand.php b/src/Command/RemoveRedirectsCommand.php index c76fbe1..c101cc1 100644 --- a/src/Command/RemoveRedirectsCommand.php +++ b/src/Command/RemoveRedirectsCommand.php @@ -4,24 +4,25 @@ namespace Setono\SyliusRedirectPlugin\Command; -use Exception; -use Setono\SyliusRedirectPlugin\Repository\RedirectRepository; +use Setono\SyliusRedirectPlugin\Repository\RedirectRepositoryInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class RemoveRedirectsCommand extends Command { - /** @var RedirectRepository */ - private $redirectRepository; + protected static $defaultName = 'setono:sylius-redirect:remove'; - /** @var int */ - private $removeAfter; + protected static $defaultDescription = 'This command will remove redirects that have not been accessed later than x days ago where x is the `setono_sylius_redirect.remove_after` parameter'; + + private RedirectRepositoryInterface $redirectRepository; + + private int $removeAfter; /** * @param int $removeAfter The number of days that has to go before removing redirects */ - public function __construct(RedirectRepository $redirectRepository, int $removeAfter) + public function __construct(RedirectRepositoryInterface $redirectRepository, int $removeAfter) { parent::__construct(); @@ -29,17 +30,6 @@ public function __construct(RedirectRepository $redirectRepository, int $removeA $this->removeAfter = $removeAfter; } - protected function configure(): void - { - $this - ->setName('setono:sylius-redirect:remove') - ->setDescription('This command will remove redirects that have not been accessed later than x days ago where x is the `setono_sylius_redirect.remove_after` parameter') - ; - } - - /** - * @throws Exception - */ protected function execute(InputInterface $input, OutputInterface $output): int { $this->redirectRepository->removeNotAccessed($this->removeAfter); diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 6b6c211..2ee2ddb 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -23,6 +23,7 @@ public function getConfigTreeBuilder(): TreeBuilder /** @var ArrayNodeDefinition $rootNode */ $rootNode = $treeBuilder->getRootNode(); + /** @psalm-suppress UndefinedInterfaceMethod,PossiblyNullReference,MixedMethodCall */ $rootNode ->addDefaultsIfNotSet() ->children() @@ -30,8 +31,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->integerNode('remove_after') ->info('0 means disabled. If the value is > 0 then redirects that have not been accessed in the last x days will be removed') ->defaultValue(0) - ->end() - ->end(); + ; $this->addResourcesSection($rootNode); @@ -40,6 +40,7 @@ public function getConfigTreeBuilder(): TreeBuilder private function addResourcesSection(ArrayNodeDefinition $node): void { + /** @psalm-suppress MixedMethodCall,PossiblyNullReference,UndefinedInterfaceMethod,PossiblyUndefinedMethod */ $node ->children() ->arrayNode('resources') @@ -57,13 +58,6 @@ private function addResourcesSection(ArrayNodeDefinition $node): void ->scalarNode('repository')->defaultValue(RedirectRepository::class)->cannotBeEmpty()->end() ->scalarNode('factory')->defaultValue(Factory::class)->end() ->scalarNode('form')->defaultValue(RedirectType::class)->cannotBeEmpty()->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() ; } } diff --git a/src/DependencyInjection/SetonoSyliusRedirectExtension.php b/src/DependencyInjection/SetonoSyliusRedirectExtension.php index e10716b..50d951b 100644 --- a/src/DependencyInjection/SetonoSyliusRedirectExtension.php +++ b/src/DependencyInjection/SetonoSyliusRedirectExtension.php @@ -13,6 +13,11 @@ final class SetonoSyliusRedirectExtension extends AbstractResourceExtension { public function load(array $configs, ContainerBuilder $container): void { + /** + * @psalm-suppress PossiblyNullArgument + * + * @var array{driver: string, resources: array, remove_after: int} $config + */ $config = $this->processConfiguration($this->getConfiguration([], $container), $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); diff --git a/src/EventListener/ControllerSubscriber.php b/src/EventListener/ControllerSubscriber.php index 72253ab..1c64407 100644 --- a/src/EventListener/ControllerSubscriber.php +++ b/src/EventListener/ControllerSubscriber.php @@ -17,14 +17,11 @@ final class ControllerSubscriber implements EventSubscriberInterface { use RedirectResponseTrait; - /** @var ObjectManager */ - private $objectManager; + private ObjectManager $objectManager; - /** @var ChannelContextInterface */ - private $channelContext; + private ChannelContextInterface $channelContext; - /** @var RedirectionPathResolverInterface */ - private $redirectionPathResolver; + private RedirectionPathResolverInterface $redirectionPathResolver; public function __construct( ObjectManager $objectManager, diff --git a/src/EventListener/NotFoundSubscriber.php b/src/EventListener/NotFoundSubscriber.php index 656ee77..69687a9 100644 --- a/src/EventListener/NotFoundSubscriber.php +++ b/src/EventListener/NotFoundSubscriber.php @@ -5,7 +5,6 @@ namespace Setono\SyliusRedirectPlugin\EventListener; use Doctrine\Persistence\ObjectManager; -use Setono\MainRequestTrait\MainRequestTrait; use Setono\SyliusRedirectPlugin\Resolver\RedirectionPathResolverInterface; use Sylius\Component\Channel\Context\ChannelContextInterface; use Sylius\Component\Channel\Context\ChannelNotFoundException; @@ -18,18 +17,13 @@ class NotFoundSubscriber implements EventSubscriberInterface { - use MainRequestTrait; - use RedirectResponseTrait; - /** @var ObjectManager */ - private $objectManager; + private ObjectManager $objectManager; - /** @var ChannelContextInterface */ - private $channelContext; + private ChannelContextInterface $channelContext; - /** @var RedirectionPathResolverInterface */ - private $redirectionPathResolver; + private RedirectionPathResolverInterface $redirectionPathResolver; public function __construct( ObjectManager $objectManager, @@ -50,7 +44,7 @@ public static function getSubscribedEvents(): array public function onKernelException(ExceptionEvent $event): void { - if (!$this->isMainRequest($event)) { + if (!$event->isMainRequest()) { return; } diff --git a/src/EventListener/RedirectResponseTrait.php b/src/EventListener/RedirectResponseTrait.php index 6787aad..321dee7 100644 --- a/src/EventListener/RedirectResponseTrait.php +++ b/src/EventListener/RedirectResponseTrait.php @@ -17,7 +17,7 @@ trait RedirectResponseTrait { public static function getRedirectResponse(RedirectInterface $lastRedirect, string $queryString = null): RedirectResponse { - $uri = Uri::createFromString($lastRedirect->getDestination()); + $uri = Uri::createFromString((string) $lastRedirect->getDestination()); if ($lastRedirect->keepQueryString() && null !== $queryString) { $uri = UriModifier::appendQuery($uri, $queryString); diff --git a/src/Exception/SlugUpdateHandlerValidationException.php b/src/Exception/SlugUpdateHandlerValidationException.php index 777ea20..1a0966a 100644 --- a/src/Exception/SlugUpdateHandlerValidationException.php +++ b/src/Exception/SlugUpdateHandlerValidationException.php @@ -8,8 +8,7 @@ final class SlugUpdateHandlerValidationException extends SlugUpdateHandlerException { - /** @var ConstraintViolationListInterface */ - private $constraintViolationList; + private ConstraintViolationListInterface $constraintViolationList; public function __construct(ConstraintViolationListInterface $constraintViolationList) { diff --git a/src/Factory/RedirectFactory.php b/src/Factory/RedirectFactory.php index 762bd66..92a3164 100644 --- a/src/Factory/RedirectFactory.php +++ b/src/Factory/RedirectFactory.php @@ -6,11 +6,11 @@ use Setono\SyliusRedirectPlugin\Model\RedirectInterface; use Sylius\Component\Resource\Factory\FactoryInterface; +use Webmozart\Assert\Assert; final class RedirectFactory implements RedirectFactoryInterface { - /** @var FactoryInterface */ - private $decoratedFactory; + private FactoryInterface $decoratedFactory; public function __construct(FactoryInterface $decoratedFactory) { @@ -19,8 +19,9 @@ public function __construct(FactoryInterface $decoratedFactory) public function createNew(): RedirectInterface { - /** @var RedirectInterface $redirect */ + /** @var object|RedirectInterface $redirect */ $redirect = $this->decoratedFactory->createNew(); + Assert::isInstanceOf($redirect, RedirectInterface::class); return $redirect; } diff --git a/src/Factory/RedirectFactoryInterface.php b/src/Factory/RedirectFactoryInterface.php index fe288d1..1852ef8 100644 --- a/src/Factory/RedirectFactoryInterface.php +++ b/src/Factory/RedirectFactoryInterface.php @@ -5,12 +5,16 @@ namespace Setono\SyliusRedirectPlugin\Factory; use Setono\SyliusRedirectPlugin\Model\RedirectInterface; +use Sylius\Component\Channel\Model\ChannelInterface; use Sylius\Component\Resource\Factory\FactoryInterface; interface RedirectFactoryInterface extends FactoryInterface { public function createNew(): RedirectInterface; + /** + * @param iterable $channels + */ public function createNewWithValues( string $source, string $destination, diff --git a/src/Finder/RemovableRedirectFinder.php b/src/Finder/RemovableRedirectFinder.php index 804e445..b41431a 100644 --- a/src/Finder/RemovableRedirectFinder.php +++ b/src/Finder/RemovableRedirectFinder.php @@ -11,8 +11,7 @@ final class RemovableRedirectFinder implements RemovableRedirectFinderInterface { - /** @var RedirectionPathResolverInterface */ - private $redirectionPathResolver; + private RedirectionPathResolverInterface $redirectionPathResolver; public function __construct(RedirectionPathResolverInterface $redirectionPathResolver) { @@ -21,18 +20,21 @@ public function __construct(RedirectionPathResolverInterface $redirectionPathRes public function findRedirectsTargetedBy(RedirectInterface $redirect): Collection { + /** @var ArrayCollection $result */ $result = new ArrayCollection(); if ($redirect->getChannels()->isEmpty()) { $redirectionPath = $this->redirectionPathResolver->resolve((string) $redirect->getDestination()); - if (!$redirectionPath->isEmpty() && !$result->contains($redirectionPath->first())) { - $result->add($redirectionPath->first()); + $firstRedirect = $redirectionPath->first(); + if (null !== $firstRedirect && !$result->contains($firstRedirect)) { + $result->add($firstRedirect); } } else { foreach ($redirect->getChannels() as $channel) { $redirectionPath = $this->redirectionPathResolver->resolve((string) $redirect->getDestination(), $channel); - if (!$redirectionPath->isEmpty() && !$result->contains($redirectionPath->first())) { - $result->add($redirectionPath->first()); + $firstRedirect = $redirectionPath->first(); + if (null !== $firstRedirect && !$result->contains($firstRedirect)) { + $result->add($firstRedirect); } } } diff --git a/src/Finder/RemovableRedirectFinderInterface.php b/src/Finder/RemovableRedirectFinderInterface.php index 705cead..b471018 100644 --- a/src/Finder/RemovableRedirectFinderInterface.php +++ b/src/Finder/RemovableRedirectFinderInterface.php @@ -18,7 +18,7 @@ interface RemovableRedirectFinderInterface * If all those redirect had multiple channels, this would result in : * new ArrayCollection(['a -> b (channel1)', 'a -> b (channel2)', 'a -> b (channel3)', ...]) * - * @return Collection|RedirectInterface[] + * @return Collection */ public function findRedirectsTargetedBy(RedirectInterface $redirect): Collection; } diff --git a/src/Form/Extension/AutomaticRedirectTypeExtension.php b/src/Form/Extension/AutomaticRedirectTypeExtension.php index cc2cdd7..b4e82ad 100644 --- a/src/Form/Extension/AutomaticRedirectTypeExtension.php +++ b/src/Form/Extension/AutomaticRedirectTypeExtension.php @@ -19,17 +19,14 @@ abstract class AutomaticRedirectTypeExtension extends AbstractTypeExtension { - /** @var string */ protected const FIELD_NAME = 'addAutomaticRedirect'; - /** @var SlugUpdateHandlerInterface */ - private $slugUpdateHandler; + private SlugUpdateHandlerInterface $slugUpdateHandler; - /** @var ViolationMapper */ - private $violationMapper; + private ViolationMapper $violationMapper; /** @var array */ - private $oldSlugs = []; + private array $oldSlugs = []; public function __construct(SlugUpdateHandlerInterface $slugUpdateHandler) { diff --git a/src/Model/Redirect.php b/src/Model/Redirect.php index d953b76..a7155e2 100644 --- a/src/Model/Redirect.php +++ b/src/Model/Redirect.php @@ -8,8 +8,7 @@ use DateTimeInterface; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; -use Sylius\Component\Channel\Model\ChannelInterface as BaseChannelInterface; -use Sylius\Component\Core\Model\ChannelInterface; +use Sylius\Component\Channel\Model\ChannelInterface; use Sylius\Component\Resource\Model\TimestampableTrait; use Sylius\Component\Resource\Model\ToggleableTrait; @@ -19,31 +18,23 @@ class Redirect implements RedirectInterface use ToggleableTrait; - /** @var int */ - protected $id; + protected ?int $id = null; - /** @var string|null */ - protected $source; + protected ?string $source = null; - /** @var string|null */ - protected $destination; + protected ?string $destination = null; - /** @var bool */ - protected $permanent = true; + protected bool $permanent = true; - /** @var int */ - protected $count = 0; + protected int $count = 0; - /** @var DateTimeInterface|null */ - protected $lastAccessed; + protected ?DateTimeInterface $lastAccessed = null; - /** @var bool */ - protected $only404 = true; + protected bool $only404 = true; - /** @var bool */ - protected $keepQueryString = false; + protected bool $keepQueryString = false; - /** @var Collection|ChannelInterface[] */ + /** @var Collection */ protected $channels; public function __construct() @@ -127,21 +118,21 @@ public function getChannels(): Collection return $this->channels; } - public function addChannel(BaseChannelInterface $channel): void + public function addChannel(ChannelInterface $channel): void { if (!$this->hasChannel($channel)) { $this->channels->add($channel); } } - public function removeChannel(BaseChannelInterface $channel): void + public function removeChannel(ChannelInterface $channel): void { if ($this->hasChannel($channel)) { $this->channels->removeElement($channel); } } - public function hasChannel(BaseChannelInterface $channel): bool + public function hasChannel(ChannelInterface $channel): bool { return $this->channels->contains($channel); } diff --git a/src/Model/RedirectionPath.php b/src/Model/RedirectionPath.php index aaccc6a..a7abb1f 100644 --- a/src/Model/RedirectionPath.php +++ b/src/Model/RedirectionPath.php @@ -11,15 +11,14 @@ final class RedirectionPath implements Countable /** * Array of seen redirect ids * - * @var array + * @var array */ - private $seen = []; + private array $seen = []; - /** @var RedirectInterface[] */ - private $redirects = []; + /** @var list */ + private array $redirects = []; - /** @var bool */ - private $cycle = false; + private bool $cycle = false; public function addRedirect(RedirectInterface $redirect): void { @@ -28,7 +27,7 @@ public function addRedirect(RedirectInterface $redirect): void } $this->redirects[] = $redirect; - $this->seen[$redirect->getId()] = true; + $this->seen[(int) $redirect->getId()] = true; } /** @@ -43,11 +42,11 @@ public function markAsAccessed(): void public function isEmpty(): bool { - return $this->count() === 0; + return [] === $this->redirects; } /** - * @return RedirectInterface[] + * @return list */ public function all(): array { diff --git a/src/Repository/RedirectRepository.php b/src/Repository/RedirectRepository.php index 879e688..9150b1f 100644 --- a/src/Repository/RedirectRepository.php +++ b/src/Repository/RedirectRepository.php @@ -6,16 +6,12 @@ use DateInterval; use DateTime; -use Exception; use Setono\SyliusRedirectPlugin\Model\RedirectInterface; use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository; use Sylius\Component\Channel\Model\ChannelInterface; class RedirectRepository extends EntityRepository implements RedirectRepositoryInterface { - /** - * @throws Exception - */ public function removeNotAccessed(int $threshold): void { if ($threshold <= 0) { diff --git a/src/Resolver/RedirectionPathResolver.php b/src/Resolver/RedirectionPathResolver.php index ab91edf..36aa9fd 100644 --- a/src/Resolver/RedirectionPathResolver.php +++ b/src/Resolver/RedirectionPathResolver.php @@ -12,8 +12,7 @@ final class RedirectionPathResolver implements RedirectionPathResolverInterface { - /** @var RedirectRepositoryInterface */ - private $redirectRepository; + private RedirectRepositoryInterface $redirectRepository; public function __construct(RedirectRepositoryInterface $redirectRepository) { @@ -36,8 +35,10 @@ public function resolve( } if ($redirectionPath->hasCycle()) { + $firstRedirect = $redirectionPath->first(); + throw new InfiniteLoopException( - $redirectionPath->first() !== null ? ($redirectionPath->first()->getSource() ?? $source) : $source + null !== $firstRedirect ? ($firstRedirect->getSource() ?? $source) : $source ); } } while (null !== $redirect && !$redirect->isOnly404()); // See this issue for explanation of this: https://github.com/Setono/SyliusRedirectPlugin/issues/27 diff --git a/src/SlugUpdateHandler/SlugUpdateHandler.php b/src/SlugUpdateHandler/SlugUpdateHandler.php index 335fab4..0cc2dbe 100644 --- a/src/SlugUpdateHandler/SlugUpdateHandler.php +++ b/src/SlugUpdateHandler/SlugUpdateHandler.php @@ -9,6 +9,7 @@ use Setono\SyliusRedirectPlugin\Factory\RedirectFactoryInterface; use Setono\SyliusRedirectPlugin\Finder\RemovableRedirectFinderInterface; use Sylius\Component\Channel\Model\ChannelAwareInterface; +use Sylius\Component\Channel\Model\ChannelInterface; use Sylius\Component\Channel\Model\ChannelsAwareInterface; use Sylius\Component\Resource\Model\TranslationInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -16,24 +17,22 @@ abstract class SlugUpdateHandler implements SlugUpdateHandlerInterface { - /** @var RedirectFactoryInterface */ - protected $redirectFactory; + protected RedirectFactoryInterface $redirectFactory; - /** @var EntityManagerInterface */ - protected $redirectManager; + protected EntityManagerInterface $redirectManager; - /** @var UrlGeneratorInterface */ - protected $urlGenerator; + protected UrlGeneratorInterface $urlGenerator; - /** @var RemovableRedirectFinderInterface */ - protected $removableRedirectFinder; + protected RemovableRedirectFinderInterface $removableRedirectFinder; - /** @var ValidatorInterface */ - protected $validator; + protected ValidatorInterface $validator; - /** @var array */ - protected $validationGroups; + /** @var list */ + protected array $validationGroups; + /** + * @param list $validationGroups + */ public function __construct( RedirectFactoryInterface $redirectFactory, EntityManagerInterface $redirectManager, @@ -71,10 +70,14 @@ public function handle(SlugUpdateHandlerCommand $slugUpdateHandlerCommand): void $oldUrl = $this->generateUrl($slugUpdateHandlerCommand->getOldSlug(), $locale); $newUrl = $this->generateUrl($slugUpdateHandlerCommand->getNewSlug(), $locale); + /** @var list $channels */ $channels = []; - if ($obj instanceof ChannelAwareInterface && $obj->getChannel() !== null) { - $channels[] = $obj->getChannel(); + if ($obj instanceof ChannelAwareInterface) { + $channel = $obj->getChannel(); + if (null !== $channel) { + $channels[] = $channel; + } } if ($obj instanceof ChannelsAwareInterface) { diff --git a/src/SlugUpdateHandler/SlugUpdateHandlerCommand.php b/src/SlugUpdateHandler/SlugUpdateHandlerCommand.php index 6b3c185..26f5a9b 100644 --- a/src/SlugUpdateHandler/SlugUpdateHandlerCommand.php +++ b/src/SlugUpdateHandler/SlugUpdateHandlerCommand.php @@ -6,14 +6,11 @@ final class SlugUpdateHandlerCommand { - /** @var object */ - private $object; + private object $object; - /** @var string */ - private $oldSlug; + private string $oldSlug; - /** @var string */ - private $newSlug; + private string $newSlug; public function __construct(object $object, string $oldSlug, string $newSlug) { diff --git a/src/Validator/Constraints/InfiniteLoop.php b/src/Validator/Constraints/InfiniteLoop.php index 9585cf1..674e959 100644 --- a/src/Validator/Constraints/InfiniteLoop.php +++ b/src/Validator/Constraints/InfiniteLoop.php @@ -8,8 +8,7 @@ final class InfiniteLoop extends Constraint { - /** @var string */ - public $message = 'The path creates an infinite loop'; + public string $message = 'The path creates an infinite loop'; public function getTargets(): string { diff --git a/src/Validator/Constraints/InfiniteLoopValidator.php b/src/Validator/Constraints/InfiniteLoopValidator.php index f63d0eb..1ec489b 100644 --- a/src/Validator/Constraints/InfiniteLoopValidator.php +++ b/src/Validator/Constraints/InfiniteLoopValidator.php @@ -15,11 +15,9 @@ final class InfiniteLoopValidator extends ConstraintValidator { - /** @var ChannelRepositoryInterface */ - private $channelRepository; + private ChannelRepositoryInterface $channelRepository; - /** @var RedirectionPathResolverInterface */ - private $redirectionPathResolver; + private RedirectionPathResolverInterface $redirectionPathResolver; public function __construct( ChannelRepositoryInterface $channelRepository, @@ -30,35 +28,36 @@ public function __construct( } /** - * @param mixed $redirect + * @param mixed $value */ - public function validate($redirect, Constraint $constraint): void + public function validate($value, Constraint $constraint): void { - if (null === $redirect) { + if (null === $value) { return; } if (!$constraint instanceof InfiniteLoop) { - throw new UnexpectedTypeException($redirect, InfiniteLoop::class); + throw new UnexpectedTypeException($value, InfiniteLoop::class); } - if (!$redirect instanceof RedirectInterface) { - throw new UnexpectedTypeException($redirect, RedirectInterface::class); + if (!$value instanceof RedirectInterface) { + throw new UnexpectedTypeException($value, RedirectInterface::class); } - if ($redirect->getSource() === null) { + $source = $value->getSource(); + if (null === $source) { return; } - if (!$redirect->isEnabled()) { + if (!$value->isEnabled()) { return; } try { /** @var ChannelInterface $channel */ foreach ($this->channelRepository->findAll() as $channel) { - $this->redirectionPathResolver->resolve($redirect->getSource(), $channel); - $this->redirectionPathResolver->resolve($redirect->getSource(), $channel, true); + $this->redirectionPathResolver->resolve($source, $channel); + $this->redirectionPathResolver->resolve($source, $channel, true); } } catch (InfiniteLoopException $e) { $this->context->buildViolation($constraint->message) diff --git a/src/Validator/Constraints/Source.php b/src/Validator/Constraints/Source.php index 3543a54..6be1e76 100644 --- a/src/Validator/Constraints/Source.php +++ b/src/Validator/Constraints/Source.php @@ -8,8 +8,7 @@ final class Source extends Constraint { - /** @var string */ - public $message = 'There is already a redirection with source "{{ source }}". Redirection ID : {{ conflictingId }}'; + public string $message = 'There is already a redirection with source "{{ source }}". Redirection ID : {{ conflictingId }}'; public function getTargets(): string { diff --git a/src/Validator/Constraints/SourceRegexValidator.php b/src/Validator/Constraints/SourceRegexValidator.php index 4190754..3486c43 100644 --- a/src/Validator/Constraints/SourceRegexValidator.php +++ b/src/Validator/Constraints/SourceRegexValidator.php @@ -10,8 +10,7 @@ final class SourceRegexValidator extends RegexValidator { - /** @var string */ - private $pattern; + private string $pattern; public function __construct(string $pattern) { diff --git a/src/Validator/Constraints/SourceValidator.php b/src/Validator/Constraints/SourceValidator.php index 4d2e335..8710737 100644 --- a/src/Validator/Constraints/SourceValidator.php +++ b/src/Validator/Constraints/SourceValidator.php @@ -12,8 +12,7 @@ final class SourceValidator extends ConstraintValidator { - /** @var RedirectRepositoryInterface */ - private $redirectRepository; + private RedirectRepositoryInterface $redirectRepository; public function __construct(RedirectRepositoryInterface $redirectRepository) { @@ -21,45 +20,47 @@ public function __construct(RedirectRepositoryInterface $redirectRepository) } /** - * @param mixed $redirect + * @param mixed $value */ - public function validate($redirect, Constraint $constraint): void + public function validate($value, Constraint $constraint): void { - if (null === $redirect) { + if (null === $value) { return; } if (!$constraint instanceof Source) { - throw new UnexpectedTypeException($redirect, Source::class); + throw new UnexpectedTypeException($value, Source::class); } - if (!$redirect instanceof RedirectInterface) { - throw new UnexpectedTypeException($redirect, RedirectInterface::class); + if (!$value instanceof RedirectInterface) { + throw new UnexpectedTypeException($value, RedirectInterface::class); } - if ($redirect->getSource() === null) { + $source = $value->getSource(); + + if (null === $source) { return; } - if (!$redirect->isEnabled()) { + if (!$value->isEnabled()) { return; } - if ($redirect->getChannels()->isEmpty()) { - $conflictingRedirect = $this->redirectRepository->findOneEnabledBySource($redirect->getSource()); - if (null === $conflictingRedirect || $redirect->getId() === $conflictingRedirect->getId()) { + if ($value->getChannels()->isEmpty()) { + $conflictingRedirect = $this->redirectRepository->findOneEnabledBySource($source); + if (null === $conflictingRedirect || $value->getId() === $conflictingRedirect->getId()) { return; } - $this->buildViolation($constraint, $redirect->getSource(), (int) $conflictingRedirect->getId()); + $this->buildViolation($constraint, $source, (int) $conflictingRedirect->getId()); } else { - foreach ($redirect->getChannels() as $channel) { - $conflictingRedirect = $this->redirectRepository->findOneEnabledBySource($redirect->getSource(), $channel); - if (null === $conflictingRedirect || $redirect->getId() === $conflictingRedirect->getId()) { + foreach ($value->getChannels() as $channel) { + $conflictingRedirect = $this->redirectRepository->findOneEnabledBySource($source, $channel); + if (null === $conflictingRedirect || $value->getId() === $conflictingRedirect->getId()) { return; } - $this->buildViolation($constraint, $redirect->getSource(), (int) $conflictingRedirect->getId()); + $this->buildViolation($constraint, $source, (int) $conflictingRedirect->getId()); } } } diff --git a/tests/Behat/Context/Setup/RedirectContext.php b/tests/Behat/Context/Setup/RedirectContext.php index 36c19f9..0003920 100644 --- a/tests/Behat/Context/Setup/RedirectContext.php +++ b/tests/Behat/Context/Setup/RedirectContext.php @@ -12,11 +12,9 @@ final class RedirectContext implements Context { - /** @var RepositoryInterface */ - private $redirectRepository; + private RepositoryInterface $redirectRepository; - /** @var FactoryInterface */ - private $redirectFactory; + private FactoryInterface $redirectFactory; public function __construct(RepositoryInterface $brandRepository, FactoryInterface $brandFactory) { diff --git a/tests/Behat/Context/Transform/RedirectContext.php b/tests/Behat/Context/Transform/RedirectContext.php index 3854cdc..4e447c8 100644 --- a/tests/Behat/Context/Transform/RedirectContext.php +++ b/tests/Behat/Context/Transform/RedirectContext.php @@ -10,8 +10,7 @@ final class RedirectContext implements Context { - /** @var RepositoryInterface */ - private $redirectRepository; + private RepositoryInterface $redirectRepository; public function __construct(RepositoryInterface $redirectRepository) { diff --git a/tests/Behat/Context/Ui/Admin/ManagingRedirectsContext.php b/tests/Behat/Context/Ui/Admin/ManagingRedirectsContext.php index 54e6015..08719e3 100644 --- a/tests/Behat/Context/Ui/Admin/ManagingRedirectsContext.php +++ b/tests/Behat/Context/Ui/Admin/ManagingRedirectsContext.php @@ -13,14 +13,11 @@ final class ManagingRedirectsContext implements Context { - /** @var IndexRedirectPage */ - private $indexRedirectPage; + private IndexRedirectPage $indexRedirectPage; - /** @var CreateRedirectPage */ - private $createRedirectPage; + private CreateRedirectPage $createRedirectPage; - /** @var UpdateRedirectPage */ - private $updateRedirectPage; + private UpdateRedirectPage $updateRedirectPage; public function __construct(IndexRedirectPage $indexRedirectPage, CreateRedirectPage $createRedirectPage, UpdateRedirectPage $updateRedirectPage) { diff --git a/tests/Behat/Context/Ui/Shop/RedirectContext.php b/tests/Behat/Context/Ui/Shop/RedirectContext.php index 48f3b5c..953bedf 100644 --- a/tests/Behat/Context/Ui/Shop/RedirectContext.php +++ b/tests/Behat/Context/Ui/Shop/RedirectContext.php @@ -9,8 +9,7 @@ final class RedirectContext implements Context { - /** @var Page */ - private $oldPathPage; + private Page $oldPathPage; public function __construct(Page $oldPathPage) {