Skip to content

Commit d876e66

Browse files
committed
fix: upgrade subresource with resource (#4747)
1 parent 1483306 commit d876e66

File tree

2 files changed

+72
-99
lines changed

2 files changed

+72
-99
lines changed

src/Core/Bridge/Symfony/Bundle/Command/UpgradeApiResourceCommand.php

+59-98
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ final class UpgradeApiResourceCommand extends Command
4444
private $subresourceTransformer;
4545
private $reader;
4646
private $identifiersExtractor;
47-
private $localCache = [];
4847

4948
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, SubresourceOperationFactoryInterface $subresourceOperationFactory, SubresourceTransformer $subresourceTransformer, IdentifiersExtractorInterface $identifiersExtractor, AnnotationReader $reader = null)
5049
{
@@ -83,111 +82,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8382
return Command::INVALID;
8483
}
8584

86-
$this->transformApiSubresource($input, $output);
87-
$this->transformApiResource($input, $output);
85+
$subresources = $this->getSubresources();
8886

89-
return Command::SUCCESS;
90-
}
91-
92-
/**
93-
* This computes a local cache with resource classes having subresources.
94-
* We first loop over all the classes and re-map the metadata on the correct Resource class.
95-
* Then we transform the ApiSubresource to an ApiResource class.
96-
*/
97-
private function transformApiSubresource(InputInterface $input, OutputInterface $output): void
98-
{
99-
foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
100-
try {
101-
new \ReflectionClass($resourceClass);
102-
} catch (\Exception $e) {
103-
continue;
104-
}
105-
106-
if (!isset($this->localCache[$resourceClass])) {
107-
$this->localCache[$resourceClass] = [];
108-
}
109-
110-
foreach ($this->subresourceOperationFactory->create($resourceClass) as $subresourceMetadata) {
111-
if (!isset($this->localCache[$subresourceMetadata['resource_class']])) {
112-
$this->localCache[$subresourceMetadata['resource_class']] = [];
113-
}
114-
115-
foreach ($this->localCache[$subresourceMetadata['resource_class']] as $currentSubresourceMetadata) {
116-
if ($currentSubresourceMetadata['path'] === $subresourceMetadata['path']) {
117-
continue 2;
118-
}
119-
}
120-
$this->localCache[$subresourceMetadata['resource_class']][] = $subresourceMetadata;
121-
}
122-
}
123-
124-
// Compute URI variables
125-
foreach ($this->localCache as $class => $subresources) {
126-
if (!$subresources) {
127-
unset($this->localCache[$class]);
128-
continue;
129-
}
130-
131-
foreach ($subresources as $i => $subresourceMetadata) {
132-
$this->localCache[$class][$i]['uri_variables'] = $this->subresourceTransformer->toUriVariables($subresourceMetadata);
133-
}
134-
}
135-
136-
foreach ($this->localCache as $resourceClass => $linkedSubresourceMetadata) {
137-
$fileName = (new \ReflectionClass($resourceClass))->getFilename();
138-
139-
$referenceType = null;
140-
try {
141-
$metadata = $this->resourceMetadataFactory->create($resourceClass);
142-
$referenceType = $metadata->getAttribute('url_generation_strategy');
143-
} catch (\Exception $e) {
144-
}
145-
146-
foreach ($linkedSubresourceMetadata as $subresourceMetadata) {
147-
$lexer = new Emulative([
148-
'usedAttributes' => [
149-
'comments',
150-
'startLine', 'endLine',
151-
'startTokenPos', 'endTokenPos',
152-
],
153-
]);
154-
$parser = new Php7($lexer);
155-
156-
$traverser = new NodeTraverser();
157-
$traverser->addVisitor(new UpgradeApiSubresourceVisitor($subresourceMetadata, $referenceType));
158-
$prettyPrinter = new Standard();
159-
160-
$oldCode = file_get_contents($fileName);
161-
$oldStmts = $parser->parse($oldCode);
162-
$oldTokens = $lexer->getTokens();
163-
164-
$newStmts = $traverser->traverse($oldStmts);
165-
166-
$newCode = $prettyPrinter->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
167-
168-
if (!$input->getOption('force') && $input->getOption('dry-run')) {
169-
if ($input->getOption('silent')) {
170-
continue;
171-
}
172-
173-
$this->printDiff($oldCode, $newCode, $output);
174-
continue;
175-
}
176-
177-
file_put_contents($fileName, $newCode);
178-
}
179-
}
180-
}
181-
182-
private function transformApiResource(InputInterface $input, OutputInterface $output): void
183-
{
18487
$prettyPrinter = new Standard();
18588
foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
18689
try {
18790
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
18891
} catch (ResourceClassNotFoundException $e) {
18992
continue;
19093
}
94+
19195
$lexer = new Emulative([
19296
'usedAttributes' => [
19397
'comments',
@@ -209,6 +113,13 @@ private function transformApiResource(InputInterface $input, OutputInterface $ou
209113

210114
$traverser->addVisitor(new UpgradeApiResourceVisitor($attribute, $isAnnotation, $this->identifiersExtractor, $resourceClass));
211115

116+
if (isset($subresources[$resourceClass])) {
117+
$referenceType = $resourceMetadata->getAttribute('url_generation_strategy');
118+
foreach ($subresources[$resourceClass] as $subresourceMetadata) {
119+
$traverser->addVisitor(new UpgradeApiSubresourceVisitor($subresourceMetadata, $referenceType));
120+
}
121+
}
122+
212123
$oldCode = file_get_contents($fileName);
213124
$oldStmts = $parser->parse($oldCode);
214125
$oldTokens = $lexer->getTokens();
@@ -227,6 +138,56 @@ private function transformApiResource(InputInterface $input, OutputInterface $ou
227138

228139
file_put_contents($fileName, $newCode);
229140
}
141+
142+
return Command::SUCCESS;
143+
}
144+
145+
/**
146+
* This computes a local cache with resource classes having subresources.
147+
* We first loop over all the classes and re-map the metadata on the correct Resource class.
148+
* Then we transform the ApiSubresource to an ApiResource class.
149+
*/
150+
private function getSubresources(): array
151+
{
152+
$localCache = [];
153+
foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
154+
try {
155+
new \ReflectionClass($resourceClass);
156+
} catch (\Exception $e) {
157+
continue;
158+
}
159+
160+
if (!isset($localCache[$resourceClass])) {
161+
$localCache[$resourceClass] = [];
162+
}
163+
164+
foreach ($this->subresourceOperationFactory->create($resourceClass) as $subresourceMetadata) {
165+
if (!isset($localCache[$subresourceMetadata['resource_class']])) {
166+
$localCache[$subresourceMetadata['resource_class']] = [];
167+
}
168+
169+
foreach ($localCache[$subresourceMetadata['resource_class']] as $currentSubresourceMetadata) {
170+
if ($currentSubresourceMetadata['path'] === $subresourceMetadata['path']) {
171+
continue 2;
172+
}
173+
}
174+
$localCache[$subresourceMetadata['resource_class']][] = $subresourceMetadata;
175+
}
176+
}
177+
178+
// Compute URI variables
179+
foreach ($localCache as $class => $subresources) {
180+
if (!$subresources) {
181+
unset($localCache[$class]);
182+
continue;
183+
}
184+
185+
foreach ($subresources as $i => $subresourceMetadata) {
186+
$localCache[$class][$i]['uri_variables'] = $this->subresourceTransformer->toUriVariables($subresourceMetadata);
187+
}
188+
}
189+
190+
return $localCache;
230191
}
231192

232193
private function printDiff(string $oldCode, string $newCode, OutputInterface $output): void

src/Core/Upgrade/UpgradeApiSubresourceVisitor.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public function enterNode(Node $node)
4343
$operationToCreate = $this->subresourceMetadata['collection'] ? GetCollection::class : Get::class;
4444
$operationUseStatementNeeded = true;
4545
$apiResourceUseStatementNeeded = true;
46+
$linkUseStatementNeeded = true;
4647

4748
$comment = $node->getDocComment();
4849
if ($comment && preg_match('/@ApiSubresource/', $comment->getText())) {
@@ -65,6 +66,11 @@ public function enterNode(Node $node)
6566
continue;
6667
}
6768

69+
if (Link::class === $useStatement) {
70+
$linkUseStatementNeeded = false;
71+
continue;
72+
}
73+
6874
if ($useStatement === $operationToCreate) {
6975
$operationUseStatementNeeded = false;
7076
continue;
@@ -93,7 +99,13 @@ public function enterNode(Node $node)
9399
ApiResource::class
94100
)
95101
),
96-
]),
102+
])
103+
);
104+
}
105+
106+
if ($linkUseStatementNeeded) {
107+
array_unshift(
108+
$node->stmts,
97109
new Node\Stmt\Use_([
98110
new Node\Stmt\UseUse(
99111
new Node\Name(

0 commit comments

Comments
 (0)