Skip to content

Commit

Permalink
Merge pull request #109 from Setono/batch-iterator
Browse files Browse the repository at this point in the history
Create batch iterator
  • Loading branch information
loevgaard authored Jan 25, 2024
2 parents 732e66b + 444c1d4 commit d9f7d82
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 20 deletions.
69 changes: 69 additions & 0 deletions src/BatchIterator/BatchIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusCalloutPlugin\BatchIterator;

use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use DoctrineBatchUtils\BatchProcessing\SimpleBatchIteratorAggregate;
use Psr\EventDispatcher\EventDispatcherInterface;
use Setono\DoctrineObjectManagerTrait\ORM\ORMManagerTrait;
use Setono\SyliusCalloutPlugin\Event\BatchIteratorEvent;

/**
* @template T
*
* @implements BatchIteratorInterface<T>
*/
final class BatchIterator implements BatchIteratorInterface
{
use ORMManagerTrait;

/** @var list<callable> */
private array $modifications = [];

/**
* @param class-string<T> $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<array-key, T>
*/
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<array-key, T> $iterator */
$iterator = SimpleBatchIteratorAggregate::fromQuery($qb->getQuery(), 100);

return $iterator;
}
}
26 changes: 26 additions & 0 deletions src/BatchIterator/BatchIteratorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusCalloutPlugin\BatchIterator;

use Doctrine\Persistence\ManagerRegistry;
use Psr\EventDispatcher\EventDispatcherInterface;
use Setono\DoctrineObjectManagerTrait\ORM\ORMManagerTrait;

final class BatchIteratorFactory implements BatchIteratorFactoryInterface
{
use ORMManagerTrait;

public function __construct(
private readonly EventDispatcherInterface $eventDispatcher,
ManagerRegistry $managerRegistry,
) {
$this->managerRegistry = $managerRegistry;
}

public function create(string $class): BatchIteratorInterface
{
return new BatchIterator($this->eventDispatcher, $this->managerRegistry, $class);
}
}
17 changes: 17 additions & 0 deletions src/BatchIterator/BatchIteratorFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusCalloutPlugin\BatchIterator;

interface BatchIteratorFactoryInterface
{
/**
* @template T
*
* @param class-string<T> $class
*
* @return BatchIteratorInterface<T>
*/
public function create(string $class): BatchIteratorInterface;
}
20 changes: 20 additions & 0 deletions src/BatchIterator/BatchIteratorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusCalloutPlugin\BatchIterator;

use Doctrine\ORM\QueryBuilder;

/**
* @template T
*
* @extends \IteratorAggregate<array-key, T>
*/
interface BatchIteratorInterface extends \IteratorAggregate
{
/**
* @param callable(QueryBuilder): void $callable
*/
public function modify(callable $callable): static;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
}
}
29 changes: 12 additions & 17 deletions src/Message/Handler/AbstractAssignCalloutsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<ProductInterface> $productClass */
protected readonly string $productClass,
) {
$this->managerRegistry = $managerRegistry;
Expand All @@ -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<ProductInterface> $products */
$products = SimpleBatchIteratorAggregate::fromQuery($qb->getQuery(), 100);
}

$resetCallouts = false;
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<imports>
<import resource="services/batch_iterator.xml"/>
<import resource="services/block_event_listener.xml"/>
<import resource="services/checker.xml"/>
<import resource="services/command.xml"/>
Expand Down
13 changes: 13 additions & 0 deletions src/Resources/config/services/batch_iterator.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>

<container xmlns="http://symfony.com/schema/dic/services"
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">
<services>
<service id="setono_sylius_callout.batch_iterator.factory"
class="Setono\SyliusCalloutPlugin\BatchIterator\BatchIteratorFactory">
<argument type="service" id="event_dispatcher"/>
<argument type="service" id="doctrine"/>
</service>
</services>
</container>
2 changes: 1 addition & 1 deletion src/Resources/config/services/message.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<service id="setono_sylius_callout.message.handler.abstract_assign_callouts"
class="Setono\SyliusCalloutPlugin\Message\Handler\AbstractAssignCalloutsHandler" abstract="true">
<argument type="service" id="setono_sylius_callout.repository.callout"/>
<argument type="service" id="event_dispatcher"/>
<argument type="service" id="setono_sylius_callout.checker.eligibility.composite"/>
<argument type="service" id="setono_sylius_callout.batch_iterator.factory"/>
<argument type="service" id="doctrine"/>
<argument>%sylius.model.product.class%</argument>
</service>
Expand Down

0 comments on commit d9f7d82

Please sign in to comment.