Skip to content

Commit 42028dc

Browse files
authored
Allow jobs to define their name using interface method in a Symfony framework context (#46)
* Allow jobs to define their name using interface method in a Symfony framework context * Fixed use case : service without class
1 parent a9f5b65 commit 42028dc

File tree

6 files changed

+92
-22
lines changed

6 files changed

+92
-22
lines changed

docs/getting-started.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,7 @@ Then the job will be triggered with its service id:
124124
/** @var \Yokai\Batch\Launcher\JobLauncherInterface $launcher */
125125
$launcher->launch(\App\Job\ImportUsersJob::class);
126126
```
127+
128+
> **note**: when registering jobs with dedicated class, you can use the
129+
> [JobWithStaticNameInterface](../src/JobWithStaticNameInterface.php) interface
130+
> to be able to specify the job name of your service.

src/DependencyInjection/CompilerPass/RegisterJobsCompilerPass.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
88
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
99
use Symfony\Component\DependencyInjection\ContainerBuilder;
10+
use Symfony\Component\DependencyInjection\Definition;
1011
use Symfony\Component\DependencyInjection\Reference;
12+
use Yokai\Batch\Bridge\Symfony\Framework\JobWithStaticNameInterface;
1113

1214
final class RegisterJobsCompilerPass implements CompilerPassInterface
1315
{
@@ -18,12 +20,30 @@ public function process(ContainerBuilder $container): void
1820
{
1921
$jobs = [];
2022
foreach ($container->findTaggedServiceIds('yokai_batch.job') as $serviceId => $tags) {
23+
$serviceDefinition = $container->findDefinition($serviceId);
2124
foreach ($tags as $attributes) {
22-
$jobs[$attributes['job'] ?? $serviceId] = new Reference($serviceId);
25+
$jobs[$this->getJobName($serviceId, $serviceDefinition, $attributes)] = new Reference($serviceId);
2326
}
2427
}
2528

2629
$container->getDefinition('yokai_batch.job_registry')
2730
->setArgument('$jobs', ServiceLocatorTagPass::register($container, $jobs));
2831
}
32+
33+
/**
34+
* @phpstan-param array<string, mixed> $attributes
35+
*/
36+
private function getJobName(string $id, Definition $definition, array $attributes): string
37+
{
38+
if (isset($attributes['job'])) {
39+
return (string)$attributes['job'];
40+
}
41+
42+
$serviceClass = $definition->getClass();
43+
if ($serviceClass !== null && \is_a($serviceClass, JobWithStaticNameInterface::class, true)) {
44+
return $serviceClass::getJobName();
45+
}
46+
47+
return $id;
48+
}
2949
}

src/JobWithStaticNameInterface.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Bridge\Symfony\Framework;
6+
7+
/**
8+
* A job that implement this interface can define the associated job name via a static method.
9+
* This is very useful if you are registering jobs using PSR services registering.
10+
* Without implementing, the job name will be the service id,
11+
* in the case of a PSR service registering : the job class.
12+
*/
13+
interface JobWithStaticNameInterface
14+
{
15+
public static function getJobName(): string;
16+
}

tests/Fixtures/DummyJob.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Framework\Fixtures;
6+
7+
use Yokai\Batch\Job\AbstractJob;
8+
use Yokai\Batch\JobExecution;
9+
10+
final class DummyJob extends AbstractJob
11+
{
12+
protected function doExecute(JobExecution $jobExecution): void
13+
{
14+
// dummy
15+
}
16+
}

tests/Fixtures/DummyJobWithName.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Framework\Fixtures;
6+
7+
use Yokai\Batch\Bridge\Symfony\Framework\JobWithStaticNameInterface;
8+
use Yokai\Batch\Job\AbstractJob;
9+
use Yokai\Batch\JobExecution;
10+
11+
final class DummyJobWithName extends AbstractJob implements JobWithStaticNameInterface
12+
{
13+
public static function getJobName(): string
14+
{
15+
return 'export_orders_job';
16+
}
17+
18+
protected function doExecute(JobExecution $jobExecution): void
19+
{
20+
// dummy
21+
}
22+
}

tests/YokaiBatchBundleTest.php

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@
66

77
use PHPUnit\Framework\TestCase;
88
use Symfony\Component\DependencyInjection\ContainerBuilder;
9-
use Symfony\Component\DependencyInjection\Definition;
109
use Yokai\Batch\Bridge\Symfony\Framework\YokaiBatchBundle;
11-
use Yokai\Batch\Job\Item\ItemJob;
12-
use Yokai\Batch\Job\Item\Processor\NullProcessor;
13-
use Yokai\Batch\Job\Item\Reader\StaticIterableReader;
10+
use Yokai\Batch\Job\JobInterface;
1411
use Yokai\Batch\Registry\JobRegistry;
15-
use Yokai\Batch\Storage\NullJobExecutionStorage;
16-
use Yokai\Batch\Test\Job\Item\Writer\InMemoryWriter;
12+
use Yokai\Batch\Tests\Bridge\Symfony\Framework\Fixtures\DummyJob;
13+
use Yokai\Batch\Tests\Bridge\Symfony\Framework\Fixtures\DummyJobWithName;
1714

1815
class YokaiBatchBundleTest extends TestCase
1916
{
@@ -23,27 +20,22 @@ public function testBuild(): void
2320
$container->register('yokai_batch.job_registry', JobRegistry::class)
2421
->setPublic(true);
2522

26-
$this->job($container, 'job.named.with.service.id')
23+
$container->register(DummyJobWithName::class, DummyJobWithName::class)
2724
->addTag('yokai_batch.job');
28-
$this->job($container, 'job.named.with.tag.attribute')
25+
$container->register(DummyJob::class, DummyJob::class)
26+
->addTag('yokai_batch.job');
27+
$container->register('job.named.with.service.id', DummyJob::class)
28+
->addTag('yokai_batch.job');
29+
$container->register('job.named.with.tag.attribute', DummyJob::class)
2930
->addTag('yokai_batch.job', ['job' => 'job.name.in.attribute']);
3031

3132
(new YokaiBatchBundle())->build($container);
3233

3334
$container->compile();
3435
$registry = $container->get('yokai_batch.job_registry');
35-
self::assertInstanceOf(ItemJob::class, $registry->get('job.named.with.service.id'));
36-
self::assertInstanceOf(ItemJob::class, $registry->get('job.name.in.attribute'));
37-
}
38-
39-
private function job(ContainerBuilder $container, string $id): Definition
40-
{
41-
return $container->register($id, ItemJob::class)
42-
->setArgument('$batchSize', 100)
43-
->setArgument('$reader', (new Definition(StaticIterableReader::class))->setArgument('$items', []))
44-
->setArgument('$processor', new Definition(NullProcessor::class))
45-
->setArgument('$writer', new Definition(InMemoryWriter::class))
46-
->setArgument('$executionStorage', new Definition(NullJobExecutionStorage::class))
47-
;
36+
self::assertInstanceOf(JobInterface::class, $registry->get('export_orders_job'));
37+
self::assertInstanceOf(JobInterface::class, $registry->get(DummyJob::class));
38+
self::assertInstanceOf(JobInterface::class, $registry->get('job.named.with.service.id'));
39+
self::assertInstanceOf(JobInterface::class, $registry->get('job.name.in.attribute'));
4840
}
4941
}

0 commit comments

Comments
 (0)