Skip to content

Commit d99d012

Browse files
committed
WIP
1 parent feefd6f commit d99d012

10 files changed

+319
-2
lines changed

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
"symfony/dependency-injection": "^6.4 || ^7.3",
2929
"symfony/framework-bundle": "^6.4 || ^7.3",
3030
"symfony/messenger": "^6.4 || ^7.3",
31+
"symfony/property-access": "^6.4 || ^7.3",
32+
"symfony/serializer": "^6.4 || ^7.3",
3133
"symfony/ux-live-component": "^2.12",
32-
"symfony/uid": "^6.4 || ^7.3"
34+
"symfony/uid": "^6.4 || ^7.3",
35+
"webmozart/assert": "^1.11"
3336
},
3437
"require-dev": {
3538
"phpstan/phpstan": "^1.12",

config/services.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555

5656
<service id="sylius_import_export.messenger.command_handler.import" class="Sylius\ImportExport\Messenger\Handler\ImportCommandHandler">
5757
<argument type="service" id="sylius_import_export.repository.process_import" />
58+
<argument type="service" id="sylius_import_export.denormalizer.registry" />
59+
<argument type="service" id="doctrine.orm.entity_manager" />
5860

5961
<tag name="messenger.message_handler" bus="sylius.command_bus" />
6062
</service>

config/services/denormalizer.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="sylius_import_export.denormalizer.relation_resolver" class="Sylius\ImportExport\Denormalizer\DoctrineRelationResolver">
9+
<argument type="service" id="doctrine.orm.entity_manager" />
10+
</service>
11+
12+
<service id="sylius_import_export.denormalizer.default_resource" class="Sylius\ImportExport\Denormalizer\DefaultResourceDenormalizer">
13+
<argument type="service" id="serializer" />
14+
<argument type="service" id="sylius_import_export.denormalizer.relation_resolver" />
15+
<argument type="service" id="doctrine.orm.entity_manager" />
16+
</service>
17+
18+
<service id="sylius_import_export.denormalizer.registry" class="Sylius\ImportExport\Denormalizer\DenormalizerRegistry">
19+
<argument type="service" id="sylius_import_export.denormalizer.default_resource" />
20+
<argument type="tagged_iterator" tag="sylius_import_export.resource_denormalizer" />
21+
</service>
22+
23+
<service id="Sylius\ImportExport\Denormalizer\DenormalizerRegistryInterface" alias="sylius_import_export.denormalizer.registry" />
24+
<service id="Sylius\ImportExport\Denormalizer\RelationResolverInterface" alias="sylius_import_export.denormalizer.relation_resolver" />
25+
</services>
26+
</container>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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\Denormalizer;
15+
16+
use Doctrine\ORM\EntityManagerInterface;
17+
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
18+
use Webmozart\Assert\Assert;
19+
20+
final readonly class DefaultResourceDenormalizer implements ResourceDenormalizerInterface
21+
{
22+
public function __construct(
23+
private DenormalizerInterface $denormalizer,
24+
private RelationResolverInterface $relationResolver,
25+
private EntityManagerInterface $entityManager,
26+
) {
27+
}
28+
29+
public function denormalize(array $data, string $resourceClass): object
30+
{
31+
$metadata = $this->entityManager->getClassMetadata($resourceClass);
32+
$processedData = [];
33+
34+
foreach ($data as $field => $value) {
35+
if (null === $value || '' === $value) {
36+
continue;
37+
}
38+
39+
if ($metadata->hasAssociation($field)) {
40+
$associationMapping = $metadata->getAssociationMapping($field);
41+
$targetEntity = $associationMapping['targetEntity'];
42+
Assert::string($targetEntity);
43+
44+
if ($metadata->isCollectionValuedAssociation($field)) {
45+
if (is_array($value) && !empty($value)) {
46+
$processedData[$field] = $this->relationResolver->resolveCollection($targetEntity, $value);
47+
} else {
48+
$processedData[$field] = [];
49+
}
50+
} else {
51+
if (is_array($value) && !empty($value)) {
52+
$processedData[$field] = $this->relationResolver->resolveEntity($targetEntity, $value);
53+
}
54+
}
55+
} elseif (is_array($value)) {
56+
$processedData[$field] = $this->processNestedArray($value);
57+
} else {
58+
$processedData[$field] = $value;
59+
}
60+
}
61+
62+
$result = $this->denormalizer->denormalize($processedData, $resourceClass);
63+
Assert::object($result);
64+
65+
return $result;
66+
}
67+
68+
private function processNestedArray(array $data): array
69+
{
70+
return $data;
71+
}
72+
73+
public function supports(string $resourceClass): bool
74+
{
75+
return true;
76+
}
77+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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\Denormalizer;
15+
16+
final class DenormalizerRegistry implements DenormalizerRegistryInterface
17+
{
18+
/** @var ResourceDenormalizerInterface[] */
19+
private array $denormalizers = [];
20+
21+
private ResourceDenormalizerInterface $defaultDenormalizer;
22+
23+
/**
24+
* @param iterable<ResourceDenormalizerInterface> $denormalizers
25+
*/
26+
public function __construct(ResourceDenormalizerInterface $defaultDenormalizer, iterable $denormalizers = [])
27+
{
28+
$this->defaultDenormalizer = $defaultDenormalizer;
29+
30+
foreach ($denormalizers as $denormalizer) {
31+
$this->register($denormalizer);
32+
}
33+
}
34+
35+
public function register(ResourceDenormalizerInterface $denormalizer): void
36+
{
37+
$this->denormalizers[] = $denormalizer;
38+
}
39+
40+
public function get(string $resourceClass): ResourceDenormalizerInterface
41+
{
42+
foreach ($this->denormalizers as $denormalizer) {
43+
if ($denormalizer->supports($resourceClass)) {
44+
return $denormalizer;
45+
}
46+
}
47+
48+
return $this->defaultDenormalizer;
49+
}
50+
51+
public function has(string $resourceClass): bool
52+
{
53+
foreach ($this->denormalizers as $denormalizer) {
54+
if ($denormalizer->supports($resourceClass)) {
55+
return true;
56+
}
57+
}
58+
59+
return true;
60+
}
61+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Denormalizer;
15+
16+
interface DenormalizerRegistryInterface
17+
{
18+
public function get(string $resourceClass): ResourceDenormalizerInterface;
19+
20+
public function has(string $resourceClass): bool;
21+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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\Denormalizer;
15+
16+
use Doctrine\ORM\EntityManagerInterface;
17+
18+
final readonly class DoctrineRelationResolver implements RelationResolverInterface
19+
{
20+
public function __construct(
21+
private EntityManagerInterface $entityManager,
22+
) {
23+
}
24+
25+
public function resolveEntity(string $entityClass, array $data): ?object
26+
{
27+
if (empty($data)) {
28+
return null;
29+
}
30+
31+
$repository = $this->entityManager->getRepository($entityClass);
32+
$identifierField = $this->getIdentifierField($entityClass, $data);
33+
34+
if (!isset($data[$identifierField])) {
35+
return null;
36+
}
37+
38+
$identifier = $data[$identifierField];
39+
40+
if ('id' === $identifierField) {
41+
return $repository->find($identifier);
42+
}
43+
44+
return $repository->findOneBy([$identifierField => $identifier]);
45+
}
46+
47+
public function resolveCollection(string $entityClass, array $dataCollection): array
48+
{
49+
if (empty($dataCollection)) {
50+
return [];
51+
}
52+
53+
$entities = [];
54+
foreach ($dataCollection as $data) {
55+
$entity = $this->resolveEntity($entityClass, $data);
56+
if (null !== $entity) {
57+
$entities[] = $entity;
58+
}
59+
}
60+
61+
return $entities;
62+
}
63+
64+
private function getIdentifierField(string $entityClass, array $data): string
65+
{
66+
if (isset($data['code'])) {
67+
return 'code';
68+
}
69+
70+
if (isset($data['id'])) {
71+
return 'id';
72+
}
73+
74+
return 'id';
75+
}
76+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Denormalizer;
15+
16+
interface RelationResolverInterface
17+
{
18+
public function resolveEntity(string $entityClass, array $data): ?object;
19+
20+
public function resolveCollection(string $entityClass, array $dataCollection): array;
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Denormalizer;
15+
16+
interface ResourceDenormalizerInterface
17+
{
18+
public function denormalize(array $data, string $resourceClass): object;
19+
20+
public function supports(string $resourceClass): bool;
21+
}

src/Messenger/Handler/ImportCommandHandler.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
namespace Sylius\ImportExport\Messenger\Handler;
1515

16+
use Doctrine\ORM\EntityManagerInterface;
17+
use Sylius\ImportExport\Denormalizer\DenormalizerRegistryInterface;
1618
use Sylius\ImportExport\Entity\ImportProcessInterface;
1719
use Sylius\ImportExport\Exception\ImportFailedException;
1820
use Sylius\ImportExport\Messenger\Command\ImportCommand;
@@ -23,6 +25,8 @@ class ImportCommandHandler
2325
/** @param RepositoryInterface<ImportProcessInterface> $processRepository */
2426
public function __construct(
2527
protected RepositoryInterface $processRepository,
28+
protected DenormalizerRegistryInterface $denormalizerRegistry,
29+
protected EntityManagerInterface $entityManager,
2630
) {
2731
}
2832

@@ -35,13 +39,18 @@ public function __invoke(ImportCommand $command): void
3539

3640
try {
3741
$importedCount = 0;
42+
$resourceClass = $process->getResource();
43+
$denormalizer = $this->denormalizerRegistry->get($resourceClass);
3844

3945
foreach ($command->batchData as $recordData) {
40-
// TODO: Process the record
46+
$entity = $denormalizer->denormalize($recordData, $resourceClass);
47+
$this->entityManager->persist($entity);
4148

4249
++$importedCount;
4350
}
4451

52+
$this->entityManager->flush();
53+
4554
$process->setBatchesCount($process->getBatchesCount() - 1);
4655
$process->setImportedCount($process->getImportedCount() + $importedCount);
4756

0 commit comments

Comments
 (0)