[DoctrineCodeQuality] Add few entity rules (#3972)

* [DoctrineCodeQuality] Add few entity rules

* [rector] [DoctrineCodeQuality] Add few entity rules

* [cs] [DoctrineCodeQuality] Add few entity rules

* [rector] [cs] [DoctrineCodeQuality] Add few entity rules

* [cs] [cs] [DoctrineCodeQuality] Add few entity rules

Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
Tomas Votruba 2020-08-16 14:39:59 +02:00 committed by GitHub
parent 003afc1435
commit c3eb9f6ada
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1842 additions and 4 deletions

View File

@ -1,4 +1,4 @@
# All 559 Rectors Overview
# All 564 Rectors Overview
- [Projects](#projects)
---
@ -14,7 +14,7 @@
- [Decomplex](#decomplex) (1)
- [Decouple](#decouple) (1)
- [Doctrine](#doctrine) (17)
- [DoctrineCodeQuality](#doctrinecodequality) (2)
- [DoctrineCodeQuality](#doctrinecodequality) (7)
- [DoctrineGedmoToKnplabs](#doctrinegedmotoknplabs) (7)
- [Downgrade](#downgrade) (1)
- [DynamicTypeAnalysis](#dynamictypeanalysis) (3)
@ -3949,6 +3949,62 @@ Change array to ArrayCollection in setParameters method of query builder
<br><br>
### `CorrectDatetimeEntityPropertyDefaultToConstructorRector`
- class: [`Rector\DoctrineCodeQuality\Rector\Class_\CorrectDatetimeEntityPropertyDefaultToConstructorRector`](/../master/rules/doctrine-code-quality/src/Rector/Class_/CorrectDatetimeEntityPropertyDefaultToConstructorRector.php)
- [test fixtures](/../master/rules/doctrine-code-quality/tests/Rector/Property/CorrectDatetimeEntityPropertyDefaultToConstructorRector/Fixture)
Change default value in string on datetime property to entity constructor
```diff
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
- * @ORM\Column(name="log_cas", type="datetime", nullable=false, options={"default"="1900-01-01 00=00=00"})
+ * @ORM\Column(name="log_cas", type="datetime", nullable=false)
*/
- private $when = '1900-01-01 00:00:00';
+ private $when;
+
+ public function __construct()
+ {
+ $this->when = new DateTime('1900-01-01 00:00:00');
+ }
}
```
<br><br>
### `CorrectDefaultTypesOnEntityPropertyRector`
- class: [`Rector\DoctrineCodeQuality\Rector\Class_\CorrectDefaultTypesOnEntityPropertyRector`](/../master/rules/doctrine-code-quality/src/Rector/Class_/CorrectDefaultTypesOnEntityPropertyRector.php)
- [test fixtures](/../master/rules/doctrine-code-quality/tests/Rector/Property/CorrectDefaultTypesOnEntityPropertyRector/Fixture)
Change default value types to match Doctrine annotation type
```diff
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="is_old", type="boolean")
*/
- private $isOld = '0';
+ private $isOld = false;
}
```
<br><br>
### `InitializeDefaultEntityCollectionRector`
- class: [`Rector\DoctrineCodeQuality\Rector\Class_\InitializeDefaultEntityCollectionRector`](/../master/rules/doctrine-code-quality/src/Rector/Class_/InitializeDefaultEntityCollectionRector.php)
@ -3978,6 +4034,99 @@ Initialize collection property in Entity constructor
<br><br>
### `MakeEntityDateTimePropertyDateTimeInterfaceRector`
- class: [`Rector\DoctrineCodeQuality\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector`](/../master/rules/doctrine-code-quality/src/Rector/ClassMethod/MakeEntityDateTimePropertyDateTimeInterfaceRector.php)
- [test fixtures](/../master/rules/doctrine-code-quality/tests/Rector/ClassMethod/MakeEntityDateTimePropertyDateTimeInterfaceRector/Fixture)
Make maker bundle generate DateTime property accept DateTimeInterface too
```diff
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
- * @var DateTime|null
+ * @var DateTimeInterface|null
*/
private $bornAt;
public function setBornAt(DateTimeInterface $bornAt)
{
$this->bornAt = $bornAt;
}
}
```
<br><br>
### `MakeEntitySetterNullabilityInSyncWithPropertyRector`
- class: [`Rector\DoctrineCodeQuality\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector`](/../master/rules/doctrine-code-quality/src/Rector/ClassMethod/MakeEntitySetterNullabilityInSyncWithPropertyRector.php)
- [test fixtures](/../master/rules/doctrine-code-quality/tests/Rector/ClassMethod/MakeEntitySetterNullabilityInSyncWithPropertyRector/Fixture)
Make nullability in setter class method with respect to property
```diff
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Product
{
/**
* @ORM\ManyToOne(targetEntity="AnotherEntity")
*/
private $anotherEntity;
- public function setAnotherEntity(?AnotherEntity $anotherEntity)
+ public function setAnotherEntity(AnotherEntity $anotherEntity)
{
$this->anotherEntity = $anotherEntity;
}
}
```
<br><br>
### `MoveCurrentDateTimeDefaultInEntityToConstructorRector`
- class: [`Rector\DoctrineCodeQuality\Rector\Class_\MoveCurrentDateTimeDefaultInEntityToConstructorRector`](/../master/rules/doctrine-code-quality/src/Rector/Class_/MoveCurrentDateTimeDefaultInEntityToConstructorRector.php)
- [test fixtures](/../master/rules/doctrine-code-quality/tests/Rector/Property/MoveCurrentDateTimeDefaultInEntityToConstructorRector/Fixture)
Move default value for entity property to constructor, the safest place
```diff
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTimeInterface
*
- * @ORM\Column(type="datetime", nullable=false, options={"default"="now()"})
+ * @ORM\Column(type="datetime", nullable=false)
*/
- private $when = 'now()';
+ private $when;
+
+ public function __construct()
+ {
+ $this->when = new \DateTime();
+ }
}
```
<br><br>
## DoctrineGedmoToKnplabs
### `BlameableBehaviorRector`

View File

@ -32,6 +32,14 @@ final class ColumnTagValueNode extends AbstractDoctrineTagValueNode implements P
return '@ORM\Column';
}
/**
* @return array<string, mixed>
*/
public function getOptions(): array
{
return $this->items['options'] ?? [];
}
public function toAttributeString(): string
{
$items = $this->createAttributeItems();

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->defaults()
->public()
->autowire()
->autoconfigure();
$services->load('Rector\DoctrineCodeQuality\\', __DIR__ . '/../src')
->exclude([__DIR__ . '/../src/Rector/*']);
};

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeAnalyzer;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class ColumnDatetimePropertyAnalyzer
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function matchDateTimeColumnTagValueNodeInProperty(Property $property): ?ColumnTagValueNode
{
if (! $this->doctrineDocBlockResolver->isDoctrineProperty($property)) {
return null;
}
/** @var PhpDocInfo $phpDocInfo */
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
$columnTagValueNode = $phpDocInfo->getByType(ColumnTagValueNode::class);
if ($columnTagValueNode === null) {
return null;
}
/** @var ColumnTagValueNode $columnTagValueNode */
if ($columnTagValueNode->getType() !== 'datetime') {
return null;
}
return $columnTagValueNode;
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeAnalyzer;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class ColumnPropertyAnalyzer
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function matchDoctrineColumnTagValue(Property $property): ?ColumnTagValueNode
{
if (! $this->doctrineDocBlockResolver->isDoctrineProperty($property)) {
return null;
}
/** @var PhpDocInfo $phpDocInfo */
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
return $phpDocInfo->getByType(ColumnTagValueNode::class);
}
}

View File

@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\TypeWithClassName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class SetterClassMethodAnalyzer
{
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver)
{
$this->nodeTypeResolver = $nodeTypeResolver;
$this->nodeNameResolver = $nodeNameResolver;
}
public function matchNullalbeClassMethodProperty(ClassMethod $classMethod): ?Property
{
$propertyFetch = $this->matchNullalbeClassMethodPropertyFetch($classMethod);
if ($propertyFetch === null) {
return null;
}
return $this->getPropertyByPropertyFetch($classMethod, $propertyFetch);
}
public function matchDateTimeSetterProperty(ClassMethod $classMethod): ?Property
{
$propertyFetch = $this->matchDateTimeSetterPropertyFetch($classMethod);
if ($propertyFetch === null) {
return null;
}
return $this->getPropertyByPropertyFetch($classMethod, $propertyFetch);
}
/**
* Matches:
*
* public function setSomething(?Type $someValue);
* {
* <$this->someProperty> = $someValue;
* }
*/
private function matchNullalbeClassMethodPropertyFetch(ClassMethod $classMethod): ?PropertyFetch
{
$propertyFetch = $this->matchSetterOnlyPropertyFetch($classMethod);
if ($propertyFetch === null) {
return null;
}
// is nullable param
$onlyParam = $classMethod->params[0];
if (! $this->nodeTypeResolver->isNullableObjectType($onlyParam)) {
return null;
}
return $propertyFetch;
}
/**
* @return null|Property
*/
private function getPropertyByPropertyFetch(ClassMethod $classMethod, PropertyFetch $propertyFetch)
{
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
if (! $classLike instanceof Class_) {
return null;
}
$propertyName = $this->nodeNameResolver->getName($propertyFetch);
if ($propertyName === null) {
return null;
}
return $classLike->getProperty($propertyName);
}
private function matchDateTimeSetterPropertyFetch(ClassMethod $classMethod): ?PropertyFetch
{
$propertyFetch = $this->matchSetterOnlyPropertyFetch($classMethod);
if ($propertyFetch === null) {
return null;
}
$param = $classMethod->params[0];
$paramType = $this->nodeTypeResolver->getStaticType($param);
if (! $paramType instanceof TypeWithClassName) {
return null;
}
if ($paramType->getClassName() !== 'DateTimeInterface') {
return null;
}
return $propertyFetch;
}
private function matchSetterOnlyPropertyFetch(ClassMethod $classMethod): ?PropertyFetch
{
if (count($classMethod->params) !== 1) {
return null;
}
if (count((array) $classMethod->stmts) !== 1) {
return null;
}
$onlyStmt = $classMethod->stmts[0];
if ($onlyStmt instanceof Expression) {
$onlyStmt = $onlyStmt->expr;
}
if (! $onlyStmt instanceof Assign) {
return null;
}
if (! $onlyStmt->var instanceof PropertyFetch) {
return null;
}
$propertyFetch = $onlyStmt->var;
if (! $this->isVariableName($propertyFetch->var, 'this')) {
return null;
}
return $propertyFetch;
}
private function isVariableName(?Node $node, string $name): bool
{
if (! $node instanceof Variable) {
return false;
}
return $this->nodeNameResolver->isName($node, $name);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Expression;
final class ValueAssignFactory
{
public function createDefaultDateTimeAssign(string $propertyName): Expression
{
$propertyFetch = $this->createPropertyFetch($propertyName);
$assign = new Assign($propertyFetch, $this->createNewDateTime());
return new Expression($assign);
}
public function createDefaultDateTimeWithValueAssign(string $propertyName, Expr $defaultExpr): Expression
{
$propertyFetch = $this->createPropertyFetch($propertyName);
$newDateTime = $this->createNewDateTime();
$newDateTime->args[] = new Arg($defaultExpr);
$assign = new Assign($propertyFetch, $newDateTime);
return new Expression($assign);
}
private function createPropertyFetch(string $propertyName): PropertyFetch
{
return new PropertyFetch(new Variable('this'), $propertyName);
}
private function createNewDateTime(): New_
{
return new New_(new FullyQualified('DateTime'));
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeManipulator;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
final class ColumnDatetimePropertyManipulator
{
public function removeDefaultOption(ColumnTagValueNode $columnTagValueNode): void
{
$options = $columnTagValueNode->getOptions();
unset($options['default']);
$columnTagValueNode->changeItem('options', $options);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeManipulator;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\PhpParser\Node\Manipulator\ClassInsertManipulator;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class ConstructorManipulator
{
/**
* @var NodeFactory
*/
private $nodeFactory;
/**
* @var ClassInsertManipulator
*/
private $classInsertManipulator;
public function __construct(NodeFactory $nodeFactory, ClassInsertManipulator $classInsertManipulator)
{
$this->nodeFactory = $nodeFactory;
$this->classInsertManipulator = $classInsertManipulator;
}
public function addStmtToConstructor(Class_ $class, Expression $newExpression): void
{
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
if ($constructClassMethod instanceof ClassMethod) {
$constructClassMethod->stmts[] = $newExpression;
} else {
$constructClassMethod = $this->nodeFactory->createPublicMethod(MethodName::CONSTRUCT);
$constructClassMethod->stmts[] = $newExpression;
$this->classInsertManipulator->addAsFirstMethod($class, $constructClassMethod);
$class->setAttribute(AttributeKey::ORIGINAL_NODE, null);
}
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeManipulator;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockClassRenamer;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
final class PropertyTypeManipulator
{
/**
* @var DocBlockClassRenamer
*/
private $docBlockClassRenamer;
public function __construct(DocBlockClassRenamer $docBlockClassRenamer)
{
$this->docBlockClassRenamer = $docBlockClassRenamer;
}
public function changePropertyType(Property $property, string $oldClass, string $newClass): void
{
if ($property->type !== null) {
// fix later
throw new NotImplementedYetException();
}
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
return;
}
$this->docBlockClassRenamer->renamePhpDocType(
$phpDocInfo->getPhpDocNode(),
new FullyQualifiedObjectType($oldClass),
new FullyQualifiedObjectType($newClass),
$property
);
}
}

View File

@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\DoctrineCodeQuality\NodeAnalyzer\SetterClassMethodAnalyzer;
use Rector\DoctrineCodeQuality\NodeManipulator\PropertyTypeManipulator;
/**
* @sponsor Thanks https://www.luzanky.cz/ for sponsoring this rule
*
* @see related to maker bundle https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html
*
* @see \Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector\MakeEntityDateTimePropertyDateTimeInterfaceRectorTest
*/
final class MakeEntityDateTimePropertyDateTimeInterfaceRector extends AbstractRector
{
/**
* @var SetterClassMethodAnalyzer
*/
private $setterClassMethodAnalyzer;
/**
* @var PropertyTypeManipulator
*/
private $propertyTypeManipulator;
public function __construct(
SetterClassMethodAnalyzer $setterClassMethodAnalyzer,
PropertyTypeManipulator $propertyTypeManipulator
) {
$this->setterClassMethodAnalyzer = $setterClassMethodAnalyzer;
$this->propertyTypeManipulator = $propertyTypeManipulator;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Make maker bundle generate DateTime property accept DateTimeInterface too', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTime|null
*/
private $bornAt;
public function setBornAt(DateTimeInterface $bornAt)
{
$this->bornAt = $bornAt;
}
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTimeInterface|null
*/
private $bornAt;
public function setBornAt(DateTimeInterface $bornAt)
{
$this->bornAt = $bornAt;
}
}
PHP
),
]);
}
/**
* @return array<int, string>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
$property = $this->setterClassMethodAnalyzer->matchDateTimeSetterProperty($node);
if ($property === null) {
return null;
}
if (! $this->isObjectType($property, 'DateTime')) {
return null;
}
$this->propertyTypeManipulator->changePropertyType($property, 'DateTime', 'DateTimeInterface');
return $node;
}
}

View File

@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ManyToOneTagValueNode;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\DoctrineCodeQuality\NodeAnalyzer\SetterClassMethodAnalyzer;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @sponsor Thanks https://www.luzanky.cz/ for sponsoring this rule
*
* @see related to maker bundle https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html
*
* @see \Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector\MakeEntitySetterNullabilityInSyncWithPropertyRectorTest
*/
final class MakeEntitySetterNullabilityInSyncWithPropertyRector extends AbstractRector
{
/**
* @var SetterClassMethodAnalyzer
*/
private $setterClassMethodAnalyzer;
public function __construct(SetterClassMethodAnalyzer $setterClassMethodAnalyzer)
{
$this->setterClassMethodAnalyzer = $setterClassMethodAnalyzer;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Make nullability in setter class method with respect to property', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Product
{
/**
* @ORM\ManyToOne(targetEntity="AnotherEntity")
*/
private $anotherEntity;
public function setAnotherEntity(?AnotherEntity $anotherEntity)
{
$this->anotherEntity = $anotherEntity;
}
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Product
{
/**
* @ORM\ManyToOne(targetEntity="AnotherEntity")
*/
private $anotherEntity;
public function setAnotherEntity(AnotherEntity $anotherEntity)
{
$this->anotherEntity = $anotherEntity;
}
}
PHP
),
]);
}
/**
* @return array<int, string>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
// is setter in doctrine?
if (! $this->isInDoctrineEntityClass($node)) {
return null;
}
$property = $this->setterClassMethodAnalyzer->matchNullalbeClassMethodProperty($node);
if ($property === null) {
return null;
}
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
return null;
}
$manyToOneTagValueNode = $phpDocInfo->getByType(ManyToOneTagValueNode::class);
if ($manyToOneTagValueNode === null) {
return null;
}
$param = $node->params[0];
/** @var NullableType $paramType */
$paramType = $param->type;
$param->type = $paramType->type;
return $node;
}
}

View File

@ -26,7 +26,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
final class ChangeQuerySetParametersMethodParameterFromArrayToArrayCollectionRector extends AbstractRector
{
/**
* @return string[]
* @return array<int, string>
*/
public function getNodeTypes(): array
{

View File

@ -0,0 +1,152 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnDatetimePropertyAnalyzer;
use Rector\DoctrineCodeQuality\NodeFactory\ValueAssignFactory;
use Rector\DoctrineCodeQuality\NodeManipulator\ColumnDatetimePropertyManipulator;
use Rector\DoctrineCodeQuality\NodeManipulator\ConstructorManipulator;
/**
* @see https://stackoverflow.com/a/7698687/1348344
*
* @todo possible merge with
* @see MoveCurrentDateTimeDefaultInEntityToConstructorRector
*
* @see \Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDatetimeEntityPropertyDefaultToConstructorRector\CorrectDatetimeEntityPropertyDefaultToConstructorRectorTest
*/
final class CorrectDatetimeEntityPropertyDefaultToConstructorRector extends AbstractRector
{
/**
* @var ColumnDatetimePropertyAnalyzer
*/
private $columnDatetimePropertyAnalyzer;
/**
* @var ValueAssignFactory
*/
private $valueAssignFactory;
/**
* @var ConstructorManipulator
*/
private $constructorManipulator;
/**
* @var ColumnDatetimePropertyManipulator
*/
private $columnDatetimePropertyManipulator;
public function __construct(
ColumnDatetimePropertyAnalyzer $columnDatetimePropertyAnalyzer,
ValueAssignFactory $valueAssignFactory,
ConstructorManipulator $constructorManipulator,
ColumnDatetimePropertyManipulator $columnDatetimePropertyManipulator
) {
$this->columnDatetimePropertyAnalyzer = $columnDatetimePropertyAnalyzer;
$this->valueAssignFactory = $valueAssignFactory;
$this->constructorManipulator = $constructorManipulator;
$this->columnDatetimePropertyManipulator = $columnDatetimePropertyManipulator;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change default value in string on datetime property to entity constructor', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="log_cas", type="datetime", nullable=false, options={"default"="1900-01-01 00=00=00"})
*/
private $when = '1900-01-01 00:00:00';
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="log_cas", type="datetime", nullable=false)
*/
private $when;
public function __construct()
{
$this->when = new DateTime('1900-01-01 00:00:00');
}
}
PHP
),
]);
}
/**
* @return array<int, string>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
foreach ($node->getProperties() as $property) {
$this->refactorProperty($property, $node);
}
return $node;
}
private function refactorProperty(Property $property, Class_ $class): void
{
if (! $this->isDoctrineProperty($property)) {
return;
}
// nothing to change → skip
$onlyProperty = $property->props[0];
if ($onlyProperty->default === null) {
return;
}
$columnTagValueNode = $this->columnDatetimePropertyAnalyzer->matchDateTimeColumnTagValueNodeInProperty(
$property
);
if ($columnTagValueNode === null) {
return;
}
$defaultValue = $onlyProperty->default;
$onlyProperty->default = null;
$this->columnDatetimePropertyManipulator->removeDefaultOption($columnTagValueNode);
/** @var string $propertyName */
$propertyName = $this->getName($onlyProperty);
$expression = $this->valueAssignFactory->createDefaultDateTimeWithValueAssign($propertyName, $defaultValue);
$this->constructorManipulator->addStmtToConstructor($class, $expression);
}
}

View File

@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\PropertyProperty;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnPropertyAnalyzer;
/**
* @sponsor Thanks https://www.luzanky.cz/ for sponsoring this rule
*
* @see \Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\CorrectDefaultTypesOnEntityPropertyRectorTest
*/
final class CorrectDefaultTypesOnEntityPropertyRector extends AbstractRector
{
/**
* @var ColumnPropertyAnalyzer
*/
private $columnPropertyAnalyzer;
public function __construct(ColumnPropertyAnalyzer $columnPropertyAnalyzer)
{
$this->columnPropertyAnalyzer = $columnPropertyAnalyzer;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change default value types to match Doctrine annotation type', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="is_old", type="boolean")
*/
private $isOld = '0';
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="is_old", type="boolean")
*/
private $isOld = false;
}
PHP
),
]);
}
/**
* @return array<int, string>
*/
public function getNodeTypes(): array
{
return [Property::class];
}
/**
* @param Property $node
*/
public function refactor(Node $node): ?Node
{
$columnTagValueNode = $this->columnPropertyAnalyzer->matchDoctrineColumnTagValue($node);
if ($columnTagValueNode === null) {
return null;
}
$onlyProperty = $node->props[0];
$defaultValue = $onlyProperty->default;
if ($defaultValue === null) {
return null;
}
if (in_array($columnTagValueNode->getType(), ['bool', 'boolean'], true)) {
return $this->refactorToBoolType($onlyProperty, $node);
}
if (in_array($columnTagValueNode->getType(), ['int', 'integer', 'bigint', 'smallint'], true)) {
return $this->refactorToIntType($onlyProperty, $node);
}
return null;
}
private function refactorToBoolType(PropertyProperty $propertyProperty, Property $property): ?Property
{
if ($propertyProperty->default === null) {
return null;
}
$defaultExpr = $propertyProperty->default;
if ($defaultExpr instanceof String_) {
$propertyProperty->default = boolval($defaultExpr->value) ? $this->createTrue() : $this->createFalse();
return $property;
}
if ($defaultExpr instanceof ConstFetch) {
// already ok
return null;
}
throw new NotImplementedYetException();
}
private function refactorToIntType(PropertyProperty $propertyProperty, Property $property): ?Property
{
if ($propertyProperty->default === null) {
return null;
}
$defaultExpr = $propertyProperty->default;
if ($defaultExpr instanceof String_) {
$propertyProperty->default = new LNumber((int) $defaultExpr->value);
return $property;
}
if ($defaultExpr instanceof LNumber) {
// already correct
return null;
}
throw new NotImplementedYetException();
}
}

