All Projects → Setono → doctrine-orm-batcher

Setono / doctrine-orm-batcher

Licence: MIT license
No description or website provided.

Programming Languages

PHP
23972 projects - #3 most used programming language

Projects that are alternatives of or similar to doctrine-orm-batcher

Doctrineextensions
Doctrine2 behavioral extensions, Translatable, Sluggable, Tree-NestedSet, Timestampable, Loggable, Sortable
Stars: ✭ 3,668 (+13485.19%)
Mutual labels:  doctrine, doctrine-orm
doctrine-filter
Quickly add advanced filtering/searching and sorting capabilities to any resource in your APIs or Web apps that use Doctrine.
Stars: ✭ 27 (+0%)
Mutual labels:  doctrine, doctrine-orm
doctrine-extensions
Doctrine2 behavioral extension Transformable
Stars: ✭ 14 (-48.15%)
Mutual labels:  doctrine, doctrine-orm
Stofdoctrineextensionsbundle
Integration bundle for DoctrineExtensions by l3pp4rd in Symfony
Stars: ✭ 1,713 (+6244.44%)
Mutual labels:  doctrine, doctrine-orm
DoctrineTranslated
Translated strings for Doctrine
Stars: ✭ 12 (-55.56%)
Mutual labels:  doctrine
rector-doctrine
Rector upgrades rules for Doctrine
Stars: ✭ 37 (+37.04%)
Mutual labels:  doctrine
doctrine-orm-bridge
[READ ONLY] Bridge for using commands and events with Doctrine ORM. Full documentation can be found here:
Stars: ✭ 31 (+14.81%)
Mutual labels:  doctrine-orm
symbok-bundle
Symfony annotations bundle
Stars: ✭ 50 (+85.19%)
Mutual labels:  doctrine
ip
Immutable value object for IPv4 and IPv6 addresses, including helper methods and Doctrine support.
Stars: ✭ 212 (+685.19%)
Mutual labels:  doctrine
MostGenerator
Transformation cartridges for generating Symfony bundles from ModuleStudio models.
Stars: ✭ 21 (-22.22%)
Mutual labels:  doctrine
Lumen-Doctrine-DDD-Example
Domain Driven Design Application Example, built with Lumen 5.3 and Doctrine.
Stars: ✭ 72 (+166.67%)
Mutual labels:  doctrine
dbal-rds-data
A driver to use the aws aurora serverless rds data api in the doctrine database abstraction layer
Stars: ✭ 24 (-11.11%)
Mutual labels:  doctrine
domain
A dependency-free package to help building a business domain layer
Stars: ✭ 33 (+22.22%)
Mutual labels:  doctrine
DoctrineBehaviors
[DEPRECATED]
Stars: ✭ 11 (-59.26%)
Mutual labels:  doctrine
mukadi-wordpress-bundle
Integrate wordpress and symfony in the same application
Stars: ✭ 24 (-11.11%)
Mutual labels:  doctrine
slim-doctrine
Slim-Doctrine managers integration
Stars: ✭ 16 (-40.74%)
Mutual labels:  doctrine
doctrine-phpstorm-meta
PhpStorm meta data for expected arguments completion.
Stars: ✭ 35 (+29.63%)
Mutual labels:  doctrine
petstore
A simple skeleton to build api's based on the chubbyphp-framework, mezzio (former zend-expressive) or slim.
Stars: ✭ 34 (+25.93%)
Mutual labels:  doctrine
php-orm-benchmark
The benchmark to compare performance of PHP ORM solutions.
Stars: ✭ 82 (+203.7%)
Mutual labels:  doctrine
DoctrineMongoODMModule
Laminas Module for Doctrine MongoDB ODM
Stars: ✭ 83 (+207.41%)
Mutual labels:  doctrine

Doctrine ORM Batcher library

Latest Version on Packagist Software License Build Status

Use this library when you need to process large amounts of entities and maybe in an asynchronous way.

Why do we need this library? Why not just use a paginator library like Pagerfanta or normal batch processing in Doctrine?

Well, because MySQL is not very good with LIMIT and OFFSET when the tables become too large. As for Doctrine batch processing capabilities the difference is that this library is very opinionated. It will work very well in a message based architecture where large processing will likely be done in an asynchronous way.

How does it work then? It uses the seek method to paginate results instead.

Installation

$ composer require setono/doctrine-orm-batcher

Usage

There are two ways to get results: Getting a range of ids or getting a collection (either of ids or entities).

Range of ids

A range is a lower and upper bound of ids. This is typically intended to be used in an asynchronous environment where you will dispatch a message with the lower and upper bounds so that the consumer of that message will be able to easily fetch the respective entities based on these bounds.

Example

You want to process all your Product entities. A query builder for that would look like:

<?php
use Doctrine\ORM\EntityManagerInterface;

/** @var EntityManagerInterface $em */

$qb = $em->createQueryBuilder();
$qb->select('o')->from(Product::class, 'o');

# OR even simpler:
# $qb = $productRepository->createQueryBuilder('o');

Now inject that query builder into the id range batcher and dispatch a message:

