Skip to content

Commit 6cf466b

Browse files
authored
Allow ItemJob to skip items for any reason (#41)
* Replace InvalidItemException with SkipItemException and let developer what to do with these exception * Handle impact of SkipInvalidItemException on symfony/validator bridge * Handle impact of SkipInvalidItemException on symfony/serializer bridge * Enhanced documentation of sources * Assert skip item exception are updating summary
1 parent b0d1988 commit 6cf466b

File tree

5 files changed

+81
-73
lines changed

5 files changed

+81
-73
lines changed

src/DenormalizeItemProcessor.php

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,18 @@
55
namespace Yokai\Batch\Bridge\Symfony\Serializer;
66

77
use Symfony\Component\Serializer\Exception\ExceptionInterface;
8+
use Symfony\Component\Serializer\Exception\UnsupportedException;
89
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
9-
use Yokai\Batch\Job\Item\InvalidItemException;
10+
use Yokai\Batch\Job\Item\Exception\SkipItemException;
1011
use Yokai\Batch\Job\Item\ItemProcessorInterface;
1112

13+
/**
14+
* This {@see ItemProcessorInterface} uses Symfony's serializer to denormalize items.
15+
*/
1216
final class DenormalizeItemProcessor implements ItemProcessorInterface
1317
{
14-
/**
15-
* @var DenormalizerInterface
16-
*/
1718
private DenormalizerInterface $denormalizer;
18-
19-
/**
20-
* @var string
21-
*/
2219
private string $type;
23-
24-
/**
25-
* @var string|null
26-
*/
2720
private ?string $format;
2821

2922
/**
@@ -51,28 +44,17 @@ public function __construct(
5144
*/
5245
public function process($item)
5346
{
54-
if (!$this->denormalizer->supportsDenormalization($item, $this->type, $this->format)) {
55-
throw new InvalidItemException(
56-
'Unable to denormalize item. Not supported.',
57-
[
58-
'item' => is_object($item) ? get_class($item) : gettype($item),
59-
'format' => $this->format,
60-
]
61-
);
62-
}
63-
6447
try {
48+
if (!$this->denormalizer->supportsDenormalization($item, $this->type, $this->format)) {
49+
throw new UnsupportedException('Unable to denormalize item. Not supported.');
50+
}
51+
6552
$object = $this->denormalizer->denormalize($item, $this->type, $this->format, $this->context);
6653
} catch (ExceptionInterface $exception) {
67-
throw new InvalidItemException(
68-
'Unable to denormalize item. An exception occurred.',
69-
[
70-
'item' => is_object($item) ? get_class($item) : gettype($item),
71-
'format' => $this->format,
72-
'context' => $this->context,
73-
],
74-
0,
75-
$exception
54+
throw SkipItemException::onError(
55+
$item,
56+
$exception,
57+
['format' => $this->format, 'context' => $this->context]
7658
);
7759
}
7860

src/NormalizeItemProcessor.php

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,17 @@
55
namespace Yokai\Batch\Bridge\Symfony\Serializer;
66

77
use Symfony\Component\Serializer\Exception\ExceptionInterface;
8+
use Symfony\Component\Serializer\Exception\UnsupportedException;
89
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
9-
use Yokai\Batch\Job\Item\InvalidItemException;
10+
use Yokai\Batch\Job\Item\Exception\SkipItemException;
1011
use Yokai\Batch\Job\Item\ItemProcessorInterface;
1112

13+
/**
14+
* This {@see ItemProcessorInterface} uses Symfony's serializer to normalize items.
15+
*/
1216
final class NormalizeItemProcessor implements ItemProcessorInterface
1317
{
14-
/**
15-
* @var NormalizerInterface
16-
*/
1718
private NormalizerInterface $normalizer;
18-
19-
/**
20-
* @var string|null
21-
*/
2219
private ?string $format;
2320

2421
/**
@@ -41,28 +38,17 @@ public function __construct(NormalizerInterface $normalizer, string $format = nu
4138
*/
4239
public function process($item)
4340
{
44-
if (!$this->normalizer->supportsNormalization($item, $this->format)) {
45-
throw new InvalidItemException(
46-
'Unable to normalize item. Not supported.',
47-
[
48-
'item' => is_object($item) ? get_class($item) : gettype($item),
49-
'format' => $this->format,
50-
]
51-
);
52-
}
53-
5441
try {
42+
if (!$this->normalizer->supportsNormalization($item, $this->format)) {
43+
throw new UnsupportedException('Unable to normalize item. Not supported.');
44+
}
45+
5546
return $this->normalizer->normalize($item, $this->format, $this->context);
5647
} catch (ExceptionInterface $exception) {
57-
throw new InvalidItemException(
58-
'Unable to normalize item. An exception occurred.',
59-
[
60-
'item' => is_object($item) ? get_class($item) : gettype($item),
61-
'format' => $this->format,
62-
'context' => $this->context,
63-
],
64-
0,
65-
$exception
48+
throw SkipItemException::onError(
49+
$item,
50+
$exception,
51+
['format' => $this->format, 'context' => $this->context]
6652
);
6753
}
6854
}

tests/DenormalizeItemProcessorTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Symfony\Component\Serializer\Exception\ExceptionInterface;
1515
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
1616
use Yokai\Batch\Bridge\Symfony\Serializer\DenormalizeItemProcessor;
17-
use Yokai\Batch\Job\Item\InvalidItemException;
17+
use Yokai\Batch\Job\Item\Exception\SkipItemException;
1818

1919
final class DenormalizeItemProcessorTest extends TestCase
2020
{
@@ -52,7 +52,7 @@ public function testProcess(string $type, ?string $format, array $context, $item
5252
*/
5353
public function testUnsupported(string $type, ?string $format, array $context, $item): void
5454
{
55-
$this->expectException(InvalidItemException::class);
55+
$this->expectException(SkipItemException::class);
5656

5757
$this->denormalizer->supportsDenormalization($item, $type, $format)
5858
->shouldBeCalled()
@@ -70,7 +70,7 @@ public function testUnsupported(string $type, ?string $format, array $context, $
7070
*/
7171
public function testException(string $type, ?string $format, array $context, $item): void
7272
{
73-
$this->expectException(InvalidItemException::class);
73+
$this->expectException(SkipItemException::class);
7474

7575
$this->denormalizer->supportsDenormalization($item, $type, $format)
7676
->shouldBeCalled()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Serializer\Job\Item\Exception;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Yokai\Batch\Job\Item\Exception\SkipItemWithWarning;
9+
use Yokai\Batch\JobExecution;
10+
11+
class SkipItemWithWarningTest extends TestCase
12+
{
13+
public function test(): void
14+
{
15+
$execution = JobExecution::createRoot('123', 'testing');
16+
$cause = new SkipItemWithWarning('An arbitrary message...');
17+
$cause->report($execution, 'itemIndex', 'item');
18+
19+
self::assertCount(1, $execution->getWarnings());
20+
self::assertSame('An arbitrary message...', $execution->getWarnings()[0]->getMessage());
21+
self::assertSame([], $execution->getWarnings()[0]->getParameters());
22+
self::assertSame(['itemIndex' => 'itemIndex', 'item' => 'item'], $execution->getWarnings()[0]->getContext());
23+
}
24+
}

tests/NormalizeItemProcessorTest.php

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
use Prophecy\Argument;
1212
use Prophecy\PhpUnit\ProphecyTrait;
1313
use Prophecy\Prophecy\ObjectProphecy;
14-
use Symfony\Component\Serializer\Exception\ExceptionInterface;
14+
use Symfony\Component\Serializer\Exception\BadMethodCallException;
1515
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
1616
use Yokai\Batch\Bridge\Symfony\Serializer\NormalizeItemProcessor;
17-
use Yokai\Batch\Job\Item\InvalidItemException;
17+
use Yokai\Batch\Job\Item\Exception\SkipItemException;
18+
use Yokai\Batch\Job\Item\Exception\SkipItemOnError;
1819

1920
final class NormalizeItemProcessorTest extends TestCase
2021
{
@@ -52,8 +53,6 @@ public function testProcess(?string $format, array $context, $item, $expected):
5253
*/
5354
public function testUnsupported(?string $format, array $context, $item): void
5455
{
55-
$this->expectException(InvalidItemException::class);
56-
5756
$this->normalizer->supportsNormalization($item, $format)
5857
->shouldBeCalled()
5958
->willReturn(false);
@@ -62,29 +61,46 @@ public function testUnsupported(?string $format, array $context, $item): void
6261

6362
$processor = new NormalizeItemProcessor($this->normalizer->reveal(), $format, $context);
6463

65-
$processor->process($item);
64+
$exception = null;
65+
try {
66+
$processor->process($item);
67+
} catch (SkipItemException $exception) {
68+
// just capture the exception
69+
}
70+
71+
self::assertNotNull($exception, 'Processor has thrown an exception');
72+
$cause = $exception->getCause();
73+
self::assertInstanceOf(SkipItemOnError::class, $cause);
74+
/** @var SkipItemOnError $cause */
75+
self::assertSame('Unable to normalize item. Not supported.', $cause->getError()->getMessage());
6676
}
6777

6878
/**
6979
* @dataProvider sets
7080
*/
7181
public function testException(?string $format, array $context, $item): void
7282
{
73-
$this->expectException(InvalidItemException::class);
74-
7583
$this->normalizer->supportsNormalization($item, $format)
7684
->shouldBeCalled()
7785
->willReturn(true);
7886
$this->normalizer->normalize($item, $format, $context)
7987
->shouldBeCalled()
80-
->willThrow(
81-
new class extends \Exception implements ExceptionInterface {
82-
}
83-
);
88+
->willThrow($exceptionThrown = new BadMethodCallException());
8489

8590
$processor = new NormalizeItemProcessor($this->normalizer->reveal(), $format, $context);
8691

87-
$processor->process($item);
92+
$exception = null;
93+
try {
94+
$processor->process($item);
95+
} catch (SkipItemException $exception) {
96+
// just capture the exception
97+
}
98+
99+
self::assertNotNull($exception, 'Processor has thrown an exception');
100+
$cause = $exception->getCause();
101+
self::assertInstanceOf(SkipItemOnError::class, $cause);
102+
/** @var SkipItemOnError $cause */
103+
self::assertSame($exceptionThrown, $cause->getError());
88104
}
89105

90106
public function sets(): Generator

0 commit comments

Comments
 (0)