Bridge with symfony/framework-bundle

Refer to the official documentation on Symfony’s website.

This bridge provides library configuration, and services registering in a Symfony framework project.

Configure the Job launcher(s)

You can use many different job launcher in your application, you will be able to register these using configuration:

# config/packages/yokai_batch.yaml
yokai_batch:
  launcher:
    default: simple
    launchers:
      simple: ...
      async: ...

Note

If you do not configure anything here, you will be using the SimpleJobLauncher.

The default job launcher, must reference a launcher name, defined in the launchers list.
The default job launcher will be the autowired instance of job launcher when you ask for one.
All launchers will be registered as a service, and an autowire named alias will be configured for it.
For instance, in the example below, you will be able to register all these launchers like this:
<?php

declare(strict_types=1);

namespace App\Service;

use Yokai\Batch\Launcher\JobLauncherInterface;

final class YourAppCode
{
    public function __construct(
        private JobLauncherInterface $jobLauncher, // will inject the default job launcher
        private JobLauncherInterface $simpleJobLauncher, // will inject the "simple" job launcher
        private JobLauncherInterface $messengerJobLauncher, // will inject the "messenger" job launcher
    ) {
    }
}

All launchers are configured using a DSN, every scheme has it’s own associated factory:

  • simple://simple: a SimpleJobLauncher, no configuration allowed

  • messenger://messenger: a DispatchMessageJobLauncher, no configuration allowed

  • console://console: a RunCommandJobLauncher, configurable options:

    • log: the filename where command output will be redirected (defaults to batch_execute.log)

  • service://service: pointing to a service of your choice, configurable options:

    • service: the id of the service to use (required, an exception will be thrown otherwise)

You might define multiple job launchers, and will want to configure the relation between job and launcher.
For instance, you might prefer running some jobs with an async job launcher, but not all.
You can configure this routing like the following:
# config/packages/yokai_batch.yaml
yokai_batch:
  launcher:
    default: simple
    launchers:
      simple: simple://simple
      console: console://console
    routing:
      export_job_name: simple
      import_job_name: console

Note

It is not required to configure every single job in the routing. The default will be the fallback for all jobs you did not not configured in the routing.

Note

If you configure config.launcher.routing, it will replace your configured default from autowiring perspective.

Configure the JobExecution storage

You can have only one storage for your JobExecution, and you have several options:

  • filesystem will create a file for each JobExecution in %kernel.project_dir%/var/batch/{execution.jobName}/{execution.id}.json

  • dbal will create a row in a table for each JobExecution

  • service will use a service you have defined in your application

# config/packages/yokai_batch.yaml
yokai_batch:
  storage:
    filesystem: ~
    # Or with yokai/batch-doctrine-dbal (& doctrine/dbal)
    # dbal: ~
    # Or with a service of yours
    # service: ~

Note

The default storage is filesystem, because it only requires a writeable filesystem.
But if you already have doctrine/dbal in your project, it is highly recommended to use it instead.
Because querying JobExecution in a filesystem might be slow, specially if you are planing to add UIs on top.

You can also configure the storage using a DSN string, which is especially useful to switch storage per environment via an environment variable:

# config/packages/yokai_batch.yaml
yokai_batch:
  storage: '%env(BATCH_STORAGE_DSN)%'

All storage DSN use the scheme://...?options format. Every scheme has its own associated factory:

  • filesystem://{dir}: a FilesystemJobExecutionStorage, configurable options:

    • serializer: the service id of the serializer to use (defaults to JsonJobExecutionSerializer)

    • Example: filesystem://%kernel.project_dir%/var/batch

    • Example with options: filesystem://%kernel.project_dir%/var/batch?serializer=Yokai\Batch\Serializer\JsonJobExecutionSerializer

  • dbal://{connection}: a DoctrineDBALJobExecutionStorage, configurable options:

    • table: the table name to use (defaults to built-in default, use null to keep default)

    • Example: dbal://default

    • Example with options: dbal://default?table=my_batch_table

  • service://service: pointing to a service of your choice, configurable options:

    • id: the id of the service to use (required, an exception will be thrown otherwise)

    • Example: service://service?id=App\Batch\MyCustomStorage

Configure the JobExecution id generator

When it is created, every JobExecution is assigned with a unique identifier. You can configure what your id will be like:

Note

The default storage is uniqid, because it only requires the function with the same name that is a PHP standard.
# config/packages/yokai_batch.yaml
yokai_batch:
  id: uniqid
  # Or with yokai/batch-symfony-uid (& symfony/uid)
  # id: symfony.uuid.random
  # id: symfony.uuid.time
  # id: symfony.ulid

User interface to visualize JobExecution

The package is shipped with few routes that will allow you and your users, to watch for JobExecution.

