Skip to content

Commit

Permalink
[Php80] Add DoctrineCoverterterAttributeDecorator to convert "false"/…
Browse files Browse the repository at this point in the history
…"true" string to false/true on nullable arg on Doctrine\ORM\Mapping\Column (#5629)

* [Php80] Add DoctrineCoverterterAttributeDecorator to convert "false"/"true" string to false/true on nullable arg on Doctrine\ORM\Mapping\Column

* [ci-review] Rector Rectify

* [ci-review] Rector Rectify

---------

Co-authored-by: GitHub Action <actions@github.com>
  • Loading branch information
samsonasik and actions-user committed Feb 17, 2024
1 parent 2ccf2de commit a533e70
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 7 deletions.
@@ -0,0 +1,33 @@
<?php

namespace Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Fixture\Doctrine;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity(repositoryClass="App\Some\Class")
*/
class NullableBoolValue
{
/**
* @ORM\Column(type="bigint", nullable="true")
*/
private int $stop_ts;
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\Class_\AnnotationToAttributeRector\Fixture\Doctrine;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: \App\Some\Class::class)]
class NullableBoolValue
{
#[ORM\Column(type: 'bigint', nullable: true)]
private int $stop_ts;
}

?>
Expand Up @@ -29,6 +29,7 @@
// doctrine
new AnnotationToAttribute('Doctrine\ORM\Mapping\Entity', null, ['repositoryClass']),
new AnnotationToAttribute('Doctrine\ORM\Mapping\DiscriminatorMap'),
new AnnotationToAttribute('Doctrine\ORM\Mapping\Column'),

// validation
new AnnotationToAttribute('Symfony\Component\Validator\Constraints\Choice'),
Expand Down
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Rector\Php80\AttributeDecorator;

use PhpParser\Node\Attribute;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use Rector\Php80\Contract\ConverterAttributeDecoratorInterface;

final class DoctrineCoverterterAttributeDecorator implements ConverterAttributeDecoratorInterface
{
public function getAttributeName(): string
{
return 'Doctrine\ORM\Mapping\Column';
}

public function decorate(Attribute $attribute): void
{
foreach ($attribute->args as $arg) {
if (! $arg->name instanceof Identifier) {
continue;
}

if ($arg->name->toString() !== 'nullable') {
continue;
}

$value = $arg->value;
if (! $value instanceof String_) {
continue;
}

if (! in_array($value->value, ['true', 'false'], true)) {
continue;
}

$arg->value = $value->value === 'true' ? new ConstFetch(new Name('true')) : new ConstFetch(new Name('false'));
break;
}
}
}
Expand Up @@ -5,8 +5,9 @@
namespace Rector\Php80\AttributeDecorator;

use PhpParser\Node\Attribute;
use Rector\Php80\Contract\ConverterAttributeDecoratorInterface;

final class SensioParamConverterAttributeDecorator
final class SensioParamConverterAttributeDecorator implements ConverterAttributeDecoratorInterface
{
public function getAttributeName(): string
{
Expand Down
14 changes: 14 additions & 0 deletions rules/Php80/Contract/ConverterAttributeDecoratorInterface.php
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Rector\Php80\Contract;

use PhpParser\Node\Attribute;

interface ConverterAttributeDecoratorInterface
{
public function getAttributeName(): string;

public function decorate(Attribute $attribute): void;
}
Expand Up @@ -6,12 +6,15 @@

use PhpParser\Node\AttributeGroup;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\AttributeDecorator\SensioParamConverterAttributeDecorator;
use Rector\Php80\Contract\ConverterAttributeDecoratorInterface;

final readonly class AttributeGroupNamedArgumentManipulator
{
/**
* @param ConverterAttributeDecoratorInterface[] $converterAttributeDecorators
*/
public function __construct(
private SensioParamConverterAttributeDecorator $sensioParamConverterAttributeDecorator
private array $converterAttributeDecorators
) {
}

Expand All @@ -24,11 +27,13 @@ public function decorate(array $attributeGroups): void
foreach ($attributeGroup->attrs as $attr) {
$phpAttributeName = $attr->name->getAttribute(AttributeKey::PHP_ATTRIBUTE_NAME);

if ($this->sensioParamConverterAttributeDecorator->getAttributeName() !== $phpAttributeName) {
continue;
}
foreach ($this->converterAttributeDecorators as $converterAttributeDecorator) {
if ($converterAttributeDecorator->getAttributeName() !== $phpAttributeName) {
continue;
}

$this->sensioParamConverterAttributeDecorator->decorate($attr);
$converterAttributeDecorator->decorate($attr);
}
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions src/DependencyInjection/LazyContainerFactory.php
Expand Up @@ -101,6 +101,10 @@
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\StmtKeyNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
use Rector\Php80\AttributeDecorator\DoctrineCoverterterAttributeDecorator;
use Rector\Php80\AttributeDecorator\SensioParamConverterAttributeDecorator;
use Rector\Php80\Contract\ConverterAttributeDecoratorInterface;
use Rector\Php80\NodeManipulator\AttributeGroupNamedArgumentManipulator;
use Rector\PhpAttribute\AnnotationToAttributeMapper;
use Rector\PhpAttribute\AnnotationToAttributeMapper\ArrayAnnotationToAttributeMapper;
use Rector\PhpAttribute\AnnotationToAttributeMapper\ArrayItemNodeAnnotationToAttributeMapper;
Expand Down Expand Up @@ -365,6 +369,14 @@ final class LazyContainerFactory
*/
private const SKIP_VOTER_CLASSES = [ClassSkipVoter::class];

/**
* @var array<class-string<ConverterAttributeDecoratorInterface>>
*/
private const CONVERTER_ATTRIBUTE_DECORATOR_CLASSES = [
SensioParamConverterAttributeDecorator::class,
DoctrineCoverterterAttributeDecorator::class,
];

/**
* @api used as next rectorConfig factory
*/
Expand Down Expand Up @@ -506,6 +518,12 @@ static function (

$this->registerTagged($rectorConfig, self::SKIP_VOTER_CLASSES, SkipVoterInterface::class);

$rectorConfig->when(AttributeGroupNamedArgumentManipulator::class)
->needs('$converterAttributeDecorators')
->giveTagged(ConverterAttributeDecoratorInterface::class);

$this->registerTagged($rectorConfig, self::CONVERTER_ATTRIBUTE_DECORATOR_CLASSES, ConverterAttributeDecoratorInterface::class);

$rectorConfig->afterResolving(
AbstractRector::class,
static function (AbstractRector $rector, Container $container): void {
Expand Down

0 comments on commit a533e70

Please sign in to comment.