Skip to content

Commit c7e2cda

Browse files
authored
Merge pull request #1464 from meyerbaptiste/add_data_persister
Add a data persistence layer
2 parents abf7e9c + c8f5c64 commit c7e2cda

File tree

20 files changed

+732
-17
lines changed

20 files changed

+732
-17
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* Automatically enable FOSUser support if the bundle is installed
1414
* Add an `AbstractCollectionNormalizer` to help supporting custom formats
1515
* Deprecate NelmioApiDocBundle 2 support (upgrade to v3, it has native API Platform support)
16+
* Deprecate the `ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener` class in favor of the new `ApiPlatform\Core\EventListener\WriteListener` class.
17+
* Delete the `api_platform.doctrine.listener.view.write` event listener service.
18+
* Add a data persistence layer with a new `ApiPlatform\Core\DataPersister\DataPersisterInterface` interface.
1619

1720
## 2.1.2
1821

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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 ApiPlatform\Core\Bridge\Doctrine\Common;
15+
16+
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
17+
use ApiPlatform\Core\Util\ClassInfoTrait;
18+
use Doctrine\Common\Persistence\ManagerRegistry;
19+
use Doctrine\Common\Persistence\ObjectManager as DoctrineObjectManager;
20+
21+
/**
22+
* Data persister for Doctrine.
23+
*
24+
* @author Baptiste Meyer <[email protected]>
25+
*/
26+
final class DataPersister implements DataPersisterInterface
27+
{
28+
use ClassInfoTrait;
29+
30+
private $managerRegistry;
31+
32+
public function __construct(ManagerRegistry $managerRegistry)
33+
{
34+
$this->managerRegistry = $managerRegistry;
35+
}
36+
37+
/**
38+
* {@inheritdoc}
39+
*/
40+
public function supports($data): bool
41+
{
42+
return null !== $this->getManager($data);
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
*/
48+
public function persist($data)
49+
{
50+
if (!$manager = $this->getManager($data)) {
51+
return;
52+
}
53+
54+
$manager->persist($data);
55+
$manager->flush();
56+
}
57+
58+
/**
59+
* {@inheritdoc}
60+
*/
61+
public function remove($data)
62+
{
63+
if (!$manager = $this->getManager($data)) {
64+
return;
65+
}
66+
67+
$manager->remove($data);
68+
$manager->flush();
69+
}
70+
71+
/**
72+
* Gets the Doctrine object manager associated with given data.
73+
*
74+
* @param mixed $data
75+
*
76+
* @return DoctrineObjectManager|null
77+
*/
78+
private function getManager($data)
79+
{
80+
return is_object($data) ? $this->managerRegistry->getManagerForClass($this->getObjectClass($data)) : null;
81+
}
82+
}

src/Bridge/Doctrine/EventListener/WriteListener.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Core\Bridge\Doctrine\EventListener;
1515

16+
use ApiPlatform\Core\EventListener\WriteListener as BaseWriteListener;
1617
use Doctrine\Common\Persistence\ManagerRegistry;
1718
use Doctrine\Common\Persistence\ObjectManager;
1819
use Symfony\Component\HttpFoundation\Request;
@@ -29,6 +30,8 @@ final class WriteListener
2930

3031
public function __construct(ManagerRegistry $managerRegistry)
3132
{
33+
@trigger_error(sprintf('The %s class is deprecated since version 2.2 and will be removed in 3.0. Use the %s class instead.', __CLASS__, BaseWriteListener::class), E_USER_DEPRECATED);
34+
3235
$this->managerRegistry = $managerRegistry;
3336
}
3437

src/Bridge/Symfony/Bundle/ApiPlatformBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Core\Bridge\Symfony\Bundle;
1515

1616
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\AnnotationFilterPass;
17+
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\DataPersisterPass;
1718
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\DataProviderPass;
1819
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\DoctrineQueryExtensionPass;
1920
use ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler\FilterPass;
@@ -34,6 +35,7 @@ public function build(ContainerBuilder $container)
3435
{
3536
parent::build($container);
3637

38+
$container->addCompilerPass(new DataPersisterPass());
3739
$container->addCompilerPass(new DataProviderPass());
3840
$container->addCompilerPass(new AnnotationFilterPass());
3941
$container->addCompilerPass(new FilterPass());

src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
1717
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
18+
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
1819
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
1920
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
2021
use ApiPlatform\Core\Exception\RuntimeException;
@@ -86,9 +87,12 @@ public function load(array $configs, ContainerBuilder $container)
8687

8788
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
8889
$loader->load('api.xml');
90+
$loader->load('data_persister.xml');
8991
$loader->load('data_provider.xml');
9092
$loader->load('filter.xml');
9193

94+
$container->registerForAutoconfiguration(DataPersisterInterface::class)
95+
->addTag('api_platform.data_persister');
9296
$container->registerForAutoconfiguration(ItemDataProviderInterface::class)
9397
->addTag('api_platform.item_data_provider');
9498
$container->registerForAutoconfiguration(CollectionDataProviderInterface::class)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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 ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\Compiler;
15+
16+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
17+
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
use Symfony\Component\DependencyInjection\Reference;
19+
20+
/**
21+
* Registers data persisters.
22+
*
23+
* @internal
24+
*
25+
* @author Baptiste Meyer <[email protected]>
26+
*/
27+
final class DataPersisterPass implements CompilerPassInterface
28+
{
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
public function process(ContainerBuilder $container)
33+
{
34+
$persisters = [];
35+
$services = $container->findTaggedServiceIds('api_platform.data_persister', true);
36+
37+
foreach ($services as $serviceId => $tags) {
38+
$persisters[] = new Reference($serviceId);
39+
}
40+
41+
$container->getDefinition('api_platform.data_persister')->addArgument($persisters);
42+
}
43+
}

src/Bridge/Symfony/Bundle/Resources/config/api.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@
135135
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="4" />
136136
</service>
137137

138+
<service id="api_platform.listener.view.write" class="ApiPlatform\Core\EventListener\WriteListener">
139+
<argument type="service" id="api_platform.data_persister" />
140+
141+
<tag name="kernel.event_listener" event="kernel.view" method="onKernelView" priority="32" />
142+
</service>
143+
138144
<service id="api_platform.listener.request.deserialize" class="ApiPlatform\Core\EventListener\DeserializeListener">
139145
<argument type="service" id="api_platform.serializer" />
140146
<argument type="service" id="api_platform.serializer.context_builder" />
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" ?>
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="api_platform.data_persister" class="ApiPlatform\Core\DataPersister\ChainDataPersister" public="false" />
9+
</services>
10+
11+
</container>

src/Bridge/Symfony/Bundle/Resources/config/doctrine_orm.xml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
<factory service="doctrine.orm.default_entity_manager" method="getMetadataFactory" />
1010
</service>
1111

12+
<service id="api_platform.doctrine.orm.data_persister" class="ApiPlatform\Core\Bridge\Doctrine\Common\DataPersister" public="false">
13+
<argument type="service" id="doctrine" />
14+
15+
<tag name="api_platform.data_persister" />
16+
</service>
17+
1218
<service id="api_platform.doctrine.orm.collection_data_provider" public="false" abstract="true">
1319
<argument type="service" id="doctrine" />
1420
<argument type="collection" /> <!-- extensions -->
@@ -95,14 +101,6 @@
95101
<argument type="service" id="api_platform.doctrine.orm.metadata.property.metadata_factory.inner" />
96102
</service>
97103

98-
<!-- Event listener -->
99-
100-
<service id="api_platform.doctrine.listener.view.write" class="ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener">
101-
<argument type="service" id="doctrine" />
102-
103-
<tag name="kernel.event_listener" event="kernel.view" method="onKernelView" priority="32" />
104-
</service>
105-
106104
<!-- Doctrine Query extensions -->
107105

108106
<service id="api_platform.doctrine.orm.query_extension.eager_loading" class="ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\EagerLoadingExtension" public="false">
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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 ApiPlatform\Core\DataPersister;
15+
16+
/**
17+
* Chained data persisters.
18+
*
19+
* @author Baptiste Meyer <[email protected]>
20+
*/
21+
final class ChainDataPersister implements DataPersisterInterface
22+
{
23+
private $persisters;
24+
25+
/**
26+
* @param DataPersisterInterface[] $persisters
27+
*/
28+
public function __construct(array $persisters)
29+
{
30+
$this->persisters = $persisters;
31+
}
32+
33+
/**
34+
* {@inheritdoc}
35+
*/
36+
public function supports($data): bool
37+
{
38+
foreach ($this->persisters as $persister) {
39+
if ($persister->supports($data)) {
40+
return true;
41+
}
42+
}
43+
44+
return false;
45+
}
46+
47+
/**
48+
* {@inheritdoc}
49+
*/
50+
public function persist($data)
51+
{
52+
foreach ($this->persisters as $persister) {
53+
if ($persister->supports($data)) {
54+
$persister->persist($data);
55+
}
56+
}
57+
}
58+
59+
/**
60+
* {@inheritdoc}
61+
*/
62+
public function remove($data)
63+
{
64+
foreach ($this->persisters as $persister) {
65+
if ($persister->supports($data)) {
66+
$persister->remove($data);
67+
}
68+
}
69+
}
70+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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 ApiPlatform\Core\DataPersister;
15+
16+
/**
17+
* Manages data persistence.
18+
*
19+
* @author Baptiste Meyer <[email protected]>
20+
*/
21+
interface DataPersisterInterface
22+
{
23+
/**
24+
* Is the data supported by the persister?
25+
*
26+
* @param mixed $data
27+
*
28+
* @return bool
29+
*/
30+
public function supports($data): bool;
31+
32+
/**
33+
* Persists the data.
34+
*
35+
* @param mixed $data
36+
*/
37+
public function persist($data);
38+
39+
/**
40+
* Removes the data.
41+
*
42+
* @param mixed $data
43+
*/
44+
public function remove($data);
45+
}

0 commit comments

Comments
 (0)