setono/doctrine-orm-batcher-bundle
Symfony bundle that integrates Setono’s Doctrine ORM Batcher, making it easy to process large Doctrine queries in batches. Provides injectable services like BatcherFactoryInterface and QueryRebuilderInterface with autowiring support.
INSERT, UPDATE, DELETE, or complex queries) by chunking results. This directly addresses Laravel/PHP pain points like N+1 query issues, memory spikes, or timeout errors during large dataset processing (e.g., exports, migrations, or reporting).QueryRebuilderInterface allows dynamic query splitting, which is useful for Laravel apps with complex, parameterized queries (e.g., multi-join reports or filtered exports).doctrine/dbal and doctrine/orm alongside Laravel’s illuminate/database. Potential conflicts may arise from duplicate DBAL configurations or connection pooling.DB::statement() to execute Doctrine-generated SQL.BatcherFactoryInterface) requires manual binding in a service provider.bundles.php has no Laravel equivalent; configuration must be mapped to Laravel’s config/services.php or a custom provider.User::where('active', true)->orderBy('name') to DQL:
SELECT u FROM App\Entity\User u WHERE u.active = :active ORDER BY u.name
batch_size and memory_limit.DB::transaction() may conflict or nest poorly with Doctrine transactions.DatabaseMigrations, DatabaseTransactions).with(), select(), or raw expressions)?memory_limit be adjusted to prevent crashes?DB::transaction() interact with Doctrine’s batcher?chunk())?DB::statement(), queue:batch, or laravel-excel) that could reduce complexity?join(), whereHas(), or custom scopes) be translated to DQL? Will all use cases be supported?Model::chunk(), DB::unprepared())? What’s the break-even point for adoption?Doctrine ORM in Laravel:
doctrine/dbal and doctrine/orm to composer.json:
composer require doctrine/dbal doctrine/orm
config/doctrine.php to define Doctrine’s DBAL and ORM settings, ensuring no conflicts with Laravel’s config/database.php:
return [
'dbal' => [
'driver' => 'pdo_mysql',
'url' => env('DATABASE_URL'), // Must match Laravel's DB config
'server_version' => env('DB_CONNECTION', 'mysql'),
],
'orm' => [
'entity_managers' => [
'default' => [
'connection' => 'default',
'mappings' => [
['type' => 'annotation', 'namespace' => 'App\Entity', 'path' => 'config/doctrine'],
],
],
],
],
];
src/Entity/User.php) and map them in config/doctrine.php. Note: Avoid mixing Eloquent models and Doctrine entities for the same table unless using a shared table inheritance pattern.Service Integration:
BatcherFactoryInterface to Laravel’s container:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Setono\DoctrineORMBatcher\Factory\BatcherFactory;
use Setono\DoctrineORMBatcher\Factory\BatcherFactoryInterface;
class DoctrineBatcherServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(BatcherFactoryInterface::class, function ($app) {
$entityManager = $app->make('doctrine.orm.entity_manager');
return new BatcherFactory($entityManager);
});
}
}
config/app.php under providers.Query Adapter Layer:
namespace App\Services;
use Doctrine\ORM\QueryBuilder;
use Illuminate\Database\Eloquent\Builder;
class QueryAdapter
{
public function adaptToDql(Builder $queryBuilder): string
{
$dqlParts = [];
// Example: Convert WHERE clauses
foreach ($queryBuilder->getWhereConditions() as $condition) {
$dqlParts[] = $this->conditionToDql($condition);
}
return implode(' AND ', $dqlParts);
}
private function conditionToDql($condition): string
{
// Implement logic to convert Eloquent conditions to DQL
// e.g., `active = true` → `u.active = :active`
return "u.{$condition['column']} = :{$condition['column']}";
}
}
User).$dql = "SELECT u FROM App\Entity\User u WHERE u.active = :active";
$batcher = $this->factory->createBatcher($entityManager, $dql);
$batcher->setParameter('active', false);
$batcher->setBatchSize(200);
$results = $batcher->execute();
chunk():
User::
How can I help you explore Laravel packages today?