Skip to content

Commit c8f5c64

Browse files
committed
Fix dunglas' comments
1 parent d9d986d commit c8f5c64

File tree

5 files changed

+265
-3
lines changed

5 files changed

+265
-3
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: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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\EventListener;
15+
16+
use ApiPlatform\Core\EventListener\WriteListener as BaseWriteListener;
17+
use Doctrine\Common\Persistence\ManagerRegistry;
18+
use Doctrine\Common\Persistence\ObjectManager;
19+
use Symfony\Component\HttpFoundation\Request;
20+
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
21+
22+
/**
23+
* Bridges Doctrine and the API system.
24+
*
25+
* @author Kévin Dunglas <[email protected]>
26+
*/
27+
final class WriteListener
28+
{
29+
private $managerRegistry;
30+
31+
public function __construct(ManagerRegistry $managerRegistry)
32+
{
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+
35+
$this->managerRegistry = $managerRegistry;
36+
}
37+
38+
/**
39+
* Persists, updates or delete data return by the controller if applicable.
40+
*
41+
* @param GetResponseForControllerResultEvent $event
42+
*/
43+
public function onKernelView(GetResponseForControllerResultEvent $event)
44+
{
45+
$request = $event->getRequest();
46+
if ($request->isMethodSafe(false)) {
47+
return;
48+
}
49+
50+
$resourceClass = $request->attributes->get('_api_resource_class');
51+
if (null === $resourceClass) {
52+
return;
53+
}
54+
55+
$controllerResult = $event->getControllerResult();
56+
if (null === $objectManager = $this->getManager($resourceClass, $controllerResult)) {
57+
return;
58+
}
59+
60+
switch ($request->getMethod()) {
61+
case Request::METHOD_POST:
62+
$objectManager->persist($controllerResult);
63+
break;
64+
case Request::METHOD_DELETE:
65+
$objectManager->remove($controllerResult);
66+
$event->setControllerResult(null);
67+
break;
68+
}
69+
70+
$objectManager->flush();
71+
}
72+
73+
/**
74+
* Gets the manager if applicable.
75+
*
76+
* @param string $resourceClass
77+
* @param mixed $data
78+
*
79+
* @return ObjectManager|null
80+
*/
81+
private function getManager(string $resourceClass, $data)
82+
{
83+
$objectManager = $this->managerRegistry->getManagerForClass($resourceClass);
84+
if (null === $objectManager || !is_object($data)) {
85+
return null;
86+
}
87+
88+
return $objectManager;
89+
}
90+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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\Tests\Bridge\Doctrine\EventListener;
15+
16+
use ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener;
17+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
18+
use Doctrine\Common\Persistence\ManagerRegistry;
19+
use Doctrine\Common\Persistence\ObjectManager;
20+
use PHPUnit\Framework\TestCase;
21+
use Symfony\Component\HttpFoundation\Request;
22+
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
23+
use Symfony\Component\HttpKernel\HttpKernelInterface;
24+
25+
/**
26+
* @author Amrouche Hamza <[email protected]>
27+
*
28+
* @group legacy
29+
*/
30+
class WriteListenerTest extends TestCase
31+
{
32+
/**
33+
* @expectedDeprecation The ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener class is deprecated since version 2.2 and will be removed in 3.0. Use the ApiPlatform\Core\EventListener\WriteListener class instead.
34+
*/
35+
public function testOnKernelViewWithControllerResultAndPostMethod()
36+
{
37+
$dummy = new Dummy();
38+
$dummy->setName('Dummyrino');
39+
40+
$objectManagerProphecy = $this->prophesize(ObjectManager::class);
41+
$objectManagerProphecy->persist($dummy)->shouldBeCalled();
42+
$objectManagerProphecy->flush()->shouldBeCalled();
43+
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
44+
$managerRegistryProphecy->getManagerForClass('Dummy')->willReturn($objectManagerProphecy->reveal());
45+
46+
$writeListener = new WriteListener($managerRegistryProphecy->reveal());
47+
$httpKernelProphecy = $this->prophesize(HttpKernelInterface::class);
48+
$request = new Request();
49+
$request->setMethod(Request::METHOD_POST);
50+
$request->attributes->set('_api_resource_class', 'Dummy');
51+
$event = new GetResponseForControllerResultEvent($httpKernelProphecy->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, $dummy);
52+
53+
$this->assertNull($writeListener->onKernelView($event));
54+
$this->assertNotEquals($dummy, $writeListener->onKernelView($event));
55+
}
56+
57+
/**
58+
* @expectedDeprecation The ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener class is deprecated since version 2.2 and will be removed in 3.0. Use the ApiPlatform\Core\EventListener\WriteListener class instead.
59+
*/
60+
public function testOnKernelViewWithControllerResultAndDeleteMethod()
61+
{
62+
$dummy = new Dummy();
63+
$dummy->setName('Dummyrino');
64+
65+
$objectManagerProphecy = $this->prophesize(ObjectManager::class);
66+
$objectManagerProphecy->remove($dummy)->shouldBeCalled();
67+
$objectManagerProphecy->flush()->shouldBeCalled();
68+
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
69+
$managerRegistryProphecy->getManagerForClass('Dummy')->willReturn($objectManagerProphecy->reveal());
70+
71+
$writeListener = new WriteListener($managerRegistryProphecy->reveal());
72+
$request = new Request();
73+
$request->setMethod(Request::METHOD_DELETE);
74+
$request->attributes->set('_api_resource_class', 'Dummy');
75+
$event = $this->prophesize(GetResponseForControllerResultEvent::class);
76+
$event->setControllerResult(null)->shouldBeCalled();
77+
$event->getRequest()->willReturn($request);
78+
$event->getControllerResult()->willReturn($dummy);
79+
$this->assertNull($writeListener->onKernelView($event->reveal()));
80+
$this->assertNotEquals($dummy, $writeListener->onKernelView($event->reveal()));
81+
}
82+
83+
/**
84+
* @expectedDeprecation The ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener class is deprecated since version 2.2 and will be removed in 3.0. Use the ApiPlatform\Core\EventListener\WriteListener class instead.
85+
*/
86+
public function testOnKernelViewWithSafeMethod()
87+
{
88+
$dummy = new Dummy();
89+
$dummy->setName('Dummyrino');
90+
91+
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
92+
93+
$writeListener = new WriteListener($managerRegistryProphecy->reveal());
94+
$httpKernelProphecy = $this->prophesize(HttpKernelInterface::class);
95+
$request = new Request();
96+
$request->setMethod(Request::METHOD_HEAD);
97+
$event = new GetResponseForControllerResultEvent($httpKernelProphecy->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, $dummy);
98+
99+
$this->assertNull($writeListener->onKernelView($event));
100+
$this->assertNotEquals($dummy, $writeListener->onKernelView($event));
101+
}
102+
103+
/**
104+
* @expectedDeprecation The ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener class is deprecated since version 2.2 and will be removed in 3.0. Use the ApiPlatform\Core\EventListener\WriteListener class instead.
105+
*/
106+
public function testOnKernelViewWithNoResourceClass()
107+
{
108+
$dummy = new Dummy();
109+
$dummy->setName('Dummyrino');
110+
111+
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
112+
113+
$writeListener = new WriteListener($managerRegistryProphecy->reveal());
114+
$httpKernelProphecy = $this->prophesize(HttpKernelInterface::class);
115+
$request = new Request();
116+
$request->setMethod(Request::METHOD_POST);
117+
$event = new GetResponseForControllerResultEvent($httpKernelProphecy->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, $dummy);
118+
119+
$this->assertNull($writeListener->onKernelView($event));
120+
$this->assertNotEquals($dummy, $writeListener->onKernelView($event));
121+
}
122+
123+
/**
124+
* @expectedDeprecation The ApiPlatform\Core\Bridge\Doctrine\EventListener\WriteListener class is deprecated since version 2.2 and will be removed in 3.0. Use the ApiPlatform\Core\EventListener\WriteListener class instead.
125+
*/
126+
public function testOnKernelViewWithNoManager()
127+
{
128+
$dummy = new Dummy();
129+
$dummy->setName('Dummyrino');
130+
131+
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
132+
$managerRegistryProphecy->getManagerForClass('Dummy')->willReturn(null);
133+
134+
$writeListener = new WriteListener($managerRegistryProphecy->reveal());
135+
$httpKernelProphecy = $this->prophesize(HttpKernelInterface::class);
136+
$request = new Request();
137+
$request->setMethod(Request::METHOD_DELETE);
138+
$request->attributes->set('_api_resource_class', 'Dummy');
139+
$event = new GetResponseForControllerResultEvent($httpKernelProphecy->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, $dummy);
140+
141+
$this->assertNull($writeListener->onKernelView($event));
142+
$this->assertNotEquals($dummy, $writeListener->onKernelView($event));
143+
}
144+
}

tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ private function getBaseContainerBuilderProphecy()
526526

527527
$definitions = [
528528
'api_platform.action.graphql_entrypoint',
529+
'api_platform.doctrine.listener.http_cache.purge',
529530
'api_platform.doctrine.metadata_factory',
530531
'api_platform.doctrine.orm.boolean_filter',
531532
'api_platform.doctrine.orm.collection_data_provider',
@@ -547,7 +548,6 @@ private function getBaseContainerBuilderProphecy()
547548
'api_platform.doctrine.orm.range_filter',
548549
'api_platform.doctrine.orm.search_filter',
549550
'api_platform.doctrine.orm.subresource_data_provider',
550-
'api_platform.doctrine.listener.http_cache.purge',
551551
'api_platform.graphql.collection_resolver_factory',
552552
'api_platform.graphql.executor',
553553
'api_platform.graphql.item_resolver_factory',

tests/EventListener/WriteListenerTest.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function testOnKernelViewWithControllerResultAndPersist()
3636
$dataPersisterProphecy->persist($dummy)->shouldBeCalled();
3737

3838
$request = new Request();
39-
$request->attributes->set('_api_resource_class', 'Dummy');
39+
$request->attributes->set('_api_resource_class', Dummy::class);
4040

4141
$event = new GetResponseForControllerResultEvent(
4242
$this->prophesize(HttpKernelInterface::class)->reveal(),
@@ -63,7 +63,7 @@ public function testOnKernelViewWithControllerResultAndRemove()
6363

6464
$request = new Request();
6565
$request->setMethod(Request::METHOD_DELETE);
66-
$request->attributes->set('_api_resource_class', 'Dummy');
66+
$request->attributes->set('_api_resource_class', Dummy::class);
6767

6868
$event = new GetResponseForControllerResultEvent(
6969
$this->prophesize(HttpKernelInterface::class)->reveal(),
@@ -87,6 +87,7 @@ public function testOnKernelViewWithSafeMethod()
8787

8888
$request = new Request();
8989
$request->setMethod(Request::METHOD_HEAD);
90+
$request->attributes->set('_api_resource_class', Dummy::class);
9091

9192
$event = new GetResponseForControllerResultEvent(
9293
$this->prophesize(HttpKernelInterface::class)->reveal(),
@@ -120,4 +121,28 @@ public function testOnKernelViewWithNoResourceClass()
120121

121122
(new WriteListener($dataPersisterProphecy->reveal()))->onKernelView($event);
122123
}
124+
125+
public function testOnKernelViewWithNoDataPersisterSupport()
126+
{
127+
$dummy = new Dummy();
128+
$dummy->setName('Dummyrino');
129+
130+
$dataPersisterProphecy = $this->prophesize(DataPersisterInterface::class);
131+
$dataPersisterProphecy->supports($dummy)->willReturn(false)->shouldBeCalled();
132+
$dataPersisterProphecy->persist($dummy)->shouldNotBeCalled();
133+
$dataPersisterProphecy->remove($dummy)->shouldNotBeCalled();
134+
135+
$request = new Request();
136+
$request->setMethod(Request::METHOD_POST);
137+
$request->attributes->set('_api_resource_class', 'Dummy');
138+
139+
$event = new GetResponseForControllerResultEvent(
140+
$this->prophesize(HttpKernelInterface::class)->reveal(),
141+
$request,
142+
HttpKernelInterface::MASTER_REQUEST,
143+
$dummy
144+
);
145+
146+
(new WriteListener($dataPersisterProphecy->reveal()))->onKernelView($event);
147+
}
123148
}

0 commit comments

Comments
 (0)