Skip to content

Commit bc77ba8

Browse files
committed
Minor fixes
1 parent 0c0483f commit bc77ba8

File tree

9 files changed

+197
-95
lines changed

9 files changed

+197
-95
lines changed

config/config/grid/process_import.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ sylius_grid:
3131
type: show
3232
delete:
3333
type: delete
34-
options:
35-
enabled: "resource.status in ['success', 'failed', 'cancelled']"
3634
bulk:
3735
delete:
3836
type: delete
39-
options:
40-
enabled: "resource.status in ['success', 'failed', 'cancelled']"

config/services.xml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,21 @@
5353
<tag name="messenger.message_handler" bus="sylius.command_bus" />
5454
</service>
5555

56-
<service id="sylius_import_export.messenger.command_handler.import" class="Sylius\ImportExport\Messenger\Handler\ImportCommandHandler">
57-
<argument type="service" id="sylius_import_export.repository.process_import" />
56+
<service id="sylius_import_export.validator.import" class="Sylius\ImportExport\Validator\ImportValidator">
57+
<argument type="service" id="validator" />
58+
</service>
59+
60+
<service id="sylius_import_export.processor.batch" class="Sylius\ImportExport\Processor\BatchProcessor">
5861
<argument type="service" id="sylius_import_export.denormalizer.registry" />
5962
<argument type="service" id="doctrine.orm.entity_manager" />
6063
<argument type="service" id="sylius.resource_registry" />
61-
<argument type="service" id="validator" />
64+
<argument type="service" id="sylius_import_export.validator.import" />
65+
</service>
66+
67+
<service id="sylius_import_export.messenger.command_handler.import" class="Sylius\ImportExport\Messenger\Handler\ImportCommandHandler">
68+
<argument type="service" id="sylius_import_export.repository.process_import" />
69+
<argument type="service" id="doctrine.orm.entity_manager" />
70+
<argument type="service" id="sylius_import_export.processor.batch" />
6271

6372
<tag name="messenger.message_handler" bus="sylius.command_bus" />
6473
</service>

src/Controller/ImportAction.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function __invoke(Request $request, string $grid): Response
8383

8484
$session->getFlashBag()->add('success', 'sylius_import_export.import_started');
8585
} catch (\Throwable $e) {
86-
$session->getFlashBag()->add('error', 'sylius_import_export.upload_failed');
86+
$session->getFlashBag()->add('error', 'sylius_import_export.failed');
8787
}
8888

8989
return new RedirectResponse($request->headers->get('referer') ?? '/');
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\ImportExport\Exception;
15+
16+
class ValidationFailedException extends \Exception
17+
{
18+
}

src/Messenger/Handler/ImportCommandHandler.php

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,20 @@
1414
namespace Sylius\ImportExport\Messenger\Handler;
1515

1616
use Doctrine\ORM\EntityManagerInterface;
17-
use Sylius\ImportExport\Denormalizer\DenormalizerRegistryInterface;
1817
use Sylius\ImportExport\Entity\ImportProcessInterface;
1918
use Sylius\ImportExport\Exception\ImportFailedException;
19+
use Sylius\ImportExport\Exception\ValidationFailedException;
2020
use Sylius\ImportExport\Messenger\Command\ImportCommand;
21+
use Sylius\ImportExport\Processor\BatchProcessor;
2122
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;
22-
use Sylius\Resource\Metadata\RegistryInterface;
23-
use Symfony\Component\Validator\Validator\ValidatorInterface;
2423

2524
class ImportCommandHandler
2625
{
2726
/** @param RepositoryInterface<ImportProcessInterface> $processRepository */
2827
public function __construct(
2928
protected RepositoryInterface $processRepository,
30-
protected DenormalizerRegistryInterface $denormalizerRegistry,
3129
protected EntityManagerInterface $entityManager,
32-
protected RegistryInterface $metadataRegistry,
33-
protected ValidatorInterface $validator,
30+
protected BatchProcessor $batchProcessor,
3431
) {
3532
}
3633

@@ -42,42 +39,29 @@ public function __invoke(ImportCommand $command): void
4239
}
4340

