Skip to content

Do not try to refresh attributes#6750

Merged
samsonasik merged 1 commit intorectorphp:mainfrom
lyrixx:refresh-attribute
Feb 21, 2025
Merged

Do not try to refresh attributes#6750
samsonasik merged 1 commit intorectorphp:mainfrom
lyrixx:refresh-attribute

Conversation

@lyrixx
Copy link
Copy Markdown
Contributor

@lyrixx lyrixx commented Feb 21, 2025

with the following code and test, it crashed

<?php

namespace App;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\HttpOperation;
use ApiPlatform\OpenApi\Model\Operation;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor;
use PhpParser\Node\Attribute;
use PhpParser\Node\Expr\New_;
use Rector\PhpParser\Node\Value\ValueResolver;
use Rector\Rector\AbstractRector;

final class ApipMigrateOpenApiRector extends AbstractRector
{
    public function __construct(
        private readonly ValueResolver $valueResolver,
    ) {
    }

    public function getNodeTypes(): array
    {
        return [New_::class, Attribute::class];
    }

    public function refactor(Node $node)
    {
        if ($node instanceof New_ && is_a($this->getName($node->class), HttpOperation::class, true)) {
            return $this->convert($node);
        }

        if ($node instanceof Attribute && ApiProperty::class === $this->getName($node->name)) {
            return $this->convert($node);
        }

        return null;
    }

    private function convert(Node $node): ?Node
    {
        $scope = $node->getAttribute('scope');
        $update = false;

        foreach ($node->args as $arg) {
            if ('openapiContext' !== $this->getName($arg)) {
                continue;
            }


            $arg->name->name = 'openapi';

            $argValue = $arg->value;


            if (!$argValue instanceof Node\Expr\Array_) {
                // It should be an array! If it's not, we can't do anything.
                continue;
            }
            $update = true;

            $openApiArgs = [];

            foreach ($argValue->items as $item) {
                $openApiArgs[] = $i = new Node\Arg(
                    $item->value,
                    name: new Node\Identifier($this->valueResolver->getValue($item->key)),
                );
                $i->setAttribute('multiline', true);
                // Should we copy the current scope ? 
                // $i->setAttribute('scope', $scope);
            }

            $arg->value = new New_(
                new Node\Name\FullyQualified(Operation::class),
                $openApiArgs,
                [
                    'scope' => $scope,
                ]
            );

            return $node;
        }
 
        return null;
    }
}
<?php

namespace AppBundle\Api\Dto\AuditLog;

use ApiPlatform\Metadata\ApiProperty;
use AppBundle\Entity\Organization as OrganizationEntity;
use Symfony\Component\Serializer\Attribute\Groups;

#[Groups('auditLog/read')]
class Organization
{
    public function __construct(
        public ?OrganizationEntity $organization,
        public string $organizationName,
        public bool $loginPasswordAllowed,
        public bool $twoFactorRequired,
        #[ApiProperty(openapiContext: [
            'type' => 'object',
            'properties' => [
                'allowed' => ['type' => 'boolean'],
                'providers' => ['type' => 'object', 'additionalProperties' => ['type' => 'boolean']],
            ],
        ])]
        public ?array $oAuthRestriction = null,
    ) {
    }
}
-----
<?php

namespace AppBundle\Api\Dto\AuditLog;

use ApiPlatform\OpenApi\Model\Operation;
use ApiPlatform\Metadata\ApiProperty;
use AppBundle\Entity\Organization as OrganizationEntity;
use Symfony\Component\Serializer\Attribute\Groups;

#[Groups('auditLog/read')]
class Organization
{
    public function __construct(
        public ?OrganizationEntity $organization,
        public string $organizationName,
        public bool $loginPasswordAllowed,
        public bool $twoFactorRequired,
        #[ApiProperty(openapi: new Operation(
            type: 'object',
            properties: [
                'allowed' => ['type' => 'boolean'],
                'providers' => ['type' => 'object', 'additionalProperties' => ['type' => 'boolean']],
            ],
        ))]
        public ?array $oAuthRestriction = null,
    ) {
    }
}

@samsonasik
Copy link
Copy Markdown
Member

Thank you, it is better to use the statement that the attribute belong instead of direct Attribute so you always got correct refresh scope, but this change is ok for me :)

@samsonasik samsonasik merged commit a8eabc6 into rectorphp:main Feb 21, 2025
44 checks passed
@lyrixx lyrixx deleted the refresh-attribute branch February 21, 2025 17:26
@github-actions
Copy link
Copy Markdown
Contributor

This pull request has been automatically locked because it has been closed for 150 days. Please open a new PR if you want to continue the work.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 14, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants