From 444c1d4af640cc3d665905c3cc11e3d9fd34b958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Thu, 25 Jan 2024 13:04:26 +0100 Subject: [PATCH] Create batch iterator --- src/BatchIterator/BatchIterator.php | 69 +++++++++++++++++++ src/BatchIterator/BatchIteratorFactory.php | 26 +++++++ .../BatchIteratorFactoryInterface.php | 17 +++++ src/BatchIterator/BatchIteratorInterface.php | 20 ++++++ ...uilderEvent.php => BatchIteratorEvent.php} | 7 +- .../Handler/AbstractAssignCalloutsHandler.php | 29 ++++---- src/Resources/config/services.xml | 1 + .../config/services/batch_iterator.xml | 13 ++++ src/Resources/config/services/message.xml | 2 +- 9 files changed, 164 insertions(+), 20 deletions(-) create mode 100644 src/BatchIterator/BatchIterator.php create mode 100644 src/BatchIterator/BatchIteratorFactory.php create mode 100644 src/BatchIterator/BatchIteratorFactoryInterface.php create mode 100644 src/BatchIterator/BatchIteratorInterface.php rename src/Event/{ProductQueryBuilderEvent.php => BatchIteratorEvent.php} (60%) create mode 100644 src/Resources/config/services/batch_iterator.xml diff --git a/src/BatchIterator/BatchIterator.php b/src/BatchIterator/BatchIterator.php new file mode 100644 index 0000000..2f614f5 --- /dev/null +++ b/src/BatchIterator/BatchIterator.php @@ -0,0 +1,69 @@ + + */ +final class BatchIterator implements BatchIteratorInterface +{ + use ORMManagerTrait; + + /** @var list */ + private array $modifications = []; + + /** + * @param class-string $class + */ + public function __construct( + private readonly EventDispatcherInterface $eventDispatcher, + ManagerRegistry $managerRegistry, + private readonly string $class, + ) { + $this->managerRegistry = $managerRegistry; + } + + /** + * @param callable(QueryBuilder): void $callable + */ + public function modify(callable $callable): static + { + $this->modifications[] = $callable; + + return $this; + } + + /** + * @return SimpleBatchIteratorAggregate + */ + public function getIterator(): SimpleBatchIteratorAggregate + { + $manager = $this->getManager($this->class); + $qb = $manager + ->createQueryBuilder() + ->select('o') + ->from($this->class, 'o'); + + foreach ($this->modifications as $modification) { + $modification($qb); + } + + $this->eventDispatcher->dispatch(new BatchIteratorEvent($qb, $this->class)); + + /** @var SimpleBatchIteratorAggregate $iterator */ + $iterator = SimpleBatchIteratorAggregate::fromQuery($qb->getQuery(), 100); + + return $iterator; + } +} diff --git a/src/BatchIterator/BatchIteratorFactory.php b/src/BatchIterator/BatchIteratorFactory.php new file mode 100644 index 0000000..4dcb775 --- /dev/null +++ b/src/BatchIterator/BatchIteratorFactory.php @@ -0,0 +1,26 @@ +managerRegistry = $managerRegistry; + } + + public function create(string $class): BatchIteratorInterface + { + return new BatchIterator($this->eventDispatcher, $this->managerRegistry, $class); + } +} diff --git a/src/BatchIterator/BatchIteratorFactoryInterface.php b/src/BatchIterator/BatchIteratorFactoryInterface.php new file mode 100644 index 0000000..e3eba75 --- /dev/null +++ b/src/BatchIterator/BatchIteratorFactoryInterface.php @@ -0,0 +1,17 @@ + $class + * + * @return BatchIteratorInterface + */ + public function create(string $class): BatchIteratorInterface; +} diff --git a/src/BatchIterator/BatchIteratorInterface.php b/src/BatchIterator/BatchIteratorInterface.php new file mode 100644 index 0000000..17facf5 --- /dev/null +++ b/src/BatchIterator/BatchIteratorInterface.php @@ -0,0 +1,20 @@ + + */ +interface BatchIteratorInterface extends \IteratorAggregate +{ + /** + * @param callable(QueryBuilder): void $callable + */ + public function modify(callable $callable): static; +} diff --git a/src/Event/ProductQueryBuilderEvent.php b/src/Event/BatchIteratorEvent.php similarity index 60% rename from src/Event/ProductQueryBuilderEvent.php rename to src/Event/BatchIteratorEvent.php index 790ee77..7677b30 100644 --- a/src/Event/ProductQueryBuilderEvent.php +++ b/src/Event/BatchIteratorEvent.php @@ -6,9 +6,12 @@ use Doctrine\ORM\QueryBuilder; -final class ProductQueryBuilderEvent +final class BatchIteratorEvent { - public function __construct(public readonly QueryBuilder $queryBuilder) + /** + * @param class-string $class + */ + public function __construct(public readonly QueryBuilder $queryBuilder, public readonly string $class) { } } diff --git a/src/Message/Handler/AbstractAssignCalloutsHandler.php b/src/Message/Handler/AbstractAssignCalloutsHandler.php index bac02bd..4edfc3a 100644 --- a/src/Message/Handler/AbstractAssignCalloutsHandler.php +++ b/src/Message/Handler/AbstractAssignCalloutsHandler.php @@ -4,12 +4,11 @@ namespace Setono\SyliusCalloutPlugin\Message\Handler; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; -use DoctrineBatchUtils\BatchProcessing\SimpleBatchIteratorAggregate; -use Psr\EventDispatcher\EventDispatcherInterface; use Setono\DoctrineObjectManagerTrait\ORM\ORMManagerTrait; +use Setono\SyliusCalloutPlugin\BatchIterator\BatchIteratorFactoryInterface; use Setono\SyliusCalloutPlugin\Checker\Eligibility\CalloutEligibilityCheckerInterface; -use Setono\SyliusCalloutPlugin\Event\ProductQueryBuilderEvent; use Setono\SyliusCalloutPlugin\Model\CalloutInterface; use Setono\SyliusCalloutPlugin\Model\ProductInterface; use Setono\SyliusCalloutPlugin\Repository\CalloutRepositoryInterface; @@ -20,10 +19,10 @@ class AbstractAssignCalloutsHandler public function __construct( protected readonly CalloutRepositoryInterface $calloutRepository, - protected readonly EventDispatcherInterface $eventDispatcher, protected readonly CalloutEligibilityCheckerInterface $eligibilityChecker, + protected readonly BatchIteratorFactoryInterface $batchIteratorFactory, ManagerRegistry $managerRegistry, - /** @var class-string $productClass */ + /** @var class-string $productClass */ protected readonly string $productClass, ) { $this->managerRegistry = $managerRegistry; @@ -38,19 +37,15 @@ protected function assign(iterable $products = [], iterable $callouts = []): voi $manager = $this->getManager($this->productClass); if ([] === $products) { - $qb = $manager - ->createQueryBuilder() - ->select('o') - ->from($this->productClass, 'o') - // todo the following two 'wheres' should be moved to event subscribers and be able to be disabled in the configuration of the plugin - ->andWhere('o.enabled = true') - ->andWhere('SIZE(o.channels) > 0') + $products = $this->batchIteratorFactory + ->create($this->productClass) + ->modify(function (QueryBuilder $qb): void { + $qb + ->andWhere('o.enabled = true') + ->andWhere('SIZE(o.channels) > 0') + ; + }) ; - - $this->eventDispatcher->dispatch(new ProductQueryBuilderEvent($qb)); - - /** @var iterable $products */ - $products = SimpleBatchIteratorAggregate::fromQuery($qb->getQuery(), 100); } $resetCallouts = false; diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 94b9de4..f375948 100755 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -4,6 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + diff --git a/src/Resources/config/services/batch_iterator.xml b/src/Resources/config/services/batch_iterator.xml new file mode 100644 index 0000000..c846359 --- /dev/null +++ b/src/Resources/config/services/batch_iterator.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/src/Resources/config/services/message.xml b/src/Resources/config/services/message.xml index 70fd736..3af1892 100644 --- a/src/Resources/config/services/message.xml +++ b/src/Resources/config/services/message.xml @@ -7,8 +7,8 @@ - + %sylius.model.product.class%