4441
try {
45-
$importedCount = 0;
46-
$resourceMetadata = $this->metadataRegistry->get($process->getResource());
47-
$resourceClass = $resourceMetadata->getClass('model');
48-
$denormalizer = $this->denormalizerRegistry->get($resourceClass);
49-
50-
foreach ($command->batchData as $recordData) {
51-
$entity = $denormalizer->denormalize($recordData, $resourceClass);
52-
53-
$validationGroups = $process->getParameters()['validation_groups'] ?? ['Default'];
54-
$violations = $this->validator->validate($entity, groups: $validationGroups);
55-
56-
if (count($violations) > 0) {
57-
$errorMessages = [];
58-
foreach ($violations as $violation) {
59-
$errorMessages[] = sprintf('%s: %s', $violation->getPropertyPath(), $violation->getMessage());
60-
}
61-
62-
throw new ImportFailedException(sprintf('Validation failed for record: %s', implode(', ', $errorMessages)));
63-
}
64-
65-
$this->entityManager->persist($entity);
66-
67-
++$importedCount;
68-
}
69-
70-
$this->entityManager->flush();
42+
$importedCount = $this->batchProcessor->processBatch($process, $command->batchData);
7143

7244
$process->setBatchesCount($process->getBatchesCount() - 1);
7345
$process->setImportedCount($process->getImportedCount() + $importedCount);
7446

7547
if ($process->getBatchesCount() <= 0) {
7648
$process->setStatus('success');
7749
}
50+
} catch (ValidationFailedException $e) {
51+
$this->entityManager->clear();
52+
$process = $this->processRepository->find($command->processId);
53+
if (null === $process) {
54+
throw new ImportFailedException(sprintf('Process with uuid "%s" not found after validation failure.', $command->processId));
55+
}
56+
$process->setStatus('failed');
57+
$process->setErrorMessage($e->getMessage());
58+
$this->entityManager->persist($process);
59+
$this->entityManager->flush();
7860
} catch (\Throwable $e) {
7961
$process->setStatus('failed');
8062
$process->setErrorMessage($e->getMessage());
63+
64+
$this->entityManager->flush();
8165
}
8266
}
8367
}

src/Processor/BatchProcessor.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\ImportExport\Processor;
15+
16+
use Doctrine\ORM\EntityManagerInterface;
17+
use Sylius\ImportExport\Denormalizer\DenormalizerRegistryInterface;
18+
use Sylius\ImportExport\Entity\ImportProcessInterface;
19+
use Sylius\ImportExport\Validator\ImportValidator;
20+
use Sylius\Resource\Metadata\RegistryInterface;
21+
22+
class BatchProcessor
23+
{
24+
public function __construct(
25+
private DenormalizerRegistryInterface $denormalizerRegistry,
26+
private EntityManagerInterface $entityManager,
27+
private RegistryInterface $metadataRegistry,
28+
private ImportValidator $importValidator,
29+
) {
30+
}
31+
32+
public function processBatch(ImportProcessInterface $process, array $batchData): int
33+
{
34+
$importedCount = 0;
35+
$resourceMetadata = $this->metadataRegistry->get($process->getResource());
36+
$resourceClass = $resourceMetadata->getClass('model');
37+
$denormalizer = $this->denormalizerRegistry->get($resourceClass);
38+
$validationGroups = $process->getParameters()['validation_groups'] ?? ['sylius_pricing_lists'];
39+
40+
foreach ($batchData as $recordData) {
41+
$entity = $denormalizer->denormalize($recordData, $resourceClass);
42+
43+
$this->importValidator->validate($entity, $validationGroups);
44+
45+
$this->entityManager->persist($entity);
46+
++$importedCount;
47+
}
48+
49+
$this->entityManager->flush();
50+
51+
return $importedCount;
52+
}
53+
}

src/Validator/ImportValidator.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\ImportExport\Validator;
15+
16+
use Sylius\ImportExport\Exception\ValidationFailedException;
17+
use Symfony\Component\Validator\Validator\ValidatorInterface;
18+
19+
class ImportValidator
20+
{
21+
public function __construct(
22+
private ValidatorInterface $validator,
23+
) {
24+
}
25+
26+
public function validate(object $entity, array $validationGroups): void
27+
{
28+
$violations = $this->validator->validate($entity, groups: $validationGroups);
29+
30+
if (count($violations) > 0) {
31+
$errorMessages = [];
32+
foreach ($violations as $violation) {
33+
$errorMessages[] = sprintf('%s: %s', $violation->getPropertyPath(), $violation->getMessage());
34+
}
35+
36+
throw new ValidationFailedException(sprintf('Validation failed for record: %s', implode(', ', $errorMessages)));
37+
}
38+
}
39+
}