View File

@ -78,7 +78,7 @@ PHP
}
/**
* @return string[]
* @return array<int, string>
*/
public function getNodeTypes(): array
{

View File

@ -0,0 +1,178 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnDatetimePropertyAnalyzer;
use Rector\DoctrineCodeQuality\NodeFactory\ValueAssignFactory;
use Rector\DoctrineCodeQuality\NodeManipulator\ColumnDatetimePropertyManipulator;
use Rector\DoctrineCodeQuality\NodeManipulator\ConstructorManipulator;
use Rector\NodeCollector\NodeFinder\ClassLikeParsedNodesFinder;
/**
* @sponsor Thanks https://www.luzanky.cz/ for sponsoring this rule
*
* @see https://stackoverflow.com/a/7698687/1348344
*
* @see \Rector\DoctrineCodeQuality\Tests\Rector\Property\MoveCurrentDateTimeDefaultInEntityToConstructorRector\MoveCurrentDateTimeDefaultInEntityToConstructorRectorTest
*/
final class MoveCurrentDateTimeDefaultInEntityToConstructorRector extends AbstractRector
{
/**
* @var ColumnDatetimePropertyAnalyzer
*/
private $columnDatetimePropertyAnalyzer;
/**
* @var ConstructorManipulator
*/
private $constructorManipulator;
/**
* @var ValueAssignFactory
*/
private $valueAssignFactory;
/**
* @var ColumnDatetimePropertyManipulator
*/
private $columnDatetimePropertyManipulator;
public function __construct(
ClassLikeParsedNodesFinder $classLikeParsedNodesFinder,
ColumnDatetimePropertyAnalyzer $columnDatetimePropertyAnalyzer,
ConstructorManipulator $constructorManipulator,
ValueAssignFactory $valueAssignFactory,
ColumnDatetimePropertyManipulator $columnDatetimePropertyManipulator
) {
$this->classLikeParsedNodesFinder = $classLikeParsedNodesFinder;
$this->columnDatetimePropertyAnalyzer = $columnDatetimePropertyAnalyzer;
$this->constructorManipulator = $constructorManipulator;
$this->valueAssignFactory = $valueAssignFactory;
$this->columnDatetimePropertyManipulator = $columnDatetimePropertyManipulator;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Move default value for entity property to constructor, the safest place', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTimeInterface
*
* @ORM\Column(type="datetime", nullable=false, options={"default"="now()"})
*/
private $when = 'now()';
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTimeInterface
*
* @ORM\Column(type="datetime", nullable=false)
*/
private $when;
public function __construct()
{
$this->when = new \DateTime();
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class, Property::class];
}
/**
* @param Class_|Property $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof Property) {
return $this->refactorProperty($node);
}
if ($node instanceof Class_) {
return $this->refactorClass($node);
}
return null;
}
private function refactorProperty(Property $property): ?Property
{
if (! $this->isObjectType($property, 'DateTimeInterface')) {
return null;
}
$columnTagValueNode = $this->columnDatetimePropertyAnalyzer->matchDateTimeColumnTagValueNodeInProperty(
$property
);
if ($columnTagValueNode === null) {
return null;
}
$this->columnDatetimePropertyManipulator->removeDefaultOption($columnTagValueNode);
// 2. remove default value
$onlyProperty = $property->props[0];
$onlyProperty->default = null;
return $property;
}
private function refactorClass(Class_ $class): ?Class_
{
foreach ($class->getProperties() as $property) {
if (! $this->isObjectType($property, 'DateTimeInterface')) {
return null;
}
$columnTagValueNode = $this->columnDatetimePropertyAnalyzer->matchDateTimeColumnTagValueNodeInProperty(
$property
);
if ($columnTagValueNode === null) {
continue;
}
/** @var string $propertyName */
$propertyName = $this->getName($property);
$assign = $this->valueAssignFactory->createDefaultDateTimeAssign($propertyName);
$this->constructorManipulator->addStmtToConstructor($class, $assign);
}
return $class;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector\Fixture;
use DateTime;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTime|null
*/
private $bornAt;
public function setBornAt(DateTimeInterface $bornAt)
{
$this->bornAt = $bornAt;
}
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector\Fixture;
use DateTime;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var \DateTimeInterface|null
*/
private $bornAt;
public function setBornAt(DateTimeInterface $bornAt)
{
$this->bornAt = $bornAt;
}
}
?>

