Skip to content

Commit ce38f6e

Browse files
feat: api platform 2.7 attributes generation (#367)
1 parent 5df7d1b commit ce38f6e

29 files changed

+304
-221
lines changed

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@
4444
"symfony/yaml": "^5.2 || ^6.0",
4545
"symfony/filesystem": "^5.2 || ^6.0",
4646
"twig/twig": "^3.0",
47-
"nette/php-generator": "^3.6 || ^4.0-dev",
47+
"nette/php-generator": "^3.6 || ^4.0",
4848
"nette/utils": "^3.1 || ^4.0-dev",
4949
"nikic/php-parser": "^4.13",
5050
"cebe/php-openapi": "^1.6",
5151
"symfony/string": "^5.2 || ^6.0"
5252
},
5353
"require-dev": {
54-
"api-platform/core": "^2.5",
54+
"api-platform/core": "^v2.7.0-beta.1",
5555
"doctrine/orm": "^2.7",
5656
"myclabs/php-enum": "^1.7",
5757
"symfony/doctrine-bridge": "^5.2 || ^6.0",

composer.lock

Lines changed: 25 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpstan.neon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ parameters:
3333
attributes: array<string, (int|bool|null|string|string[]|string[][]|\Nette\PhpGenerator\Literal)[]|null>,
3434
parent: false|string,
3535
guessFrom: string,
36-
operations: array<string, array<string, string[]>>,
36+
operations: array<string, ?array<string, string|int|bool|string[]|null>>,
3737
allProperties: boolean,
3838
properties: array<string, PropertyConfiguration>
3939
}
@@ -44,6 +44,7 @@ parameters:
4444
vocabularyNamespace: string,
4545
relations: string[],
4646
debug: boolean,
47+
apiPlatformOldAttributes: boolean,
4748
id: array{generate: boolean, generationStrategy: string, writable: boolean, onClass: string},
4849
useInterface: boolean,
4950
checkIsGoodRelations: boolean,

src/AttributeGenerator/ApiPlatformCoreAttributeGenerator.php

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,21 @@
1313

1414
namespace ApiPlatform\SchemaGenerator\AttributeGenerator;
1515

16-
use ApiPlatform\Core\Annotation\ApiProperty;
17-
use ApiPlatform\Core\Annotation\ApiResource;
16+
use ApiPlatform\Core\Annotation\ApiProperty as OldApiProperty;
17+
use ApiPlatform\Core\Annotation\ApiResource as OldApiResource;
18+
use ApiPlatform\Metadata\ApiProperty;
19+
use ApiPlatform\Metadata\ApiResource;
20+
use ApiPlatform\Metadata\Delete;
21+
use ApiPlatform\Metadata\Get;
22+
use ApiPlatform\Metadata\GetCollection;
23+
use ApiPlatform\Metadata\Patch;
24+
use ApiPlatform\Metadata\Post;
25+
use ApiPlatform\Metadata\Put;
1826
use ApiPlatform\SchemaGenerator\Model\Attribute;
1927
use ApiPlatform\SchemaGenerator\Model\Class_;
2028
use ApiPlatform\SchemaGenerator\Model\Property;
2129
use ApiPlatform\SchemaGenerator\Model\Use_;
30+
use Nette\PhpGenerator\Literal;
2231
use Symfony\Component\OptionsResolver\OptionsResolver;
2332