tests/Functional/Importing/ImportHandlerTest.php

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -248,80 +248,80 @@ public static function getImportData(): array
248248
{
249249
return [
250250
'single basic dummy' => [
251-
'importData' => [
252251
[
253-
'uuid' => 'basic-uuid-1',
254-
'text' => 'Basic Text',
255-
'counter' => 10,
256-
'config' => ['enabled' => false],
252+
[
253+
'uuid' => 'basic-uuid-1',
254+
'text' => 'Basic Text',
255+
'counter' => 10,
256+
'config' => ['enabled' => false],
257+
],
257258
],
258-
],
259-
'expectedCount' => 1,
259+
1,
260260
],
261261
'multiple basic dummies' => [
262-
'importData' => [
263-
[
264-
'uuid' => 'multi-uuid-1',
265-
'text' => 'Multi Text 1',
266-
'counter' => 20,
267-
'config' => ['priority' => 'high'],
268-
],
269262
[
270-
'uuid' => 'multi-uuid-2',
271-
'text' => 'Multi Text 2',
272-
'counter' => 30,
273-
'config' => ['priority' => 'low'],
263+
[
264+
'uuid' => 'multi-uuid-1',
265+
'text' => 'Multi Text 1',
266+
'counter' => 20,
267+
'config' => ['priority' => 'high'],
268+
],
269+
[
270+
'uuid' => 'multi-uuid-2',
271+
'text' => 'Multi Text 2',
272+
'counter' => 30,
273+
'config' => ['priority' => 'low'],
274+
],
274275
],
275-
],
276-
'expectedCount' => 2,
276+
2,
277277
],
278278
'complex nested config dummies' => [
279-
'importData' => [
280279
[
281-
'uuid' => 'complex-uuid-1',
282-
'text' => 'Complex Text 1',
283-
'counter' => 100,
284-
'config' => [
285-
'enabled' => true,
286-
'metadata' => [
287-
'tags' => ['important', 'urgent'],
288-
'created_by' => 'system',
280+
[
281+
'uuid' => 'complex-uuid-1',
282+
'text' => 'Complex Text 1',
283+
'counter' => 100,
284+
'config' => [
285+
'enabled' => true,
286+
'metadata' => [
287+
'tags' => ['important', 'urgent'],
288+
'created_by' => 'system',
289+
],
289290
],
290291
],
291-
],
292-
[
293-
'uuid' => 'complex-uuid-2',
294-
'text' => 'Complex Text 2',
295-
'counter' => 200,
296-
'config' => [
297-
'enabled' => false,
298-
'settings' => [
299-
'auto_process' => true,
300-
'retry_count' => 3,
292+
[
293+
'uuid' => 'complex-uuid-2',
294+
'text' => 'Complex Text 2',
295+
'counter' => 200,
296+
'config' => [
297+
'enabled' => false,
298+
'settings' => [
299+
'auto_process' => true,
300+
'retry_count' => 3,
301+
],
301302
],
302303
],
303304
],
304-
],
305-
'expectedCount' => 2,
305+
2,
306306
],
307307
'edge case values' => [
308-
'importData' => [
309-
[
310-
'uuid' => 'edge-uuid-1',
311-
'text' => '',
312-
'counter' => 0,
313-
'config' => [],
314-
],
315308
[
316-
'uuid' => 'edge-uuid-2',
317-
'text' => 'Simple edge case text',
318-
'counter' => 999999,
319-
'config' => [
320-
'special_chars' => '!@#$%^&*()_+-={}|[]\\:";\'<>?,./',
309+
[
310+
'uuid' => 'edge-uuid-1',
311+
'text' => 'Valid text',
312+
'counter' => 0,
313+
'config' => [],
314+
],
315+
[
316+
'uuid' => 'edge-uuid-2',
317+
'text' => 'Simple edge case text',
318+
'counter' => 999999,
319+
'config' => [
320+
'special_chars' => '!@#$%^&*()_+-={}|[]\\:";\'<>?,./',
321+
],
321322
],
322323
],
323-
],
324-
'expectedCount' => 2,
324+
2,
325325
],
326326
];
327327
}

tests/TestApplication/src/Entity/Dummy.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Sylius\ImportExport\Serializer\DefaultSerializationGroups;
2121
use Sylius\Resource\Model\ResourceInterface;
2222
use Symfony\Component\Serializer\Attribute\Groups;
23+
use Symfony\Component\Validator\Constraints as Assert;
2324

2425
#[Entity]
2526
#[ORM\Table(name: 'sylius_test_dummy')]
@@ -33,10 +34,12 @@ class Dummy implements ResourceInterface
3334

3435
#[ORM\Column(name: 'text')]
3536
#[Groups(DefaultSerializationGroups::EXPORT_GROUP)]
37+
#[Assert\NotBlank]
3638
private string $text;
3739

3840
#[ORM\Column(name: 'counter', type: 'integer')]
3941
#[Groups(DefaultSerializationGroups::EXPORT_GROUP)]
42+
#[Assert\PositiveOrZero]
4043
private int $counter;
4144

4245
#[ORM\Column(name: 'config', type: 'json')]

0 commit comments

Comments
 (0)