Installation:
composer require overblog/dataloader-bundle
Register the bundle in config/bundles.php:
return [
// ...
Overblog\DataLoaderBundle\OverblogDataLoaderBundle::class => ['all' => true],
];
Basic Configuration (config/packages/overblog_dataloader.yaml):
overblog_dataloader:
defaults:
promise_adapter: "overblog_dataloader.react_promise_adapter"
loaders:
users:
batch_load_fn: "@app.service.user:fetchUsers"
First Use Case: Inject the loader into a service and use it to fetch batched data:
use Overblog\DataLoaderBundle\DataLoader\DataLoaderInterface;
class UserResolver
{
public function __construct(private DataLoaderInterface $usersLoader) {}
public function resolveUser(int $id): mixed
{
return $this->usersLoader->load($id);
}
}
batch: true for batched queries (reduces N+1 queries).
loaders:
posts:
batch_load_fn: "App\Service\PostService::fetchPosts"
options:
batch: true
max_batch_size: 20
cache: true and specify a cache map:
loaders:
images:
batch_load_fn: "App\Service\ImageService::fetchImages"
options:
cache: true
cache_map: "app.cache.map"
Create a custom factory for complex loader initialization:
loaders:
custom_loader:
factory: "App\Factory\CustomLoaderFactory"
batch_load_fn: "@app.service.custom:loadData"
Factory class:
class CustomLoaderFactory
{
public function __invoke(ContainerInterface $container): DataLoaderInterface
{
return new CustomLoader(
$container->get('promise_adapter'),
$container->get('custom_service')
);
}
}
overblog_graphql:
overblog_graphql:
services:
promise_adapter: "webonyx_graphql.sync_promise_adapter"
overblog_dataloader:
defaults:
promise_adapter: "overblog_dataloader.webonyx_graphql_sync_promise_adapter"
public function resolveShip(int $id): mixed
{
return $this->container->get('ships_loader')->load($id);
}
Autowire loaders directly:
class UserController
{
public function __construct(
private DataLoaderInterface $usersLoader,
private DataLoaderInterface $postsLoader
) {}
}
Promise Adapter Mismatch:
react, guzzle, or webonyx) matches the async library you’re using.react_promise_adapter for ReactPHP-based apps.Batch Load Function Signatures:
batch_load_fn must return a Promise (or array in sync mode) of results.public function batchLoad(array $ids): array|PromiseInterface
{
return $this->repository->findBy(['id' => $ids]);
}
Caching Quirks:
cache_map is misconfigured, the cache may not persist. Use a valid cache key function:
options:
cache_key_fn: "@app.cache:generateKey"
Symfony 6+ Compatibility:
config/services.yaml:
Overblog\DataLoaderBundle\DataLoader\DataLoaderInterface: ~
Log Promises:
Wrap load() calls in a then() to inspect results:
$this->usersLoader->load($id)->then(
function ($user) { logger("Loaded: " . $user->getName()); }
);
Check Batch Sizes:
max_batch_size to avoid memory issues. Start with 10 and adjust.Clear Cache:
php bin/console cache:clear
Custom Promise Adapters:
Extend the bundle by adding new adapters in config/packages/overblog_dataloader.yaml:
services:
overblog_dataloader.custom_promise_adapter:
class: App\Promise\CustomAdapter
tags: ['overblog_dataloader.promise_adapter']
Dynamic Loaders: Create loaders programmatically in services:
$loader = $this->container->get('overblog_dataloader.factory')->createLoader(
'dynamic_loader',
$batchLoadFn,
['batch' => true]
);
Testing:
Mock DataLoaderInterface in tests:
$mockLoader = $this->createMock(DataLoaderInterface::class);
$mockLoader->method('load')->willReturn($expectedResult);
How can I help you explore Laravel packages today?