View File

@ -0,0 +1,22 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector\Fixture;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class SkipDateTimeInterface
{
/**
* @var DateTimeInterface|null
*/
private $bornAt;
public function setBornAt(DateTimeInterface $bornAt)
{
$this->bornAt = $bornAt;
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MakeEntityDateTimePropertyDateTimeInterfaceRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return \Rector\DoctrineCodeQuality\Rector\ClassMethod\MakeEntityDateTimePropertyDateTimeInterfaceRector::class;
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Product
{
/**
* @ORM\ManyToOne(targetEntity="AnotherEntity")
*/
private $anotherEntity;
public function setAnotherEntity(?AnotherEntity $anotherEntity)
{
$this->anotherEntity = $anotherEntity;
}
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Product
{
/**
* @ORM\ManyToOne(targetEntity="AnotherEntity")
*/
private $anotherEntity;
public function setAnotherEntity(AnotherEntity $anotherEntity)
{
$this->anotherEntity = $anotherEntity;
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\DoctrineCodeQuality\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MakeEntitySetterNullabilityInSyncWithPropertyRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return MakeEntitySetterNullabilityInSyncWithPropertyRector::class;
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDatetimeEntityPropertyDefaultToConstructorRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class CorrectDatetimeEntityPropertyDefaultToConstructorRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return \Rector\DoctrineCodeQuality\Rector\Class_\CorrectDatetimeEntityPropertyDefaultToConstructorRector::class;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDatetimeEntityPropertyDefaultToConstructorRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(type="datetime", nullable=false, options={"default"="1900-01-01 00=00=00"})
*/
private $when = '1900-01-01 00:00:00';
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDatetimeEntityPropertyDefaultToConstructorRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(type="datetime", nullable=false)
*/
private $when;
public function __construct()
{
$this->when = new \DateTime('1900-01-01 00:00:00');
}
}
?>

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class CorrectDefaultTypesOnEntityPropertyRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return \Rector\DoctrineCodeQuality\Rector\Class_\CorrectDefaultTypesOnEntityPropertyRector::class;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="is_old", type="boolean")
*/
private $isOld = '0';
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @ORM\Column(name="is_old", type="boolean")
*/
private $isOld = false;
}
?>

View File

@ -0,0 +1,37 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class IntegerColumn
{
/**
* @ORM\Column(type="integer")
*/
private $stav = '1';
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class IntegerColumn
{
/**
* @ORM\Column(type="integer")
*/
private $stav = 1;
}
?>

View File

@ -0,0 +1,21 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class SkipAlready
{
/**
* @ORM\Column(type="integer")
*/
private $stav = 1;
/**
* @ORM\Column(type="boolean")
*/
private $can = true;
}

View File

@ -0,0 +1,37 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class SmallInt
{
/**
* @ORM\Column(type="smallint")
*/
private $stav = '1';
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class SmallInt
{
/**
* @ORM\Column(type="smallint")
*/
private $stav = 1;
}
?>

View File

@ -0,0 +1,54 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\MoveCurrentDateTimeDefaultInEntityToConstructorRector\Fixture;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class AlreadyConstructor
{
/**
* @var DateTimeInterface
*
* @ORM\Column(type="datetime", nullable=false, options={"default"="now()"})
*/
private $when = 'now()';
public function __construct()
{
$value = 10;
}
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\MoveCurrentDateTimeDefaultInEntityToConstructorRector\Fixture;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class AlreadyConstructor
{
/**
* @var DateTimeInterface
*
* @ORM\Column(type="datetime", nullable=false)
*/
private $when;
public function __construct()
{
$value = 10;
$this->when = new \DateTime();
}
}
?>

View File

@ -0,0 +1,47 @@
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\MoveCurrentDateTimeDefaultInEntityToConstructorRector\Fixture;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTimeInterface
*
* @ORM\Column(type="datetime", nullable=false, options={"default"="now()"})
*/
private $when = 'now()';
}
?>
-----
<?php
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\MoveCurrentDateTimeDefaultInEntityToConstructorRector\Fixture;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class User
{
/**
* @var DateTimeInterface
*
* @ORM\Column(type="datetime", nullable=false)
*/
private $when;
public function __construct()
{
$this->when = new \DateTime();
}
}
?>

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\MoveCurrentDateTimeDefaultInEntityToConstructorRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MoveCurrentDateTimeDefaultInEntityToConstructorRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return \Rector\DoctrineCodeQuality\Rector\Class_\MoveCurrentDateTimeDefaultInEntityToConstructorRector::class;
}
}