diff --git a/composer-require-checker.json b/composer-require-checker.json index dafe6a89..507f7d75 100644 --- a/composer-require-checker.json +++ b/composer-require-checker.json @@ -33,6 +33,9 @@ "Sylius\\Component\\Inventory\\Model\\StockableInterface", "Sylius\\Component\\Locale\\Context\\LocaleContextInterface", "Sylius\\Component\\Locale\\Model\\LocaleInterface", - "Sylius\\Component\\Product\\Resolver\\ProductVariantResolverInterface" + "Sylius\\Component\\Product\\Resolver\\ProductVariantResolverInterface", + "League\\Flysystem\\FileNotFoundException", + "League\\Flysystem\\FilesystemInterface", + "League\\Flysystem\\RootViolationException" ] } diff --git a/composer.json b/composer.json index eabf30f8..32f290ae 100644 --- a/composer.json +++ b/composer.json @@ -10,8 +10,8 @@ "doctrine/orm": "^2.7", "doctrine/persistence": "^1.3 || ^2.0", "knplabs/knp-menu": "^3.1", - "league/flysystem": "^1.1", - "league/flysystem-bundle": "^1.1", + "league/flysystem": "^1.1 || ^2.1", + "league/flysystem-bundle": "^1.1 || ^2.4", "liip/imagine-bundle": "^2.4", "psr/event-dispatcher": "^1.0", "psr/log": "^1.0 || ^2.0 || ^3.0", diff --git a/src/Controller/Action/Shop/ShowFeedAction.php b/src/Controller/Action/Shop/ShowFeedAction.php index 4aa6871a..46398c45 100644 --- a/src/Controller/Action/Shop/ShowFeedAction.php +++ b/src/Controller/Action/Shop/ShowFeedAction.php @@ -4,7 +4,9 @@ namespace Setono\SyliusFeedPlugin\Controller\Action\Shop; +use InvalidArgumentException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; use RuntimeException; use Setono\SyliusFeedPlugin\Generator\FeedPathGeneratorInterface; use Setono\SyliusFeedPlugin\Repository\FeedRepositoryInterface; @@ -14,6 +16,10 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Mime\MimeTypesInterface; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class ShowFeedAction { private FeedRepositoryInterface $repository; @@ -24,23 +30,39 @@ final class ShowFeedAction private FeedPathGeneratorInterface $feedPathGenerator; - private FilesystemInterface $filesystem; + /** @var FilesystemInterface|FilesystemOperator */ + private $filesystem; private MimeTypesInterface $mimeTypes; + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemInterface|FilesystemOperator $filesystem + */ public function __construct( FeedRepositoryInterface $repository, ChannelContextInterface $channelContext, LocaleContextInterface $localeContext, FeedPathGeneratorInterface $feedPathGenerator, - FilesystemInterface $filesystem, + $filesystem, MimeTypesInterface $mimeTypes ) { $this->repository = $repository; $this->channelContext = $channelContext; $this->localeContext = $localeContext; $this->feedPathGenerator = $feedPathGenerator; - $this->filesystem = $filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $this->filesystem = $filesystem; + } elseif ($filesystem instanceof FilesystemOperator) { + $this->filesystem = $filesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } $this->mimeTypes = $mimeTypes; } @@ -56,11 +78,19 @@ public function __invoke(string $code): StreamedResponse $feedPath = $this->feedPathGenerator->generate($feed, $channelCode, $localeCode); - if (!$this->filesystem->has((string) $feedPath)) { - throw new NotFoundHttpException(sprintf('The feed with id %s has not been generated', $code)); + $filesystem = $this->filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + if (!$filesystem->has((string) $feedPath)) { + throw new NotFoundHttpException(sprintf('The feed with id %s has not been generated', $code)); + } + } else { + if (!$filesystem->fileExists((string) $feedPath)) { + throw new NotFoundHttpException(sprintf('The feed with id %s has not been generated', $code)); + } } - $stream = $this->filesystem->readStream((string) $feedPath); + /** @var resource|false $stream */ + $stream = $filesystem->readStream((string) $feedPath); if (false === $stream) { throw new RuntimeException(sprintf('An error occurred trying to read the feed file %s', $feedPath)); } diff --git a/src/DependencyInjection/Compiler/RegisterFilesystemPass.php b/src/DependencyInjection/Compiler/RegisterFilesystemPass.php index d3358b65..64d28447 100644 --- a/src/DependencyInjection/Compiler/RegisterFilesystemPass.php +++ b/src/DependencyInjection/Compiler/RegisterFilesystemPass.php @@ -6,6 +6,8 @@ use InvalidArgumentException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; +use RuntimeException; use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -38,14 +40,28 @@ public function process(ContainerBuilder $container): void $definitionClass = $container->getDefinition($parameterValue)->getClass(); Assert::notNull($definitionClass); - if (!is_a($definitionClass, FilesystemInterface::class, true)) { - throw new InvalidDefinitionException(sprintf( - 'The config parameter "%s" references a service %s, which is not an instance of %s. Fix this by creating a valid service that implements %s.', - $parameter, - $definitionClass, - FilesystemInterface::class, - FilesystemInterface::class - )); + if (interface_exists(FilesystemInterface::class)) { + if (!is_a($definitionClass, FilesystemInterface::class, true)) { + throw new InvalidDefinitionException(sprintf( + 'The config parameter "%s" references a service %s, which is not an instance of %s. Fix this by creating a valid service that implements %s.', + $parameter, + $definitionClass, + FilesystemInterface::class, + FilesystemInterface::class, + )); + } + } elseif (interface_exists(FilesystemOperator::class)) { + if (!is_a($definitionClass, FilesystemOperator::class, true)) { + throw new InvalidDefinitionException(sprintf( + 'The config parameter "%s" references a service %s, which is not an instance of %s. Fix this by creating a valid service that implements %s.', + $parameter, + $definitionClass, + FilesystemOperator::class, + FilesystemOperator::class, + )); + } + } else { + throw new RuntimeException('It looks like both of league/flysystem v1 and v2 are not installed!'); } $container->setAlias($parameter, $parameterValue); diff --git a/src/EventListener/DeleteGeneratedFilesSubscriber.php b/src/EventListener/DeleteGeneratedFilesSubscriber.php index e836b7a6..c5704308 100644 --- a/src/EventListener/DeleteGeneratedFilesSubscriber.php +++ b/src/EventListener/DeleteGeneratedFilesSubscriber.php @@ -4,21 +4,44 @@ namespace Setono\SyliusFeedPlugin\EventListener; +use InvalidArgumentException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; use League\Flysystem\RootViolationException; +use League\Flysystem\UnableToDeleteDirectory; use Setono\SyliusFeedPlugin\Model\FeedInterface; use Setono\SyliusFeedPlugin\Workflow\FeedGraph; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Workflow\Event\TransitionEvent; use Webmozart\Assert\Assert; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class DeleteGeneratedFilesSubscriber implements EventSubscriberInterface { - private FilesystemInterface $filesystem; + /** @var FilesystemInterface|FilesystemOperator */ + private $filesystem; - public function __construct(FilesystemInterface $filesystem) + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemInterface|FilesystemOperator $filesystem + */ + public function __construct($filesystem) { - $this->filesystem = $filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $this->filesystem = $filesystem; + } elseif ($filesystem instanceof FilesystemOperator) { + $this->filesystem = $filesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } } public static function getSubscribedEvents(): array @@ -38,8 +61,13 @@ public function delete(TransitionEvent $event): void Assert::isInstanceOf($feed, FeedInterface::class); try { - $this->filesystem->deleteDir($feed->getCode()); - } catch (RootViolationException $e) { + $filesystem = $this->filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $filesystem->deleteDir($feed->getCode()); + } else { + $filesystem->deleteDirectory($feed->getCode()); + } + } catch (RootViolationException|UnableToDeleteDirectory $e) { } } } diff --git a/src/EventListener/MoveGeneratedFeedSubscriber.php b/src/EventListener/MoveGeneratedFeedSubscriber.php index 273b975a..3718c31c 100644 --- a/src/EventListener/MoveGeneratedFeedSubscriber.php +++ b/src/EventListener/MoveGeneratedFeedSubscriber.php @@ -4,8 +4,11 @@ namespace Setono\SyliusFeedPlugin\EventListener; +use InvalidArgumentException; use League\Flysystem\FileNotFoundException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; +use League\Flysystem\UnableToDeleteFile; use RuntimeException; use Setono\SyliusFeedPlugin\Generator\FeedPathGeneratorInterface; use Setono\SyliusFeedPlugin\Generator\TemporaryFeedPathGenerator; @@ -15,24 +18,56 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Workflow\Event\TransitionEvent; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class MoveGeneratedFeedSubscriber implements EventSubscriberInterface { - private FilesystemInterface $temporaryFilesystem; + /** @var FilesystemInterface|FilesystemOperator */ + private $temporaryFilesystem; - private FilesystemInterface $filesystem; + /** @var FilesystemInterface|FilesystemOperator */ + private $filesystem; private FeedPathGeneratorInterface $temporaryFeedPathGenerator; private FeedPathGeneratorInterface $feedPathGenerator; + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemInterface|FilesystemOperator $temporaryFilesystem + * @param FilesystemInterface|FilesystemOperator $filesystem + */ public function __construct( - FilesystemInterface $temporaryFilesystem, - FilesystemInterface $filesystem, + $temporaryFilesystem, + $filesystem, FeedPathGeneratorInterface $temporaryFeedPathGenerator, FeedPathGeneratorInterface $feedPathGenerator ) { - $this->temporaryFilesystem = $temporaryFilesystem; - $this->filesystem = $filesystem; + if (interface_exists(FilesystemInterface::class) && $temporaryFilesystem instanceof FilesystemInterface) { + $this->temporaryFilesystem = $temporaryFilesystem; + } elseif ($temporaryFilesystem instanceof FilesystemOperator) { + $this->temporaryFilesystem = $temporaryFilesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $this->filesystem = $filesystem; + } elseif ($filesystem instanceof FilesystemOperator) { + $this->filesystem = $filesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } $this->temporaryFeedPathGenerator = $temporaryFeedPathGenerator; $this->feedPathGenerator = $feedPathGenerator; } @@ -62,8 +97,10 @@ public function move(TransitionEvent $event): void (string) $channel->getCode(), (string) $locale->getCode() ); + $temporaryFilesystem = $this->temporaryFilesystem; $temporaryPath = TemporaryFeedPathGenerator::getBaseFile($temporaryDir); - $tempFile = $this->temporaryFilesystem->readStream((string) $temporaryPath); + /** @var resource|false $tempFile */ + $tempFile = $temporaryFilesystem->readStream((string) $temporaryPath); if (false === $tempFile) { throw new \RuntimeException(sprintf( 'The file with path "%s" could not be found', @@ -78,20 +115,31 @@ public function move(TransitionEvent $event): void (string) $locale->getCode() ); $path = sprintf('%s/%s', $newPath->getPath(), uniqid('feed-', true)); - $res = $this->filesystem->writeStream($path, $tempFile); + $filesystem = $this->filesystem; - if (false === $res) { - throw new RuntimeException('An error occurred when trying to write the feed to the filesystem'); + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + /** @var resource|false $res */ + $res = $filesystem->writeStream($path, $tempFile); + + if (false === $res) { + throw new RuntimeException('An error occurred when trying to write the feed to the filesystem'); + } + } else { + $filesystem->writeStream($path, $tempFile); } try { - $this->filesystem->delete((string) $newPath); - } catch (FileNotFoundException $e) { + $filesystem->delete((string) $newPath); + } catch (FileNotFoundException|UnableToDeleteFile $e) { } - $this->filesystem->rename($path, (string) $newPath); + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $filesystem->rename($path, (string) $newPath); + } else { + $filesystem->move($path, (string) $newPath); + } - $this->temporaryFilesystem->delete((string) $temporaryPath); + $temporaryFilesystem->delete((string) $temporaryPath); } } } diff --git a/src/Generator/TemporaryFeedPathGenerator.php b/src/Generator/TemporaryFeedPathGenerator.php index 30708d09..a1bf3ca8 100644 --- a/src/Generator/TemporaryFeedPathGenerator.php +++ b/src/Generator/TemporaryFeedPathGenerator.php @@ -4,11 +4,17 @@ namespace Setono\SyliusFeedPlugin\Generator; +use InvalidArgumentException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; use Setono\SyliusFeedPlugin\Model\FeedInterface; use SplFileInfo; use Webmozart\Assert\Assert; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class TemporaryFeedPathGenerator implements FeedPathGeneratorInterface { public const BASE_FILENAME = '_feed'; @@ -29,11 +35,28 @@ public static function getBaseFile(SplFileInfo $dir): SplFileInfo return new SplFileInfo($dir->getPathname() . '/' . self::BASE_FILENAME); } - public static function getPartialFile(SplFileInfo $dir, FilesystemInterface $filesystem): SplFileInfo + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemInterface|FilesystemOperator $filesystem + */ + public static function getPartialFile(SplFileInfo $dir, $filesystem): SplFileInfo { - do { - $path = $dir->getPathname() . '/' . uniqid('partial-', true); - } while ($filesystem->has($path)); + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + do { + $path = $dir->getPathname() . '/' . uniqid('partial-', true); + } while ($filesystem->has($path)); + } elseif ($filesystem instanceof FilesystemOperator) { + do { + $path = $dir->getPathname() . '/' . uniqid('partial-', true); + } while ($filesystem->fileExists($path)); + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } return new SplFileInfo($path); } diff --git a/src/Message/Handler/FinishGenerationHandler.php b/src/Message/Handler/FinishGenerationHandler.php index 23ea657b..7b24d728 100644 --- a/src/Message/Handler/FinishGenerationHandler.php +++ b/src/Message/Handler/FinishGenerationHandler.php @@ -6,7 +6,10 @@ use Doctrine\Persistence\ObjectManager; use InvalidArgumentException; +use League\Flysystem\DirectoryListing; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; +use League\Flysystem\StorageAttributes; use Psr\Log\LoggerInterface; use RuntimeException; use Setono\SyliusFeedPlugin\FeedType\FeedTypeInterface; @@ -26,13 +29,18 @@ use Twig\Environment; use Webmozart\Assert\Assert; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class FinishGenerationHandler implements MessageHandlerInterface { use GetFeedTrait; private ObjectManager $feedManager; - private FilesystemInterface $filesystem; + /** @var FilesystemInterface|FilesystemOperator */ + private $filesystem; private Registry $workflowRegistry; @@ -44,10 +52,15 @@ final class FinishGenerationHandler implements MessageHandlerInterface private LoggerInterface $logger; + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemInterface|FilesystemOperator $filesystem + */ public function __construct( FeedRepositoryInterface $feedRepository, ObjectManager $feedManager, - FilesystemInterface $filesystem, + $filesystem, Registry $workflowRegistry, Environment $twig, FeedTypeRegistryInterface $feedTypeRegistry, @@ -56,7 +69,17 @@ public function __construct( ) { $this->feedRepository = $feedRepository; $this->feedManager = $feedManager; - $this->filesystem = $filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $this->filesystem = $filesystem; + } elseif ($filesystem instanceof FilesystemOperator) { + $this->filesystem = $filesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } $this->workflowRegistry = $workflowRegistry; $this->twig = $twig; $this->feedTypeRegistry = $feedTypeRegistry; @@ -92,22 +115,27 @@ public function __invoke(FinishGeneration $message): void fwrite($batchStream, $feedStart); - $files = $this->filesystem->listContents((string) $dir); - /** @var array{basename: string, path: string} $file */ + $filesystem = $this->filesystem; + + /** @var array|DirectoryListing $files */ + $files = $filesystem->listContents((string) $dir); foreach ($files as $file) { - Assert::isArray($file); - Assert::keyExists($file, 'basename'); - Assert::keyExists($file, 'path'); + if (is_array($file)) { + Assert::keyExists($file, 'basename'); + Assert::keyExists($file, 'path'); - if (TemporaryFeedPathGenerator::BASE_FILENAME === $file['basename']) { - continue; + if (TemporaryFeedPathGenerator::BASE_FILENAME === $file['basename']) { + continue; + } } - - $fp = $this->filesystem->readStream($file['path']); + /** @var string $path */ + $path = $file['path']; + /** @var resource|false $fp */ + $fp = $filesystem->readStream($path); if (false === $fp) { throw new \RuntimeException(sprintf( 'The file "%s" could not be opened as a resource', - $file['path'] + $path )); } @@ -117,19 +145,24 @@ public function __invoke(FinishGeneration $message): void fclose($fp); - $this->filesystem->delete($file['path']); + $filesystem->delete($path); } fwrite($batchStream, $feedEnd); - $res = $this->filesystem->writeStream((string) TemporaryFeedPathGenerator::getBaseFile($dir), $batchStream); + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + /** @var resource|false $res */ + $res = $filesystem->writeStream((string) TemporaryFeedPathGenerator::getBaseFile($dir), $batchStream); + + if (false === $res) { + throw new RuntimeException('An error occurred when trying to write the finished feed write'); + } + } else { + $filesystem->writeStream((string) TemporaryFeedPathGenerator::getBaseFile($dir), $batchStream); + } // tries to close the file pointer although it may already have been closed by flysystem fclose($batchStream); - - if (false === $res) { - throw new RuntimeException('An error occurred when trying to write the finished feed write'); - } } } diff --git a/src/Message/Handler/GenerateBatchHandler.php b/src/Message/Handler/GenerateBatchHandler.php index de3aa518..4241c3d3 100644 --- a/src/Message/Handler/GenerateBatchHandler.php +++ b/src/Message/Handler/GenerateBatchHandler.php @@ -12,6 +12,7 @@ use const JSON_UNESCAPED_SLASHES; use const JSON_UNESCAPED_UNICODE; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerInterface; use Setono\SyliusFeedPlugin\Event\BatchGeneratedEvent; @@ -44,6 +45,10 @@ use Twig\Environment; use Webmozart\Assert\Assert; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class GenerateBatchHandler implements MessageHandlerInterface { use GetChannelTrait; @@ -60,7 +65,8 @@ final class GenerateBatchHandler implements MessageHandlerInterface private Environment $twig; - private FilesystemInterface $filesystem; + /** @var FilesystemInterface|FilesystemOperator */ + private $filesystem; private FeedPathGeneratorInterface $temporaryFeedPathGenerator; @@ -78,6 +84,11 @@ final class GenerateBatchHandler implements MessageHandlerInterface private LoggerInterface $logger; + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemOperator|FilesystemInterface $filesystem + */ public function __construct( FeedRepositoryInterface $feedRepository, ChannelRepositoryInterface $channelRepository, @@ -85,7 +96,7 @@ public function __construct( ObjectManager $feedManager, FeedTypeRegistryInterface $feedTypeRegistry, Environment $twig, - FilesystemInterface $filesystem, + $filesystem, FeedPathGeneratorInterface $temporaryFeedPathGenerator, EventDispatcherInterface $eventDispatcher, Registry $workflowRegistry, @@ -101,7 +112,17 @@ public function __construct( $this->feedManager = $feedManager; $this->feedTypeRegistry = $feedTypeRegistry; $this->twig = $twig; - $this->filesystem = $filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $this->filesystem = $filesystem; + } elseif ($filesystem instanceof FilesystemOperator) { + $this->filesystem = $filesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } $this->temporaryFeedPathGenerator = $temporaryFeedPathGenerator; $this->eventDispatcher = $eventDispatcher; $this->workflowRegistry = $workflowRegistry; @@ -206,13 +227,18 @@ public function __invoke(GenerateBatch $message): void } $dir = $this->temporaryFeedPathGenerator->generate($feed, (string) $channel->getCode(), (string) $locale->getCode()); - $path = TemporaryFeedPathGenerator::getPartialFile($dir, $this->filesystem); - - $res = $this->filesystem->writeStream((string) $path, $stream); + $filesystem = $this->filesystem; + $path = TemporaryFeedPathGenerator::getPartialFile($dir, $filesystem); - fclose($stream); + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $res = $filesystem->writeStream((string) $path, $stream); + fclose($stream); - Assert::true($res, 'An error occurred when trying to write a feed item'); + Assert::true($res, 'An error occurred when trying to write a feed item'); + } else { + $filesystem->writeStream((string) $path, $stream); + fclose($stream); + } $this->feedManager->flush(); $this->feedManager->clear(); diff --git a/tests/Behat/Context/Cli/ProcessFeedsContext.php b/tests/Behat/Context/Cli/ProcessFeedsContext.php index 6b2c1b0f..b21b9cb6 100644 --- a/tests/Behat/Context/Cli/ProcessFeedsContext.php +++ b/tests/Behat/Context/Cli/ProcessFeedsContext.php @@ -7,6 +7,7 @@ use Behat\Behat\Context\Context; use InvalidArgumentException; use League\Flysystem\FilesystemInterface; +use League\Flysystem\FilesystemOperator; use Setono\SyliusFeedPlugin\Command\ProcessFeedsCommand; use Setono\SyliusFeedPlugin\Generator\FeedPathGeneratorInterface; use Setono\SyliusFeedPlugin\Model\FeedInterface; @@ -18,6 +19,10 @@ use Symfony\Component\HttpKernel\KernelInterface; use Webmozart\Assert\Assert; +/** + * @psalm-suppress UndefinedDocblockClass + * @psalm-suppress UndefinedClass + */ final class ProcessFeedsContext implements Context { /** @var KernelInterface */ @@ -32,7 +37,7 @@ final class ProcessFeedsContext implements Context /** @var ProcessFeedsCommand */ private $command; - /** @var FilesystemInterface */ + /** @var FilesystemInterface|FilesystemOperator */ private $filesystem; /** @var FeedProcessorInterface */ @@ -44,15 +49,30 @@ final class ProcessFeedsContext implements Context /** @var RepositoryInterface */ private $feedRepository; + /** + * @psalm-suppress UndefinedDocblockClass + * + * @param FilesystemInterface|FilesystemOperator $filesystem + */ public function __construct( KernelInterface $kernel, - FilesystemInterface $filesystem, + $filesystem, FeedProcessorInterface $processor, FeedPathGeneratorInterface $feedPathGenerator, RepositoryInterface $feedRepository ) { $this->kernel = $kernel; - $this->filesystem = $filesystem; + if (interface_exists(FilesystemInterface::class) && $filesystem instanceof FilesystemInterface) { + $this->filesystem = $filesystem; + } elseif ($filesystem instanceof FilesystemOperator) { + $this->filesystem = $filesystem; + } else { + throw new InvalidArgumentException(sprintf( + 'The filesystem must be an instance of %s or %s', + FilesystemInterface::class, + FilesystemOperator::class + )); + } $this->processor = $processor; $this->feedPathGenerator = $feedPathGenerator; $this->feedRepository = $feedRepository; @@ -90,16 +110,26 @@ public function aFileShouldExistWithTheRightContent(): void Assert::count($feeds, 1); $feed = $feeds[0]; + /** @var FilesystemInterface|FilesystemOperator $filesystem */ + $filesystem = $this->filesystem; /** @var ChannelInterface $channel */ foreach ($feed->getChannels() as $channel) { foreach ($channel->getLocales() as $locale) { $path = $this->feedPathGenerator->generate($feed, $channel->getCode(), $locale->getCode()); - Assert::true($this->filesystem->has($path)); + if ($filesystem instanceof FilesystemOperator) { + Assert::true($filesystem->fileExists((string) $path)); + } else { + Assert::true($filesystem->has($path)); + } $expectedContent = $this->getExpectedContent($channel->getCode()); - $actualContent = $this->removeWhitespace($this->filesystem->read($path)); + if ($filesystem instanceof FilesystemOperator) { + $actualContent = $this->removeWhitespace($filesystem->read((string) $path)); + } else { + $actualContent = $this->removeWhitespace($filesystem->read($path)); + } $actualContent = $this->normalizeImageLink($actualContent); Assert::same($actualContent, $expectedContent);