2433
/**
@@ -43,30 +52,51 @@ public function generateClassAttributes(Class_ $class): array
4352
if ($class->name() !== $localName = $class->shortName()) {
4453
$arguments['shortName'] = $localName;
4554
}
55+
4656
if ($class->rdfType()) {
47-
$arguments['iri'] = $class->rdfType();
57+
if ($this->config['apiPlatformOldAttributes']) {
58+
$arguments['iri'] = $class->rdfType();
59+
} else {
60+
$arguments['types'] = [$class->rdfType()];
61+
}
4862
}
4963

5064
if ($class->operations) {
51-
$operations = $this->validateClassOperations($class->operations);
52-
foreach ($operations as $operationTarget => $targetOperations) {
53-
$targetArguments = [];
54-
foreach ($targetOperations as $method => $methodConfig) {
55-
$methodArguments = [];
56-
foreach ($methodConfig ?? [] as $key => $value) {
57-
$methodArguments[$key] = $value;
65+
if ($this->config['apiPlatformOldAttributes']) {
66+
$operations = $this->validateClassOperations($class->operations);
67+
foreach ($operations as $operationTarget => $targetOperations) {
68+
$targetArguments = [];
69+
foreach ($targetOperations ?? [] as $method => $methodConfig) {
70+
$methodArguments = [];
71+
if (!is_iterable($methodConfig)) {
72+
continue;
73+
}
74+
foreach ($methodConfig as $key => $value) {
75+
$methodArguments[$key] = $value;
76+
}
77+
$targetArguments[$method] = $methodArguments;
5878
}
59-
$targetArguments[$method] = $methodArguments;
79+
$arguments[sprintf('%sOperations', $operationTarget)] = $targetArguments;
80+
}
81+
} else {
82+
$arguments['operations'] = [];
83+
foreach ($class->operations as $operationMetadataClass => $methodConfig) {
84+
$arguments['operations'][] = new Literal(sprintf('new %s(%s)',
85+
$operationMetadataClass,
86+
implode(', ', array_map(
87+
fn ($k, $v) => sprintf('%s: %s', $k, (\is_string($v) ? sprintf("'%s'", addslashes($v)) : (\is_scalar($v) ? $v : ''))),
88+
array_keys($methodConfig ?? []), array_values($methodConfig ?? [])
89+
))
90+
));
6091
}
61-
$arguments[sprintf('%sOperations', $operationTarget)] = $targetArguments;
6292
}
6393
}
6494

6595
return [new Attribute('ApiResource', $arguments)];
6696
}
6797

6898
/**
69-
* Verifies that the operations config is valid.
99+
* Verifies that the operations' config is valid.
70100
*
71101
* @template T of array
72102
*
@@ -92,7 +122,11 @@ public function generatePropertyAttributes(Property $property, string $className
92122
$arguments = [];
93123

94124
if ($property->rdfType()) {
95-
$arguments['iri'] = $property->rdfType();
125+
if ($this->config['apiPlatformOldAttributes']) {
126+
$arguments['iri'] = $property->rdfType();
127+
} else {
128+
$arguments['types'] = [$property->rdfType()];
129+
}
96130
}
97131

98132
return $property->isCustom ? [] : [new Attribute('ApiProperty', $arguments)];
@@ -103,6 +137,19 @@ public function generatePropertyAttributes(Property $property, string $className
103137
*/
104138
public function generateUses(Class_ $class): array
105139
{
106-
return [new Use_(ApiResource::class), new Use_(ApiProperty::class)];
140+
if ($this->config['apiPlatformOldAttributes']) {
141+
return [new Use_(OldApiResource::class), new Use_(OldApiProperty::class)];
142+
}
143+
144+
return [
145+
new Use_(ApiResource::class),
146+
new Use_(ApiProperty::class),
147+
new Use_(Get::class),
148+
new Use_(Put::class),
149+
new Use_(Patch::class),
150+
new Use_(Delete::class),
151+
new Use_(GetCollection::class),
152+
new Use_(Post::class),
153+
];
107154
}
108155
}

src/FilesGenerator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ private function fixCs(array $files): void
153153
$fixers = (new FixerFactory())
154154
->registerBuiltInFixers()
155155
->useRuleSet(new $rulesetClass([ // @phpstan-ignore-line
156+
'@PhpCsFixer' => true,
156157
'@Symfony' => true,
157158
'array_syntax' => ['syntax' => 'short'],
158159
'phpdoc_order' => true,

src/Model/Class_.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ abstract class Class_
4545
public bool $isAbstract = false;
4646
public bool $hasChild = false;
4747
public bool $isEmbeddable = false;
48-
/** @var array<string, array<string, string[]|null>> */
48+
/** @var array<string, ?array<string, string|int|bool|string[]|null>> */
4949
public array $operations = [];
5050

5151
/**

src/OpenApi/ClassGenerator.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,14 @@ public function generate(OpenApi $openApi, array $config): array
123123
$pathCollection = $openApi->paths->getPath(sprintf('/%s', $collectionResourceName));
124124
$listOperation = $pathCollection->get ?? null;
125125
$createOperation = $pathCollection->post ?? null;
126-
$class->operations = [
127-
'item' => array_merge(
128-
$showOperation ? ['get' => null] : [],
129-
$putOperation ? ['put' => null] : [],
130-
$patchOperation ? ['patch' => null] : [],
131-
$deleteOperation ? ['delete' => null] : [],
132-
),
133-
'collection' => array_merge(
134-
$listOperation ? ['get' => null] : [],
135-
$createOperation ? ['post' => null] : [],
136-
),
137-
];
126+
$class->operations = array_merge(
127+
$showOperation ? ['Get' => null] : [],
128+
$putOperation ? ['Put' => null] : [],
129+
$patchOperation ? ['Patch' => null] : [],
130+
$deleteOperation ? ['Delete' => null] : [],
131+
$listOperation ? ['GetCollection' => null] : [],
132+
$createOperation ? ['Post' => null] : [],
133+
);
138134

139135
$classes[$name] = $class;
140136
}

src/SchemaGeneratorConfiguration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public function getConfigTreeBuilder(): TreeBuilder
102102
->scalarPrototype()->end()
103103
->end()
104104
->booleanNode('debug')->defaultFalse()->info('Debug mode')->end()
105+
->booleanNode('apiPlatformOldAttributes')->defaultFalse()->info('Use old API Platform attributes (API Platform < 2.7)')->end()
105106
->arrayNode('id')
106107
->addDefaultsIfNotSet()
107108
->info('IDs configuration')

src/TypesGenerator.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,9 @@ private function defineTypesToGenerate(array $graphs, array $config): array
459459
}
460460

461461
foreach ($config['types'] as $typeName => $typeConfig) {
462+
if ($typeConfig['exclude']) {
463+
continue;
464+
}
462465
$vocabularyNamespace = $typeConfig['vocabularyNamespace'] ?? $config['vocabularyNamespace'];
463466

464467
$resource = null;

0 commit comments

Comments
 (0)