yokai/batch-symfony-framework
Symfony integration for Yokai Batch that makes it easy to define and run batch jobs using framework-native service configuration, console commands, and event handling. Manage jobs, steps, and execution from your Symfony application.
Install the bridge (it pulls in yokai/batch and symfony/framework-bundle):
composer require yokai/batch-symfony-framework
Register the bundle in config/bundles.php:
return [
// ...
Yokai\Batch\Bridge\Symfony\Framework\YokaiBatchBundle::class => ['all' => true],
];
Verify the actual bundle class name against the installed version — with a 1-star, single-release package, the FQCN in the README is the source of truth, not memory.
Create a minimal config at config/packages/yokai_batch.yaml. Start empty; the bundle's own defaults are usually enough to boot.
Where to look first: vendor/yokai/batch/README.md for the core concepts (Job → Step → Reader/Processor/Writer) and vendor/yokai/batch-symfony-framework/ for the DI extension and the console command it registers. The bridge is thin — almost all real behavior lives in yokai/batch, so read that first.
First use case: a single "import a CSV into the database" job. Define it as a service, wire a Reader/Processor/Writer chain, and run it from the console command the bundle exposes (typically bin/console yokai:batch:run <job> — confirm the exact name with bin/console list). That one flow exercises DI wiring, job execution, and logging, which is 90% of what the bridge does for you.
Jobs as services, not classes you instantiate. The main value of this bridge is that jobs participate in the Symfony container. Define them as services and let autowiring inject your readers, processors, writers, and any collaborators (repositories, HTTP clients, loggers). This is how you get testability and reuse out of an otherwise plain-PHP library.
final class ImportCustomersJob extends Job
{
public function __construct(
private CustomerCsvReader $reader,
private CustomerWriter $writer,
) {
parent::__construct(
new Step\ItemStep('import', $reader, null, $writer),
);
}
}
Tag-based registration. The bundle's extension will expose configuration for registering jobs/steps with the runner. Register jobs explicitly in YAML or tag them so the compiler pass collects them — pick one convention and stick to it across the codebase, because mixing tagged and manually-registered jobs makes it hard to answer "what actually runs in production."
Compose steps, don't build monoliths. A job is a sequence of steps; each step is a reader/processor/writer chain. Model each step around a single unit of work (fetch, transform, persist) so failures map to a named step in the logs and partial reruns are possible.
Run from the console, schedule from cron or Messenger. The bundle's console command is the intended entry point. For scheduled work, invoke it from cron/symfony/scheduler rather than trying to run jobs from a controller — batch work is long-running and shouldn't share a web request's time/memory budget.
Keep job state in a JobExecution and persist it. If the bridge exposes the execution storage (filesystem or DB), configure it early. Day-to-day this is what lets you answer "did last night's import succeed?" without grepping logs. A DB-backed storage is worth it as soon as you have more than a couple of jobs.
Integrate with Symfony's tooling. Because everything is a service, you get the profiler, debug:container, Monolog channels, and Messenger for free. Route batch logging to a dedicated channel (monolog.channels: ['batch']) so batch noise doesn't drown the app log.
Testing pattern: unit-test readers/processors/writers in isolation (they're plain services); integration-test the job by booting the kernel and executing it against a test database. Avoid mocking the container.
composer.json and read the bridge source before upgrading yokai/batch — the bridge is small enough to fork and vendor if it stalls.symfony/framework-bundle range; if you're on a newer Symfony, Composer may resolve to an old framework version or fail outright. Check composer why-not yokai/batch-symfony-framework when it fights your other packages.config/bundles.php, the DI extension and console command simply don't exist, and you'll get a confusing "command not found" rather than an error pointing at the cause.bin/console list yokai immediately after install and treat that output as documentation. Options for selecting a job, retrying, or forcing re-execution vary.debug:container --tag=<job tag> after a config change to confirm exactly what got registered.max_execution_time expectations from web config. Set php -d memory_limit=... in your cron entry and log peak memory per step; the readers often hold entire datasets in memory.-vvv, check the job execution storage first (it usually records the failing step and exception), then look at the step's reader — most "hangs" are a reader waiting on an external resource rather than framework misbehavior.JobExecution storage are the intended customization seams; do not patch the bundle for business logic. If you need more, subclass Job and register it as a normal service.How can I help you explore Laravel packages today?