<?php
use Setono\DoctrineORMBatcher\Batch\RangeBatch;
use Setono\DoctrineORMBatcher\Batcher\Collection\ObjectCollectionBatcher;
use Setono\DoctrineORMBatcher\Batcher\Collection\IdCollectionBatcher;
use Setono\DoctrineORMBatcher\Batcher\Range\NaiveIdRangeBatcher;
use Setono\DoctrineORMBatcher\Batcher\Range\IdRangeBatcher;
use Setono\DoctrineORMBatcher\Factory\BatcherFactory;

class ProcessProductBatchMessage
{
    private $batch;
    
    public function __construct(RangeBatch $batch)
    {
        $this->batch = $batch;        
    }
    
    public function getBatch(): RangeBatch
    {
        return $this->batch;
    }
}

$factory = new BatcherFactory(
    ObjectCollectionBatcher::class,
    IdCollectionBatcher::class,
    NaiveIdRangeBatcher::class,
    IdRangeBatcher::class
);
$idRangeBatcher = $factory->createIdRangeBatcher($qb);

/** @var RangeBatch[] $batches */
$batches = $idRangeBatcher->getBatches(50);
foreach ($batches as $batch) {
    $commandBus->dispatch(new ProcessProductBatchMessage($batch));
}

Then sometime somewhere a consumer will receive that message and process the products:

<?php
use Setono\DoctrineORMBatcher\Query\QueryRebuilderInterface;

class ProcessProductBatchMessageHandler
{
    public function __invoke(ProcessProductBatchMessage $message)
    {
        /** @var QueryRebuilderInterface $queryRebuilder */
        $q = $queryRebuilder->rebuild($message->getBatch());
        $products = $q->getResult();
        
        foreach ($products as $product) {
            // process $product
        }
    }
}

This approach is extremely fast, but if you have complex queries it may be easier to use the collection batchers.

Collection of ids

Should be used for async handling of sets that selected with complex queries.

Example

You want to process only enabled Product entities.

<?php

use Doctrine\ORM\EntityManagerInterface;
use Setono\DoctrineORMBatcher\Factory\BatcherFactory;
use Setono\DoctrineORMBatcher\Batch\CollectionBatch;
use Setono\DoctrineORMBatcher\Batcher\Collection\ObjectCollectionBatcher;
use Setono\DoctrineORMBatcher\Batcher\Collection\IdCollectionBatcher;
use Setono\DoctrineORMBatcher\Batcher\Range\NaiveIdRangeBatcher;
use Setono\DoctrineORMBatcher\Batcher\Range\IdRangeBatcher;

class ProcessEnabledProductBatchMessage
{
    /** @var CollectionBatch */
    private $batch;
    
    public function __construct(CollectionBatch $batch)
    {
        $this->batch = $batch;        
    }
    
    public function getBatch(): CollectionBatch
    {
        return $this->batch;
    }
}

/** @var EntityManagerInterface $em */
$qb = $em->createQueryBuilder();
$qb->select('o')
    ->from(Product::class, 'o')
    ->where('o.enabled = 1')
;
$factory = new BatcherFactory(
    ObjectCollectionBatcher::class,
    IdCollectionBatcher::class,
    NaiveIdRangeBatcher::class,
    IdRangeBatcher::class
);
$idCollectionBatcher = $factory->createIdCollectionBatcher($qb);

/** @var CollectionBatch[] $batches */
$batches = $idCollectionBatcher->getBatches(50);
foreach ($batches as $batch) {
    $commandBus->dispatch(new ProcessEnabledProductBatchMessage($batch));
}

Then sometime somewhere a consumer will receive that message and process the products:

<?php
use Setono\DoctrineORMBatcher\Query\QueryRebuilderInterface;

class ProcessProductBatchMessageHandler
{
    public function __invoke(ProcessEnabledProductBatchMessage $message)
    {
        /** @var QueryRebuilderInterface $queryRebuilder */
        $q = $queryRebuilder->rebuild($message->getBatch());
        $products = $q->getResult();
        
        foreach ($products as $product) {
            // process $product
        }
    }
}

Collection of objects

Should be used for immediate handing objects that selected with complex queries.

Example

You want to immediately process only enabled Product entities.

<?php

use Doctrine\ORM\EntityManagerInterface;
use Setono\DoctrineORMBatcher\Factory\BatcherFactory;
use Setono\DoctrineORMBatcher\Batch\CollectionBatch;
use Setono\DoctrineORMBatcher\Batcher\Collection\ObjectCollectionBatcher;
use Setono\DoctrineORMBatcher\Batcher\Collection\IdCollectionBatcher;
use Setono\DoctrineORMBatcher\Batcher\Range\NaiveIdRangeBatcher;
use Setono\DoctrineORMBatcher\Batcher\Range\IdRangeBatcher;

/** @var EntityManagerInterface $em */
$qb = $em->createQueryBuilder();
$qb->select('o')
    ->from(Product::class, 'o')
    ->where('o.enabled = 1')
;
$factory = new BatcherFactory(
    ObjectCollectionBatcher::class,
    IdCollectionBatcher::class,
    NaiveIdRangeBatcher::class,
    IdRangeBatcher::class
);
$collectionBatcher = $factory->createObjectCollectionBatcher($qb);

/** @var CollectionBatch[] $batches */
$batches = $collectionBatcher->getBatches(50);
foreach ($batches as $batch) {
    /** @var Product $product */
    foreach ($batch->getCollection() as $product) {
        // process $product
    }
}

Framework integration

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].