From c9b5973e27f0fbdff4b3cd379b32dda85b8c31a7 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 10:18:41 +0200 Subject: [PATCH 01/31] WIP Check changes command --- config/services/command.xml | 6 + src/Command/ServicesChangesCommand.php | 213 ++++++++++++++++++ .../Compiler/DecoratorServicePass.php | 118 ++++++++++ .../Compiler/RemoveUnusedDefinitionsPass.php | 83 +++++++ 4 files changed, 420 insertions(+) create mode 100644 src/Command/ServicesChangesCommand.php create mode 100644 src/DependencyInjection/Compiler/DecoratorServicePass.php create mode 100644 src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php diff --git a/config/services/command.xml b/config/services/command.xml index f73f2a9..3493067 100644 --- a/config/services/command.xml +++ b/config/services/command.xml @@ -6,5 +6,11 @@ %kernel.project_dir% + + + + %kernel.project_dir% + + diff --git a/src/Command/ServicesChangesCommand.php b/src/Command/ServicesChangesCommand.php new file mode 100644 index 0000000..64dda4c --- /dev/null +++ b/src/Command/ServicesChangesCommand.php @@ -0,0 +1,213 @@ +getApplication()->getKernel(); + $buildContainer = \Closure::bind(function () { + $this->initializeBundles(); + + return $this->buildContainer(); + }, $rawKernel, \get_class($rawKernel)); + /** @var ContainerBuilder $rawContainerBuilder */ + $rawContainerBuilder = $buildContainer(); + $removeUnusedDefinitionsPass = new RemoveUnusedDefinitionsPass(); + $decoratorServiceDefinitionsPass = new DecoratorServicePass(); + $this->compile($rawContainerBuilder, $removeUnusedDefinitionsPass, $decoratorServiceDefinitionsPass); + $rawKernel->boot(); + + // todo: with this association we can search the diff for the classpath with psr4 logic and determine if some of these decorated services + // changed or not + + $decoratedServicesAssociation = []; + $decoratedDefintions = $decoratorServiceDefinitionsPass::$decoratedServices; + + // todo: repositories don't seem to be in removedDefinitions +// $removedDefinitions = $removeUnusedDefinitionsPass::$removedDefinitions; +// foreach ($removedDefinitions as $key => $definition) { +// if (str_contains(strtolower($key), 'app') || str_contains(strtolower($key), 'sylius')) { +// $output->writeln(sprintf('Found service "%s"', $key)); +// } +// } + + $rawDefinitions = $rawContainerBuilder->getDefinitions(); + foreach ($rawDefinitions as $alias => $definition) { + // todo: Check that it is an "App" service? And not maybe a third party plugin service + + if (str_contains(strtolower($alias), 'province_naming_provider')) { + $output->writeln(sprintf('### Found service "%s"', $alias)); + } + + // the replaced service must be a "Sylius" service + // todo: or an App service: you can find it's definition in the $decoratedDefintions array + if (!(str_starts_with($alias, 'sylius.') || str_starts_with($alias, 'Sylius\\') || str_starts_with($alias, '\\Sylius\\'))) { + continue; + } + + $definitionClass = $definition->getClass(); + if (!is_string($definitionClass)) { + continue; + } + + $aliasNormalized = strtolower($alias); + // ignore repositories and controllers 'cause they are magically registered + if (str_contains($aliasNormalized, 'repository') || str_contains($aliasNormalized, 'controller')) { + $output->writeln(sprintf('Repository or controller service "%s"', $alias)); + + continue; + } + + // the new service must be an "App" service + if (!str_starts_with($definitionClass, 'App\\')) { + // this internal service class could have been replaced with an App class even though the original service alias is still untouched + + // todo: search in $decoratedDefintions by alias? + $decoratedDef = $decoratedDefintions[$definitionClass]['definition'] ?? null; + if (!$decoratedDef) { + continue; + } + + $decoratedDefClass = $decoratedDef->getClass(); + if (!str_starts_with($decoratedDefClass, 'App\\') || !class_exists($decoratedDefClass)) { + continue; + } + + $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; + $output->writeln(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + $output->writeln(sprintf("\tFound classpath by 'decorated definitions' %s", $decoratedDefClass)); + + continue; + } + + $output->writeln(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + if (class_exists($alias)) { + $decoratedServicesAssociation[$definitionClass] = $alias; + $output->writeln(sprintf("\tFound classpath by alias %s", $alias)); + + continue; + } + + $decoratedDefintion = $decoratedDefintions[$alias] ?? null; + if ($decoratedDefintion) { + $class = $decoratedDefintion['definition']?->getClass(); + if ($class !== null && class_exists($class)) { + $decoratedServicesAssociation[$definitionClass] = $class; + $output->writeln(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); + + continue; + } + } + + if (str_ends_with($alias, 'Interface')) { + $class = str_replace('Interface', '', $alias); + if (class_exists($class)) { + $decoratedServicesAssociation[$definitionClass] = $class; + $output->writeln(sprintf("\tFound classpath with 'Interface substitution' %s", $class)); + + continue; + } + } + + $innerServiceId = $definition->innerServiceId; + if ($innerServiceId !== null && str_contains($innerServiceId, '.inner')) { + $originalServiceId = str_replace('.inner', '', $innerServiceId); + $decoratedDefintion = $decoratedDefintions[$originalServiceId] ?? null; + if ($decoratedDefintion) { + $class = $decoratedDefintion['definition']?->getClass(); + if ($class !== null && class_exists($class)) { + $decoratedServicesAssociation[$definitionClass] = $class; + $output->writeln(sprintf("\tFound classpath with '.inner substitution' %s", $class)); + + continue; + } + } + } + +// $innerServiceId = $definition->innerServiceId; +// if ($innerServiceId !== null) { +// $innerService = $removedDefinitions[$innerServiceId] ?? null; +// if ($innerService instanceof Definition) { +// $replacedServices[$alias] = $definition; +// $output->writeln("\tFound"); +// } +// } +// +// continue; + + $output->writeln(sprintf("\tNot found classpath for alias %s", $alias)); + } + + $diff = @file_get_contents('https://github.com/Sylius/Sylius/compare/v1.11.0..v1.12.0.diff'); + file_put_contents('diff.txt', $diff); + $diffLines = explode(\PHP_EOL, $diff); + foreach ($diffLines as $diffLine) { + if (strpos($diffLine, 'diff --git') !== 0) { + continue; + } + $diffLineParts = explode(' ', $diffLine); + $changedFileName = substr($diffLineParts[2], 2); + + if (!str_starts_with($changedFileName, 'src/')) { + continue; + } + + foreach ($decoratedServicesAssociation as $newService => $oldService) { + $pathFromNamespace = str_replace('\\', \DIRECTORY_SEPARATOR, $oldService); + if (!str_contains($changedFileName, $pathFromNamespace)) { + continue; + } + $output->writeln( + sprintf( + 'Service "%s" must be checked because the service that it decorates "%s" has changed in these versions', + $newService, + $oldService, + ), + ); + } + } + + return 0; + } + + private function compile(ContainerBuilder $rawContainerBuilder, RemoveUnusedDefinitionsPass $removeUnusedDefinitionsPass, DecoratorServicePass $decoratorServiceDefinitionsPass): void + { + $compiler = $rawContainerBuilder->getCompiler(); + + foreach ($rawContainerBuilder->getCompilerPassConfig()->getPasses() as $pass) { + if ($pass instanceof BaseRemoveUnusedDefinitionsPass) { + $removeUnusedDefinitionsPass->process($rawContainerBuilder); + + continue; + } + if ($pass instanceof BaseDecoratorServicePass) { + $decoratorServiceDefinitionsPass->process($rawContainerBuilder); + + continue; + } + $pass->process($rawContainerBuilder); + } + + $compiler->getServiceReferenceGraph()->clear(); + } +} diff --git a/src/DependencyInjection/Compiler/DecoratorServicePass.php b/src/DependencyInjection/Compiler/DecoratorServicePass.php new file mode 100644 index 0000000..d5c084d --- /dev/null +++ b/src/DependencyInjection/Compiler/DecoratorServicePass.php @@ -0,0 +1,118 @@ +getDefinitions() as $id => $definition) { + if (!$decorated = $definition->getDecoratedService()) { + continue; + } + $definitions->insert([$id, $definition], [$decorated[2], --$order]); + } + $decoratingDefinitions = []; + + $tagsToKeep = $container->hasParameter('container.behavior_describing_tags') + ? $container->getParameter('container.behavior_describing_tags') + : ['proxy', 'container.do_not_inline', 'container.service_locator', 'container.service_subscriber', 'container.service_subscriber.locator']; + + foreach ($definitions as [$id, $definition]) { + $decoratedService = $definition->getDecoratedService(); + [$inner, $renamedId] = $decoratedService; + $invalidBehavior = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + + $definition->setDecoratedService(null); + + if (!$renamedId) { + $renamedId = $id . '.inner'; + } + + $this->currentId = $renamedId; + $this->processValue($definition); + + $definition->innerServiceId = $renamedId; + $definition->decorationOnInvalid = $invalidBehavior; + + // we create a new alias/service for the service we are replacing + // to be able to reference it in the new one + if ($container->hasAlias($inner)) { + $alias = $container->getAlias($inner); + $public = $alias->isPublic(); + $container->setAlias($renamedId, new Alias((string) $alias, false)); + $decoratedDefinition = $container->findDefinition($alias); + } elseif ($container->hasDefinition($inner)) { + $decoratedDefinition = $container->getDefinition($inner); + $public = $decoratedDefinition->isPublic(); + $decoratedDefinition->setPublic(false); + $container->setDefinition($renamedId, $decoratedDefinition); + $decoratingDefinitions[$inner] = $decoratedDefinition; + } elseif (ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) { + $container->removeDefinition($id); + + continue; + } elseif (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) { + $public = $definition->isPublic(); + $decoratedDefinition = null; + } else { + throw new ServiceNotFoundException($inner, $id); + } + + if ($decoratedDefinition?->isSynthetic()) { + throw new InvalidArgumentException(sprintf('A synthetic service cannot be decorated: service "%s" cannot decorate "%s".', $id, $inner)); + } + + if (isset($decoratingDefinitions[$inner])) { + $decoratingDefinition = $decoratingDefinitions[$inner]; + + $decoratingTags = $decoratingDefinition->getTags(); + $resetTags = []; + + // Behavior-describing tags must not be transferred out to decorators + foreach ($tagsToKeep as $containerTag) { + if (isset($decoratingTags[$containerTag])) { + $resetTags[$containerTag] = $decoratingTags[$containerTag]; + unset($decoratingTags[$containerTag]); + } + } + + $definition->setTags(array_merge($decoratingTags, $definition->getTags())); + $decoratingDefinition->setTags($resetTags); + $decoratingDefinitions[$inner] = $definition; + } + self::$decoratedServices[$id] = [ + 'id' => $inner, + 'definition' => $decoratedDefinition, + ]; + + $container->setAlias($inner, $id)->setPublic($public); + } + } + + protected function processValue(mixed $value, bool $isRoot = false): mixed + { + if ($value instanceof Reference && '.inner' === (string) $value) { + return new Reference($this->currentId, $value->getInvalidBehavior()); + } + + return parent::processValue($value, $isRoot); + } +} diff --git a/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php b/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php new file mode 100644 index 0000000..da95965 --- /dev/null +++ b/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php @@ -0,0 +1,83 @@ +enableExpressionProcessing(); + $this->container = $container; + $connectedIds = []; + $aliases = $container->getAliases(); + + foreach ($aliases as $id => $alias) { + if ($alias->isPublic()) { + $this->connectedIds[] = (string) $aliases[$id]; + } + } + + foreach ($container->getDefinitions() as $id => $definition) { + if ($definition->isPublic()) { + $connectedIds[$id] = true; + $this->processValue($definition); + } + } + + while ($this->connectedIds) { + $ids = $this->connectedIds; + $this->connectedIds = []; + foreach ($ids as $id) { + if (!isset($connectedIds[$id]) && $container->hasDefinition($id)) { + $connectedIds[$id] = true; + $this->processValue($container->getDefinition($id)); + } + } + } + + foreach ($container->getDefinitions() as $id => $definition) { + if (!isset($connectedIds[$id])) { + self::$removedDefinitions[$id] = $definition; + $container->removeDefinition($id); + $container->resolveEnvPlaceholders(!$definition->hasErrors() ? serialize($definition) : $definition); + $container->log($this, sprintf('Removed service "%s"; reason: unused.', $id)); + } + } + } finally { + $this->container = null; + $this->connectedIds = []; + } + } + + /** + * @inheritdoc + */ + protected function processValue($value, bool $isRoot = false) + { + if (!$value instanceof Reference) { + return parent::processValue($value, $isRoot); + } + + if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) { + $this->connectedIds[] = (string) $value; + } + + return $value; + } +} From 17448cac044380fd14b7a574573218ab10cd51e8 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 10:20:28 +0200 Subject: [PATCH 02/31] WIP check in decoratedDefitions with sylius class id (#24187) --- src/Command/ServicesChangesCommand.php | 57 ++++++++++++-------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/Command/ServicesChangesCommand.php b/src/Command/ServicesChangesCommand.php index 64dda4c..32debb6 100644 --- a/src/Command/ServicesChangesCommand.php +++ b/src/Command/ServicesChangesCommand.php @@ -37,31 +37,38 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->compile($rawContainerBuilder, $removeUnusedDefinitionsPass, $decoratorServiceDefinitionsPass); $rawKernel->boot(); - // todo: with this association we can search the diff for the classpath with psr4 logic and determine if some of these decorated services - // changed or not - $decoratedServicesAssociation = []; $decoratedDefintions = $decoratorServiceDefinitionsPass::$decoratedServices; - // todo: repositories don't seem to be in removedDefinitions -// $removedDefinitions = $removeUnusedDefinitionsPass::$removedDefinitions; -// foreach ($removedDefinitions as $key => $definition) { -// if (str_contains(strtolower($key), 'app') || str_contains(strtolower($key), 'sylius')) { -// $output->writeln(sprintf('Found service "%s"', $key)); -// } -// } + $output->writeln("\n\n### DEBUG: Computing decorated services"); $rawDefinitions = $rawContainerBuilder->getDefinitions(); foreach ($rawDefinitions as $alias => $definition) { - // todo: Check that it is an "App" service? And not maybe a third party plugin service + $decoratedDef = $decoratedDefintions[$alias] ?? null; + + // if the service is an "App" service, seek for the original Sylius service in the decorated definitions + if ($decoratedDef && (str_starts_with($alias, 'App\\') || str_starts_with($alias, 'app.'))) { + $decoratedServiceId = $decoratedDef['id']; + if (str_starts_with($decoratedServiceId, 'sylius.') || + str_starts_with($decoratedServiceId, 'Sylius\\') || + str_starts_with($decoratedServiceId, '\\Sylius\\')) { + $class = $decoratedDef['definition']?->getClass(); + if ($class !== null && class_exists($class)) { + $decoratedServicesAssociation[$alias] = $class; + $output->writeln(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); + $output->writeln(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); - if (str_contains(strtolower($alias), 'province_naming_provider')) { - $output->writeln(sprintf('### Found service "%s"', $alias)); + continue; + } + } } - // the replaced service must be a "Sylius" service - // todo: or an App service: you can find it's definition in the $decoratedDefintions array - if (!(str_starts_with($alias, 'sylius.') || str_starts_with($alias, 'Sylius\\') || str_starts_with($alias, '\\Sylius\\'))) { + + // otherwise, the replaced service must be a "Sylius" service + if (!(str_starts_with($alias, 'sylius.') || + str_starts_with($alias, 'Sylius\\') || + str_starts_with($alias, '\\Sylius\\')) + ) { continue; } @@ -73,8 +80,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $aliasNormalized = strtolower($alias); // ignore repositories and controllers 'cause they are magically registered if (str_contains($aliasNormalized, 'repository') || str_contains($aliasNormalized, 'controller')) { - $output->writeln(sprintf('Repository or controller service "%s"', $alias)); - continue; } @@ -144,20 +149,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } -// $innerServiceId = $definition->innerServiceId; -// if ($innerServiceId !== null) { -// $innerService = $removedDefinitions[$innerServiceId] ?? null; -// if ($innerService instanceof Definition) { -// $replacedServices[$alias] = $definition; -// $output->writeln("\tFound"); -// } -// } -// -// continue; - $output->writeln(sprintf("\tNot found classpath for alias %s", $alias)); } + + $output->writeln("\n\n### Computing changed services"); $diff = @file_get_contents('https://github.com/Sylius/Sylius/compare/v1.11.0..v1.12.0.diff'); file_put_contents('diff.txt', $diff); $diffLines = explode(\PHP_EOL, $diff); @@ -179,7 +175,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $output->writeln( sprintf( - 'Service "%s" must be checked because the service that it decorates "%s" has changed in these versions', +// 'Service "%s" must be checked because the service that it decorates "%s" has changed in these versions', + "\t%s | %s", $newService, $oldService, ), From 0263f289cdfd47c652ccfae364f59bd24eb4d07d Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 10:21:28 +0200 Subject: [PATCH 03/31] Verbose output --- src/Command/ServicesChangesCommand.php | 44 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/Command/ServicesChangesCommand.php b/src/Command/ServicesChangesCommand.php index 32debb6..a9f5c67 100644 --- a/src/Command/ServicesChangesCommand.php +++ b/src/Command/ServicesChangesCommand.php @@ -21,8 +21,12 @@ final class ServicesChangesCommand extends Command protected static $defaultName = 'app:process:services-changes'; + private OutputInterface $output; + protected function execute(InputInterface $input, OutputInterface $output): int { + $this->output = $output; + /** @var Kernel $rawKernel */ $rawKernel = $this->getApplication()->getKernel(); $buildContainer = \Closure::bind(function () { @@ -40,7 +44,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $decoratedServicesAssociation = []; $decoratedDefintions = $decoratorServiceDefinitionsPass::$decoratedServices; - $output->writeln("\n\n### DEBUG: Computing decorated services"); + $this->outputVerbose("\n\n### DEBUG: Computing decorated services"); $rawDefinitions = $rawContainerBuilder->getDefinitions(); foreach ($rawDefinitions as $alias => $definition) { @@ -55,8 +59,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDef['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$alias] = $class; - $output->writeln(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); - $output->writeln(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); continue; } @@ -99,16 +103,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; - $output->writeln(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); - $output->writeln(sprintf("\tFound classpath by 'decorated definitions' %s", $decoratedDefClass)); + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' %s", $decoratedDefClass)); + } continue; } - $output->writeln(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + } if (class_exists($alias)) { $decoratedServicesAssociation[$definitionClass] = $alias; - $output->writeln(sprintf("\tFound classpath by alias %s", $alias)); + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf("\tFound classpath by alias %s", $alias)); + } continue; } @@ -118,7 +128,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $output->writeln(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); continue; } @@ -128,7 +138,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = str_replace('Interface', '', $alias); if (class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $output->writeln(sprintf("\tFound classpath with 'Interface substitution' %s", $class)); + $this->outputVerbose(sprintf("\tFound classpath with 'Interface substitution' %s", $class)); continue; } @@ -142,18 +152,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $output->writeln(sprintf("\tFound classpath with '.inner substitution' %s", $class)); + $this->outputVerbose(sprintf("\tFound classpath with '.inner substitution' %s", $class)); continue; } } } - $output->writeln(sprintf("\tNot found classpath for alias %s", $alias)); + $this->outputVerbose(sprintf("\tNot found classpath for alias %s", $alias)); } - $output->writeln("\n\n### Computing changed services"); + $this->outputVerbose("\n\n### Computing changed services"); $diff = @file_get_contents('https://github.com/Sylius/Sylius/compare/v1.11.0..v1.12.0.diff'); file_put_contents('diff.txt', $diff); $diffLines = explode(\PHP_EOL, $diff); @@ -175,8 +185,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $output->writeln( sprintf( -// 'Service "%s" must be checked because the service that it decorates "%s" has changed in these versions', - "\t%s | %s", + 'Service "%s" must be checked because the service that it decorates "%s" has changed between given versions', $newService, $oldService, ), @@ -207,4 +216,11 @@ private function compile(ContainerBuilder $rawContainerBuilder, RemoveUnusedDefi $compiler->getServiceReferenceGraph()->clear(); } + + private function outputVerbose(string $message): void + { + if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->output->writeln($message); + } + } } From deda4f75265f73b1f29fd1ab94480d648673b91b Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 10:29:52 +0200 Subject: [PATCH 04/31] Rename service --- .../{ServicesChangesCommand.php => ServiceChangesCommand.php} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/Command/{ServicesChangesCommand.php => ServiceChangesCommand.php} (98%) diff --git a/src/Command/ServicesChangesCommand.php b/src/Command/ServiceChangesCommand.php similarity index 98% rename from src/Command/ServicesChangesCommand.php rename to src/Command/ServiceChangesCommand.php index a9f5c67..7885373 100644 --- a/src/Command/ServicesChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Command; +namespace Webgriffe\SyliusUpgradePlugin\Command; use App\DependencyInjection\Compiler\DecoratorServicePass; use App\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; @@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass as BaseRemoveUnusedDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; -final class ServicesChangesCommand extends Command +final class ServiceChangesCommand extends Command { use BuildDebugContainerTrait; From 33ca7fab209bcac75bc900bd33747bb678e79bb4 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 10:44:23 +0200 Subject: [PATCH 05/31] Get diff using git dependency --- config/services/command.xml | 1 - src/Command/ServiceChangesCommand.php | 102 +++++++++++++++++++++----- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/config/services/command.xml b/config/services/command.xml index 3493067..d4ad715 100644 --- a/config/services/command.xml +++ b/config/services/command.xml @@ -9,7 +9,6 @@ - %kernel.project_dir% diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 7885373..2e45213 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -9,23 +9,59 @@ use App\Kernel; use Symfony\Bundle\FrameworkBundle\Command\BuildDebugContainerTrait; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass as BaseDecoratorServicePass; use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass as BaseRemoveUnusedDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; final class ServiceChangesCommand extends Command { + public const FROM_VERSION_ARGUMENT_NAME = 'from'; + + public const TO_VERSION_ARGUMENT_NAME = 'to'; + use BuildDebugContainerTrait; - protected static $defaultName = 'app:process:services-changes'; + protected static $defaultName = 'webgriffe:upgrade:service-changes'; private OutputInterface $output; + /** @psalm-suppress PropertyNotSetInConstructor */ + private string $toVersion; + + /** @psalm-suppress PropertyNotSetInConstructor */ + private string $fromVersion; + + public function __construct(private GitInterface $gitClient, string $name = null) + { + parent::__construct($name); + } + + protected function configure(): void + { + $this + ->setDescription( + 'Print the list of your services that decorates or replaces a service that changed between two given Sylius versions.', + ) + ->addArgument( + self::FROM_VERSION_ARGUMENT_NAME, + InputArgument::REQUIRED, + 'Starting Sylius version to use for changes computation.', + ) + ->addArgument( + self::TO_VERSION_ARGUMENT_NAME, + InputArgument::REQUIRED, + 'Target Sylius version to use for changes computation.', + ); + } + protected function execute(InputInterface $input, OutputInterface $output): int { $this->output = $output; + $this->loadInputs($input); /** @var Kernel $rawKernel */ $rawKernel = $this->getApplication()->getKernel(); @@ -36,6 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int }, $rawKernel, \get_class($rawKernel)); /** @var ContainerBuilder $rawContainerBuilder */ $rawContainerBuilder = $buildContainer(); + // todo: this is not used, remove? $removeUnusedDefinitionsPass = new RemoveUnusedDefinitionsPass(); $decoratorServiceDefinitionsPass = new DecoratorServicePass(); $this->compile($rawContainerBuilder, $removeUnusedDefinitionsPass, $decoratorServiceDefinitionsPass); @@ -164,23 +201,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->outputVerbose("\n\n### Computing changed services"); - $diff = @file_get_contents('https://github.com/Sylius/Sylius/compare/v1.11.0..v1.12.0.diff'); - file_put_contents('diff.txt', $diff); - $diffLines = explode(\PHP_EOL, $diff); - foreach ($diffLines as $diffLine) { - if (strpos($diffLine, 'diff --git') !== 0) { - continue; - } - $diffLineParts = explode(' ', $diffLine); - $changedFileName = substr($diffLineParts[2], 2); - - if (!str_starts_with($changedFileName, 'src/')) { - continue; - } - + $this->output->writeln(sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion)); + $filesChanged = $this->getFilesChangedBetweenTwoVersions(); + foreach ($filesChanged as $fileChanged) { foreach ($decoratedServicesAssociation as $newService => $oldService) { $pathFromNamespace = str_replace('\\', \DIRECTORY_SEPARATOR, $oldService); - if (!str_contains($changedFileName, $pathFromNamespace)) { + if (!str_contains($fileChanged, $pathFromNamespace)) { continue; } $output->writeln( @@ -196,8 +222,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - private function compile(ContainerBuilder $rawContainerBuilder, RemoveUnusedDefinitionsPass $removeUnusedDefinitionsPass, DecoratorServicePass $decoratorServiceDefinitionsPass): void + /** + * @return string[] + */ + private function getFilesChangedBetweenTwoVersions(): array { + $diff = $this->gitClient->getDiffBetweenTags($this->fromVersion, $this->toVersion); + $versionChangedFiles = []; + $diffLines = explode(\PHP_EOL, $diff); + foreach ($diffLines as $diffLine) { + if (strpos($diffLine, 'diff --git') !== 0) { + continue; + } + $diffLineParts = explode(' ', $diffLine); + $changedFileName = substr($diffLineParts[2], 2); + + if (!str_starts_with($changedFileName, 'src/')) { + continue; + } + $versionChangedFiles[] = $changedFileName; + } + + return $versionChangedFiles; + } + + private function compile( + ContainerBuilder $rawContainerBuilder, + RemoveUnusedDefinitionsPass $removeUnusedDefinitionsPass, + DecoratorServicePass $decoratorServiceDefinitionsPass + ): void { $compiler = $rawContainerBuilder->getCompiler(); foreach ($rawContainerBuilder->getCompilerPassConfig()->getPasses() as $pass) { @@ -223,4 +276,19 @@ private function outputVerbose(string $message): void $this->output->writeln($message); } } + + private function loadInputs(InputInterface $input): void + { + $fromVersion = $input->getArgument(self::FROM_VERSION_ARGUMENT_NAME); + if (!is_string($fromVersion) || trim($fromVersion) === '') { + throw new \RuntimeException(sprintf('Argument "%s" is not a valid non-empty string', self::FROM_VERSION_ARGUMENT_NAME)); + } + $this->fromVersion = $fromVersion; + + $toVersion = $input->getArgument(self::TO_VERSION_ARGUMENT_NAME); + if (!is_string($toVersion) || trim($toVersion) === '') { + throw new \RuntimeException(sprintf('Argument "%s" is not a valid non-empty string', self::TO_VERSION_ARGUMENT_NAME)); + } + $this->toVersion = $toVersion; + } } From 722e944d8dce3220a0be96e2f508565e9d577165 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 11:58:17 +0200 Subject: [PATCH 06/31] Change namespace of passes --- src/Command/ServiceChangesCommand.php | 4 ++-- src/DependencyInjection/Compiler/DecoratorServicePass.php | 4 ++-- .../Compiler/RemoveUnusedDefinitionsPass.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 2e45213..2f7815b 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -4,8 +4,6 @@ namespace Webgriffe\SyliusUpgradePlugin\Command; -use App\DependencyInjection\Compiler\DecoratorServicePass; -use App\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; use App\Kernel; use Symfony\Bundle\FrameworkBundle\Command\BuildDebugContainerTrait; use Symfony\Component\Console\Command\Command; @@ -16,6 +14,8 @@ use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass as BaseRemoveUnusedDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; +use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; +use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; final class ServiceChangesCommand extends Command { diff --git a/src/DependencyInjection/Compiler/DecoratorServicePass.php b/src/DependencyInjection/Compiler/DecoratorServicePass.php index d5c084d..d6c2968 100644 --- a/src/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/DependencyInjection/Compiler/DecoratorServicePass.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DependencyInjection\Compiler; +namespace Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass; @@ -58,7 +58,7 @@ public function process(ContainerBuilder $container) $alias = $container->getAlias($inner); $public = $alias->isPublic(); $container->setAlias($renamedId, new Alias((string) $alias, false)); - $decoratedDefinition = $container->findDefinition($alias); + $decoratedDefinition = $container->findDefinition((string) $alias); } elseif ($container->hasDefinition($inner)) { $decoratedDefinition = $container->getDefinition($inner); $public = $decoratedDefinition->isPublic(); diff --git a/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php b/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php index da95965..11eca6c 100644 --- a/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php +++ b/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DependencyInjection\Compiler; +namespace Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass; use Symfony\Component\DependencyInjection\ContainerBuilder; From b69425ea6782e226d1c7506a77122b7ea33a8079 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 9 Oct 2023 12:19:46 +0200 Subject: [PATCH 07/31] Add first test for service changes command --- src/Command/ServiceChangesCommand.php | 47 +++++++++-- tests/Application/config/services_test.yaml | 5 ++ .../Command/ServiceChangesCommandTest.php | 58 +++++++++++++ .../git.diff | 82 +++++++++++++++++++ .../DirectlyDecoratedService.php | 9 ++ 5 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 tests/Integration/Command/ServiceChangesCommandTest.php create mode 100644 tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_changed_decorated_services/git.diff create mode 100644 tests/Stub/ServiceChangesCommand/DirectlyDecoratedService.php diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 2f7815b..f5113b9 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -4,7 +4,6 @@ namespace Webgriffe\SyliusUpgradePlugin\Command; -use App\Kernel; use Symfony\Bundle\FrameworkBundle\Command\BuildDebugContainerTrait; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -13,6 +12,7 @@ use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass as BaseDecoratorServicePass; use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass as BaseRemoveUnusedDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Tests\Webgriffe\SyliusUpgradePlugin\Application\Kernel; use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; @@ -23,6 +23,10 @@ final class ServiceChangesCommand extends Command public const TO_VERSION_ARGUMENT_NAME = 'to'; + public const NAMESPACE_PREFIX_OPTION_NAME = 'namespace-prefix'; + + public const ALIAS_PREFIX_OPTION_NAME = 'alias-prefix'; + use BuildDebugContainerTrait; protected static $defaultName = 'webgriffe:upgrade:service-changes'; @@ -35,6 +39,10 @@ final class ServiceChangesCommand extends Command /** @psalm-suppress PropertyNotSetInConstructor */ private string $fromVersion; + private string $namespacePrefix; + + private string $aliasPrefix; + public function __construct(private GitInterface $gitClient, string $name = null) { parent::__construct($name); @@ -55,6 +63,20 @@ protected function configure(): void self::TO_VERSION_ARGUMENT_NAME, InputArgument::REQUIRED, 'Target Sylius version to use for changes computation.', + ) + ->addOption( + self::NAMESPACE_PREFIX_OPTION_NAME, + 'np', + InputArgument::OPTIONAL, + 'The first part of the namespace of your app services, like "App" in "App\Calculator\PriceCalculator". Default: "App".', + 'App', + ) + ->addOption( + self::ALIAS_PREFIX_OPTION_NAME, + 'ap', + InputArgument::OPTIONAL, + 'The first part of the alias of your app services, like "app" in "app.calculator.price". Default: "app".', + 'App', ); } @@ -88,7 +110,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $decoratedDef = $decoratedDefintions[$alias] ?? null; // if the service is an "App" service, seek for the original Sylius service in the decorated definitions - if ($decoratedDef && (str_starts_with($alias, 'App\\') || str_starts_with($alias, 'app.'))) { + if ($decoratedDef && + (str_starts_with($alias, sprintf('%s\\', $this->namespacePrefix)) || + str_starts_with($alias, sprintf('%s.', $this->aliasPrefix))) + ) { $decoratedServiceId = $decoratedDef['id']; if (str_starts_with($decoratedServiceId, 'sylius.') || str_starts_with($decoratedServiceId, 'Sylius\\') || @@ -125,8 +150,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // the new service must be an "App" service - if (!str_starts_with($definitionClass, 'App\\')) { - // this internal service class could have been replaced with an App class even though the original service alias is still untouched + if (!str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix))) { + // this internal service class could have been replaced with an "App" class even though the original service alias is still untouched // todo: search in $decoratedDefintions by alias? $decoratedDef = $decoratedDefintions[$definitionClass]['definition'] ?? null; @@ -135,7 +160,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $decoratedDefClass = $decoratedDef->getClass(); - if (!str_starts_with($decoratedDefClass, 'App\\') || !class_exists($decoratedDefClass)) { + if (!str_starts_with($decoratedDefClass, sprintf('%s\\', $this->namespacePrefix)) || !class_exists($decoratedDefClass)) { continue; } @@ -290,5 +315,17 @@ private function loadInputs(InputInterface $input): void throw new \RuntimeException(sprintf('Argument "%s" is not a valid non-empty string', self::TO_VERSION_ARGUMENT_NAME)); } $this->toVersion = $toVersion; + + $namespacePrefix = $input->getOption(self::NAMESPACE_PREFIX_OPTION_NAME); + if (!is_string($namespacePrefix) || trim($namespacePrefix) === '') { + throw new \RuntimeException(sprintf('Option "%s" is not a valid non-empty string', self::NAMESPACE_PREFIX_OPTION_NAME)); + } + $this->namespacePrefix = $namespacePrefix; + + $aliasPrefix = $input->getOption(self::ALIAS_PREFIX_OPTION_NAME); + if (!is_string($aliasPrefix) || trim($aliasPrefix) === '') { + throw new \RuntimeException(sprintf('Option "%s" is not a valid non-empty string', self::NAMESPACE_PREFIX_OPTION_NAME)); + } + $this->aliasPrefix = $aliasPrefix; } } diff --git a/tests/Application/config/services_test.yaml b/tests/Application/config/services_test.yaml index c73d223..7b729ff 100644 --- a/tests/Application/config/services_test.yaml +++ b/tests/Application/config/services_test.yaml @@ -16,3 +16,8 @@ services: - '@webgriffe_sylius_upgrade.client.git' - 'vfs://root' tags: { name: "console.command" } + + ## ServiceChangesCommandTest ## + webgriffe_sylius_upgrade.service_changes_command.directly_decorated_service: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DirectlyDecoratedService + decorates: 'Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManagerInterface' diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php new file mode 100644 index 0000000..b039aba --- /dev/null +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -0,0 +1,58 @@ +commandTester = new CommandTester($application->find('webgriffe:upgrade:service-changes')); + } + + protected function tearDown(): void + { + + } + + public function test_it_detects_changed_decorated_services(): void + { + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + + $result = $this->commandTester->execute( + [ + ServiceChangesCommand::FROM_VERSION_ARGUMENT_NAME => '1.11.0', + ServiceChangesCommand::TO_VERSION_ARGUMENT_NAME => '1.12.0', + '--' . ServiceChangesCommand::NAMESPACE_PREFIX_OPTION_NAME => 'Tests', + '--' . ServiceChangesCommand::ALIAS_PREFIX_OPTION_NAME => 'webgriffe_sylius_upgrade', + ], + ); + + self::assertEquals(0, $result); + + $output = $this->commandTester->getDisplay(); + $expectedOutput = <<getCustomer()->getEmail(); ++ Assert::notNull($email); ++ + $this->emailSender->send( + Emails::ORDER_CONFIRMATION_RESENT, +- [$order->getCustomer()->getEmail()], ++ [$email], + [ + 'order' => $order, + 'channel' => $order->getChannel(), + 'localeCode' => $order->getLocaleCode(), +- ] ++ ], + ); + } + } +diff --git a/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php b/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php +index 5270cc23123..02f6b26fcf7 100644 +--- a/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php ++++ b/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php +@@ -17,6 +17,7 @@ + use Sylius\Component\Core\Model\OrderInterface; + use Sylius\Component\Core\Model\ShipmentInterface; + use Sylius\Component\Mailer\Sender\SenderInterface; ++use Webmozart\Assert\Assert; + + final class ShipmentEmailManager implements ShipmentEmailManagerInterface + { +@@ -28,12 +29,18 @@ public function sendConfirmationEmail(ShipmentInterface $shipment): void + { + /** @var OrderInterface $order */ + $order = $shipment->getOrder(); ++ $email = $order->getCustomer()->getEmail(); ++ Assert::notNull($email); + +- $this->emailSender->send(Emails::SHIPMENT_CONFIRMATION, [$order->getCustomer()->getEmail()], [ +- 'shipment' => $shipment, +- 'order' => $order, +- 'channel' => $order->getChannel(), +- 'localeCode' => $order->getLocaleCode(), +- ]); ++ $this->emailSender->send( ++ Emails::SHIPMENT_CONFIRMATION, ++ [$email], ++ [ ++ 'shipment' => $shipment, ++ 'order' => $order, ++ 'channel' => $order->getChannel(), ++ 'localeCode' => $order->getLocaleCode(), ++ ], ++ ); + } + } +diff --git a/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php b/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php +index 7e2cfde7545..da90d9fd52c 100644 +--- a/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php ++++ b/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php +@@ -25,7 +25,7 @@ public function __construct( + FactoryInterface $factory, + ItemInterface $menu, + private OrderInterface $order, +- private StateMachineInterface $stateMachine ++ private StateMachineInterface $stateMachine, + ) { + parent::__construct($factory, $menu); + } diff --git a/tests/Stub/ServiceChangesCommand/DirectlyDecoratedService.php b/tests/Stub/ServiceChangesCommand/DirectlyDecoratedService.php new file mode 100644 index 0000000..28178ba --- /dev/null +++ b/tests/Stub/ServiceChangesCommand/DirectlyDecoratedService.php @@ -0,0 +1,9 @@ + Date: Mon, 13 Nov 2023 12:54:28 +0100 Subject: [PATCH 08/31] Catch exception in test tearDown The kernel was already shut down, so we catch the error here to avoid a red test --- tests/Integration/Command/ServiceChangesCommandTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index b039aba..08074b0 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -28,7 +28,11 @@ protected function setUp(): void protected function tearDown(): void { + try { + parent::tearDown(); + } catch (\Throwable) { // the kernel was already shut down, so we catch the error here to avoid a red test + } } public function test_it_detects_changed_decorated_services(): void From 0d57df07904a89f567ddd917b6fbe5698d501fe1 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 27 Nov 2023 10:41:03 +0100 Subject: [PATCH 09/31] Test directly decorated services --- src/Command/ServiceChangesCommand.php | 19 +++-- tests/Application/config/services_test.yaml | 26 +++++- .../Command/ServiceChangesCommandTest.php | 5 +- .../git.diff | 82 ------------------- .../git.diff | 24 ++++++ .../DecorateCustomerUniqueAddressAdder.php | 9 ++ .../DecorateNewShopBased.php} | 4 +- .../DecorateOrderEmailManagerInterface.php | 9 ++ 8 files changed, 80 insertions(+), 98 deletions(-) delete mode 100644 tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_changed_decorated_services/git.diff create mode 100644 tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_directly_decorated_services_that_changed/git.diff create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_directly_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php rename tests/Stub/ServiceChangesCommand/{DirectlyDecoratedService.php => test_it_detects_directly_decorated_services_that_changed/DecorateNewShopBased.php} (50%) create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_directly_decorated_services_that_changed/DecorateOrderEmailManagerInterface.php diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index f5113b9..345e00c 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -196,15 +196,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - if (str_ends_with($alias, 'Interface')) { - $class = str_replace('Interface', '', $alias); - if (class_exists($class)) { - $decoratedServicesAssociation[$definitionClass] = $class; - $this->outputVerbose(sprintf("\tFound classpath with 'Interface substitution' %s", $class)); - - continue; - } - } + // todo: this is not applying a valid logic actually +// if (str_ends_with($alias, 'Interface')) { +// $class = str_replace('Interface', '', $alias); +// if (class_exists($class)) { +// $decoratedServicesAssociation[$definitionClass] = $class; +// $this->outputVerbose(sprintf("\tFound classpath with 'Interface substitution' %s", $class)); +// +// continue; +// } +// } $innerServiceId = $definition->innerServiceId; if ($innerServiceId !== null && str_contains($innerServiceId, '.inner')) { diff --git a/tests/Application/config/services_test.yaml b/tests/Application/config/services_test.yaml index 7b729ff..9c2c7c0 100644 --- a/tests/Application/config/services_test.yaml +++ b/tests/Application/config/services_test.yaml @@ -17,7 +17,27 @@ services: - 'vfs://root' tags: { name: "console.command" } - ## ServiceChangesCommandTest ## - webgriffe_sylius_upgrade.service_changes_command.directly_decorated_service: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DirectlyDecoratedService + + ### ServiceChangesCommandTest ### + + ## test_it_detects_directly_decorated_services_that_changed + # decorate via alias + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_new_shop_based: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateNewShopBased + decorates: sylius.context.cart.new_shop_based + + # decorate via class + # NOTE: This case does not exist in "sylius/sylius". It is only by interface or by alias. +# webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_minimum_price_distributor: +# class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateMinimumPriceDistributor +# decorates: Sylius\Component\Core\Distributor\MinimumPriceDistributor + + # decorate via interface + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_order_email_manager: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateOrderEmailManagerInterface decorates: 'Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManagerInterface' + + # decorated BUT not changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_customer_unique_address_adder: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateCustomerUniqueAddressAdder + decorates: sylius.customer_unique_address_adder diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index 08074b0..9d47796 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -35,7 +35,7 @@ protected function tearDown(): void } } - public function test_it_detects_changed_decorated_services(): void + public function test_it_detects_directly_decorated_services_that_changed(): void { Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); @@ -53,7 +53,8 @@ public function test_it_detects_changed_decorated_services(): void $output = $this->commandTester->getDisplay(); $expectedOutput = <<getCustomer()->getEmail(); -+ Assert::notNull($email); -+ - $this->emailSender->send( - Emails::ORDER_CONFIRMATION_RESENT, -- [$order->getCustomer()->getEmail()], -+ [$email], - [ - 'order' => $order, - 'channel' => $order->getChannel(), - 'localeCode' => $order->getLocaleCode(), -- ] -+ ], - ); - } - } -diff --git a/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php b/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php -index 5270cc23123..02f6b26fcf7 100644 ---- a/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php -+++ b/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php -@@ -17,6 +17,7 @@ - use Sylius\Component\Core\Model\OrderInterface; - use Sylius\Component\Core\Model\ShipmentInterface; - use Sylius\Component\Mailer\Sender\SenderInterface; -+use Webmozart\Assert\Assert; - - final class ShipmentEmailManager implements ShipmentEmailManagerInterface - { -@@ -28,12 +29,18 @@ public function sendConfirmationEmail(ShipmentInterface $shipment): void - { - /** @var OrderInterface $order */ - $order = $shipment->getOrder(); -+ $email = $order->getCustomer()->getEmail(); -+ Assert::notNull($email); - -- $this->emailSender->send(Emails::SHIPMENT_CONFIRMATION, [$order->getCustomer()->getEmail()], [ -- 'shipment' => $shipment, -- 'order' => $order, -- 'channel' => $order->getChannel(), -- 'localeCode' => $order->getLocaleCode(), -- ]); -+ $this->emailSender->send( -+ Emails::SHIPMENT_CONFIRMATION, -+ [$email], -+ [ -+ 'shipment' => $shipment, -+ 'order' => $order, -+ 'channel' => $order->getChannel(), -+ 'localeCode' => $order->getLocaleCode(), -+ ], -+ ); - } - } -diff --git a/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php b/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php -index 7e2cfde7545..da90d9fd52c 100644 ---- a/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php -+++ b/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php -@@ -25,7 +25,7 @@ public function __construct( - FactoryInterface $factory, - ItemInterface $menu, - private OrderInterface $order, -- private StateMachineInterface $stateMachine -+ private StateMachineInterface $stateMachine, - ) { - parent::__construct($factory, $menu); - } diff --git a/tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_directly_decorated_services_that_changed/git.diff b/tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_directly_decorated_services_that_changed/git.diff new file mode 100644 index 0000000..37d763a --- /dev/null +++ b/tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_directly_decorated_services_that_changed/git.diff @@ -0,0 +1,24 @@ +diff --git a/src/Sylius/Bundle/AdminBundle/EmailManager/OrderEmailManager.php b/src/Sylius/Bundle/AdminBundle/EmailManager/OrderEmailManager.php +index 4eaff957874..60d2decf5e8 100644 +--- a/src/Sylius/Bundle/AdminBundle/EmailManager/OrderEmailManager.php ++++ b/src/Sylius/Bundle/AdminBundle/EmailManager/OrderEmailManager.php + +diff --git a/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php b/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php +index 5270cc23123..02f6b26fcf7 100644 +--- a/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php ++++ b/src/Sylius/Bundle/AdminBundle/EmailManager/ShipmentEmailManager.php + +diff --git a/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php b/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php +index 7e2cfde7545..da90d9fd52c 100644 +--- a/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php ++++ b/src/Sylius/Bundle/AdminBundle/Event/OrderShowMenuBuilderEvent.php + +diff --git a/src/Sylius/Component/Core/Cart/Context/ShopBasedCartContext.php b/src/Sylius/Component/Core/Cart/Context/ShopBasedCartContext.php +index 7e2cfde7545..da90d9fd52c 100644 +--- a/src/Sylius/Component/Core/Cart/Context/ShopBasedCartContext.php ++++ b/src/Sylius/Component/Core/Cart/Context/ShopBasedCartContext.php + +diff --git a/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php b/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php +index 7e2cfde7545..da90d9fd52c 100644 +--- a/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php ++++ b/src/Sylius/Component/Core/Distributor/MinimumPriceDistributor.php diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_directly_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php b/tests/Stub/ServiceChangesCommand/test_it_detects_directly_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php new file mode 100644 index 0000000..b15fbb9 --- /dev/null +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_directly_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php @@ -0,0 +1,9 @@ + Date: Mon, 27 Nov 2023 12:50:46 +0100 Subject: [PATCH 10/31] Test for other decoration strategy --- tests/Application/config/services_test.yaml | 35 +++++++++++++ .../Command/ServiceChangesCommandTest.php | 51 +++++++++++++++++++ .../git.diff | 14 +++++ .../git.diff | 14 +++++ .../DecorateSendOrderConfirmationHandler.php | 9 ++++ ...teSendShipmentConfirmationEmailHandler.php | 9 ++++ .../DecorateCustomerOrderAddressesSaver.php | 14 +++++ .../DecorateOrderPaymentProcessor.php | 14 +++++ .../DecorateProvinceNamingProvider.php | 14 +++++ 9 files changed, 174 insertions(+) create mode 100644 tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed/git.diff create mode 100644 tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed/git.diff create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed/DecorateSendOrderConfirmationHandler.php create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed/DecorateSendShipmentConfirmationEmailHandler.php create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed/DecorateCustomerOrderAddressesSaver.php create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed/DecorateOrderPaymentProcessor.php create mode 100644 tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed/DecorateProvinceNamingProvider.php diff --git a/tests/Application/config/services_test.yaml b/tests/Application/config/services_test.yaml index 9c2c7c0..be6d76e 100644 --- a/tests/Application/config/services_test.yaml +++ b/tests/Application/config/services_test.yaml @@ -41,3 +41,38 @@ services: webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_customer_unique_address_adder: class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateCustomerUniqueAddressAdder decorates: sylius.customer_unique_address_adder + + + ## test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed.decorate_province_naming_provider: + public: true + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed\DecorateProvinceNamingProvider + decorates: sylius.province_naming_provider + arguments: + - '@.inner' + + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed.decorate_order_payment_processor: + public: true + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed\DecorateOrderPaymentProcessor + decorates: sylius.order_processing.order_payment_processor.after_checkout + decoration_priority: 100 + arguments: + - '@.inner' + + # decorated BUT not changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed.decorate_customer_order_addresses_saver: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed\DecorateCustomerOrderAddressesSaver + decorates: sylius.customer_order_addresses_saver + arguments: + - '@.inner' + + + ## test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed.decorate_send_order_confirmation: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed\DecorateSendOrderConfirmationHandler + decorates: Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendOrderConfirmationHandler + + # decorated BUT not changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed.decorate_send_shipment_confirmation_email_handler: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed\DecorateSendShipmentConfirmationEmailHandler + decorates: Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendShipmentConfirmationEmailHandler diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index 9d47796..203972a 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -56,6 +56,57 @@ public function test_it_detects_directly_decorated_services_that_changed(): void Service "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_directly_decorated_services_that_changed\DecorateOrderEmailManagerInterface" must be checked because the service that it decorates "Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManager" has changed between given versions Service "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_directly_decorated_services_that_changed\DecorateNewShopBased" must be checked because the service that it decorates "Sylius\Component\Core\Cart\Context\ShopBasedCartContext" has changed between given versions +TXT; + + self::assertEquals($expectedOutput, $output); + } + + public function test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed(): void + { + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + + $result = $this->commandTester->execute( + [ + ServiceChangesCommand::FROM_VERSION_ARGUMENT_NAME => '1.11.0', + ServiceChangesCommand::TO_VERSION_ARGUMENT_NAME => '1.12.0', + '--' . ServiceChangesCommand::NAMESPACE_PREFIX_OPTION_NAME => 'Tests', + '--' . ServiceChangesCommand::ALIAS_PREFIX_OPTION_NAME => 'webgriffe_sylius_upgrade', + ], + ); + + self::assertEquals(0, $result); + + $output = $this->commandTester->getDisplay(); + $expectedOutput = <<getName() . '/git.diff'); + + $result = $this->commandTester->execute( + [ + ServiceChangesCommand::FROM_VERSION_ARGUMENT_NAME => '1.11.0', + ServiceChangesCommand::TO_VERSION_ARGUMENT_NAME => '1.12.0', + '--' . ServiceChangesCommand::NAMESPACE_PREFIX_OPTION_NAME => 'Tests', + '--' . ServiceChangesCommand::ALIAS_PREFIX_OPTION_NAME => 'webgriffe_sylius_upgrade', + ], + ); + + self::assertEquals(0, $result); + + $output = $this->commandTester->getDisplay(); + $expectedOutput = << Date: Mon, 27 Nov 2023 12:58:26 +0100 Subject: [PATCH 11/31] Refactor naming and paths --- src/Command/ServiceChangesCommand.php | 12 +++--- tests/Application/config/services_test.yaml | 42 +++++++++---------- .../Command/ServiceChangesCommandTest.php | 16 +++---- .../git.diff | 0 .../git.diff | 0 .../git.diff | 0 .../DecorateSendOrderConfirmationHandler.php | 2 +- ...teSendShipmentConfirmationEmailHandler.php | 2 +- .../DecorateCustomerOrderAddressesSaver.php | 2 +- .../DecorateOrderPaymentProcessor.php | 2 +- .../DecorateProvinceNamingProvider.php | 2 +- .../DecorateCustomerUniqueAddressAdder.php | 2 +- .../DecorateNewShopBased.php | 2 +- .../DecorateOrderEmailManagerInterface.php | 2 +- 14 files changed, 43 insertions(+), 43 deletions(-) rename tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/{test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_alias_strategy_those_decorated_services_that_changed}/git.diff (100%) rename tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/{test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed}/git.diff (100%) rename tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/{test_it_detects_directly_decorated_services_that_changed => test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed}/git.diff (100%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_alias_strategy_those_decorated_services_that_changed}/DecorateSendOrderConfirmationHandler.php (61%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_alias_strategy_those_decorated_services_that_changed}/DecorateSendShipmentConfirmationEmailHandler.php (63%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed}/DecorateCustomerOrderAddressesSaver.php (90%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed}/DecorateOrderPaymentProcessor.php (89%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed => test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed}/DecorateProvinceNamingProvider.php (90%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_directly_decorated_services_that_changed => test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed}/DecorateCustomerUniqueAddressAdder.php (60%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_directly_decorated_services_that_changed => test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed}/DecorateNewShopBased.php (58%) rename tests/Stub/ServiceChangesCommand/{test_it_detects_directly_decorated_services_that_changed => test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed}/DecorateOrderEmailManagerInterface.php (60%) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 345e00c..9923264 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -122,7 +122,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$alias] = $class; $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); continue; } @@ -167,7 +167,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' %s", $decoratedDefClass)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $decoratedDefClass)); } continue; @@ -179,7 +179,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (class_exists($alias)) { $decoratedServicesAssociation[$definitionClass] = $alias; if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf("\tFound classpath by alias %s", $alias)); + $this->outputVerbose(sprintf("\tFound classpath by 'alias' strategy: %s", $alias)); } continue; @@ -190,7 +190,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' %s", $class)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); continue; } @@ -201,7 +201,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // $class = str_replace('Interface', '', $alias); // if (class_exists($class)) { // $decoratedServicesAssociation[$definitionClass] = $class; -// $this->outputVerbose(sprintf("\tFound classpath with 'Interface substitution' %s", $class)); +// $this->outputVerbose(sprintf("\tFound classpath by 'Interface substitution' strategy: %s", $class)); // // continue; // } @@ -215,7 +215,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $this->outputVerbose(sprintf("\tFound classpath with '.inner substitution' %s", $class)); + $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); continue; } diff --git a/tests/Application/config/services_test.yaml b/tests/Application/config/services_test.yaml index be6d76e..81bf7e6 100644 --- a/tests/Application/config/services_test.yaml +++ b/tests/Application/config/services_test.yaml @@ -20,59 +20,59 @@ services: ### ServiceChangesCommandTest ### - ## test_it_detects_directly_decorated_services_that_changed + ## test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed # decorate via alias - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_new_shop_based: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateNewShopBased + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed.decorate_new_shop_based: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateNewShopBased decorates: sylius.context.cart.new_shop_based # decorate via class # NOTE: This case does not exist in "sylius/sylius". It is only by interface or by alias. -# webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_minimum_price_distributor: -# class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateMinimumPriceDistributor +# webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed.decorate_minimum_price_distributor: +# class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateMinimumPriceDistributor # decorates: Sylius\Component\Core\Distributor\MinimumPriceDistributor # decorate via interface - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_order_email_manager: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateOrderEmailManagerInterface + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed.decorate_order_email_manager: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateOrderEmailManagerInterface decorates: 'Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManagerInterface' # decorated BUT not changed - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_directly_decorated_services_that_changed.decorate_customer_unique_address_adder: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_directly_decorated_services_that_changed\DecorateCustomerUniqueAddressAdder + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed.decorate_customer_unique_address_adder: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateCustomerUniqueAddressAdder decorates: sylius.customer_unique_address_adder - ## test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed.decorate_province_naming_provider: + ## test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_province_naming_provider: public: true - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed\DecorateProvinceNamingProvider + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed\DecorateProvinceNamingProvider decorates: sylius.province_naming_provider arguments: - '@.inner' - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed.decorate_order_payment_processor: + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_order_payment_processor: public: true - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed\DecorateOrderPaymentProcessor + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed\DecorateOrderPaymentProcessor decorates: sylius.order_processing.order_payment_processor.after_checkout decoration_priority: 100 arguments: - '@.inner' # decorated BUT not changed - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed.decorate_customer_order_addresses_saver: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_directly_decorated_services_that_changed\DecorateCustomerOrderAddressesSaver + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_customer_order_addresses_saver: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed\DecorateCustomerOrderAddressesSaver decorates: sylius.customer_order_addresses_saver arguments: - '@.inner' - ## test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed.decorate_send_order_confirmation: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed\DecorateSendOrderConfirmationHandler + ## test_it_detects_with_alias_strategy_those_decorated_services_that_changed + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_decorated_services_that_changed.decorate_send_order_confirmation: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendOrderConfirmationHandler decorates: Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendOrderConfirmationHandler # decorated BUT not changed - webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed.decorate_send_shipment_confirmation_email_handler: - class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_directly_decorated_services_that_changed\DecorateSendShipmentConfirmationEmailHandler + webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_decorated_services_that_changed.decorate_send_shipment_confirmation_email_handler: + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendShipmentConfirmationEmailHandler decorates: Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendShipmentConfirmationEmailHandler diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index 203972a..101658b 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -35,7 +35,7 @@ protected function tearDown(): void } } - public function test_it_detects_directly_decorated_services_that_changed(): void + public function test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed(): void { Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); @@ -53,15 +53,15 @@ public function test_it_detects_directly_decorated_services_that_changed(): void $output = $this->commandTester->getDisplay(); $expectedOutput = <<getName() . '/git.diff'); @@ -79,15 +79,15 @@ public function test_it_detects_with_decorated_definition_strategy_those_directl $output = $this->commandTester->getDisplay(); $expectedOutput = <<getName() . '/git.diff'); @@ -105,7 +105,7 @@ public function test_it_detects_with_alias_strategy_those_directly_decorated_ser $output = $this->commandTester->getDisplay(); $expectedOutput = << Date: Mon, 11 Dec 2023 12:19:54 +0100 Subject: [PATCH 12/31] It does not detect any changes test --- src/Command/ServiceChangesCommand.php | 6 +++++ .../Command/ServiceChangesCommandTest.php | 25 +++++++++++++++++++ .../git.diff | 14 +++++++++++ 3 files changed, 45 insertions(+) create mode 100644 tests/Integration/DataFixtures/Command/ServiceChangesCommandTest/test_it_ignores_those_decorated_services_that_changed_but_the_decoration_services_are_not_within_the_given_namespace/git.diff diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 9923264..19dbf52 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -229,12 +229,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->outputVerbose("\n\n### Computing changed services"); $this->output->writeln(sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion)); $filesChanged = $this->getFilesChangedBetweenTwoVersions(); + $atLeastOneChanged = false; foreach ($filesChanged as $fileChanged) { foreach ($decoratedServicesAssociation as $newService => $oldService) { $pathFromNamespace = str_replace('\\', \DIRECTORY_SEPARATOR, $oldService); if (!str_contains($fileChanged, $pathFromNamespace)) { continue; } + $atLeastOneChanged = true; $output->writeln( sprintf( 'Service "%s" must be checked because the service that it decorates "%s" has changed between given versions', @@ -245,6 +247,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + if (!$atLeastOneChanged) { + $this->output->writeln('No changes detected'); + } + return 0; } diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index 101658b..1286410 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -107,6 +107,31 @@ public function test_it_detects_with_alias_strategy_those_decorated_services_tha Computing modified services between 1.11.0 and 1.12.0 Service "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendOrderConfirmationHandler" must be checked because the service that it decorates "Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendOrderConfirmationHandler" has changed between given versions +TXT; + + self::assertEquals($expectedOutput, $output); + } + + public function test_it_ignores_those_decorated_services_that_changed_but_the_decoration_services_are_not_within_the_given_namespace(): void + { + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + + $result = $this->commandTester->execute( + [ + ServiceChangesCommand::FROM_VERSION_ARGUMENT_NAME => '1.11.0', + ServiceChangesCommand::TO_VERSION_ARGUMENT_NAME => '1.12.0', + '--' . ServiceChangesCommand::NAMESPACE_PREFIX_OPTION_NAME => 'OtherVendorTests', + '--' . ServiceChangesCommand::ALIAS_PREFIX_OPTION_NAME => 'other_vendor', + ], + ); + + self::assertEquals(0, $result); + + $output = $this->commandTester->getDisplay(); + $expectedOutput = << Date: Mon, 11 Dec 2023 12:53:05 +0100 Subject: [PATCH 13/31] Refactor + comments --- src/Command/ServiceChangesCommand.php | 17 ++++++++--------- tests/Application/config/services_test.yaml | 2 ++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 19dbf52..c61aa41 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -138,22 +138,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - $definitionClass = $definition->getClass(); - if (!is_string($definitionClass)) { - continue; - } - $aliasNormalized = strtolower($alias); // ignore repositories and controllers 'cause they are magically registered if (str_contains($aliasNormalized, 'repository') || str_contains($aliasNormalized, 'controller')) { continue; } - // the new service must be an "App" service - if (!str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix))) { - // this internal service class could have been replaced with an "App" class even though the original service alias is still untouched + $definitionClass = $definition->getClass(); + if (!is_string($definitionClass)) { + continue; + } - // todo: search in $decoratedDefintions by alias? + if (!str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix))) { + // it could happen that the definition class of the decorating service is an "App" class, + // but it still be defined with original service class and alias.. + // todo: i cannot find a way to test this case $decoratedDef = $decoratedDefintions[$definitionClass]['definition'] ?? null; if (!$decoratedDef) { continue; diff --git a/tests/Application/config/services_test.yaml b/tests/Application/config/services_test.yaml index 81bf7e6..ff2651e 100644 --- a/tests/Application/config/services_test.yaml +++ b/tests/Application/config/services_test.yaml @@ -43,6 +43,7 @@ services: decorates: sylius.customer_unique_address_adder + ## test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_province_naming_provider: public: true @@ -67,6 +68,7 @@ services: - '@.inner' + ## test_it_detects_with_alias_strategy_those_decorated_services_that_changed webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_decorated_services_that_changed.decorate_send_order_confirmation: class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendOrderConfirmationHandler From a1f8a0d2b672ffcf21215d1270f456aba48be8e8 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 15 Jan 2024 11:37:02 +0100 Subject: [PATCH 14/31] Add todos + fix verbosity --- src/Command/ServiceChangesCommand.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index c61aa41..5a1a789 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -141,6 +141,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $aliasNormalized = strtolower($alias); // ignore repositories and controllers 'cause they are magically registered if (str_contains($aliasNormalized, 'repository') || str_contains($aliasNormalized, 'controller')) { + // todo: do not know if it's possible to handle this case continue; } @@ -186,10 +187,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $decoratedDefintion = $decoratedDefintions[$alias] ?? null; if ($decoratedDefintion) { + // todo: this is not tested yet $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); + } continue; } @@ -214,7 +218,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); + } continue; } From 85de566d50c98c184daafd739b3867c3371a8131 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 15 Jan 2024 12:22:04 +0100 Subject: [PATCH 15/31] Alerts about Sylius services with "App" class --- src/Command/ServiceChangesCommand.php | 19 +++++++++++++++++-- tests/Application/config/services_test.yaml | 7 +++++++ .../Command/ServiceChangesCommandTest.php | 3 +++ .../DecorateProductVariantPriceCalculator.php | 9 +++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/Stub/ServiceChangesCommand/DecorateProductVariantPriceCalculator.php diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 5a1a789..a99b10e 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -101,6 +101,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $rawKernel->boot(); $decoratedServicesAssociation = []; + $syliusServicesWithAppClass = []; $decoratedDefintions = $decoratorServiceDefinitionsPass::$decoratedServices; $this->outputVerbose("\n\n### DEBUG: Computing decorated services"); @@ -150,7 +151,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - if (!str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix))) { + $isAppClass = str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix)); + if (!$isAppClass) { // it could happen that the definition class of the decorating service is an "App" class, // but it still be defined with original service class and alias.. // todo: i cannot find a way to test this case @@ -227,7 +229,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $this->outputVerbose(sprintf("\tNot found classpath for alias %s", $alias)); + if (class_exists($definitionClass)) { + $syliusServicesWithAppClass[$alias] = $definitionClass; + } } @@ -256,6 +260,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->output->writeln('No changes detected'); } + foreach ($syliusServicesWithAppClass as $alias => $class) { + $output->writeln( + sprintf( + 'Service with class "%s" must be checked manually because the related alias "%s" referes to a' . + ' Sylius service. Actually it\'s impossible to detects if the original class chnaged between versions.', + $class, + $alias, + ), + ); + } + return 0; } diff --git a/tests/Application/config/services_test.yaml b/tests/Application/config/services_test.yaml index ff2651e..edf374b 100644 --- a/tests/Application/config/services_test.yaml +++ b/tests/Application/config/services_test.yaml @@ -78,3 +78,10 @@ services: webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_alias_strategy_those_decorated_services_that_changed.decorate_send_shipment_confirmation_email_handler: class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendShipmentConfirmationEmailHandler decorates: Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendShipmentConfirmationEmailHandler + + + ## test_it_alerts_about_services_whose_class_has_changed_but_not_their_alias + # this + sylius.calculator.product_variant_price: + public: true + class: Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index 1286410..ad89b13 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -55,6 +55,7 @@ public function test_it_detects_with_inner_substitution_strategy_those_decorated Computing modified services between 1.11.0 and 1.12.0 Service "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateOrderEmailManagerInterface" must be checked because the service that it decorates "Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManager" has changed between given versions Service "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateNewShopBased" must be checked because the service that it decorates "Sylius\Component\Core\Cart\Context\ShopBasedCartContext" has changed between given versions +Service with class "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\DecorateProductVariantPriceCalculator" must be checked manually because the related alias "sylius.calculator.product_variant_price" referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. TXT; @@ -81,6 +82,7 @@ public function test_it_detects_with_decorated_definition_strategy_those_decorat Computing modified services between 1.11.0 and 1.12.0 Service "webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_province_naming_provider" must be checked because the service that it decorates "Sylius\Component\Addressing\Provider\ProvinceNamingProvider" has changed between given versions Service "webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_order_payment_processor" must be checked because the service that it decorates "Sylius\Component\Core\OrderProcessing\OrderPaymentProcessor" has changed between given versions +Service with class "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\DecorateProductVariantPriceCalculator" must be checked manually because the related alias "sylius.calculator.product_variant_price" referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. TXT; @@ -106,6 +108,7 @@ public function test_it_detects_with_alias_strategy_those_decorated_services_tha $expectedOutput = << Date: Mon, 22 Jan 2024 10:23:38 +0100 Subject: [PATCH 16/31] Remove unused definition pass --- src/Command/ServiceChangesCommand.php | 13 +-- .../Compiler/RemoveUnusedDefinitionsPass.php | 83 ------------------- 2 files changed, 2 insertions(+), 94 deletions(-) delete mode 100644 src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index a99b10e..fa204e9 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -10,12 +10,10 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass as BaseDecoratorServicePass; -use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass as BaseRemoveUnusedDefinitionsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Tests\Webgriffe\SyliusUpgradePlugin\Application\Kernel; use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; -use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; final class ServiceChangesCommand extends Command { @@ -94,10 +92,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int }, $rawKernel, \get_class($rawKernel)); /** @var ContainerBuilder $rawContainerBuilder */ $rawContainerBuilder = $buildContainer(); - // todo: this is not used, remove? - $removeUnusedDefinitionsPass = new RemoveUnusedDefinitionsPass(); + $decoratorServiceDefinitionsPass = new DecoratorServicePass(); - $this->compile($rawContainerBuilder, $removeUnusedDefinitionsPass, $decoratorServiceDefinitionsPass); + $this->compile($rawContainerBuilder, $decoratorServiceDefinitionsPass); $rawKernel->boot(); $decoratedServicesAssociation = []; @@ -300,17 +297,11 @@ private function getFilesChangedBetweenTwoVersions(): array private function compile( ContainerBuilder $rawContainerBuilder, - RemoveUnusedDefinitionsPass $removeUnusedDefinitionsPass, DecoratorServicePass $decoratorServiceDefinitionsPass ): void { $compiler = $rawContainerBuilder->getCompiler(); foreach ($rawContainerBuilder->getCompilerPassConfig()->getPasses() as $pass) { - if ($pass instanceof BaseRemoveUnusedDefinitionsPass) { - $removeUnusedDefinitionsPass->process($rawContainerBuilder); - - continue; - } if ($pass instanceof BaseDecoratorServicePass) { $decoratorServiceDefinitionsPass->process($rawContainerBuilder); diff --git a/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php b/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php deleted file mode 100644 index 11eca6c..0000000 --- a/src/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.php +++ /dev/null @@ -1,83 +0,0 @@ -enableExpressionProcessing(); - $this->container = $container; - $connectedIds = []; - $aliases = $container->getAliases(); - - foreach ($aliases as $id => $alias) { - if ($alias->isPublic()) { - $this->connectedIds[] = (string) $aliases[$id]; - } - } - - foreach ($container->getDefinitions() as $id => $definition) { - if ($definition->isPublic()) { - $connectedIds[$id] = true; - $this->processValue($definition); - } - } - - while ($this->connectedIds) { - $ids = $this->connectedIds; - $this->connectedIds = []; - foreach ($ids as $id) { - if (!isset($connectedIds[$id]) && $container->hasDefinition($id)) { - $connectedIds[$id] = true; - $this->processValue($container->getDefinition($id)); - } - } - } - - foreach ($container->getDefinitions() as $id => $definition) { - if (!isset($connectedIds[$id])) { - self::$removedDefinitions[$id] = $definition; - $container->removeDefinition($id); - $container->resolveEnvPlaceholders(!$definition->hasErrors() ? serialize($definition) : $definition); - $container->log($this, sprintf('Removed service "%s"; reason: unused.', $id)); - } - } - } finally { - $this->container = null; - $this->connectedIds = []; - } - } - - /** - * @inheritdoc - */ - protected function processValue($value, bool $isRoot = false) - { - if (!$value instanceof Reference) { - return parent::processValue($value, $isRoot); - } - - if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) { - $this->connectedIds[] = (string) $value; - } - - return $value; - } -} From 6cc45a8311929a47e4f22f5172872ddd0406c087 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 10:25:20 +0100 Subject: [PATCH 17/31] Output based on verbosity --- src/Command/ServiceChangesCommand.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index fa204e9..63aa06c 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -119,8 +119,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $class = $decoratedDef['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$alias] = $class; - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); + } continue; } From 449802ebdc9f7947421d3895ce5f97dceab89852 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 12:00:36 +0100 Subject: [PATCH 18/31] Refactor: extract strategies in methods --- src/Command/ServiceChangesCommand.php | 175 +++++++++++------- .../Compiler/DecoratorServicePass.php | 2 +- 2 files changed, 109 insertions(+), 68 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 63aa06c..3492c11 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -11,6 +11,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass as BaseDecoratorServicePass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Tests\Webgriffe\SyliusUpgradePlugin\Application\Kernel; use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; @@ -103,33 +104,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->outputVerbose("\n\n### DEBUG: Computing decorated services"); + /** @var array $rawDefinitions */ $rawDefinitions = $rawContainerBuilder->getDefinitions(); foreach ($rawDefinitions as $alias => $definition) { - $decoratedDef = $decoratedDefintions[$alias] ?? null; - - // if the service is an "App" service, seek for the original Sylius service in the decorated definitions - if ($decoratedDef && - (str_starts_with($alias, sprintf('%s\\', $this->namespacePrefix)) || - str_starts_with($alias, sprintf('%s.', $this->aliasPrefix))) - ) { - $decoratedServiceId = $decoratedDef['id']; - if (str_starts_with($decoratedServiceId, 'sylius.') || - str_starts_with($decoratedServiceId, 'Sylius\\') || - str_starts_with($decoratedServiceId, '\\Sylius\\')) { - $class = $decoratedDef['definition']?->getClass(); - if ($class !== null && class_exists($class)) { - $decoratedServicesAssociation[$alias] = $class; - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); - } - - continue; - } - } + $decoratedDefintion = $decoratedDefintions[$alias] ?? null; + if ($this->applyDecoratedDefinitionsStrategy($decoratedServicesAssociation, $alias, $decoratedDefintion)) { + continue; } - // otherwise, the replaced service must be a "Sylius" service if (!(str_starts_with($alias, 'sylius.') || str_starts_with($alias, 'Sylius\\') || @@ -152,47 +134,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int $isAppClass = str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix)); if (!$isAppClass) { - // it could happen that the definition class of the decorating service is an "App" class, - // but it still be defined with original service class and alias.. - // todo: i cannot find a way to test this case - $decoratedDef = $decoratedDefintions[$definitionClass]['definition'] ?? null; - if (!$decoratedDef) { - continue; - } - - $decoratedDefClass = $decoratedDef->getClass(); - if (!str_starts_with($decoratedDefClass, sprintf('%s\\', $this->namespacePrefix)) || !class_exists($decoratedDefClass)) { - continue; - } - - $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $decoratedDefClass)); - } + $this->applyDecoratedDefinitionsNonAppClassStrategy($decoratedServicesAssociation, $alias, $definitionClass); continue; } - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); - } - if (class_exists($alias)) { - $decoratedServicesAssociation[$definitionClass] = $alias; - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf("\tFound classpath by 'alias' strategy: %s", $alias)); - } - + if ($this->applyAliasStrategy($decoratedServicesAssociation, $alias, $definitionClass)) { continue; } - $decoratedDefintion = $decoratedDefintions[$alias] ?? null; + // todo: to remove if ($decoratedDefintion) { // todo: this is not tested yet $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $class, $definitionClass)); $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); } @@ -200,7 +158,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - // todo: this is not applying a valid logic actually + // todo: this is not applying a valid logic actually, remove? // if (str_ends_with($alias, 'Interface')) { // $class = str_replace('Interface', '', $alias); // if (class_exists($class)) { @@ -211,21 +169,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int // } // } - $innerServiceId = $definition->innerServiceId; - if ($innerServiceId !== null && str_contains($innerServiceId, '.inner')) { - $originalServiceId = str_replace('.inner', '', $innerServiceId); - $decoratedDefintion = $decoratedDefintions[$originalServiceId] ?? null; - if ($decoratedDefintion) { - $class = $decoratedDefintion['definition']?->getClass(); - if ($class !== null && class_exists($class)) { - $decoratedServicesAssociation[$definitionClass] = $class; - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); - } - - continue; - } - } + if ($this->applyInnerStrategy($decoratedServicesAssociation, $definition, $decoratedDefintions, $definitionClass)) { + continue; } if (class_exists($definitionClass)) { @@ -348,4 +293,100 @@ private function loadInputs(InputInterface $input): void } $this->aliasPrefix = $aliasPrefix; } + + /** + * If the service is an "App" service, seek for the original Sylius service in the decorated definitions + */ + private function applyDecoratedDefinitionsStrategy( + array &$decoratedServicesAssociation, + string $alias, + ?array $decoratedDef = null + ): bool { + if ($decoratedDef && + (str_starts_with($alias, sprintf('%s\\', $this->namespacePrefix)) || + str_starts_with($alias, sprintf('%s.', $this->aliasPrefix))) + ) { + $decoratedServiceId = $decoratedDef['id']; + if (str_starts_with($decoratedServiceId, 'sylius.') || + str_starts_with($decoratedServiceId, 'Sylius\\') || + str_starts_with($decoratedServiceId, '\\Sylius\\')) { + $class = $decoratedDef['definition']?->getClass(); + if ($class !== null && class_exists($class)) { + $decoratedServicesAssociation[$alias] = $class; + if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); + } + + return true; + } + } + } + + return false; + } + + /** + * It could happen that the definition class of the decorating service is an "App" class, + * but it still was defined with original service class and alias.. + */ + private function applyDecoratedDefinitionsNonAppClassStrategy(array &$decoratedServicesAssociation, string $alias, string $definitionClass,): bool + { + // todo: i cannot find a way to test these cases + $decoratedDef = $decoratedDefintions[$definitionClass]['definition'] ?? null; + if (!$decoratedDef) { + return true; + } + + $decoratedDefClass = $decoratedDef->getClass(); + if (!str_starts_with($decoratedDefClass, sprintf('%s\\', $this->namespacePrefix)) || !class_exists($decoratedDefClass)) { + return true; + } + + $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; + if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $decoratedDefClass)); + } + + return true; + } + + private function applyAliasStrategy(array &$decoratedServicesAssociation, string $alias, string $definitionClass,): bool + { + if (!class_exists($alias)) { + return false; + } + + $decoratedServicesAssociation[$definitionClass] = $alias; + if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by 'alias' strategy: %s", $alias)); + } + + return true; + } + + private function applyInnerStrategy(array &$decoratedServicesAssociation, Definition $definition, array $decoratedDefintions, string $definitionClass): bool + { + $innerServiceId = $definition->innerServiceId; + if ($innerServiceId !== null && str_contains($innerServiceId, '.inner')) { + $originalServiceId = str_replace('.inner', '', $innerServiceId); + $decoratedDefintion = $decoratedDefintions[$originalServiceId] ?? null; + if ($decoratedDefintion) { + $class = $decoratedDefintion['definition']?->getClass(); + if ($class !== null && class_exists($class)) { + $decoratedServicesAssociation[$definitionClass] = $class; + if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $class, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); + } + + return true; + } + } + } + + return false; + } } diff --git a/src/DependencyInjection/Compiler/DecoratorServicePass.php b/src/DependencyInjection/Compiler/DecoratorServicePass.php index d6c2968..cbd92f1 100644 --- a/src/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/DependencyInjection/Compiler/DecoratorServicePass.php @@ -15,7 +15,7 @@ class DecoratorServicePass extends AbstractRecursivePass { - /** @var Definition[] */ + /** @var array[] */ public static array $decoratedServices = []; public function process(ContainerBuilder $container) From 6972a13d26d55056f49761cf0ff79624098c49d2 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 12:03:05 +0100 Subject: [PATCH 19/31] Remove strategy that is covered by others --- src/Command/ServiceChangesCommand.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 3492c11..170f651 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -158,17 +158,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - // todo: this is not applying a valid logic actually, remove? -// if (str_ends_with($alias, 'Interface')) { -// $class = str_replace('Interface', '', $alias); -// if (class_exists($class)) { -// $decoratedServicesAssociation[$definitionClass] = $class; -// $this->outputVerbose(sprintf("\tFound classpath by 'Interface substitution' strategy: %s", $class)); -// -// continue; -// } -// } - if ($this->applyInnerStrategy($decoratedServicesAssociation, $definition, $decoratedDefintions, $definitionClass)) { continue; } From 27aaceb035a27083d9e302a6d916ff7b2023e59f Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 12:03:16 +0100 Subject: [PATCH 20/31] Remove duplicated strategy --- src/Command/ServiceChangesCommand.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 170f651..c22d894 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -143,21 +143,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - // todo: to remove - if ($decoratedDefintion) { - // todo: this is not tested yet - $class = $decoratedDefintion['definition']?->getClass(); - if ($class !== null && class_exists($class)) { - $decoratedServicesAssociation[$definitionClass] = $class; - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $class, $definitionClass)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); - } - - continue; - } - } - if ($this->applyInnerStrategy($decoratedServicesAssociation, $definition, $decoratedDefintions, $definitionClass)) { continue; } From c20b4ff0863bc856d26e106bd9fcd6b294f8d292 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 12:06:15 +0100 Subject: [PATCH 21/31] Extract utility method --- src/Command/ServiceChangesCommand.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index c22d894..8c78c31 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -113,10 +113,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } // otherwise, the replaced service must be a "Sylius" service - if (!(str_starts_with($alias, 'sylius.') || - str_starts_with($alias, 'Sylius\\') || - str_starts_with($alias, '\\Sylius\\')) - ) { + if (!($this->isSyliusService($alias))) { continue; } @@ -152,7 +149,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $this->outputVerbose("\n\n### Computing changed services"); $this->output->writeln(sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion)); $filesChanged = $this->getFilesChangedBetweenTwoVersions(); @@ -268,6 +264,13 @@ private function loadInputs(InputInterface $input): void $this->aliasPrefix = $aliasPrefix; } + private function isSyliusService(mixed $decoratedServiceId): bool + { + return str_starts_with($decoratedServiceId, 'sylius.') || + str_starts_with($decoratedServiceId, 'Sylius\\') || + str_starts_with($decoratedServiceId, '\\Sylius\\'); + } + /** * If the service is an "App" service, seek for the original Sylius service in the decorated definitions */ @@ -281,9 +284,7 @@ private function applyDecoratedDefinitionsStrategy( str_starts_with($alias, sprintf('%s.', $this->aliasPrefix))) ) { $decoratedServiceId = $decoratedDef['id']; - if (str_starts_with($decoratedServiceId, 'sylius.') || - str_starts_with($decoratedServiceId, 'Sylius\\') || - str_starts_with($decoratedServiceId, '\\Sylius\\')) { + if ($this->isSyliusService($decoratedServiceId)) { $class = $decoratedDef['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$alias] = $class; From e6a7d044b3c9303b22ddd1944868ff7ffbc27f01 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 12:46:44 +0100 Subject: [PATCH 22/31] More extraction into methods --- src/Command/ServiceChangesCommand.php | 68 +++++++++++++-------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 8c78c31..ed73953 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -149,8 +149,30 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + if (!($this->computeServicesThatChanged($decoratedServicesAssociation))) { + $this->output->writeln('No changes detected'); + } + + foreach ($syliusServicesWithAppClass as $alias => $class) { + $output->writeln( + sprintf( + 'Service with class "%s" must be checked manually because the related alias "%s" referes to a' . + ' Sylius service. Actually it\'s impossible to detects if the original class chnaged between versions.', + $class, + $alias, + ), + ); + } + + return 0; + } + + private function computeServicesThatChanged(array $decoratedServicesAssociation): bool + { $this->outputVerbose("\n\n### Computing changed services"); - $this->output->writeln(sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion)); + $this->output->writeln( + sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion) + ); $filesChanged = $this->getFilesChangedBetweenTwoVersions(); $atLeastOneChanged = false; foreach ($filesChanged as $fileChanged) { @@ -160,7 +182,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } $atLeastOneChanged = true; - $output->writeln( + $this->output->writeln( sprintf( 'Service "%s" must be checked because the service that it decorates "%s" has changed between given versions', $newService, @@ -169,23 +191,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } } - - if (!$atLeastOneChanged) { - $this->output->writeln('No changes detected'); - } - - foreach ($syliusServicesWithAppClass as $alias => $class) { - $output->writeln( - sprintf( - 'Service with class "%s" must be checked manually because the related alias "%s" referes to a' . - ' Sylius service. Actually it\'s impossible to detects if the original class chnaged between versions.', - $class, - $alias, - ), - ); - } - - return 0; + return $atLeastOneChanged; } /** @@ -288,10 +294,8 @@ private function applyDecoratedDefinitionsStrategy( $class = $decoratedDef['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$alias] = $class; - if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); - } + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $class)); return true; } @@ -319,10 +323,8 @@ private function applyDecoratedDefinitionsNonAppClassStrategy(array &$decoratedS } $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; - if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); - $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $decoratedDefClass)); - } + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by 'decorated definitions' strategy: %s", $decoratedDefClass)); return true; } @@ -334,10 +336,8 @@ private function applyAliasStrategy(array &$decoratedServicesAssociation, string } $decoratedServicesAssociation[$definitionClass] = $alias; - if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); - $this->outputVerbose(sprintf("\tFound classpath by 'alias' strategy: %s", $alias)); - } + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $alias, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by 'alias' strategy: %s", $alias)); return true; } @@ -352,10 +352,8 @@ private function applyInnerStrategy(array &$decoratedServicesAssociation, Defini $class = $decoratedDefintion['definition']?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; - if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $class, $definitionClass)); - $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); - } + $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $class, $definitionClass)); + $this->outputVerbose(sprintf("\tFound classpath by '.inner substitution' strategy: %s", $class)); return true; } From 1a35898ba29ed8ffb24ed2c32c1442f937034ca1 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 22 Jan 2024 14:37:28 +0100 Subject: [PATCH 23/31] Better output --- src/Command/ServiceChangesCommand.php | 62 ++++++++++++------- .../Command/ServiceChangesCommandTest.php | 30 ++++++--- 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index ed73953..d44fd69 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -150,18 +150,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (!($this->computeServicesThatChanged($decoratedServicesAssociation))) { - $this->output->writeln('No changes detected'); + $this->writeLine('No changes detected'); } - foreach ($syliusServicesWithAppClass as $alias => $class) { - $output->writeln( + if (count($syliusServicesWithAppClass) > 0) { + $this->writeLine(''); + $this->writeLine( sprintf( - 'Service with class "%s" must be checked manually because the related alias "%s" referes to a' . - ' Sylius service. Actually it\'s impossible to detects if the original class chnaged between versions.', - $class, - $alias, - ), + 'Found %s services that must be checked manually because the related alias referes to a Sylius' . + ' service. Actually it\'s impossible to detects if the original class chnaged between versions.' . + ' Here is the list ([decorated service] -> [decorating service]):', + count($syliusServicesWithAppClass) + ) ); + foreach ($syliusServicesWithAppClass as $alias => $class) { + $this->writeLine(sprintf('"%s" -> "%s"', $alias, $class)); + } } return 0; @@ -169,29 +173,37 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function computeServicesThatChanged(array $decoratedServicesAssociation): bool { - $this->outputVerbose("\n\n### Computing changed services"); - $this->output->writeln( + $this->writeLine( sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion) ); + $this->writeLine(''); + + $decoratedServices = []; $filesChanged = $this->getFilesChangedBetweenTwoVersions(); - $atLeastOneChanged = false; foreach ($filesChanged as $fileChanged) { foreach ($decoratedServicesAssociation as $newService => $oldService) { $pathFromNamespace = str_replace('\\', \DIRECTORY_SEPARATOR, $oldService); if (!str_contains($fileChanged, $pathFromNamespace)) { continue; } - $atLeastOneChanged = true; - $this->output->writeln( - sprintf( - 'Service "%s" must be checked because the service that it decorates "%s" has changed between given versions', - $newService, - $oldService, - ), - ); + $decoratedServices[$newService] = $oldService; } } - return $atLeastOneChanged; + if (count($decoratedServices) === 0) { + $this->writeLine('Found 0 services that changed and was decorated.'); + + return false; + } + + $this->writeLine(sprintf( + 'Found %s services that changed and were decorated ([decorated service] -> [decorating service]):', + count($decoratedServices) + )); + foreach ($decoratedServices as $newService => $oldService) { + $this->writeLine(sprintf('"%s" -> "%s"', $oldService, $newService)); + } + + return true; } /** @@ -239,8 +251,16 @@ private function compile( private function outputVerbose(string $message): void { if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $this->output->writeln($message); + $this->writeLine($message); + } + } + + private function writeLine(string $message): void + { + if ($this->output === null) { + return; } + $this->output->writeln($message); } private function loadInputs(InputInterface $input): void diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index ad89b13..f79c9dd 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -53,9 +53,13 @@ public function test_it_detects_with_inner_substitution_strategy_those_decorated $output = $this->commandTester->getDisplay(); $expectedOutput = << [decorating service]): +"Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManager" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateOrderEmailManagerInterface" +"Sylius\Component\Core\Cart\Context\ShopBasedCartContext" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateNewShopBased" + +Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. Here is the list ([decorated service] -> [decorating service]): +"sylius.calculator.product_variant_price" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator" TXT; @@ -80,9 +84,13 @@ public function test_it_detects_with_decorated_definition_strategy_those_decorat $output = $this->commandTester->getDisplay(); $expectedOutput = << [decorating service]): +"Sylius\Component\Addressing\Provider\ProvinceNamingProvider" -> "webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_province_naming_provider" +"Sylius\Component\Core\OrderProcessing\OrderPaymentProcessor" -> "webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_order_payment_processor" + +Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. Here is the list ([decorated service] -> [decorating service]): +"sylius.calculator.product_variant_price" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator" TXT; @@ -107,8 +115,12 @@ public function test_it_detects_with_alias_strategy_those_decorated_services_tha $output = $this->commandTester->getDisplay(); $expectedOutput = << [decorating service]): +"Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendOrderConfirmationHandler" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendOrderConfirmationHandler" + +Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. Here is the list ([decorated service] -> [decorating service]): +"sylius.calculator.product_variant_price" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator" TXT; @@ -133,6 +145,8 @@ public function test_it_ignores_those_decorated_services_that_changed_but_the_de $output = $this->commandTester->getDisplay(); $expectedOutput = << Date: Mon, 5 Feb 2024 12:27:47 +0100 Subject: [PATCH 24/31] Specify interfaces for decorated methods in tests --- .../DecorateProductVariantPriceCalculator.php | 14 +++++++++++++- .../DecorateSendOrderConfirmationHandler.php | 4 +++- ...orateSendShipmentConfirmationEmailHandler.php | 4 +++- .../DecorateCustomerOrderAddressesSaver.php | 8 +++++++- .../DecorateOrderPaymentProcessor.php | 8 +++++++- .../DecorateProvinceNamingProvider.php | 14 +++++++++++++- .../DecorateCustomerUniqueAddressAdder.php | 10 +++++++++- .../DecorateNewShopBased.php | 16 +++++++++++++++- .../DecorateOrderEmailManagerInterface.php | 9 ++++++++- 9 files changed, 78 insertions(+), 9 deletions(-) diff --git a/tests/Stub/ServiceChangesCommand/DecorateProductVariantPriceCalculator.php b/tests/Stub/ServiceChangesCommand/DecorateProductVariantPriceCalculator.php index 50b6f89..d1fb5aa 100644 --- a/tests/Stub/ServiceChangesCommand/DecorateProductVariantPriceCalculator.php +++ b/tests/Stub/ServiceChangesCommand/DecorateProductVariantPriceCalculator.php @@ -4,6 +4,18 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand; -final class DecorateProductVariantPriceCalculator +use Sylius\Component\Core\Calculator\ProductVariantPricesCalculatorInterface; +use Sylius\Component\Core\Model\ProductVariantInterface; + +final class DecorateProductVariantPriceCalculator implements ProductVariantPricesCalculatorInterface { + public function calculate(ProductVariantInterface $productVariant, array $context): int + { + return 0; + } + + public function calculateOriginal(ProductVariantInterface $productVariant, array $context): int + { + return 0; + } } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendOrderConfirmationHandler.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendOrderConfirmationHandler.php index b5fa1fd..ed415e9 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendOrderConfirmationHandler.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendOrderConfirmationHandler.php @@ -4,6 +4,8 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_decorated_services_that_changed; -final class DecorateSendOrderConfirmationHandler +use Symfony\Component\Messenger\Handler\MessageHandlerInterface; + +final class DecorateSendOrderConfirmationHandler implements MessageHandlerInterface { } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendShipmentConfirmationEmailHandler.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendShipmentConfirmationEmailHandler.php index 779e733..05e9e47 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendShipmentConfirmationEmailHandler.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_alias_strategy_those_decorated_services_that_changed/DecorateSendShipmentConfirmationEmailHandler.php @@ -4,6 +4,8 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_alias_strategy_those_decorated_services_that_changed; -final class DecorateSendShipmentConfirmationEmailHandler +use Symfony\Component\Messenger\Handler\MessageHandlerInterface; + +final class DecorateSendShipmentConfirmationEmailHandler implements MessageHandlerInterface { } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateCustomerOrderAddressesSaver.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateCustomerOrderAddressesSaver.php index e59141d..673621a 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateCustomerOrderAddressesSaver.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateCustomerOrderAddressesSaver.php @@ -5,10 +5,16 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed; use Sylius\Component\Core\Customer\OrderAddressesSaverInterface; +use Sylius\Component\Core\Model\OrderInterface; -final class DecorateCustomerOrderAddressesSaver +final class DecorateCustomerOrderAddressesSaver implements OrderAddressesSaverInterface { public function __construct(private OrderAddressesSaverInterface $decoratedCustomerOrderAddressesSaver) { } + + public function saveAddresses(OrderInterface $order): void + { + $this->decoratedCustomerOrderAddressesSaver->saveAddresses($order); + } } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateOrderPaymentProcessor.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateOrderPaymentProcessor.php index 2da3d7e..9c918b3 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateOrderPaymentProcessor.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateOrderPaymentProcessor.php @@ -4,11 +4,17 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed; +use Sylius\Component\Order\Model\OrderInterface; use Sylius\Component\Order\Processor\OrderProcessorInterface; -final class DecorateOrderPaymentProcessor +final class DecorateOrderPaymentProcessor implements OrderProcessorInterface { public function __construct(private OrderProcessorInterface $decoratedAfterCheckoutOrderPaymentProcessor) { } + + public function process(OrderInterface $order): void + { + $this->decoratedAfterCheckoutOrderPaymentProcessor->process($order); + } } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateProvinceNamingProvider.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateProvinceNamingProvider.php index bef4745..bb9bb57 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateProvinceNamingProvider.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed/DecorateProvinceNamingProvider.php @@ -4,11 +4,23 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed; +use Sylius\Component\Addressing\Model\AddressInterface; use Sylius\Component\Addressing\Provider\ProvinceNamingProvider as BaseProvinceNamingProvider; +use Sylius\Component\Addressing\Provider\ProvinceNamingProviderInterface; -final class DecorateProvinceNamingProvider +final class DecorateProvinceNamingProvider implements ProvinceNamingProviderInterface { public function __construct(private BaseProvinceNamingProvider $baseProvinceNamingProvider) { } + + public function getName(AddressInterface $address): string + { + return $this->baseProvinceNamingProvider->getName($address); + } + + public function getAbbreviation(AddressInterface $address): string + { + return $this->baseProvinceNamingProvider->getAbbreviation($address); + } } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php index e167600..21948f2 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateCustomerUniqueAddressAdder.php @@ -4,6 +4,14 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed; -final class DecorateCustomerUniqueAddressAdder +use Sylius\Component\Core\Customer\CustomerAddressAdderInterface; +use Sylius\Component\Core\Model\AddressInterface; +use Sylius\Component\Core\Model\CustomerInterface; + +final class DecorateCustomerUniqueAddressAdder implements CustomerAddressAdderInterface { + public function add(CustomerInterface $customer, AddressInterface $address): void + { + // TODO: Implement add() method. + } } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateNewShopBased.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateNewShopBased.php index 4c5902e..d9d35c5 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateNewShopBased.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateNewShopBased.php @@ -4,6 +4,20 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed; -final class DecorateNewShopBased +use Sylius\Component\Core\Model\Order; +use Sylius\Component\Order\Context\CartContextInterface; +use Sylius\Component\Order\Model\OrderInterface; +use Symfony\Contracts\Service\ResetInterface; + +final class DecorateNewShopBased implements CartContextInterface, ResetInterface { + public function getCart(): OrderInterface + { + return new Order(); + } + + public function reset() + { + // TODO: Implement reset() method. + } } diff --git a/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateOrderEmailManagerInterface.php b/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateOrderEmailManagerInterface.php index 0eda277..aa94e85 100644 --- a/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateOrderEmailManagerInterface.php +++ b/tests/Stub/ServiceChangesCommand/test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed/DecorateOrderEmailManagerInterface.php @@ -4,6 +4,13 @@ namespace Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed; -final class DecorateOrderEmailManagerInterface +use Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManagerInterface; +use Sylius\Component\Core\Model\OrderInterface; + +final class DecorateOrderEmailManagerInterface implements OrderEmailManagerInterface { + public function sendConfirmationEmail(OrderInterface $order): void + { + // TODO: Implement sendConfirmationEmail() method. + } } From 8d3a9404a8e6d1e018ff0eb1bef96775ea7f8a36 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 5 Feb 2024 14:21:28 +0100 Subject: [PATCH 25/31] Fix phpstan and psalm --- phpstan.neon | 2 + psalm.xml | 1 + src/Command/ServiceChangesCommand.php | 145 ++++++++++++++++++++------ 3 files changed, 117 insertions(+), 31 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 796d44e..da74e26 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,6 +8,8 @@ parameters: excludePaths: # Makes PHPStan crash - 'src/DependencyInjection/Configuration.php' + # Override a Symfony class + - 'src/DependencyInjection/Compiler/DecoratorServicePass.php' # Test dependencies - 'tests/Application/app/**.php' diff --git a/psalm.xml b/psalm.xml index 3240886..231c541 100644 --- a/psalm.xml +++ b/psalm.xml @@ -10,6 +10,7 @@ + diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index d44fd69..fe3b044 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -5,6 +5,7 @@ namespace Webgriffe\SyliusUpgradePlugin\Command; use Symfony\Bundle\FrameworkBundle\Command\BuildDebugContainerTrait; +use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -15,6 +16,7 @@ use Tests\Webgriffe\SyliusUpgradePlugin\Application\Kernel; use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; +use Webmozart\Assert\Assert; final class ServiceChangesCommand extends Command { @@ -30,17 +32,15 @@ final class ServiceChangesCommand extends Command protected static $defaultName = 'webgriffe:upgrade:service-changes'; - private OutputInterface $output; + private ?OutputInterface $output = null; - /** @psalm-suppress PropertyNotSetInConstructor */ - private string $toVersion; + private ?string $toVersion = null; - /** @psalm-suppress PropertyNotSetInConstructor */ - private string $fromVersion; + private ?string $fromVersion = null; - private string $namespacePrefix; + private ?string $namespacePrefix = null; - private string $aliasPrefix; + private ?string $aliasPrefix = null; public function __construct(private GitInterface $gitClient, string $name = null) { @@ -84,12 +84,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->output = $output; $this->loadInputs($input); - /** @var Kernel $rawKernel */ - $rawKernel = $this->getApplication()->getKernel(); - $buildContainer = \Closure::bind(function () { + /** @var Application|null $application */ + $application = $this->getApplication(); + /** @var Kernel|null $rawKernel */ + $rawKernel = $application?->getKernel(); + Assert::isInstanceOf($rawKernel, Kernel::class); + + /** @var \Closure $buildContainer */ + $buildContainer = \Closure::bind(function (): ContainerBuilder { + /** @psalm-suppress UndefinedMethod */ $this->initializeBundles(); + /** + * @var ContainerBuilder $containerBuilder + * @psalm-suppress UndefinedMethod + */ + $containerBuilder = $this->buildContainer(); - return $this->buildContainer(); + return $containerBuilder; }, $rawKernel, \get_class($rawKernel)); /** @var ContainerBuilder $rawContainerBuilder */ $rawContainerBuilder = $buildContainer(); @@ -98,13 +109,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->compile($rawContainerBuilder, $decoratorServiceDefinitionsPass); $rawKernel->boot(); + /** @var array $decoratedServicesAssociation */ $decoratedServicesAssociation = []; $syliusServicesWithAppClass = []; $decoratedDefintions = $decoratorServiceDefinitionsPass::$decoratedServices; $this->outputVerbose("\n\n### DEBUG: Computing decorated services"); - /** @var array $rawDefinitions */ $rawDefinitions = $rawContainerBuilder->getDefinitions(); foreach ($rawDefinitions as $alias => $definition) { $decoratedDefintion = $decoratedDefintions[$alias] ?? null; @@ -129,9 +140,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - $isAppClass = str_starts_with($definitionClass, sprintf('%s\\', $this->namespacePrefix)); + $isAppClass = str_starts_with($definitionClass, sprintf('%s\\', $this->getNamespacePrefix())); if (!$isAppClass) { - $this->applyDecoratedDefinitionsNonAppClassStrategy($decoratedServicesAssociation, $alias, $definitionClass); + $this->applyDecoratedDefinitionsNonAppClassStrategy($decoratedServicesAssociation, $decoratedDefintions, $alias, $definitionClass); continue; } @@ -171,10 +182,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } + /** + * @param array $decoratedServicesAssociation + */ private function computeServicesThatChanged(array $decoratedServicesAssociation): bool { $this->writeLine( - sprintf('Computing modified services between %s and %s', $this->fromVersion, $this->toVersion) + sprintf('Computing modified services between %s and %s', $this->getFromVersion(), $this->getToVersion()) ); $this->writeLine(''); @@ -211,7 +225,7 @@ private function computeServicesThatChanged(array $decoratedServicesAssociation) */ private function getFilesChangedBetweenTwoVersions(): array { - $diff = $this->gitClient->getDiffBetweenTags($this->fromVersion, $this->toVersion); + $diff = $this->gitClient->getDiffBetweenTags($this->getFromVersion(), $this->getToVersion()); $versionChangedFiles = []; $diffLines = explode(\PHP_EOL, $diff); foreach ($diffLines as $diffLine) { @@ -250,6 +264,9 @@ private function compile( private function outputVerbose(string $message): void { + if ($this->output === null) { + return; + } if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { $this->writeLine($message); } @@ -290,7 +307,7 @@ private function loadInputs(InputInterface $input): void $this->aliasPrefix = $aliasPrefix; } - private function isSyliusService(mixed $decoratedServiceId): bool + private function isSyliusService(string $decoratedServiceId): bool { return str_starts_with($decoratedServiceId, 'sylius.') || str_starts_with($decoratedServiceId, 'Sylius\\') || @@ -299,19 +316,24 @@ private function isSyliusService(mixed $decoratedServiceId): bool /** * If the service is an "App" service, seek for the original Sylius service in the decorated definitions + * + * @param array $decoratedServicesAssociation */ private function applyDecoratedDefinitionsStrategy( array &$decoratedServicesAssociation, string $alias, ?array $decoratedDef = null ): bool { - if ($decoratedDef && - (str_starts_with($alias, sprintf('%s\\', $this->namespacePrefix)) || - str_starts_with($alias, sprintf('%s.', $this->aliasPrefix))) + if ($decoratedDef !== null && + (str_starts_with($alias, sprintf('%s\\', $this->getNamespacePrefix())) || + str_starts_with($alias, sprintf('%s.', $this->getAliasPrefix()))) ) { + /** @var string $decoratedServiceId */ $decoratedServiceId = $decoratedDef['id']; if ($this->isSyliusService($decoratedServiceId)) { - $class = $decoratedDef['definition']?->getClass(); + /** @var Definition|null $definition */ + $definition = $decoratedDef['definition'] ?? null; + $class = $definition?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$alias] = $class; $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $decoratedServiceId, $alias)); @@ -328,18 +350,30 @@ private function applyDecoratedDefinitionsStrategy( /** * It could happen that the definition class of the decorating service is an "App" class, * but it still was defined with original service class and alias.. + * + * @param array $decoratedServicesAssociation */ - private function applyDecoratedDefinitionsNonAppClassStrategy(array &$decoratedServicesAssociation, string $alias, string $definitionClass,): bool - { + private function applyDecoratedDefinitionsNonAppClassStrategy( + array &$decoratedServicesAssociation, + array $decoratedDefintions, + string $alias, + string $definitionClass, + ): bool { // todo: i cannot find a way to test these cases + /** @var Definition|null $decoratedDef */ $decoratedDef = $decoratedDefintions[$definitionClass]['definition'] ?? null; - if (!$decoratedDef) { - return true; + if ($decoratedDef === null) { + return false; } $decoratedDefClass = $decoratedDef->getClass(); - if (!str_starts_with($decoratedDefClass, sprintf('%s\\', $this->namespacePrefix)) || !class_exists($decoratedDefClass)) { - return true; + if ($decoratedDefClass === null) { + return false; + } + + if (!str_starts_with($decoratedDefClass, sprintf('%s\\', $this->getNamespacePrefix())) || + !class_exists($decoratedDefClass)) { + return false; } $decoratedServicesAssociation[$definitionClass] = $decoratedDefClass; @@ -349,6 +383,9 @@ private function applyDecoratedDefinitionsNonAppClassStrategy(array &$decoratedS return true; } + /** + * @param array $decoratedServicesAssociation + */ private function applyAliasStrategy(array &$decoratedServicesAssociation, string $alias, string $definitionClass,): bool { if (!class_exists($alias)) { @@ -362,14 +399,28 @@ private function applyAliasStrategy(array &$decoratedServicesAssociation, string return true; } - private function applyInnerStrategy(array &$decoratedServicesAssociation, Definition $definition, array $decoratedDefintions, string $definitionClass): bool - { + /** + * @param array $decoratedServicesAssociation + * @param array[] $decoratedDefintions + */ + private function applyInnerStrategy( + array &$decoratedServicesAssociation, + Definition $definition, + array $decoratedDefintions, + string $definitionClass + ): bool { + /** + * @var string|null $innerServiceId + * @psalm-suppress InternalProperty + */ $innerServiceId = $definition->innerServiceId; if ($innerServiceId !== null && str_contains($innerServiceId, '.inner')) { $originalServiceId = str_replace('.inner', '', $innerServiceId); $decoratedDefintion = $decoratedDefintions[$originalServiceId] ?? null; - if ($decoratedDefintion) { - $class = $decoratedDefintion['definition']?->getClass(); + if ($decoratedDefintion !== null) { + /** @var Definition|null $definition2 */ + $definition2 = $decoratedDefintion['definition']; + $class = $definition2?->getClass(); if ($class !== null && class_exists($class)) { $decoratedServicesAssociation[$definitionClass] = $class; $this->outputVerbose(sprintf('Sylius service "%s" has been replaced with "%s"', $class, $definitionClass)); @@ -382,4 +433,36 @@ private function applyInnerStrategy(array &$decoratedServicesAssociation, Defini return false; } + + private function getFromVersion(): string + { + $value = $this->fromVersion; + Assert::notNull($value); + + return $value; + } + + private function getToVersion(): string + { + $value = $this->toVersion; + Assert::notNull($value); + + return $value; + } + + private function getNamespacePrefix(): string + { + $value = $this->namespacePrefix; + Assert::notNull($value); + + return $value; + } + + private function getAliasPrefix(): string + { + $value = $this->aliasPrefix; + Assert::notNull($value); + + return $value; + } } From 4b3afae95bb793385b73f4f4937f8760e3e6bcfd Mon Sep 17 00:00:00 2001 From: Luca Date: Mon, 12 Feb 2024 11:32:19 +0100 Subject: [PATCH 26/31] Typos Co-authored-by: Lorenzo Ruozzi --- src/Command/ServiceChangesCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index fe3b044..a243dcf 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -169,7 +169,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->writeLine( sprintf( 'Found %s services that must be checked manually because the related alias referes to a Sylius' . - ' service. Actually it\'s impossible to detects if the original class chnaged between versions.' . + ' service. Actually it\'s impossible to detect if the original class changed between versions.' . ' Here is the list ([decorated service] -> [decorating service]):', count($syliusServicesWithAppClass) ) From 2a5d7dd80aadadade758174ef941feb25bba07b0 Mon Sep 17 00:00:00 2001 From: Lorenzo Ruozzi Date: Mon, 13 May 2024 12:20:11 +0200 Subject: [PATCH 27/31] Fixes after upgrade --- .../Command/ServiceChangesCommandTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Integration/Command/ServiceChangesCommandTest.php b/tests/Integration/Command/ServiceChangesCommandTest.php index f79c9dd..849a571 100644 --- a/tests/Integration/Command/ServiceChangesCommandTest.php +++ b/tests/Integration/Command/ServiceChangesCommandTest.php @@ -37,7 +37,7 @@ protected function tearDown(): void public function test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed(): void { - Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->name() . '/git.diff'); $result = $this->commandTester->execute( [ @@ -58,7 +58,7 @@ public function test_it_detects_with_inner_substitution_strategy_those_decorated "Sylius\Bundle\AdminBundle\EmailManager\OrderEmailManager" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateOrderEmailManagerInterface" "Sylius\Component\Core\Cart\Context\ShopBasedCartContext" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_inner_substitution_strategy_those_decorated_services_that_changed\DecorateNewShopBased" -Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. Here is the list ([decorated service] -> [decorating service]): +Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detect if the original class changed between versions. Here is the list ([decorated service] -> [decorating service]): "sylius.calculator.product_variant_price" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator" TXT; @@ -68,7 +68,7 @@ public function test_it_detects_with_inner_substitution_strategy_those_decorated public function test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed(): void { - Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->name() . '/git.diff'); $result = $this->commandTester->execute( [ @@ -89,7 +89,7 @@ public function test_it_detects_with_decorated_definition_strategy_those_decorat "Sylius\Component\Addressing\Provider\ProvinceNamingProvider" -> "webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_province_naming_provider" "Sylius\Component\Core\OrderProcessing\OrderPaymentProcessor" -> "webgriffe_sylius_upgrade.service_changes_command.test_it_detects_with_decorated_definition_strategy_those_decorated_services_that_changed.decorate_order_payment_processor" -Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. Here is the list ([decorated service] -> [decorating service]): +Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detect if the original class changed between versions. Here is the list ([decorated service] -> [decorating service]): "sylius.calculator.product_variant_price" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator" TXT; @@ -99,7 +99,7 @@ public function test_it_detects_with_decorated_definition_strategy_those_decorat public function test_it_detects_with_alias_strategy_those_decorated_services_that_changed(): void { - Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->name() . '/git.diff'); $result = $this->commandTester->execute( [ @@ -119,7 +119,7 @@ public function test_it_detects_with_alias_strategy_those_decorated_services_tha Found 1 services that changed and were decorated ([decorated service] -> [decorating service]): "Sylius\Bundle\ApiBundle\CommandHandler\Checkout\SendOrderConfirmationHandler" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\\test_it_detects_with_alias_strategy_those_decorated_services_that_changed\DecorateSendOrderConfirmationHandler" -Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detects if the original class chnaged between versions. Here is the list ([decorated service] -> [decorating service]): +Found 1 services that must be checked manually because the related alias referes to a Sylius service. Actually it's impossible to detect if the original class changed between versions. Here is the list ([decorated service] -> [decorating service]): "sylius.calculator.product_variant_price" -> "Tests\Webgriffe\SyliusUpgradePlugin\Stub\ServiceChangesCommand\DecorateProductVariantPriceCalculator" TXT; @@ -129,7 +129,7 @@ public function test_it_detects_with_alias_strategy_those_decorated_services_tha public function test_it_ignores_those_decorated_services_that_changed_but_the_decoration_services_are_not_within_the_given_namespace(): void { - Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->getName() . '/git.diff'); + Git::$diffToReturn = file_get_contents(self::FIXTURE_DIR . $this->name() . '/git.diff'); $result = $this->commandTester->execute( [ From a474b34cfa9b6ed2a8ca2d004c33c35846a25ac0 Mon Sep 17 00:00:00 2001 From: Lorenzo Ruozzi Date: Mon, 13 May 2024 12:28:45 +0200 Subject: [PATCH 28/31] Fix Psalm --- src/Command/ServiceChangesCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index a243dcf..90ab23f 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -18,6 +18,9 @@ use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; use Webmozart\Assert\Assert; +/** + * @psalm-suppress PropertyNotSetInConstructor + */ final class ServiceChangesCommand extends Command { public const FROM_VERSION_ARGUMENT_NAME = 'from'; @@ -410,7 +413,6 @@ private function applyInnerStrategy( string $definitionClass ): bool { /** - * @var string|null $innerServiceId * @psalm-suppress InternalProperty */ $innerServiceId = $definition->innerServiceId; From 8f2d0b9ff48f562d5677a975f37bffd651136683 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 13 May 2024 12:41:52 +0200 Subject: [PATCH 29/31] Do not reference test classes in non test services --- src/Command/ServiceChangesCommand.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Command/ServiceChangesCommand.php b/src/Command/ServiceChangesCommand.php index 90ab23f..ab35943 100644 --- a/src/Command/ServiceChangesCommand.php +++ b/src/Command/ServiceChangesCommand.php @@ -4,8 +4,10 @@ namespace Webgriffe\SyliusUpgradePlugin\Command; +use App\Kernel; use Symfony\Bundle\FrameworkBundle\Command\BuildDebugContainerTrait; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -13,7 +15,6 @@ use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass as BaseDecoratorServicePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Tests\Webgriffe\SyliusUpgradePlugin\Application\Kernel; use Webgriffe\SyliusUpgradePlugin\Client\GitInterface; use Webgriffe\SyliusUpgradePlugin\DependencyInjection\Compiler\DecoratorServicePass; use Webmozart\Assert\Assert; @@ -91,7 +92,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $application = $this->getApplication(); /** @var Kernel|null $rawKernel */ $rawKernel = $application?->getKernel(); - Assert::isInstanceOf($rawKernel, Kernel::class); + Assert::notNull($rawKernel, 'Kernel not found'); /** @var \Closure $buildContainer */ $buildContainer = \Closure::bind(function (): ContainerBuilder { From 4573e84964732eb9c388beac373df6268ece0dbe Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 13 May 2024 12:50:10 +0200 Subject: [PATCH 30/31] Add changed services command description and example to README --- README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ae40253..ad835a7 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ All features are implemented as **console commands**. bin/console webgriffe:upgrade:template-changes [--theme=PATH_TO_YOUR_THEME] [--legacy] -Print a list of template files (with extension .html.twig) that changed between two given Sylius versions and that has been overridden in your project: in root "templates" folder and/or in a custom theme. +Print a list of template files (with extension .html.twig) that changed between two given Sylius versions and that have been overridden in your project: in root "templates" folder and/or in a custom theme. You have to specify both the versions **from** and **to** you want to compute the changes. @@ -72,6 +72,34 @@ There are two optional parameters: bin/console webgriffe:upgrade:template-changes v1.8.8 v1.9.3 --theme=themes/my-website-theme --theme=themes/my-other-theme --theme=vendor/acme/my-vendor-theme ``` +### Decorated services changes + + bin/console webgriffe:upgrade:service-changes [--theme=PATH_TO_YOUR_THEME] [--legacy] + +Print a list of services that changed between two given Sylius versions and that have been decorated/overridden in your project. + +You have to specify both the versions **from** and **to** you want to compute the changes. + +There are two optional parameters: +* **--namespace-prefix=NAMESPACE-PREFIX**, the first part of the namespace of your app services, like "App" in "App\Calculator\PriceCalculator". Default: "App". +* **--alias-prefix=ALIAS-PREFIX**, the first part of the alias of your app services, like "app" in "app.calculator.price". Default: "app". + + +#### Examples + +* List of services that changed between Sylius v1.11.0 and v1.13.0 and that were decorated in your project: + + ```bash + bin/console webgriffe:upgrade:service-changes v1.11.0 v1.13.0 + ``` + +* List of services that changed between Sylius v1.11.0 and v1.13.0 and that were decorated in your project but with custom namespace and alias prefixes: + + ```bash + bin/console webgriffe:upgrade:service-changes v1.11.0 v1.13.0 --namespace-prefix="Webgriffe" --alias-prefix="webgriffe" + ``` + + ## Contributing To contribute to this plugin clone this repository, create a branch for your feature or bugfix, do your changes and then make sure al tests are passing. From 9a217665f852bc4c5e6272e28166135f3900b6e0 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Mon, 13 May 2024 12:52:27 +0200 Subject: [PATCH 31/31] Add sylius 1.13 to supported version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad835a7..7e3edd5 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ ## Requirements * PHP `^8.0` -* Sylius `^1.11.2 || ^1.12` +* Sylius `^1.11.2 || ^1.12 || ^1.13` ## Installation