Skip to content

Commit 2163c5b

Browse files
toby-griffithsdunglas
authored andcommitted
Add support for entity operation annotations (#176)
* Added test for expected operations config * Added support for operations class annotations * Style fixes * One more style fix
1 parent 37bdcc7 commit 2163c5b

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

src/AnnotationGenerator/ApiPlatformCoreAnnotationGenerator.php

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
use ApiPlatform\Core\Annotation\ApiProperty;
1717
use ApiPlatform\Core\Annotation\ApiResource;
1818
use ApiPlatform\SchemaGenerator\TypesGenerator;
19+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
20+
use Symfony\Component\OptionsResolver\Options;
21+
use Symfony\Component\OptionsResolver\OptionsResolver;
1922

2023
/**
2124
* Generates API Platform core annotations.
2225
*
2326
* @author Kévin Dunglas <[email protected]>
2427
*
25-
* @see https://github.com/api-platform/core
28+
* @see https://github.com/api-platform/core
2629
*/
2730
final class ApiPlatformCoreAnnotationGenerator extends AbstractAnnotationGenerator
2831
{
@@ -31,17 +34,87 @@ final class ApiPlatformCoreAnnotationGenerator extends AbstractAnnotationGenerat
3134
*/
3235
public function generateClassAnnotations(string $className): array
3336
{
34-
$resource = $this->classes[$className]['resource'];
37+
$class = $this->classes[$className];
38+
39+
$resource = $class['resource'];
40+
41+
$arguments = [sprintf('iri="%s"', $resource->getUri())];
42+
43+
if (isset($class['operations'])) {
44+
$operations = $this->validateClassOperations((array) $class['operations']);
45+
foreach ($operations as $operationTarget => $targetOperations) {
46+
$targetArguments = [];
47+
foreach ($targetOperations as $method => $methodConfig) {
48+
$methodConfig = $this->validateClassOperationMethodConfig($methodConfig);
49+
$methodArguments = [];
50+
foreach ($methodConfig as $key => $value) {
51+
$methodArguments[] = sprintf('"%s"="%s"', $key, $value);
52+
}
53+
$targetArguments[] = sprintf('"%s"={%s}', $method, implode(', ', $methodArguments));
54+
}
55+
$arguments[] = sprintf('%sOperations={%s}', $operationTarget, implode(', ', $targetArguments));
56+
}
57+
}
58+
59+
return [sprintf('@ApiResource(%s)', implode(', ', $arguments))];
60+
}
61+
62+
/**
63+
* Verifies that the operations config is valid.
64+
*
65+
* @param array $operations
66+
*
67+
* @return array
68+
*/
69+
private function validateClassOperations(array $operations)
70+
{
71+
$resolver = new OptionsResolver();
72+
$resolver->setDefaults(['item' => [], 'collection' => []]);
73+
$resolver->setAllowedTypes('item', 'array');
74+
$resolver->setAllowedTypes('collection', 'array');
75+
76+
return $resolver->resolve($operations);
77+
}
78+
79+
/**
80+
* Validates the individual method config for an item/collection operation annotation.
81+
*
82+
* @param array $methodConfig
83+
*
84+
* @return array
85+
*/
86+
private function validateClassOperationMethodConfig(array $methodConfig)
87+
{
88+
$resolver = new OptionsResolver();
89+
90+
$resolver->setDefined(['method', 'route_name']);
91+
$resolver->setAllowedTypes('method', 'string');
92+
$resolver->setAllowedTypes('route_name', 'string');
93+
$resolver->setNormalizer(
94+
'route_name',
95+
function (Options $options, $value) {
96+
if (isset($options['method'])) {
97+
throw new InvalidOptionsException('You must provide only \'method\' or \'route_name\', but not both');
98+
}
99+
100+
return $value;
101+
}
102+
);
35103

36-
return [sprintf('@ApiResource(iri="%s")', $resource->getUri())];
104+
return $resolver->resolve($methodConfig);
37105
}
38106

39107
/**
40108
* {@inheritdoc}
41109
*/
42110
public function generateFieldAnnotations(string $className, string $fieldName): array
43111
{
44-
return $this->classes[$className]['fields'][$fieldName]['isCustom'] ? [] : [sprintf('@ApiProperty(iri="http://schema.org/%s")', $fieldName)];
112+
return $this->classes[$className]['fields'][$fieldName]['isCustom'] ? [] : [
113+
sprintf(
114+
'@ApiProperty(iri="http://schema.org/%s")',
115+
$fieldName
116+
),
117+
];
45118
}
46119

47120
/**

tests/AnnotationGenerator/ApiPlatformCoreAnnotationGeneratorTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ public function setUp()
4848
],
4949
],
5050
'MyEnum' => ['resource' => $myEnum],
51+
'WithOperations' => [
52+
'resource' => new \EasyRdf_Resource('http://schema.org/WithOperations', $graph),
53+
'operations' => [
54+
'item' => ['get' => ['route_name' => 'api_about_get']],
55+
'collection' => [],
56+
],
57+
],
5158
]
5259
);
5360
}
@@ -57,6 +64,11 @@ public function testGenerateClassAnnotations()
5764
$this->assertSame(['@ApiResource(iri="http://schema.org/Res")'], $this->generator->generateClassAnnotations('Res'));
5865
}
5966

67+
public function testGenerateClassAnnotationsWithOperations()
68+
{
69+
$this->assertSame(['@ApiResource(iri="http://schema.org/WithOperations", itemOperations={"get"={"route_name"="api_about_get"}}, collectionOperations={})'], $this->generator->generateClassAnnotations('WithOperations'));
70+
}
71+
6072
public function testGenerateFieldAnnotations()
6173
{
6274
$this->assertSame(['@ApiProperty(iri="http://schema.org/prop")'], $this->generator->generateFieldAnnotations('Res', 'prop'));

0 commit comments

Comments
 (0)