Open BusterNeece opened 2 years ago
It does not handle nested attributes for now
I figured out how to handle nested attributes
/**
* @OA\Get(
* path="/departments",
* summary="summary",
* tags={"sit"},
- * @OA\Response(
+ * responses={@OA\Response(
* response=200,
* description="desc",
- * @OA\JsonContent(
+ * content=@OA\JsonContent(
* type="array",
* @OA\Items(ref="#/components/schemas/refff")
* ),
- * )
+ * )}
* )
*/
Thanks for the script @SlvrEagle23! However the ContainerConfigurator is deprecated and does not work that well with the new rector versions anymore.
I have refactored the script to work with the newer rector versions https://gist.github.com/LVoogd/34078de7144663db5ab2067977516130
Beware of the sets loaded on line 54, if you don't want to update other annotations please disable these.
Thanks for the script @SlvrEagle23! However the ContainerConfigurator is deprecated and does not work that well with the new rector versions anymore.
I have refactored the script to work with the newer rector versions https://gist.github.com/LVoogd/34078de7144663db5ab2067977516130
Beware of the sets loaded on line 54, if you don't want to update other annotations please disable these.
i'm not able to make your script work, it does nothing when running rector. It shows 100%, then Rector is done, but nothing changed
i'm not able to make your script work, it does nothing when running rector. It shows 100%, then Rector is done, but nothing changed
Hi @momala454,
Make sure you use the latest version of Rector (I used 0.13.5).
If that does not work maybe your notation is a bit different and therefore the script does not pick it up correctly. I did recall having to manually update some schema entities, presumably because of some special case this script does not understand. As @SlvrEagle23 stated, its a crude script and should be perceived as a good starting point. You may need to make alterations to make it work for your specific case.
Good luck!
@LVoogd i'm on 0.13.6. Thanks for the response and script. Do i need to run it on the whole project folder (including vendor folder and src folder, or do I run it on src folder ? running on whole project including vendor is super slow and generate a timeout
edit: this dummy annoation is not detected/replaced
/**
* @OA\Get(
* path="/hello",
* responses={@OA\Response(response= 200, description="")}
* )
*/
@LVoogd even trying to fix only rector.php doesn't work, it does nothing
<?php
use Rector\Doctrine\Set\DoctrineSetList;
use Rector\Symfony\Set\SymfonySetList;
use Rector\Symfony\Set\SensiolabsSetList;
use Rector\Nette\Set\NetteSetList;
use Rector\Config\RectorConfig;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Php80\ValueObject\AnnotationToAttribute;
/**
* @OpenApi\Annotations\Get(
* path="/hello"
* )
*/
return function (RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(AnnotationToAttributeRector::class, [
new AnnotationToAttribute('OpenApi\\Annotations\\AdditionalProperties', 'OpenApi\\Attributes\\AdditionalProperties'),
new AnnotationToAttribute('OpenApi\\Annotations\\Attachable', 'OpenApi\\Attributes\\Attachable'),
new AnnotationToAttribute('OpenApi\\Annotations\\Components', 'OpenApi\\Attributes\\Components'),
new AnnotationToAttribute('OpenApi\\Annotations\\Contact', 'OpenApi\\Attributes\\Contact'),
new AnnotationToAttribute('OpenApi\\Annotations\\Delete', 'OpenApi\\Attributes\\Delete'),
new AnnotationToAttribute('OpenApi\\Annotations\\Discriminator', 'OpenApi\\Attributes\\Discriminator'),
new AnnotationToAttribute('OpenApi\\Annotations\\Examples', 'OpenApi\\Attributes\\Examples'),
new AnnotationToAttribute('OpenApi\\Annotations\\ExternalDocumentation', 'OpenApi\\Attributes\\ExternalDocumentation'),
new AnnotationToAttribute('OpenApi\\Annotations\\Flow', 'OpenApi\\Attributes\\Flow'),
new AnnotationToAttribute('OpenApi\\Annotations\\Get', 'OpenApi\\Attributes\\Get'),
new AnnotationToAttribute('OpenApi\\Annotations\\Head', 'OpenApi\\Attributes\\Head'),
new AnnotationToAttribute('OpenApi\\Annotations\\Header', 'OpenApi\\Attributes\\Header'),
new AnnotationToAttribute('OpenApi\\Annotations\\Info', 'OpenApi\\Attributes\\Info'),
new AnnotationToAttribute('OpenApi\\Annotations\\Items', 'OpenApi\\Attributes\\Items'),
new AnnotationToAttribute('OpenApi\\Annotations\\JsonContent', 'OpenApi\\Attributes\\JsonContent'),
new AnnotationToAttribute('OpenApi\\Annotations\\License', 'OpenApi\\Attributes\\License'),
new AnnotationToAttribute('OpenApi\\Annotations\\Link', 'OpenApi\\Attributes\\Link'),
new AnnotationToAttribute('OpenApi\\Annotations\\MediaType', 'OpenApi\\Attributes\\MediaType'),
new AnnotationToAttribute('OpenApi\\Annotations\\OpenApi', 'OpenApi\\Attributes\\OpenApi'),
new AnnotationToAttribute('OpenApi\\Annotations\\Operation', 'OpenApi\\Attributes\\Operation'),
new AnnotationToAttribute('OpenApi\\Annotations\\Options', 'OpenApi\\Attributes\\Options'),
new AnnotationToAttribute('OpenApi\\Annotations\\Parameter', 'OpenApi\\Attributes\\Parameter'),
new AnnotationToAttribute('OpenApi\\Annotations\\Patch', 'OpenApi\\Attributes\\Patch'),
new AnnotationToAttribute('OpenApi\\Annotations\\PatchItem', 'OpenApi\\Attributes\\PatchItem'),
new AnnotationToAttribute('OpenApi\\Annotations\\PathParameter', 'OpenApi\\Attributes\\PathParameter'),
new AnnotationToAttribute('OpenApi\\Annotations\\Post', 'OpenApi\\Attributes\\Post'),
new AnnotationToAttribute('OpenApi\\Annotations\\Property', 'OpenApi\\Attributes\\Property'),
new AnnotationToAttribute('OpenApi\\Annotations\\Put', 'OpenApi\\Attributes\\Put'),
new AnnotationToAttribute('OpenApi\\Annotations\\RequestBody', 'OpenApi\\Attributes\\RequestBody'),
new AnnotationToAttribute('OpenApi\\Annotations\\Response', 'OpenApi\\Attributes\\Response'),
new AnnotationToAttribute('OpenApi\\Annotations\\Schema', 'OpenApi\\Attributes\\Schema'),
new AnnotationToAttribute('OpenApi\\Annotations\\SecurityScheme', 'OpenApi\\Attributes\\SecurityScheme'),
new AnnotationToAttribute('OpenApi\\Annotations\\Server', 'OpenApi\\Attributes\\Server'),
new AnnotationToAttribute('OpenApi\\Annotations\\ServerVariable', 'OpenApi\\Attributes\\ServerVariable'),
new AnnotationToAttribute('OpenApi\\Annotations\\Tag', 'OpenApi\\Attributes\\Tag'),
new AnnotationToAttribute('OpenApi\\Annotations\\Trace', 'OpenApi\\Attributes\\Trace'),
new AnnotationToAttribute('OpenApi\\Annotations\\Xml', 'OpenApi\\Attributes\\Xml'),
new AnnotationToAttribute('OpenApi\\Annotations\\XmlContent', 'OpenApi\\Attributes\\XmlContent'),
]);
};
php vendor/bin/rector process rector.php --dry-run --config rector.php -vvv
rector.php
[OK] Rector is done!
Hi @momala454
I have tested your example as follows
# test.php
<?php
class test {
/**
* @OpenApi\Annotations\Get(
* path="/hello"
* )
*/
public function get()
{
}
}
output:
php vendor/bin/rector process test.php --dry-run --config rector.php -vvv
test.php
[file] test.php
[rule] Rector\Php80\Rector\Class_\AnnotationToAttributeRector
[file] test.php
[rule] Rector\Php80\Rector\Class_\AnnotationToAttributeRector
[file] test.php
[rule] Rector\Php80\Rector\Class_\AnnotationToAttributeRector
1 file with changes
===================
1) test.php:1
---------- begin diff ----------
@@ @@
class test {
- /**
- * @OpenApi\Annotations\Get(
- * path="/hello"
- * )
- */
+ #[\OpenApi\Attributes\Get(path: '/hello')]
public function get()
{
-
}
}
----------- end diff -----------
Applied rules:
* AnnotationToAttributeRector (https://wiki.php.net/rfc/attributes_v2)
[OK] 1 file would have changed (dry-run) by Rector
I believe this to be the desired outcome.
using your test.php file it gives me the same result as before for me, no changes at all.
What contains your rector.php ?
php vendor/bin/rector process test.php --dry-run --config rector.php -vvv
[OK] Rector is done!
php vendor/bin/rector --version
Rector 0.13.6
@LVoogd which is your openapi library ? i'm using "zircote/swagger-php"
@LVoogd i finally was able to make it work, however it doesn't detect usage that doesnt contains the parameter name. Like mentioned here : https://github.com/zircote/swagger-php/issues/1047#issuecomment-1045965367
on the "before" of the diff
It also put everything in the same line, rendering it unreadable. Is there a parameter to put one parameter per line ?
Example
<?php
class test {
/**
* @OpenApi\Annotations\Post(
* path="/hello",
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* @OA\Property(
* property="name",
* type="string",
* description="name",
* example="My name"
* ),
* required={"name"}
* )
* )
* ),
* )
*/
public function post()
{
}
}
is converted to
<?php
class test {
#[\OpenApi\Attributes\Post(path: '/hello', new OA\RequestBody(new OA\MediaType(mediaType: 'application/json', new OA\Schema(new OA\Property(property: 'name', type: 'string', description: 'name', example: 'My name'), required: ['name']))))]
public function post()
{
}
}
but it doesn't work because "Cannot use positional argument after named argument" the "new OA\RequestBody" is not preceded by "requestBody:" Is there any automated way to replace this ? It's not the only example, i've also "schema", "mediatype" and "responses" not using named parameters.
like two @OA\Response() one after the other, so i can't do like a search/replace
Thanks @LVoogd any everyone else, these rules saved me a huge amount of time đź‘Ť
Some minor issues, which could easily be solved by adding some named parameters (those were missing in tiny percent of all migrated attributes). But all in all, this was copy & paste and done 🎉
@momala454 I'm having the exact same issue. Have you came up with a solution to address the named parameters? Is it even possible?
@reksc my "solution" was a whole lot of manual replacement
I wrote a rector rule to convert annotations to attributes: https://github.com/wenbinye/openapi-rector
The only problem is that rector cannot indent code pretty.
Thank you @momala454 You saved me countless hours !
I used a modified version of (https://github.com/zircote/swagger-php/issues/1047#issuecomment-1174858414):
<?php
use Rector\Config\RectorConfig;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Php80\ValueObject\AnnotationToAttribute;
/**
* @OA\Get(
* path="/hello"
* )
*/
return function (RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(AnnotationToAttributeRector::class, [
new AnnotationToAttribute('OA\\AdditionalProperties', 'OpenApi\\Attributes\\AdditionalProperties'),
new AnnotationToAttribute('OA\\Attachable', 'OpenApi\\Attributes\\Attachable'),
new AnnotationToAttribute('OA\\Components', 'OpenApi\\Attributes\\Components'),
new AnnotationToAttribute('OA\\Contact', 'OpenApi\\Attributes\\Contact'),
new AnnotationToAttribute('OA\\Delete', 'OpenApi\\Attributes\\Delete'),
new AnnotationToAttribute('OA\\Discriminator', 'OpenApi\\Attributes\\Discriminator'),
new AnnotationToAttribute('OA\\Examples', 'OpenApi\\Attributes\\Examples'),
new AnnotationToAttribute('OA\\ExternalDocumentation', 'OpenApi\\Attributes\\ExternalDocumentation'),
new AnnotationToAttribute('OA\\Flow', 'OpenApi\\Attributes\\Flow'),
new AnnotationToAttribute('OA\\Get', 'OpenApi\\Attributes\\Get'),
new AnnotationToAttribute('OA\\Head', 'OpenApi\\Attributes\\Head'),
new AnnotationToAttribute('OA\\Header', 'OpenApi\\Attributes\\Header'),
new AnnotationToAttribute('OA\\Info', 'OpenApi\\Attributes\\Info'),
new AnnotationToAttribute('OA\\Items', 'OpenApi\\Attributes\\Items'),
new AnnotationToAttribute('OA\\JsonContent', 'OpenApi\\Attributes\\JsonContent'),
new AnnotationToAttribute('OA\\License', 'OpenApi\\Attributes\\License'),
new AnnotationToAttribute('OA\\Link', 'OpenApi\\Attributes\\Link'),
new AnnotationToAttribute('OA\\MediaType', 'OpenApi\\Attributes\\MediaType'),
new AnnotationToAttribute('OA\\OpenApi', 'OpenApi\\Attributes\\OpenApi'),
new AnnotationToAttribute('OA\\Operation', 'OpenApi\\Attributes\\Operation'),
new AnnotationToAttribute('OA\\Options', 'OpenApi\\Attributes\\Options'),
new AnnotationToAttribute('OA\\Parameter', 'OpenApi\\Attributes\\Parameter'),
new AnnotationToAttribute('OA\\Patch', 'OpenApi\\Attributes\\Patch'),
new AnnotationToAttribute('OA\\PatchItem', 'OpenApi\\Attributes\\PatchItem'),
new AnnotationToAttribute('OA\\PathParameter', 'OpenApi\\Attributes\\PathParameter'),
new AnnotationToAttribute('OA\\Post', 'OpenApi\\Attributes\\Post'),
new AnnotationToAttribute('OA\\Property', 'OpenApi\\Attributes\\Property'),
new AnnotationToAttribute('OA\\Put', 'OpenApi\\Attributes\\Put'),
new AnnotationToAttribute('OA\\RequestBody', 'OpenApi\\Attributes\\RequestBody'),
new AnnotationToAttribute('OA\\Response', 'OpenApi\\Attributes\\Response'),
new AnnotationToAttribute('OA\\Schema', 'OpenApi\\Attributes\\Schema'),
new AnnotationToAttribute('OA\\SecurityScheme', 'OpenApi\\Attributes\\SecurityScheme'),
new AnnotationToAttribute('OA\\Server', 'OpenApi\\Attributes\\Server'),
new AnnotationToAttribute('OA\\ServerVariable', 'OpenApi\\Attributes\\ServerVariable'),
new AnnotationToAttribute('OA\\Tag', 'OpenApi\\Attributes\\Tag'),
new AnnotationToAttribute('OA\\Trace', 'OpenApi\\Attributes\\Trace'),
new AnnotationToAttribute('OA\\Xml', 'OpenApi\\Attributes\\Xml'),
new AnnotationToAttribute('OA\\XmlContent', 'OpenApi\\Attributes\\XmlContent'),
]);
};
Because my annotations where written with the short syntax.
Then I used quite a lot of vscode regex replace feature on all files, since some where quite screwed up after the migration. A lot of syntax fixed later the spec was back and running.
I wrote a rector rule to convert annotations to attributes: https://github.com/wenbinye/openapi-rector
It does not work at all, no files where changed. Seems like it was not designed for Laravel or more diverse projects.
I figured out how to handle nested attributes
/** * @OA\Get( * path="/departments", * summary="summary", * tags={"sit"}, - * @OA\Response( + * responses={@OA\Response( * response=200, * description="desc", - * @OA\JsonContent( + * content=@OA\JsonContent( * type="array", * @OA\Items(ref="#/components/schemas/refff") * ), - * ) + * )} * ) */
Note: while the @OA\Response
change is working for the Rector script provided here and for regular swagger-php
usage (before trying any migration), the @OA\JsonContent
change doesn’t seem to be accepted by swagger-php
. So if you want to incrementally adapt your annotations before doing the migration, you’ll have to skip the OA\JsonContent
ones, and possibly more.
For me it works great
#[\OpenApi\Attributes\Response(response: 200, description: 'OK', content: new \OpenApi\Attributes\JsonContent(ref: '#/components/schemas/FooBarBaz'))]
@williamdes I know the migration works ok. But I wanted to delay the migration and just incrementally commit and deploy compatible changes to prepare for the migration in a simple and safe way. The JsonContent change isn't compatible so I can't apply this technique.
@williamdes I know the migration works ok. But I wanted to delay the migration and just incrementally commit and deploy compatible changes to prepare for the migration in a simple and safe way. The JsonContent change isn't compatible so I can't apply this technique.
Oh okay, I get it now Indeed adding "responses" and stuff would have made the migration smoother
And i will move from attributes back to annotations, because its clear to read in Editor
And i will move from attributes back to annotations, because its clear to read in Editor
If it’s for your personal projects, sure go ahead. If you’re working on code with other contributes or for a client/company I would advise against it.
Since a lot of projects haven’t switched to annotations we’re still quite accustomed to them. However, these projects will become fewer over time and there will be a time that new developers have never used annotations. I can also see packages dropping support for annotations in the future.
Bottom line, using annotations now can be costly in the future. You might be forced into using attributes by a package or you need to teach fresher developers this “legacy thing” that you think looks beter in the IDE.
Yea, i stay actually on Attributes, but look this. Looks not so fine, what can we do here?
You can nest attributes but then you have to use new 🤷
Hello! Thanks for providing some light to this issue, it's going to take so many hours to manually migrate from annotations to attributes. I seem to have problems using the snippets you guys provided.
I tried running rector (v1.0.1 released just a couple days ago) adapting rector.php
with the configured rules you suggest. It works fine for most annotations, however the @OA\Response
annotation with a @OA\JsonContent
seems to create an issue, and I get '__remove_array__'
in the place of the model.
For instance, the following annotation
* @OA\Response(
* response=200,
* description="Returns all books",
* @OA\JsonContent(ref=@Model(type=BookListOutputModel::class))
* )
becomes
#[OA\Response(response: 200, description: 'Returns all books', '__remove_array__')]
Here is what my rector.php
looks like:
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Doctrine\Set\DoctrineSetList;
use Rector\Symfony\Set\SymfonySetList;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Php80\ValueObject\AnnotationToAttribute;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/config',
__DIR__ . '/public',
__DIR__ . '/src',
])
->withConfiguredRule(AnnotationToAttributeRector::class, [
new AnnotationToAttribute('OpenApi\\Annotations\\AdditionalProperties', 'OpenApi\\Attributes\\AdditionalProperties'),
new AnnotationToAttribute('OpenApi\\Annotations\\Attachable', 'OpenApi\\Attributes\\Attachable'),
new AnnotationToAttribute('OpenApi\\Annotations\\Components', 'OpenApi\\Attributes\\Components'),
new AnnotationToAttribute('OpenApi\\Annotations\\Contact', 'OpenApi\\Attributes\\Contact'),
new AnnotationToAttribute('OpenApi\\Annotations\\Delete', 'OpenApi\\Attributes\\Delete'),
new AnnotationToAttribute('OpenApi\\Annotations\\Discriminator', 'OpenApi\\Attributes\\Discriminator'),
new AnnotationToAttribute('OpenApi\\Annotations\\Examples', 'OpenApi\\Attributes\\Examples'),
new AnnotationToAttribute('OpenApi\\Annotations\\ExternalDocumentation', 'OpenApi\\Attributes\\ExternalDocumentation'),
new AnnotationToAttribute('OpenApi\\Annotations\\Flow', 'OpenApi\\Attributes\\Flow'),
new AnnotationToAttribute('OpenApi\\Annotations\\Get', 'OpenApi\\Attributes\\Get'),
new AnnotationToAttribute('OpenApi\\Annotations\\Head', 'OpenApi\\Attributes\\Head'),
new AnnotationToAttribute('OpenApi\\Annotations\\Header', 'OpenApi\\Attributes\\Header'),
new AnnotationToAttribute('OpenApi\\Annotations\\Info', 'OpenApi\\Attributes\\Info'),
new AnnotationToAttribute('OpenApi\\Annotations\\Items', 'OpenApi\\Attributes\\Items'),
new AnnotationToAttribute('OpenApi\\Annotations\\JsonContent', 'OpenApi\\Attributes\\JsonContent'),
new AnnotationToAttribute('OpenApi\\Annotations\\License', 'OpenApi\\Attributes\\License'),
new AnnotationToAttribute('OpenApi\\Annotations\\Link', 'OpenApi\\Attributes\\Link'),
new AnnotationToAttribute('OpenApi\\Annotations\\MediaType', 'OpenApi\\Attributes\\MediaType'),
new AnnotationToAttribute('OpenApi\\Annotations\\OpenApi', 'OpenApi\\Attributes\\OpenApi'),
new AnnotationToAttribute('OpenApi\\Annotations\\Operation', 'OpenApi\\Attributes\\Operation'),
new AnnotationToAttribute('OpenApi\\Annotations\\Options', 'OpenApi\\Attributes\\Options'),
new AnnotationToAttribute('OpenApi\\Annotations\\Parameter', 'OpenApi\\Attributes\\Parameter'),
new AnnotationToAttribute('OpenApi\\Annotations\\Patch', 'OpenApi\\Attributes\\Patch'),
new AnnotationToAttribute('OpenApi\\Annotations\\PatchItem', 'OpenApi\\Attributes\\PatchItem'),
new AnnotationToAttribute('OpenApi\\Annotations\\PathParameter', 'OpenApi\\Attributes\\PathParameter'),
new AnnotationToAttribute('OpenApi\\Annotations\\Post', 'OpenApi\\Attributes\\Post'),
new AnnotationToAttribute('OpenApi\\Annotations\\Property', 'OpenApi\\Attributes\\Property'),
new AnnotationToAttribute('OpenApi\\Annotations\\Put', 'OpenApi\\Attributes\\Put'),
new AnnotationToAttribute('OpenApi\\Annotations\\RequestBody', 'OpenApi\\Attributes\\RequestBody'),
new AnnotationToAttribute('OpenApi\\Annotations\\Response', 'OpenApi\\Attributes\\Response'),
new AnnotationToAttribute('OpenApi\\Annotations\\Schema', 'OpenApi\\Attributes\\Schema'),
new AnnotationToAttribute('OpenApi\\Annotations\\SecurityScheme', 'OpenApi\\Attributes\\SecurityScheme'),
new AnnotationToAttribute('OpenApi\\Annotations\\Server', 'OpenApi\\Attributes\\Server'),
new AnnotationToAttribute('OpenApi\\Annotations\\ServerVariable', 'OpenApi\\Attributes\\ServerVariable'),
new AnnotationToAttribute('OpenApi\\Annotations\\Tag', 'OpenApi\\Attributes\\Tag'),
new AnnotationToAttribute('OpenApi\\Annotations\\Trace', 'OpenApi\\Attributes\\Trace'),
new AnnotationToAttribute('OpenApi\\Annotations\\Xml', 'OpenApi\\Attributes\\Xml'),
new AnnotationToAttribute('OpenApi\\Annotations\\XmlContent', 'OpenApi\\Attributes\\XmlContent'),
])
->withSets([
DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES,
]);
Any idea on how can I fix this? Is there a better tool or new version of the snippet that can help?
Thank you!
Maybe ask rector support directly or Stackoverflow? Let us know
I had to use vscode regexes, it was not easy to fix the result
Thanks @williamdes, I've posted this as a question on Stackoverflow and will come back here if I get any useful insights.
Perhaps someone will find it useful. A bit of dirty code. If anyone is interested, I can put it all together into a rule.
To be able to translate such code
/**
* @OA\Schema(
* path="/api/data.json",
* @OA\Property(
* response="200",
* description="The data"
* )
* )
*/
To
#[OA\Schema(path: '/api/data.json')]
#[OA\Property(response: '200', description: 'The data')]
Using a rule in Rector that will look something like this
$rectorConfig->ruleWithConfiguration(NestedAnnotationToAttributeRector::class, [
new NestedAnnotationToAttribute('OA\Schema', [
new AnnotationToAttribute('OA\Property', 'OA\Property'),
]),
]
You'll need to patch a couple of files on the machine where you'll be running Rector.
Before proceeding, ensure that the files you're patching are of the same version. Usually, in local projects, versions are fixed and, as a result, not up-to-date with the latest versions of Rector and its rules. It's better to check the differences to see what will change for you.
Replace on line
if ($attributeClass instanceof AnnotationPropertyToAttributeClass) {
to
if ($attributeClass instanceof AnnotationPropertyToAttributeClass || $attributeClass instanceof AnnotationToAttribute) {
After this line add
if ($annotationPropertyToAttributeClass instanceof AnnotationToAttribute) {
continue;
}
<?php
declare(strict_types=1);
namespace Rector\Php80\ValueObject;
use Rector\Php80\Contract\ValueObject\AnnotationToAttributeInterface;
use Rector\Validation\RectorAssert;
final class NestedAnnotationToAttribute implements AnnotationToAttributeInterface
{
/**
* @var AnnotationPropertyToAttributeClass[]|AnnotationToAttribute[]
*/
private array $annotationPropertiesToAttributeClasses = [];
/**
* @param array<string, string>|string[]|AnnotationPropertyToAttributeClass[]|AnnotationToAttribute[] $annotationPropertiesToAttributeClasses
*/
public function __construct(
private readonly string $tag,
array $annotationPropertiesToAttributeClasses,
private readonly bool $removeOriginal = false,
) {
RectorAssert::className($tag);
// back compatibility for raw scalar values
foreach ($annotationPropertiesToAttributeClasses as $annotationProperty => $attributeClass) {
if ($attributeClass instanceof AnnotationPropertyToAttributeClass || $attributeClass instanceof AnnotationToAttribute) {
$this->annotationPropertiesToAttributeClasses[] = $attributeClass;
} else {
$this->annotationPropertiesToAttributeClasses[] = new AnnotationPropertyToAttributeClass(
$attributeClass,
$annotationProperty,
);
}
}
}
public function getTag(): string
{
return $this->tag;
}
/**
* @return AnnotationPropertyToAttributeClass[]|AnnotationToAttribute[]
*/
public function getAnnotationPropertiesToAttributeClasses(): array
{
return $this->annotationPropertiesToAttributeClasses;
}
public function getAttributeClass(): string
{
return $this->tag;
}
public function shouldRemoveOriginal(): bool
{
return $this->removeOriginal;
}
public function hasExplicitParameters(): bool
{
foreach ($this->annotationPropertiesToAttributeClasses as $annotationPropertyToAttributeClass) {
if ($annotationPropertyToAttributeClass instanceof AnnotationToAttribute) {
continue;
}
if (is_string($annotationPropertyToAttributeClass->getAnnotationProperty())) {
return true;
}
}
return false;
}
}
What's needed here is nesting, specifically the ability to automatically wrap @OA\Property(
in properties: []
. But I regret the time lost and the fact that I discovered this requirement late. Therefore, it would be great if my efforts could save time for someone else.
This isn't a bug report, but rather a helpful tool that might save folks moving from annotations to attributes a lot of time.
Rector has a tool that can automatically migrate annotations to attributes, so long as you provide the class mapping for it.
Here's a sample script I set up that (crudely) does the migration from annotations to attributes:
https://gist.github.com/BusterNeece/230f1bf619740b0564b88a69978de82c
It's not perfect, but it gets you to a really good starting point and takes care of a task that is extremely boring to do otherwise.
Edit: See below for a link to a repo that does this in an improved manner!