From 2a561e85aa06ad1cb9ca48957a64e900752bf53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Mon, 31 Aug 2026 10:28:51 +0200 Subject: [PATCH 1/5] Upgrade to Sylius 1.14 and switch from Psalm to PHPStan Follows the Setono plugin skeleton 1.14.x branch: - setono/sylius-plugin-pack ~1.14.1 (Sylius 1.14, PHPStan, Rector 2, Infection 0.29) - Symfony constraints narrowed to ^6.4 (the only line Sylius 1.14 supports) - psalm.xml replaced by phpstan.neon (level max) with kernel/object manager loaders - src/ made PHPStan-clean without a baseline: generic EventSubscriber with an explicit track(object $event), generics on Sylius repositories and factories, typed fixture options, corrected @var hints - phpunit.xml.dist: remove stale AppKernel reference, add coverage config Claude-Session: https://claude.ai/code/session_013jh2QjzkxAJABPDYB1UiPS --- .gitattributes | 4 +- .gitignore | 1 + composer.json | 46 +++++++++++-------- phpstan.neon | 34 ++++++++++++++ phpunit.xml.dist | 14 +++--- psalm.xml | 35 -------------- src/Context/PixelContext.php | 4 +- src/DependencyInjection/Configuration.php | 1 - .../SetonoSyliusFacebookExtension.php | 4 +- src/Event/CategoryViewedEvent.php | 3 ++ src/Event/ProductAddedToCartEvent.php | 1 - src/Event/ProductViewedEvent.php | 1 - src/EventSubscriber/AddToCartSubscriber.php | 3 ++ src/EventSubscriber/EventSubscriber.php | 20 +++++--- src/EventSubscriber/PurchaseSubscriber.php | 6 +++ .../StartCheckoutSubscriber.php | 3 ++ .../ViewCategorySubscriber.php | 5 ++ src/EventSubscriber/ViewProductSubscriber.php | 3 ++ src/Fixture/Factory/PixelExampleFactory.php | 16 ++++++- src/Model/Pixel.php | 5 +- src/Repository/PixelRepositoryInterface.php | 3 ++ src/SetonoSyliusFacebookPlugin.php | 3 ++ tests/PHPStan/console_application.php | 13 ++++++ tests/PHPStan/object_manager.php | 13 ++++++ 24 files changed, 155 insertions(+), 86 deletions(-) create mode 100644 phpstan.neon delete mode 100644 psalm.xml create mode 100644 tests/PHPStan/console_application.php create mode 100644 tests/PHPStan/object_manager.php diff --git a/.gitattributes b/.gitattributes index 260e1eb..311592c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,7 +14,7 @@ /infection.json.dist export-ignore /node_modules export-ignore /phpunit.xml.dist export-ignore -/psalm-baseline.xml export-ignore -/psalm.xml export-ignore +/phpstan-baseline.neon export-ignore +/phpstan.neon export-ignore /rector.php export-ignore /tests export-ignore diff --git a/.gitignore b/.gitignore index 4c0aa2d..4899dfc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /tests/Application/yarn.lock +/.phpunit.cache/ /.phpunit.result.cache # Symfony CLI https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project diff --git a/composer.json b/composer.json index cf84ae0..7095c6e 100644 --- a/composer.json +++ b/composer.json @@ -31,34 +31,36 @@ "sylius/resource-bundle": "^1.6", "sylius/taxonomy": "^1.0", "sylius/ui-bundle": "^1.0", - "symfony/config": "^5.4 || ^6.4 || ^7.0", - "symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", - "symfony/form": "^5.4 || ^6.4 || ^7.0", - "symfony/http-foundation": "^5.4 || ^6.4 || ^7.0", - "symfony/http-kernel": "^5.4 || ^6.4 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", + "symfony/config": "^6.4", + "symfony/dependency-injection": "^6.4", + "symfony/event-dispatcher": "^6.4", + "symfony/form": "^6.4", + "symfony/http-foundation": "^6.4", + "symfony/http-kernel": "^6.4", + "symfony/options-resolver": "^6.4", "webmozart/assert": "^1.11" }, "require-dev": { - "api-platform/core": "^2.7", + "api-platform/core": "^2.7.16", "babdev/pagerfanta-bundle": "^3.8", "behat/behat": "^3.14", "doctrine/doctrine-bundle": "^2.11", "jms/serializer-bundle": "^4.2", - "lexik/jwt-authentication-bundle": "^2.16", + "lexik/jwt-authentication-bundle": "^2.17", "nyholm/psr7": "^1.8", - "setono/sylius-plugin-pack": "^1.12", + "setono/sylius-plugin-pack": "~1.14.1", "setono/tag-bag": "^2.3", "setono/tag-bag-bundle": "^3.0", - "symfony/debug-bundle": "^5.4 || ^6.4 || ^7.0", - "symfony/dotenv": "^5.4 || ^6.4 || ^7.0", - "symfony/http-client": "^5.4 || ^6.4 || ^7.0", - "symfony/intl": "^5.4 || ^6.4 || ^7.0", - "symfony/property-info": "^5.4 || ^6.4 || ^7.0", - "symfony/serializer": "^5.4 || ^6.4 || ^7.0", - "symfony/web-profiler-bundle": "^5.4 || ^6.4 || ^7.0", - "symfony/webpack-encore-bundle": "^1.14", + "shipmonk/composer-dependency-analyser": "^1.6", + "sylius-labs/polyfill-symfony-security": "^1.1.2", + "symfony/debug-bundle": "^6.4", + "symfony/dotenv": "^6.4", + "symfony/http-client": "^6.4", + "symfony/intl": "^6.4", + "symfony/property-info": "^6.4", + "symfony/serializer": "^6.4", + "symfony/web-profiler-bundle": "^6.4", + "symfony/webpack-encore-bundle": "^1.17.2", "willdurand/negotiation": "^3.1" }, "prefer-stable": true, @@ -77,15 +79,19 @@ }, "config": { "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": false, + "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true, "infection/extension-installer": true, + "phpstan/extension-installer": true, "symfony/thanks": false }, + "audit": { + "block-insecure": false + }, "sort-packages": true }, "scripts": { - "analyse": "psalm", + "analyse": "phpstan analyse", "check-style": "ecs check", "fix-style": "ecs check --fix", "phpunit": "phpunit" diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..9b855ff --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,34 @@ +parameters: + level: max + + paths: + - src + - tests + + excludePaths: + - tests/Application/* + + bootstrapFiles: + - vendor/autoload.php + + # Symfony Configuration + symfony: + consoleApplicationLoader: tests/PHPStan/console_application.php + + # Doctrine Configuration + doctrine: + repositoryClass: Doctrine\ORM\EntityRepository + objectManagerLoader: tests/PHPStan/object_manager.php + # Sylius resources keep required fields nullable until they are set through the form (e.g. Pixel::$pixelId) + allowNullablePropertyForRequiredField: true + + reportUnmatchedIgnoredErrors: false + treatPhpDocTypesAsCertain: false + + ignoreErrors: + # Sylius maps associations to interfaces (e.g. ChannelInterface) and resolves them to the host application's + # concrete entity at runtime via resolve_target_entities. The interface is therefore the correct static type, + # even though phpstan-doctrine compares against the resolved concrete class. + - + identifier: doctrine.associationType + path: src/Model/* diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1042a69..06c44a7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,19 +1,19 @@ - + + + src/ + + tests - - - - + diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index b348f9b..0000000 --- a/psalm.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Context/PixelContext.php b/src/Context/PixelContext.php index 11331f4..e60f471 100644 --- a/src/Context/PixelContext.php +++ b/src/Context/PixelContext.php @@ -25,9 +25,7 @@ public function __construct( public function getPixels(): array { - if (null === $this->pixels) { - $this->pixels = $this->pixelRepository->findEnabledByChannel($this->channelContext->getChannel()); - } + $this->pixels ??= $this->pixelRepository->findEnabledByChannel($this->channelContext->getChannel()); return $this->pixels; } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ba1ba74..98f5df3 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -29,7 +29,6 @@ public function getConfigTreeBuilder(): TreeBuilder private function addResourcesSection(ArrayNodeDefinition $node): void { - /** @psalm-suppress MixedMethodCall,PossiblyUndefinedMethod,PossiblyNullReference,UndefinedInterfaceMethod */ $node ->children() ->arrayNode('resources') diff --git a/src/DependencyInjection/SetonoSyliusFacebookExtension.php b/src/DependencyInjection/SetonoSyliusFacebookExtension.php index 01613f3..d2aac91 100644 --- a/src/DependencyInjection/SetonoSyliusFacebookExtension.php +++ b/src/DependencyInjection/SetonoSyliusFacebookExtension.php @@ -15,9 +15,7 @@ final class SetonoSyliusFacebookExtension extends AbstractResourceExtension public function load(array $configs, ContainerBuilder $container): void { /** - * @psalm-suppress PossiblyNullArgument - * - * @var array{driver: string, resources: array} $config + * @var array{driver: string, resources: array>} $config */ $config = $this->processConfiguration($this->getConfiguration([], $container), $configs); $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); diff --git a/src/Event/CategoryViewedEvent.php b/src/Event/CategoryViewedEvent.php index 6e42dae..4b50869 100644 --- a/src/Event/CategoryViewedEvent.php +++ b/src/Event/CategoryViewedEvent.php @@ -26,6 +26,9 @@ public function __construct(TaxonInterface $taxon, array $products = []) $this->customData->contentCategory = $this->getBreadcrumb($taxon); } + /** + * @return list + */ private function getBreadcrumbs(TaxonInterface $taxon): array { $breadcrumbs = []; diff --git a/src/Event/ProductAddedToCartEvent.php b/src/Event/ProductAddedToCartEvent.php index 94a0b8a..3c5ffb4 100644 --- a/src/Event/ProductAddedToCartEvent.php +++ b/src/Event/ProductAddedToCartEvent.php @@ -88,7 +88,6 @@ private function getTaxonName(ProductInterface $product): ?string return null; } - /** @var mixed|TaxonInterface $taxon */ $taxon = $taxons->first(); Assert::isInstanceOf($taxon, TaxonInterface::class); diff --git a/src/Event/ProductViewedEvent.php b/src/Event/ProductViewedEvent.php index 45c97b1..768d896 100644 --- a/src/Event/ProductViewedEvent.php +++ b/src/Event/ProductViewedEvent.php @@ -33,7 +33,6 @@ private function getTaxonName(ProductInterface $product): ?string return null; } - /** @var mixed|TaxonInterface $taxon */ $taxon = $taxons->first(); Assert::isInstanceOf($taxon, TaxonInterface::class); diff --git a/src/EventSubscriber/AddToCartSubscriber.php b/src/EventSubscriber/AddToCartSubscriber.php index 7341447..81e0f5d 100644 --- a/src/EventSubscriber/AddToCartSubscriber.php +++ b/src/EventSubscriber/AddToCartSubscriber.php @@ -12,6 +12,9 @@ use Sylius\Component\Order\Context\CartContextInterface; use Webmozart\Assert\Assert; +/** + * @extends EventSubscriber + */ final class AddToCartSubscriber extends EventSubscriber { public function __construct( diff --git a/src/EventSubscriber/EventSubscriber.php b/src/EventSubscriber/EventSubscriber.php index 5b7f564..8e57a7f 100644 --- a/src/EventSubscriber/EventSubscriber.php +++ b/src/EventSubscriber/EventSubscriber.php @@ -8,6 +8,7 @@ use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; +use Setono\MetaConversionsApi\Event\Event; use Setono\MetaConversionsApiBundle\Event\ConversionsApiEventRaised; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Throwable; @@ -18,6 +19,8 @@ * Since we do not deem Facebook to be 'mission critical', we will catch all errors related to * sending an event to Facebook and log it as an error. This way the error won't interfere with any * 'real' business, i.e. buying stuff, but it will still be logged correctly, so that developers can act upon it + * + * @template TEvent of object */ abstract class EventSubscriber implements EventSubscriberInterface, LoggerAwareInterface { @@ -28,25 +31,28 @@ public function __construct(private readonly EventDispatcherInterface $eventDisp $this->logger = new NullLogger(); } - public function track(): void + /** + * @param TEvent $event + */ + public function track(object $event): void { try { - $event = $this->callback()(...func_get_args()); - if (null === $event) { + $conversionsApiEvent = $this->callback()($event); + if (null === $conversionsApiEvent) { return; } - $this->eventDispatcher->dispatch(new ConversionsApiEventRaised($event)); + $this->eventDispatcher->dispatch(new ConversionsApiEventRaised($conversionsApiEvent)); } catch (Throwable $e) { $this->logger->error($e->getMessage()); } } /** - * This callable will receive the event arguments coming from the originating event, - * and it must return a Setono\MetaConversionsApi\Event\Event + * This callable will receive the event from the originating event dispatch, + * and it must return a Setono\MetaConversionsApi\Event\Event (or null if nothing should be tracked) * - * @return callable(... mixed): ?\Setono\MetaConversionsApi\Event\Event + * @return callable(TEvent): ?Event */ abstract protected function callback(): callable; diff --git a/src/EventSubscriber/PurchaseSubscriber.php b/src/EventSubscriber/PurchaseSubscriber.php index c0575c6..c9d4ad8 100644 --- a/src/EventSubscriber/PurchaseSubscriber.php +++ b/src/EventSubscriber/PurchaseSubscriber.php @@ -12,8 +12,14 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; +/** + * @extends EventSubscriber + */ final class PurchaseSubscriber extends EventSubscriber { + /** + * @param OrderRepositoryInterface $orderRepository + */ public function __construct( EventDispatcherInterface $eventDispatcher, private readonly OrderRepositoryInterface $orderRepository, diff --git a/src/EventSubscriber/StartCheckoutSubscriber.php b/src/EventSubscriber/StartCheckoutSubscriber.php index df2149b..cc85350 100644 --- a/src/EventSubscriber/StartCheckoutSubscriber.php +++ b/src/EventSubscriber/StartCheckoutSubscriber.php @@ -12,6 +12,9 @@ use Symfony\Component\HttpKernel\KernelEvents; use Webmozart\Assert\Assert; +/** + * @extends EventSubscriber + */ final class StartCheckoutSubscriber extends EventSubscriber { public function __construct( diff --git a/src/EventSubscriber/ViewCategorySubscriber.php b/src/EventSubscriber/ViewCategorySubscriber.php index 273ea6b..73c90ae 100644 --- a/src/EventSubscriber/ViewCategorySubscriber.php +++ b/src/EventSubscriber/ViewCategorySubscriber.php @@ -17,9 +17,14 @@ /** * See https://developers.facebook.com/docs/marketing-api/audiences/guides/dynamic-product-audiences/#setuppixel * for reference of the 'ViewCategory' custom event + * + * @extends EventSubscriber */ final class ViewCategorySubscriber extends EventSubscriber { + /** + * @param TaxonRepositoryInterface $taxonRepository + */ public function __construct( EventDispatcherInterface $eventDispatcher, private readonly LocaleContextInterface $localeContext, diff --git a/src/EventSubscriber/ViewProductSubscriber.php b/src/EventSubscriber/ViewProductSubscriber.php index 48ed122..2c851ec 100644 --- a/src/EventSubscriber/ViewProductSubscriber.php +++ b/src/EventSubscriber/ViewProductSubscriber.php @@ -9,6 +9,9 @@ use Sylius\Component\Core\Model\ProductInterface; use Webmozart\Assert\Assert; +/** + * @extends EventSubscriber + */ final class ViewProductSubscriber extends EventSubscriber { public static function getSubscribedEvents(): array diff --git a/src/Fixture/Factory/PixelExampleFactory.php b/src/Fixture/Factory/PixelExampleFactory.php index 4284264..0a6b12d 100644 --- a/src/Fixture/Factory/PixelExampleFactory.php +++ b/src/Fixture/Factory/PixelExampleFactory.php @@ -21,6 +21,10 @@ class PixelExampleFactory extends AbstractExampleFactory private readonly OptionsResolver $optionsResolver; + /** + * @param FactoryInterface $pixelFactory + * @param ChannelRepositoryInterface $channelRepository + */ public function __construct( private readonly FactoryInterface $pixelFactory, private readonly ChannelRepositoryInterface $channelRepository, @@ -31,18 +35,24 @@ public function __construct( $this->configureOptions($this->optionsResolver); } + /** + * @param array $options + */ public function create(array $options = []): PixelInterface { $options = $this->optionsResolver->resolve($options); - /** @var PixelInterface $pixel */ $pixel = $this->pixelFactory->createNew(); if (array_key_exists('pixel_id', $options)) { + Assert::numeric($options['pixel_id']); + $pixel->setPixelId((string) $options['pixel_id']); } if (array_key_exists('access_token', $options)) { - $pixel->setAccessToken((string) $options['access_token']); + Assert::string($options['access_token']); + + $pixel->setAccessToken($options['access_token']); } else { $pixel->setAccessToken($this->faker->randomAscii); } @@ -54,6 +64,8 @@ public function create(array $options = []): PixelInterface } if (array_key_exists('channels', $options)) { + Assert::isIterable($options['channels']); + foreach ($options['channels'] as $channel) { Assert::isInstanceOf($channel, ChannelInterface::class); diff --git a/src/Model/Pixel.php b/src/Model/Pixel.php index 7e810c1..c21b5b9 100644 --- a/src/Model/Pixel.php +++ b/src/Model/Pixel.php @@ -19,10 +19,7 @@ class Pixel implements PixelInterface, \Stringable protected ?string $accessToken = null; - /** - * @var Collection|BaseChannelInterface[] - * @psalm-var Collection - */ + /** @var Collection */ protected Collection $channels; public function __construct() diff --git a/src/Repository/PixelRepositoryInterface.php b/src/Repository/PixelRepositoryInterface.php index 86c1f9e..2df879b 100644 --- a/src/Repository/PixelRepositoryInterface.php +++ b/src/Repository/PixelRepositoryInterface.php @@ -8,6 +8,9 @@ use Sylius\Component\Channel\Model\ChannelInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; +/** + * @extends RepositoryInterface + */ interface PixelRepositoryInterface extends RepositoryInterface { /** diff --git a/src/SetonoSyliusFacebookPlugin.php b/src/SetonoSyliusFacebookPlugin.php index 400378a..6797e04 100644 --- a/src/SetonoSyliusFacebookPlugin.php +++ b/src/SetonoSyliusFacebookPlugin.php @@ -14,6 +14,9 @@ final class SetonoSyliusFacebookPlugin extends AbstractResourceBundle { use SyliusPluginTrait; + /** + * @return list + */ public function getSupportedDrivers(): array { return [ diff --git a/tests/PHPStan/console_application.php b/tests/PHPStan/console_application.php new file mode 100644 index 0000000..6ee9914 --- /dev/null +++ b/tests/PHPStan/console_application.php @@ -0,0 +1,13 @@ +boot(); + +return new Application($kernel); diff --git a/tests/PHPStan/object_manager.php b/tests/PHPStan/object_manager.php new file mode 100644 index 0000000..6ea2e22 --- /dev/null +++ b/tests/PHPStan/object_manager.php @@ -0,0 +1,13 @@ +boot(); + +/** @phpstan-ignore method.notFound,method.nonObject */ +return $kernel->getContainer()->get('doctrine')->getManager(); From c58959f1ff458c6b45d87d5241d17aac6078386c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Mon, 31 Aug 2026 10:28:51 +0200 Subject: [PATCH 2/5] Upgrade test application to Sylius 1.14 - bundles.php in skeleton 1.14 order (state machine abstraction, calendar, SyliusTestPlugin, test_cached env), keeping the Setono bundles - Frontend built with @sylius-ui/frontend and Node 20 (.nvmrc); entries point at the vendored Sylius bundles, dead assets/ removed - Disable Sylius telemetry in the test application Claude-Session: https://claude.ai/code/session_013jh2QjzkxAJABPDYB1UiPS --- tests/Application/.env | 5 ++++ tests/Application/.gitignore | 2 ++ tests/Application/.nvmrc | 1 + tests/Application/assets/admin/entry.js | 1 - tests/Application/assets/shop/entry.js | 1 - tests/Application/composer.json | 2 +- tests/Application/config/bundles.php | 12 +++++---- tests/Application/package.json | 34 ++++++++----------------- tests/Application/webpack.config.js | 6 +++-- 9 files changed, 30 insertions(+), 34 deletions(-) create mode 100644 tests/Application/.nvmrc delete mode 100644 tests/Application/assets/admin/entry.js delete mode 100644 tests/Application/assets/shop/entry.js diff --git a/tests/Application/.env b/tests/Application/.env index f01628d..e74f02c 100644 --- a/tests/Application/.env +++ b/tests/Application/.env @@ -44,3 +44,8 @@ MAILER_DSN=null://localhost FACEBOOK_PIXEL_ID=1234567 FACEBOOK_ACCESS_TOKEN=wsdfWasdfsaAWEsdamas ###< setono/sylius-facebook-plugin ### + +###> sylius/sylius ### +# Telemetry is enabled by default in Sylius 1.14; keep the test application quiet +SYLIUS_TELEMETRY_ENABLED=0 +###< sylius/sylius ### diff --git a/tests/Application/.gitignore b/tests/Application/.gitignore index bc600a8..86a1e43 100644 --- a/tests/Application/.gitignore +++ b/tests/Application/.gitignore @@ -1,3 +1,5 @@ +/config/reference.php + /public/assets /public/build /public/css diff --git a/tests/Application/.nvmrc b/tests/Application/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/tests/Application/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/tests/Application/assets/admin/entry.js b/tests/Application/assets/admin/entry.js deleted file mode 100644 index 635f5ac..0000000 --- a/tests/Application/assets/admin/entry.js +++ /dev/null @@ -1 +0,0 @@ -import 'sylius/bundle/AdminBundle/Resources/private/entry'; diff --git a/tests/Application/assets/shop/entry.js b/tests/Application/assets/shop/entry.js deleted file mode 100644 index aadc317..0000000 --- a/tests/Application/assets/shop/entry.js +++ /dev/null @@ -1 +0,0 @@ -import 'sylius/bundle/ShopBundle/Resources/private/entry'; diff --git a/tests/Application/composer.json b/tests/Application/composer.json index 326735f..fc1a28d 100644 --- a/tests/Application/composer.json +++ b/tests/Application/composer.json @@ -1,5 +1,5 @@ { - "name": "sylius/plugin-skeleton-test-application", + "name": "setono/sylius-facebook-plugin-test-application", "description": "Sylius application for plugin testing purposes (composer.json needed for project dir resolving)", "license": "MIT" } diff --git a/tests/Application/config/bundles.php b/tests/Application/config/bundles.php index c95d633..379fbd2 100644 --- a/tests/Application/config/bundles.php +++ b/tests/Application/config/bundles.php @@ -8,6 +8,8 @@ Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], + Sylius\Abstraction\StateMachine\SyliusStateMachineAbstractionBundle::class => ['all' => true], + Sylius\Calendar\SyliusCalendarBundle::class => ['all' => true], Sylius\Bundle\OrderBundle\SyliusOrderBundle::class => ['all' => true], Sylius\Bundle\MoneyBundle\SyliusMoneyBundle::class => ['all' => true], Sylius\Bundle\CurrencyBundle\SyliusCurrencyBundle::class => ['all' => true], @@ -38,27 +40,27 @@ FOS\RestBundle\FOSRestBundle::class => ['all' => true], Knp\Bundle\GaufretteBundle\KnpGaufretteBundle::class => ['all' => true], Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true], - League\FlysystemBundle\FlysystemBundle::class => ['all' => true], Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true], Payum\Bundle\PayumBundle\PayumBundle::class => ['all' => true], Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true], + BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Sylius\Bundle\FixturesBundle\SyliusFixturesBundle::class => ['all' => true], Sylius\Bundle\PayumBundle\SyliusPayumBundle::class => ['all' => true], Sylius\Bundle\ThemeBundle\SyliusThemeBundle::class => ['all' => true], Sylius\Bundle\AdminBundle\SyliusAdminBundle::class => ['all' => true], Sylius\Bundle\ShopBundle\SyliusShopBundle::class => ['all' => true], - Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], - Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true], + Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true], + Sylius\Behat\Application\SyliusTestPlugin\SyliusTestPlugin::class => ['test' => true, 'test_cached' => true], ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true], Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true], SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true], - BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true], SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class => ['all' => true], + League\FlysystemBundle\FlysystemBundle::class => ['all' => true], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], Setono\BotDetectionBundle\SetonoBotDetectionBundle::class => ['all' => true], Setono\MetaConversionsApiBundle\SetonoMetaConversionsApiBundle::class => ['all' => true], Setono\TagBagBundle\SetonoTagBagBundle::class => ['all' => true], - Sylius\Calendar\SyliusCalendarBundle::class => ['all' => true], ]; diff --git a/tests/Application/package.json b/tests/Application/package.json index 8f62c4c..a05e083 100644 --- a/tests/Application/package.json +++ b/tests/Application/package.json @@ -1,30 +1,16 @@ { - "dependencies": { - "chart.js": "^3.9", - "jquery": "^3.6", - "jquery.dirtyforms": "^2.0", - "lightbox2": "^2.9", - "semantic-ui-css": "^2.2", - "slick-carousel": "^1.8" - }, - "devDependencies": { - "@symfony/webpack-encore": "^1.8", - "eslint": "^8.18", - "eslint-config-airbnb-base": "^15.0", - "eslint-import-resolver-babel-module": "^5.3", - "eslint-plugin-import": "^2.26", - "node-sass": "^7.0", - "sass-loader": "^12.0" - }, + "license": "UNLICENSED", "scripts": { - "dev": "encore dev", - "build": "encore production", + "build": "encore dev", + "build:prod": "encore production", + "postinstall": "semantic-ui-css-patch", + "lint": "yarn lint:js", "watch": "encore dev --watch" }, - "repository": { - "type": "git", - "url": "git+https://github.com/Sylius/Sylius.git" + "devDependencies": { + "@sylius-ui/frontend": "^1.0.3" }, - "author": "Paweł Jędrzejewski", - "license": "MIT" + "resolutions": { + "jquery": "^3.7.1" + } } diff --git a/tests/Application/webpack.config.js b/tests/Application/webpack.config.js index fae1429..0335bfc 100644 --- a/tests/Application/webpack.config.js +++ b/tests/Application/webpack.config.js @@ -9,7 +9,7 @@ const uiBundleResources = path.resolve(syliusBundles, 'UiBundle/Resources/privat Encore .setOutputPath('public/build/shop/') .setPublicPath('/build/shop') - .addEntry('shop-entry', './assets/shop/entry.js') + .addEntry('shop-entry', '../../vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/private/entry.js') .disableSingleRuntimeChunk() .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) @@ -29,7 +29,7 @@ Encore.reset(); Encore .setOutputPath('public/build/admin/') .setPublicPath('/build/admin') - .addEntry('admin-entry', './assets/admin/entry.js') + .addEntry('admin-entry', '../../vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/private/entry.js') .disableSingleRuntimeChunk() .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) @@ -44,4 +44,6 @@ adminConfig.resolve.alias['sylius/bundle'] = syliusBundles; adminConfig.externals = Object.assign({}, adminConfig.externals, { window: 'window', document: 'document' }); adminConfig.name = 'admin'; +Encore.reset(); + module.exports = [shopConfig, adminConfig]; From 80fcb06123a8428bd92b343eefee35466a2caa22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Mon, 31 Aug 2026 10:28:51 +0200 Subject: [PATCH 3/5] Update CI for Sylius 1.14 PHP 8.1-8.3, Symfony ~6.4.0 only, actions/checkout@v5, Rector enforced, static analysis via composer analyse (PHPStan). Claude-Session: https://claude.ai/code/session_013jh2QjzkxAJABPDYB1UiPS --- .github/workflows/build.yaml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7fc9deb..1aab9f3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -31,7 +31,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -56,7 +56,6 @@ jobs: - name: "Rector" run: "vendor/bin/rector process --dry-run" - continue-on-error: true - name: "Lint yaml files" run: "(cd tests/Application && bin/console lint:yaml ../../src/Resources)" @@ -74,18 +73,18 @@ jobs: php-version: - "8.1" - "8.2" + - "8.3" dependencies: - "lowest" - "highest" symfony: - - "~5.4.0" - "~6.4.0" steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -121,18 +120,18 @@ jobs: php-version: - "8.1" - "8.2" + - "8.3" dependencies: - "lowest" - "highest" symfony: - - "~5.4.0" - "~6.4.0" steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -153,7 +152,7 @@ jobs: dependency-versions: "${{ matrix.dependencies }}" - name: "Static analysis" - run: "vendor/bin/psalm --php-version=${{ matrix.php-version }}" + run: "composer analyse" unit-tests: name: "Unit tests (PHP${{ matrix.php-version }} | Deps: ${{ matrix.dependencies }} | SF${{ matrix.symfony }})" @@ -165,18 +164,18 @@ jobs: php-version: - "8.1" - "8.2" + - "8.3" dependencies: - "lowest" - "highest" symfony: - - "~5.4.0" - "~6.4.0" steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -206,13 +205,13 @@ jobs: php-version: - "8.1" - "8.2" + - "8.3" dependencies: - "lowest" - "highest" symfony: - - "~5.4.0" - "~6.4.0" steps: @@ -220,7 +219,7 @@ jobs: run: "sudo /etc/init.d/mysql start" - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -257,14 +256,14 @@ jobs: strategy: matrix: php-version: - - "8.2" + - "8.3" dependencies: - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -291,14 +290,14 @@ jobs: strategy: matrix: php-version: - - "8.2" + - "8.3" dependencies: - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" From 09bb7ac64dc1a292b755e62bcc8f70780990c4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Mon, 31 Aug 2026 10:33:48 +0200 Subject: [PATCH 4/5] Use actions/checkout@v7 Claude-Session: https://claude.ai/code/session_013jh2QjzkxAJABPDYB1UiPS --- .../workflows/backwards-compatibility-check.yaml | 2 +- .github/workflows/build.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/backwards-compatibility-check.yaml b/.github/workflows/backwards-compatibility-check.yaml index 806dd6a..ad10555 100644 --- a/.github/workflows/backwards-compatibility-check.yaml +++ b/.github/workflows/backwards-compatibility-check.yaml @@ -13,7 +13,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v7" with: fetch-depth: 0 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1aab9f3..cb0d16d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -31,7 +31,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -84,7 +84,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -131,7 +131,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -175,7 +175,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -219,7 +219,7 @@ jobs: run: "sudo /etc/init.d/mysql start" - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -263,7 +263,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -297,7 +297,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@v7" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" From 0f5a1d3cf82ad0e4641a38506005eeb045f6c117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Mon, 31 Aug 2026 10:47:41 +0200 Subject: [PATCH 5/5] Keep EventSubscriber::track() backwards compatible and make the BC check installable - track() keeps its parameterless signature; the originating event is read from the first dispatcher argument and typed as TEvent, so Roave no longer reports an increased number of required arguments - The BC check job now disables Composer's security-advisory blocking globally: Roave installs the baseline's dependencies, and Sylius 1.x pins api-platform/core ^2.7 which has known advisories the base branch cannot opt out of itself Claude-Session: https://claude.ai/code/session_013jh2QjzkxAJABPDYB1UiPS --- .github/workflows/backwards-compatibility-check.yaml | 5 +++++ src/EventSubscriber/EventSubscriber.php | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backwards-compatibility-check.yaml b/.github/workflows/backwards-compatibility-check.yaml index ad10555..45ad199 100644 --- a/.github/workflows/backwards-compatibility-check.yaml +++ b/.github/workflows/backwards-compatibility-check.yaml @@ -26,5 +26,10 @@ jobs: - name: "Install tool" run: "composer global require roave/backward-compatibility-check" + # Sylius 1.x depends on api-platform/core ^2.7, which has known security advisories. Composer >= 2.10 refuses to + # install such versions by default, and the baseline (the base branch) cannot opt out itself, so opt out globally + - name: "Allow installing packages with known security advisories" + run: "composer config --global policy.advisories.block false" + - name: "Check for BC breaks" run: "~/.composer/vendor/bin/roave-backward-compatibility-check --from=origin/${{ github.event.pull_request.base.ref }} --format=github-actions" diff --git a/src/EventSubscriber/EventSubscriber.php b/src/EventSubscriber/EventSubscriber.php index 8e57a7f..07def38 100644 --- a/src/EventSubscriber/EventSubscriber.php +++ b/src/EventSubscriber/EventSubscriber.php @@ -32,11 +32,14 @@ public function __construct(private readonly EventDispatcherInterface $eventDisp } /** - * @param TEvent $event + * The event dispatcher calls this method with the originating event as the first argument */ - public function track(object $event): void + public function track(): void { try { + /** @var TEvent $event */ + $event = func_get_arg(0); + $conversionsApiEvent = $this->callback()($event); if (null === $conversionsApiEvent) { return;