../_images/bootstrap4-list.png ../_images/bootstrap4-details.png ../_images/bootstrap4-children.png ../_images/bootstrap4-warnings.png

Installation

For the UI to be enabled, it is required that you install some dependencies:

composer require symfony/translation symfony/twig-bundle

The UI is disabled by default, you must enable it explicitly:

# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    enabled: true

You will also need to import bundle routes:

# config/routes/yokai_batch.yaml
_yokai_batch:
  resource: "@YokaiBatchBundle/Resources/routing/ui.xml"

Templating

The templating service is used by the JobController to render its templates.
It’s a wrapper around Twig, for you to control templates used, and variables passed.

By default

  • the templating will find templates like @YokaiBatch/bootstrap4/*.html.twig

  • the template base view will be base.html.twig

You can configure a prefix for all templates:

# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    templating:
      prefix: 'batch/job/'

Note

With this configuration, we will look for templates like batch/job/*.html.twig.

You can also configure the name of the base template for the root views of that bundle:

# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    templating:
      base_template: 'layout.html.twig'

Note

With this configuration, the template base view will be layout.html.twig.

If these are not enough, or if you need to add more variables to context, you can configure a service:

# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    templating:
      service: 'App\Batch\AppTemplating'

And create the class that will cover the templating:

<?php

declare(strict_types=1);

namespace App\Batch;

use Yokai\Batch\Bridge\Symfony\Framework\UserInterface\Templating\TemplatingInterface;

final class AppTemplating implements TemplatingInterface
{
    public function name(string $name): string
    {
        return "another-$name"; // change $name if you want
    }

    public function context(array $context): array
    {
        return \array_merge($context, ['foo' => 'bar']); // add variables to $context if you want
    }
}

Note

You can also use the Yokai\Batch\Bridge\Symfony\Framework\UserInterface\Templating\ConfigurableTemplating that will cover both prefix and static variables at construction.

Pagination

The JobExecution list is paginated. You can configure the number of items per page and the size of the page window around the current page:

# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    pagination:
      page_size: 20  # number of job executions per page (default: 20)
      page_range: 2  # number of pages shown on each side of the current page (default: 2)

Filtering

The JobExecution list includes a filter form, but you will need another optional dependency:

composer require symfony/form

Security

There is no access control over JobExecution by default, you will need another optional dependency:

composer require symfony/security-bundle

Every security attribute the bundle is using is configurable:

# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    security:
      attributes:
        list: ROLE_JOB_LIST # defaults to IS_AUTHENTICATED
        view: ROLE_JOB_VIEW # defaults to IS_AUTHENTICATED
        traces: ROLE_JOB_TRACES # defaults to IS_AUTHENTICATED
        logs: ROLE_JOB_LOGS # defaults to IS_AUTHENTICATED
Optionally, you can register a voter for these attributes.
This is especially useful if you need different access control rules per JobExecution.
<?php

declare(strict_types=1);

namespace App\Security;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Yokai\Batch\JobExecution;

final class JobVoter extends Voter
{
    protected function supports(string $attribute, mixed $subject): bool
    {
        return \str_starts_with($attribute, 'JOB_');
    }

    /**
     * @param JobExecution|null $subject
     */
    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        // TODO: Implement voteOnAttribute() method.
    }
}

Integration with SonataAdminBundle

If you are on a SonataAdmin project.
The bundle got you covered with a dedicated templating services and templates.
../_images/sonata-list.png ../_images/sonata-details.png ../_images/sonata-children.png ../_images/sonata-warnings.png
composer require sonata-project/admin-bundle
# config/packages/yokai_batch.yaml
yokai_batch:
  ui:
    templating: sonata

Note

With this configuration, we will look for templates like @YokaiBatch/sonata/*.html.twig.

Customizing templates

You can override templates like described it Symfony’s documentation.
Examples:
  • templates/bundles/YokaiBatchBundle/bootstrap4/list.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/_parameters.html.twig

But you can also register job name dedicated templates if you need some specific view for one of your jobs:

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_children-executions.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_failures.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_general.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_information.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_parameters.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_summary.html.twig

  • templates/bundles/YokaiBatchBundle/bootstrap4/show/{job name}/_warnings.html.twig

Logger service that log in JobExecution

The batch logger will log inside the JobExecution.
In a Symfony project, you can use that with the symfony autowiring by naming your variable as $yokaiBatchLogger
<?php

declare(strict_types=1);

namespace App\Service;

use Psr\Log\LoggerInterface;

final class YourService
{
    public function __construct(
        private LoggerInterface $yokaiBatchLogger,
    ) {
    }

    public function method()
    {
        $this->yokaiBatchLogger->error(...);
    }
}