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\EventListener; |
||
15 | |||
16 | use ApiPlatform\Core\Api\IriConverterInterface; |
||
17 | use ApiPlatform\Core\Api\ResourceClassResolverInterface; |
||
18 | use ApiPlatform\Core\DataPersister\DataPersisterInterface; |
||
19 | use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; |
||
20 | use ApiPlatform\Core\Metadata\Resource\ToggleableOperationAttributeTrait; |
||
21 | use ApiPlatform\Core\Util\RequestAttributesExtractor; |
||
22 | use ApiPlatform\Core\Util\ResourceClassInfoTrait; |
||
23 | use Symfony\Component\HttpFoundation\Response; |
||
24 | use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; |
||
25 | |||
26 | /** |
||
27 | * Bridges persistence and the API system. |
||
28 | * |
||
29 | * @author Kévin Dunglas <[email protected]> |
||
30 | * @author Baptiste Meyer <[email protected]> |
||
31 | */ |
||
32 | final class WriteListener |
||
33 | { |
||
34 | use ResourceClassInfoTrait; |
||
35 | use ToggleableOperationAttributeTrait; |
||
36 | |||
37 | public const OPERATION_ATTRIBUTE_KEY = 'write'; |
||
38 | |||
39 | private $dataPersister; |
||
40 | private $iriConverter; |
||
41 | |||
42 | public function __construct(DataPersisterInterface $dataPersister, IriConverterInterface $iriConverter = null, ResourceMetadataFactoryInterface $resourceMetadataFactory = null, ResourceClassResolverInterface $resourceClassResolver = null) |
||
43 | { |
||
44 | $this->dataPersister = $dataPersister; |
||
45 | $this->iriConverter = $iriConverter; |
||
46 | $this->resourceMetadataFactory = $resourceMetadataFactory; |
||
47 | $this->resourceClassResolver = $resourceClassResolver; |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * Persists, updates or delete data return by the controller if applicable. |
||
52 | */ |
||
53 | public function onKernelView(GetResponseForControllerResultEvent $event): void |
||
54 | { |
||
55 | $controllerResult = $event->getControllerResult(); |
||
56 | $request = $event->getRequest(); |
||
57 | |||
58 | if ( |
||
59 | $controllerResult instanceof Response |
||
60 | || $request->isMethodSafe(false) |
||
61 | || !($attributes = RequestAttributesExtractor::extractAttributes($request)) |
||
62 | || !$attributes['persist'] |
||
63 | || $this->isOperationAttributeDisabled($attributes, self::OPERATION_ATTRIBUTE_KEY) |
||
64 | ) { |
||
65 | return; |
||
66 | } |
||
67 | |||
68 | if (!$this->dataPersister->supports($controllerResult, $attributes)) { |
||
69 | return; |
||
70 | } |
||
71 | |||
72 | switch ($request->getMethod()) { |
||
73 | case 'PUT': |
||
74 | case 'PATCH': |
||
75 | case 'POST': |
||
76 | $persistResult = $this->dataPersister->persist($controllerResult, $attributes); |
||
77 | |||
78 | if (!\is_object($persistResult)) { |
||
79 | @trigger_error(sprintf('Not returning an object from %s::persist() is deprecated since API Platform 2.3 and will not be supported in API Platform 3.', DataPersisterInterface::class), E_USER_DEPRECATED); |
||
80 | } else { |
||
81 | $controllerResult = $persistResult; |
||
82 | $event->setControllerResult($controllerResult); |
||
83 | } |
||
84 | |||
85 | if ($controllerResult instanceof Response) { |
||
86 | break; |
||
87 | } |
||
88 | |||
89 | $hasOutput = true; |
||
90 | if ($this->resourceMetadataFactory instanceof ResourceMetadataFactoryInterface) { |
||
91 | $resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']); |
||
92 | $outputMetadata = $resourceMetadata->getOperationAttribute($attributes, 'output', [ |
||
93 | 'class' => $attributes['resource_class'], |
||
94 | ], true); |
||
95 | |||
96 | $hasOutput = \array_key_exists('class', $outputMetadata) && null !== $outputMetadata['class']; |
||
97 | } |
||
98 | |||
99 | if (!$hasOutput) { |
||
100 | break; |
||
101 | } |
||
102 | |||
103 | if ($this->iriConverter instanceof IriConverterInterface && $this->isResourceClass($this->getObjectClass($controllerResult))) { |
||
104 | $request->attributes->set('_api_write_item_iri', $this->iriConverter->getIriFromItem($controllerResult)); |
||
105 | } |
||
106 | |||
107 | break; |
||
108 | case 'DELETE': |
||
109 | $this->dataPersister->remove($controllerResult, $attributes); |
||
0 ignored issues
–
show
|
|||
110 | $event->setControllerResult(null); |
||
111 | break; |
||
112 | } |
||
113 | } |
||
114 | } |
||
115 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.