Git Product home page Git Product logo

rector-doctrine's People

Contributors

acrobat avatar alexander-schranz avatar annervisser avatar aszenz avatar bdaler avatar bobvandevijver avatar brandongillis avatar carlos-granados avatar dmaicher avatar dritter avatar fezfez avatar franmomu avatar ionbazan avatar johjohan avatar jszutkowski avatar julienfastre avatar keulinho avatar kick-the-bucket avatar mkrauser avatar oleg-andreyev avatar oskarstark avatar peterfox avatar sabbelasichon avatar samsonasik avatar tomasvotruba avatar uncaught avatar wkania avatar xthiago avatar yguedidi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

rector-doctrine's Issues

CorrectDefaultTypesOnEntityPropertyRector fails on default negative integer

Setting a default value to a negative integer where the entity property default type is integer throws a system error.

https://getrector.com/demo/9a115ab7-81a5-4624-a6c2-f24c89e4e845

[ERROR] Could not process "file.php" file, due to:
"System error: ""

     Stack trace:                                                                                                   
     #0                                                                                                             
     vendor/rector/rector/vendor/rector/rector-doctrine/rules/CodeQuality/Rector/Property/CorrectDefaultTypesOnEntit
     yPropertyRector.php(95):                                                                                       
     Rector\Doctrine\CodeQuality\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector->refactorToIntType(Objec 
     t(PhpParser\Node\Stmt\PropertyProperty), Object(PhpParser\Node\Stmt\Property))                                 
     #1 vendor/rector/rector/src/Rector/AbstractRector.php(200):                                                    
     Rector\Doctrine\CodeQuality\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector->refactor(Object(PhpPars 
     er\Node\Stmt\Property))                                                                                        
     #2 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(176):                          
     Rector\Core\Rector\AbstractRector->enterNode(Object(PhpParser\Node\Stmt\Property))                             
     #3 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(105):                          
     PhpParser\NodeTraverser->traverseArray(Array)                                                                  
     #4 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(196):                          
     PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node\Stmt\Class_))                                      
     #5 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(105):                          
     PhpParser\NodeTraverser->traverseArray(Array)                                                                  
     #6 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(196):                          
     PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node\Stmt\Namespace_))                                  
     #7 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(85):                           
     PhpParser\NodeTraverser->traverseArray(Array)                                                                  
     #8 vendor/rector/rector/src/PhpParser/NodeTraverser/RectorNodeTraverser.php(43):                               
     PhpParser\NodeTraverser->traverse(Array)                                                                       
     #9 vendor/rector/rector/src/Application/FileProcessor.php(44):                                                 
     Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser->traverse(Array)                                       
     #10 vendor/rector/rector/src/Application/FileProcessor/PhpFileProcessor.php(115):                              
     Rector\Core\Application\FileProcessor->refactor(Object(Rector\Core\ValueObject\Application\File))              
     #11 vendor/rector/rector/packages/Parallel/WorkerRunner.php(136):                                              
     Rector\Core\Application\FileProcessor\PhpFileProcessor->process(Object(Rector\Core\ValueObject\Application\Fil 
     e), Object(Rector\Core\ValueObject\Configuration))                                                             
     #12 vendor/rector/rector/packages/Parallel/WorkerRunner.php(107):                                              
     Rector\Parallel\WorkerRunner->processFile(Object(Rector\Core\ValueObject\Application\File),                    
     Object(Rector\Core\ValueObject\Configuration), Array)                                                          
     #13 vendor/rector/rector/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):                   
     Rector\Parallel\WorkerRunner->Rector\Parallel\{closure}(Array)                                                 
     #14 vendor/rector/rector/vendor/clue/ndjson-react/src/Decoder.php(117):                                        
     RectorPrefix202307\Evenement\EventEmitter->emit('data', Array)                                                 
     #15 vendor/rector/rector/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):                   
     RectorPrefix202307\Clue\React\NDJson\Decoder->handleData(Array)                                                
     #16 vendor/rector/rector/vendor/react/stream/src/Util.php(62):                                                 
     RectorPrefix202307\Evenement\EventEmitter->emit('data', Array)                                                 
     #17 vendor/rector/rector/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):                   
     RectorPrefix202307\React\Stream\Util::RectorPrefix202307\React\Stream\{closure}('{"action":"main...')          
     #18 vendor/rector/rector/vendor/react/stream/src/DuplexResourceStream.php(154):                                
     RectorPrefix202307\Evenement\EventEmitter->emit('data', Array)                                                 
     #19 vendor/rector/rector/vendor/react/event-loop/src/StreamSelectLoop.php(201):                                
     RectorPrefix202307\React\Stream\DuplexResourceStream->handleData(Resource id #2544)                            
     #20 vendor/rector/rector/vendor/react/event-loop/src/StreamSelectLoop.php(173):                                
     RectorPrefix202307\React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)                               
     #21 vendor/rector/rector/src/Console/Command/WorkerCommand.php(63):                                            
     RectorPrefix202307\React\EventLoop\StreamSelectLoop->run()                                                     
     #22 vendor/rector/rector/vendor/symfony/console/Command/Command.php(325):                                      
     Rector\Core\Console\Command\WorkerCommand->execute(Object(RectorPrefix202307\Symfony\Component\Console\Input\A 
     rgvInput), Object(RectorPrefix202307\Symfony\Component\Console\Output\ConsoleOutput))                          
     #23 vendor/rector/rector/vendor/symfony/console/Application.php(944):                                          
     RectorPrefix202307\Symfony\Component\Console\Command\Command->run(Object(RectorPrefix202307\Symfony\Component\ 
     Console\Input\ArgvInput), Object(RectorPrefix202307\Symfony\Component\Console\Output\ConsoleOutput))           
     #24 vendor/rector/rector/vendor/symfony/console/Application.php(326):                                          
     RectorPrefix202307\Symfony\Component\Console\Application->doRunCommand(Object(Rector\Core\Console\Command\Work 
     erCommand), Object(RectorPrefix202307\Symfony\Component\Console\Input\ArgvInput),                              
     Object(RectorPrefix202307\Symfony\Component\Console\Output\ConsoleOutput))                                     
     #25 vendor/rector/rector/src/Console/ConsoleApplication.php(54):                                               
     RectorPrefix202307\Symfony\Component\Console\Application->doRun(Object(RectorPrefix202307\Symfony\Component\Co 
     nsole\Input\ArgvInput), Object(RectorPrefix202307\Symfony\Component\Console\Output\ConsoleOutput))             
     #26 vendor/rector/rector/vendor/symfony/console/Application.php(212):                                          
     Rector\Core\Console\ConsoleApplication->doRun(Object(RectorPrefix202307\Symfony\Component\Console\Input\ArgvIn 
     put), Object(RectorPrefix202307\Symfony\Component\Console\Output\ConsoleOutput))                               
     #27 vendor/rector/rector/bin/rector.php(132): RectorPrefix202307\Symfony\Component\Console\Application->run()  
     #28 vendor/rector/rector/bin/rector(4): require_once('v...')                                                   
     #29 vendor/bin/rector(115): include('v...')                                                                    
     #30 {main}". On line: 136  

Class constants `Criteria::ASC|DESC` are deprecated in favor of `Doctrine\Common\Collection\Order`

According to the UPGRADE guide, classes constants related to Criteria::ASC and Criteria::DESC are deprecated, in favor of Doctrine\Common\Collection\Order.

We can also use the rule Rector\Renaming\Rector\ClassConstFetch\RenameClassConstFetchRector for this (like in #294).

Can I also write a PR for this ?

This is in the package doctrine-collection: I think I will need to create a new ruleset and test suite, isn't it ?

Annotation to Attributes - JoinColumn add to cascade array

I ran AnnotationToAttribute set and got a weird thing happening

I had this before

/**
     * @Mapping\ManyToOne(targetEntity=Application::class, inversedBy="options", fetch="EXTRA_LAZY", cascade={"persist"})
     * @Mapping\JoinColumn(name="application_id", referencedColumnName="id", nullable=false)

And after rector I got this

#[ORM\ManyToOne(targetEntity: Application::class, inversedBy: 'options', fetch: 'EXTRA_LAZY', cascade: ['persist', new ORM\JoinColumn(name: 'application_id', referencedColumnName: 'id', nullable: false)])]
#[ORM\JoinColumn(name: 'application_id', referencedColumnName: 'id', nullable: false)]

The JoinColumn was added to the cascade array and is causing the following exception

strtolower(): Argument #1 ($string) must be of type string, Doctrine\ORM\Mapping\JoinColumn given

ShouldNotHappenException entity not found with MoveRepositoryFromParentToConstructorRector

Problem

Adding the rule MoveRepositoryFromParentToConstructorRector results in a ShouldNotHappenException with the message An entity was not found for ....

Stacktrace

[file] module/App/src/Repository/TestRepository.php
[rule] Rector\Doctrine\Rector\Class_\MoveRepositoryFromParentToConstructorRector
PHP Fatal error:  Uncaught Rector\Core\Exception\ShouldNotHappenException: An entity was not found for "App\Repository\TestRepository" repository. in /app/vendor/rector/rector/vendor/rector/rector-doctrine/src/NodeFactory/RepositoryAssignFactory.php:48
Stack trace:
#0 /app/vendor/rector/rector/vendor/rector/rector-doctrine/src/Rector/Class_/MoveRepositoryFromParentToConstructorRector.php(105): Rector\Doctrine\NodeFactory\RepositoryAssignFactory->create()
#1 /app/vendor/rector/rector/src/Rector/AbstractRector.php(209): Rector\Doctrine\Rector\Class_\MoveRepositoryFromParentToConstructorRector->refactor()
#2 /app/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(176): Rector\Core\Rector\AbstractRector->enterNode()
#3 /app/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(105): PhpParser\NodeTraverser->traverseArray()
#4 /app/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(196): PhpParser\NodeTraverser->traverseNode()
#5 /app/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(85): PhpParser\NodeTraverser->traverseArray()
#6 /app/vendor/rector/rector/src/PhpParser/NodeTraverser/RectorNodeTraverser.php(43): PhpParser\NodeTraverser->traverse()
#7 /app/vendor/rector/rector/src/Application/FileProcessor.php(44): Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser->traverse()
#8 /app/vendor/rector/rector/src/Application/FileProcessor/PhpFileProcessor.php(115): Rector\Core\Application\FileProcessor->refactor()
#9 /app/vendor/rector/rector/src/Application/ApplicationFileProcessor.php(162): Rector\Core\Application\FileProcessor\PhpFileProcessor->process()
#10 /app/vendor/rector/rector/src/Application/ApplicationFileProcessor.php(132): Rector\Core\Application\ApplicationFileProcessor->processFiles()
#11 /app/vendor/rector/rector/src/Console/Command/ProcessCommand.php(123): Rector\Core\Application\ApplicationFileProcessor->run()
#12 /app/vendor/rector/rector/vendor/symfony/console/Command/Command.php(325): Rector\Core\Console\Command\ProcessCommand->execute()
#13 /app/vendor/rector/rector/vendor/symfony/console/Application.php(944): RectorPrefix202306\Symfony\Component\Console\Command\Command->run()
#14 /app/vendor/rector/rector/vendor/symfony/console/Application.php(326): RectorPrefix202306\Symfony\Component\Console\Application->doRunCommand()
#15 /app/vendor/rector/rector/src/Console/ConsoleApplication.php(49): RectorPrefix202306\Symfony\Component\Console\Application->doRun()
#16 /app/vendor/rector/rector/vendor/symfony/console/Application.php(212): Rector\Core\Console\ConsoleApplication->doRun()
#17 /app/vendor/rector/rector/bin/rector.php(132): RectorPrefix202306\Symfony\Component\Console\Application->run()
#18 /app/vendor/rector/rector/bin/rector(5): require_once('...')
#19 /app/vendor/bin/rector(120): include('...')
#20 {main}

Reproduction

Can not get it reproduced on getrector/demo, so I'll give an example.

rector.php

<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Doctrine\Rector\Class_\MoveRepositoryFromParentToConstructorRector;

return static function (RectorConfig $rectorConfig): void
{
    $rectorConfig->phpVersion(phpVersion: PhpVersion::PHP_82);
    $rectorConfig->importNames();
    $rectorConfig->importShortClasses();
    $rectorConfig->disableParallel();
    $rectorConfig->autoloadPaths(autoloadPaths: [
        __DIR__ . '/vendor/autoload.php',
    ]);
    $rectorConfig->paths(paths: [
        __DIR__ . '/module/App/src/Repository/TestRepository.php',
    ]);
    $rectorConfig->rules([
        MoveRepositoryFromParentToConstructorRector::class,
    ]);
};

module/App/src/Repository/TestRepository.php

<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Test;
use Doctrine\ORM\EntityRepository;

final class TestRepository extends EntityRepository
{
    public function findAllTest(): array {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $qb->select('t')
           ->from(Test::class, 't');

        return $qb->getQuery()->getResult();
    }
}

Run vendor/bin/rector process --clear-cache --debug gives stacktrace above as result.


After looking at the resolveFromRepositoryClass I added a method with a phpdoc having a return type.

module/App/src/Repository/TestRepository.php

<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Test;
use Doctrine\ORM\EntityRepository;

final class TestRepository extends EntityRepository
{
    public function findAllTest(): array {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $qb->select('t')
           ->from(Test::class, 't');

        return $qb->getQuery()->getResult();
    }

    /**
     * @return Test
     */
    public function findSingle(): Test {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $qb->select('t')
            ->from(Test::class, 't')
            ->setMaxResults(1);

        return $qb->getQuery()->getSingleResult();
    }
}

After running rector I get the following result:

module/App/src/Repository/TestRepository.php

<?php

declare(strict_types=1);

namespace App\Repository;

use App\Entity\Test;
use Doctrine\ORM\EntityRepository;

final class TestRepository
{
    /**
     * @var EntityRepository<Test>
     */
    private EntityRepository $repository;
    public function __construct(EntityManagerInterface $em, ClassMetadata $class, EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(\Test::class);
        parent::__construct($em, $class);
    }
    public function findAllTest(): array {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $qb->select('t')
           ->from(Test::class, 't');

        return $qb->getQuery()->getResult();
    }

    /**
     * @return Test
     */
    public function findSingle(): Test {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $qb->select('t')
            ->from(Test::class, 't')
            ->setMaxResults(1);

        return $qb->getQuery()->getSingleResult();
    }
}

Now it created the constructor but it has atleast 3 issues and does not reflect the documentation:

  1. Multiple EntityManagerInterface in the constructor.
  2. Addition of ClassMetadata in constructor, not stated in the docs.
  3. Should not be $entityManager->getRepository(\Test::class) but instead $entityManager->getRepository(Test::class)

Conclusion

The example/explanation in the documentation does not reflect what is actually required for this rule to work. With the current multitude of issues it produces it currently does not seem to work correctly.

[ORM 2.9] Add new set for migration of annotations to Attributes

Package doctrine/orm 2.9 stable now supports PHP 8.0 attribute alternatives for Doctrine annotations.

See https://www.doctrine-project.org/2021/05/24/orm2.9.html

There is place for a first-time, who would like to chip-in little work to upgrade of every Doctrine project in the world.


7 Steps to Contribute Doctrine ORM 2.9 Migration Set

  1. look at existing sets https://github.com/rectorphp/rector-doctrine/tree/main/config/sets
  2. add a new set, e.g. doctrine-orm-29.php
  3. register AnnotationToAttributeRector rule - https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md#annotationtoattributerector
  4. configure it with all Doctrine annotations that have attribute alternatives
  5. first value is annotation class, second is attribute class - in this case they're always the same
  6. e.g. for ORM\Entity, it would look like this
 $services->set(AnnotationToAttributeRector::class)
        ->call('configure', [[
            AnnotationToAttributeRector::ANNOTATION_TO_ATTRIBUTE => ValueObjectInliner::inline([
                new AnnotationToAttribute(
                    'Doctrine\ORM\Mapping\Entity',
                    'Doctrine\ORM\Mapping\Entity'
                ),
            ]),
        ]]);
  1. send PR
  2. party and share it to help your Doctrine friends ๐ŸŽ‰ ๐ŸŽ‚ ๐ŸŽˆ

Bonus Level

Would be nice, but is not needed.

Write a test so we have this behavior verified.

  • copy this test
  • configure rector.php with import('...-doctrine-orm-29.php') set
  • add single fixture file to /Fixtures directory to verify
  • ๐Ÿ‘

Nested annotation to attribute support

PHP 8.1 introduced a way to handle nested attributes, something missing from the 8.0 implementation and needed for some Doctrine annotations.

Doctrine has the annotation, @ORM\JoinColumns, used like so:

@ORM\JoinColumns({
    @ORM\JoinColumn(name="thing_id", referencedColumnName="id", nullable=false)
})

Currently, the DoctrineAnnotationClassToAttributeRector skips over this annotation, presumably due to PHP 8.0's lack of nested attribute support. Is there an update on supporting this or a plan in place?

Add DoctrinePHPDocInfoRector to fix Entity PHPDoc by Doctrine Metadata

Similar to rectorphp/rector-phpunit#114, rectorphp/rector-phpunit#114 / rectorphp/rector-phpunit#115

I would like to set the PHPDocInfo @var based on doctrine metadata. Via phpstan-doctrine phpstan already knows the correct type from the Doctrine Metadata () which should be set to the property and getter of that property.

I'm not yet sure how I can access the expected PHPStan type. Any hints how to achieve this would be welcome.

Annotation to attributes rector isn't complete

Hi! I found some problems using rector to transform annotations to attributes:

  1. @Index must be moved out of @Table
    image (Table attribute was deleted as it's not necessary anymore)

  2. same for unique constraints
    image (Table attribute was deleted as it's not necessary anymore)

  3. @JoinTable should be split

image

I had to do these modifications manually after the initial rector run โ€“ these were not easy to find, partly because of silent BC by Doctrine.

I found some information about these in doctrine/orm#9334 (comment) and https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/reference/attributes-reference.html

NotImplementedYetException when using private ?int $varName = null;

Hi,

I love rector and rector doctrine <3. But.

<?php

namespace App\Wex\BaseBundle\Entity\Traits;

use Doctrine\ORM\Mapping as ORM;

trait LinkedToAnyEntity
{
    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private ?int $entityId = null;
}
vendor/bin/rector process -vvv src/Wex/BaseBundle/Entity/Traits/LinkedToAnyEntity.php

Result :

[applying] Rector\Doctrine\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector

In CorrectDefaultTypesOnEntityPropertyRector.php line 116:
                                                      
  [Rector\Core\Exception\NotImplementedYetException]  

Probably the same problem as rectorphp/rector#5454
And should be solved by rectorphp/rector#5974

Same issue with

\Rector\Doctrine\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector::class
\Rector\Doctrine\Rector\Property\RemoveRedundantDefaultPropertyAnnotationValuesRector::class

Thanks

NullabilityColumnPropertyTypeResolver default false instead of true?

I ma not sure if I understand it correctly.

But in this function, there should be default false, not true?

private function isNullableColumn(PhpDocInfo $phpDocInfo): bool

By default ORM\Column is nullable=false. If I don't have nullable neiehter in the attribute nor in phpdoc, it souhldn't be nullable for property. Am I missing something?

Example here also show ignoring nullable:false in the attribute, but it can be due to others refactoring rules.
image

Rector forces FQN for `\Doctrine\DBAL\Types\Types`

use Doctrine\DBAL\Types\Types;

...

-    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
+    #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE)]

Types is imported but rector still tries to force usage FQN when using DoctrineSetList::DOCTRINE_CODE_QUALITY.

Incorrect behavior of RemoveRedundantDefaultPropertyAnnotationValuesRector

Moved here from rectorphp/rector#7034

Bug Report

A @JoinTable-Annotation is added, even if it is already present.

Subject Details
Rector version last dev-master
Installed as composer dependency

Minimal PHP Code Causing Issue

See https://getrector.org/demo/c057a4bc-9be7-4347-a4cd-f0d719e71c17

<?php

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="test")
 */
class Test
{
    /**
     * @ORM\ManyToMany(targetEntity="Type", inversedBy="tests")
     * @ORM\JoinTable(
     *    name="objects_portal_type",
     *    joinColumns={@ORM\JoinColumn(name="test_id", referencedColumnName="id")},
     *    inverseJoinColumns={@ORM\JoinColumn(name="type_id", referencedColumnName="id")}
     * )
     * @var \Doctrine\Common\Collections\Collection<\Type>
     */
    private \Doctrine\Common\Collections\Collection $types;

    public function __construct()
    {
        $this->types = new ArrayCollection();
    }

}

Responsible rules

  • RemoveRedundantDefaultPropertyAnnotationValuesRector

Expected Behavior

Improve the existing annotation, but do not duplicate it

DOCTRINE_CODE_QUALITY set-list is causing unnecessary qualifier

I have a doctrine definition like so:

    /**
     * @var int
     */
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'AUTO')]
    #[ORM\Column(type: 'integer', name: 'some_id')]
    protected $id;

running the code quality set list is changing it to:

    /**
     * @var int
     */
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'AUTO')]
    #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, name: 'some_id')]
    protected ?int $id = null;

I'd personally prefer Types::INTEGER to be written without a qualifier, using an import instead. But I can let my IDE handle that after rector is done, so not a huge deal. The problem is that after I change the qualifier to an import and run the set list again, the qualifier is re-introduced. I'd expect rector to leave fields alone, if they already make use of the constant.

New rule for iterate() => toIterable() since 2.8.x

With doctrine/orm#7885 & doctrine/orm#8293 there was a new function introduced to loop.

Add a rule the will move all iterate() to toIterable(). And make sure we fix cases like:

-$results = $em->select('e')->from('entity')->getQuery()->iterate();
+$results = $em->select('e')->from('entity')->getQuery()->toIterable();
foreach($resuls as $result) {
-   $entityIsHere = $result[0];
+   $entityIsHere = $result;
}

Also create a doctrine-orm-28.php

Replace LifecycleEventArgs by [event]EventArgs

See doctrine/orm@99f044c

- public function postPersist(Notification $notification, \Doctrine\ORM\Event\LifecycleEventArgs $args) : void
+ public function postPersist(Notification $notification, \Doctrine\ORM\Event\PostPersistEventArgs $args) : void

- public function postUpdate(Notification $notification, \Doctrine\ORM\Event\LifecycleEventArgs $args) : void
+ public function postUpdate(Notification $notification, \Doctrine\ORM\Event\PostUpdateEventArgs $args) : void
` ``

Faulty type-hinting and nullable state

The set-list DOCTRINE_CODE_QUALITY changes this:

    #[ORM\Column(type: 'decimal', precision: 9, scale: 2)]
    protected $amount;

into this:

    #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DECIMAL, precision: 9, scale: 2)]
    protected ?string $amount = null;

The field nullable on ORM\Column is false by default. But the set-list seems to imply it to be true, adding an undesired ? and initializing the field with null.

Check for attribute before ANNOTATIONS_TO_ATTRIBUTES applied

While working on one open source tool when Entity has both Annotation and Attributes for B/C.

Executed rector and it created dublicate Attributes.

It would be great to validate attributes before rule is applied and if Attributes alter exists, just remove the Annotation.

Unexpected refractoring of nullable datetime field

When running rector with the doctrine exension:

    $containerConfigurator->import(DoctrineSetList::DOCTRINE_CODE_QUALITY);
1) src/Cashback/Domain/Model/CashbackClaim.php:57

    ---------- begin diff ----------
@@ @@
     /**
      * @ORM\Column(type="datetime", nullable=true)
      */
-    private ?DateTimeInterface $orderDetailsOrderDate = null;
+    private ?DateTimeInterface $orderDetailsOrderDate;

     /**
      * @ORM\Column(length="256")
@@ @@

@@ @@
     {
         $uuid = Uuid::uuid4();
         $this->entityId = $uuid->toString();
+        $this->orderDetailsOrderDate = new \DateTime(null);
     }

The result is unexpected as it did add:

$this->orderDetailsOrderDate = new \DateTime(null);

Which should just stay as:

private ?DateTimeInterface $orderDetailsOrderDate = null;

CorrectDefaultTypesOnEntityPropertyRector not working for ClassConstant initialized properties

e.g. this throws a NotYetImplementedException:

<?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class User
{
    
    public const DEFAULT = false;
    /**
     * @ORM\Column(name="is_old", type="boolean")
     */
    private $isOld = self::DEFAULT;
}

see https://getrector.org/demo/5ec50f90-39ba-4292-8da4-8573f90ef578

I guess that the check here should also check if $defaultExpr is an instance of ClassConstFetch. I'll send a PR for this.

One Question though: Is there a reason why refactorToBoolType() returns in case of Constants, but refactorToIntType() does not?

RectoreRule to force jsonb for all JSON fields

Before:

    #[ORM\Column(type: Types::JSON, nullable: true)]

After:

    #[ORM\Column(type: Types::JSON, nullable: true, options: ['jsonb' => true])]

The JSONB is the modern json type for postgresql and is mostly the type you want to use. It would nice to have a rector rule for it to force it in a project.

Doctrine decimal column type mapped incorrectly as float

When applying the rule TypedPropertyFromColumnTypeRector

See https://getrector.org/demo/1ec73834-ba14-69bc-8cfe-29f5df412c73

Doctrine decimal type should be mapped to string to preserve precision as per:

https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#mapping-matrix
https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#decimal

In this case we can also use numeric-string var annotation to specify that it's a numeric string and not just any other string.

RemoveRedundantDefaultPropertyAnnotationValuesRector is adding one more line instead of replacing the existing one

The rule RemoveRedundantDefaultPropertyAnnotationValuesRector is adding one more line instead of replacing the existing one.

It only occurs when there are more annotations below the @Orm\Column. If i move the @expose and @JmsGroups lines to the line before @Orm\Column it works like expected.

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\Groups as JmsGroups;

/**
 * @ORM\Entity()
 */
class Teste
{
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     *
     * @Expose
     * @JmsGroups({"list", "details"})
     */
    private $name;

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }
}
$ vendor/bin/rector process src/Entity/Teste.php --dry-run --debug
src/Entity/Teste.php
[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\InitializeDefaultEntityCollectionRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\MoveCurrentDateTimeDefaultInEntityToConstructorRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\RemoveRedundantDefaultClassAnnotationValuesRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\MakeEntityDateTimePropertyDateTimeInterfaceRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ChangeBigIntEntityPropertyToIntTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\RemoveRedundantDefaultPropertyAnnotationValuesRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromColumnTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromToOneRelationTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromToManyRelationTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromDoctrineCollectionRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\InitializeDefaultEntityCollectionRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\MoveCurrentDateTimeDefaultInEntityToConstructorRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Class_\RemoveRedundantDefaultClassAnnotationValuesRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\MakeEntityDateTimePropertyDateTimeInterfaceRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ChangeBigIntEntityPropertyToIntTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromToOneRelationTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromToManyRelationTypeRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\TypedPropertyFromDoctrineCollectionRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector

[file] src/Entity/Teste.php
[rule] Rector\Doctrine\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector


1 file with changes
===================

1) src/Entity/Teste.php:13

    ---------- begin diff ----------
@@ @@
     /**
      * @var string
      *
+     * @ORM\Column(name="name", type="string", length=255)
      * @ORM\Column(name="name", type="string", length=255, nullable=false)
      *
      * @Expose
      * @JmsGroups({"list", "details"})
      */
-    private $name;
+    private ?string $name = null;

     public function getName(): ?string
     {
    ----------- end diff -----------

Applied rules:
 * RemoveRedundantDefaultPropertyAnnotationValuesRector (https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/reference/basic-mapping.html#property-mapping)
 * TypedPropertyFromColumnTypeRector

Add rule to update string events with constants

Lets add a rule to replace event strings with the corresponding class constants (Just like the Criteria constants)

<?php

declare(strict_types=1);

namespace App\Subscriber\Doctrine;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
+use Doctrine\ORM\Events;

class DoctrineSubscriber implements EventSubscriber
{

    public function getSubscribedEvents(): array
    {
        return [   
-            'prePersist',
-            'preUpdate',
+            Events::prePersist,
+            Events::preUpdate,
        ];
    }

    public function prePersist(LifecycleEventArgs $args) {
        //...
    }
    public function preUpdate(PreUpdateEventArgs $eventArgs) {
        //...
    }
}

I'll see if I can implement this in the future

Incorrect behavior of TypedPropertyFromColumnTypeRector

Bug Report

Subject Details
Rector version last dev-main
Installed as composer dependency

Minimal PHP Code Causing Issue

See https://getrector.com/demo/720d70fc-be2c-4a49-a67d-6c35f25f2d76

<?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
final class DemoEntity
{
    /**
     * @ORM\Column(type="decimal", scale=1, precision=4, nullable=false)
     */
    protected $productDiscount = 0;
}

Responsible rules

  • TypedPropertyFromColumnTypeRector

Expected Behavior

/**
 * @ORM\Column(type="decimal", scale=1, precision=4, nullable=false)
 */
- protected $productDiscount = 0;
+ protected float $productDiscount = 0;

RemoveRedundantDefaultPropertyAnnotationValuesRector with JoinColumn

This rule is removing JoinColumn annotation

-     * @ORM\JoinTable(name="vouchers_subscriptions",
-     *     joinColumns={@ORM\JoinColumn(name="voucher_id", referencedColumnName="id")},
-     *     inverseJoinColumns={@ORM\JoinColumn(name="subscription_id", referencedColumnName="id")}
-     *     )
+     * @ORM\JoinTable(name="vouchers_subscriptions", joinColumns={(name="voucher_id")}, inverseJoinColumns={(name="subscription_id", referencedColumnName="id")})

But in the doc it needs of JoinColumn

https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/association-mapping.html#many-to-many-unidirectional

ORM 2.9 Set doesn't properly convert `@UniqueConstraint` and `@Index` annotations to attributes

I'm trying out the new ORM 2.9 upgrade set to convert Annotations to Attributes and I found a problem.

Given I have the following entity:

/** 
 * @ORM\Table(
 *     name="table",
 *     options={"charset": "utf8mb4", "collate": "utf8mb4_bin"},
 *     uniqueConstraints={
 *         @ORM\UniqueConstraint(name="unique_review", columns={"type", "relationship_id", "user_id"})
 *     },
 *     indexes={
 *         @ORM\Index(name="index_name", columns={"user_id", "type", "relationship_id", "created_at", "is_deleted"}),
 *     },
 * )
 */
class SomeEntity

Rector changes this to:

#[Table(name: 'table', options: ['charset' => 'utf8mb4', 'collate' => 'utf8mb4_bin'], uniqueConstraints: ['(name="unique_review", columns={"type", "relationship_id", "user_id"})'], indexes: ['(name="index_name", columns={"user_id", "type", "relationship_id", "created_at", "is_deleted"})'], ')')]
class SomeEntity

As you can see, it completely trips on the nested annotations. And just dumps them in as strings.

Turns out that nested attributes are not supported.

The solution would be, to move the nested annotations to attributes on a new line, like this:

#[Table(name: 'table', options: ['charset' => 'utf8mb4', 'collate' => 'utf8mb4_bin'])]
#[UniqueConstraint(name: 'unique_review', columns=['type', 'relationship_id', 'user_id']]
#[Index(name: 'index_name', columns=['user_id', 'type', 'relationship_id', 'created_at', 'is_deleted'])]
class SomeEntity

To mitigate this bug, I tried to first manually convert the nested Annotations to Class Annotations. But Doctrine doesn't allow that:

/** 
 * @ORM\Table(name="table", options={"charset": "utf8mb4", "collate": "utf8mb4_bin"})
 * @ORM\UniqueConstraint(name="unique_review", columns={"type", "relationship_id", "user_id"})
 * @ORM\Index(name="index_name", columns={"user_id", "type", "relationship_id", "created_at", "is_deleted"})
 */
class SomeEntity
[Semantical Error] Annotation @ORM\UniqueConstraint is not allowed to be declared on class SomeEntity. 
You may only use this annotation on these code elements: ANNOTATION.

That also means that these examples are impossible/invalid:
https://github.com/rectorphp/rector-doctrine/blob/main/tests/Set/DoctrineORM29Set/Fixture/unique_constraint.php.inc
https://github.com/rectorphp/rector-doctrine/blob/main/tests/Set/DoctrineORM29Set/Fixture/index.php.inc

fetchColumn to fetchOne wont apply on Doctrine\DBAL\Result

With doctrine-dbal-211.php we added multiple rename method rules for:
Doctrine\\DBAL\\Connection
and
Doctrine\\DBAL\\Statement

i Have the following query that wont be updated:

return (int) $this->_em->getConnection()
            ->executeQuery("SELECT x")
            ->fetchColumn();

as executeQuery returns a Doctrine\DBAL\Result, we should probably add this one as well as when i update the function call it works as expected the rule looks like:

new MethodCallRename('Doctrine\\DBAL\\Result', 'fetchColumn', 'fetchOne'),

Can i add this?

Some rules produce no change for entities with native attributes

Some other rules which don't work with entities annotated using php attributes instead of doc blocks

  • TypedPropertyFromToOneRelationTypeRector
  • TypedPropertyFromToManyRelationTypeRector
  • ImproveDoctrineCollectionDocTypeInEntityRector
  • RemoveRedundantDefaultPropertyAnnotationValuesRector

Working on annotations:
https://getrector.org/demo/1ec7452c-d213-6766-899c-53572d5e860c

No change on attributes:
https://getrector.org/demo/1ec7452b-e5a8-6bc4-b0d4-752ae0c535c0

Rules not working for entities using php 8 attributes

We recently converted our doctrine entities to use php 8 attributes using rector and now we wish to apply some other rules but it seems like many rules don't work on attribute based entities.

I tried TypedPropertyFromColumnTypeRector rule, and it doesn't work on attribute based entities. It just shows Rector is done! message without changing anything even though there are many properties left un-typed.

To test I tried the same rule on old annotation based entity and it worked well.

Is there any way to use these rules now or will the attribute based entities require new rules?

Replace doctrine's deprecated fetchAll() with the new methods

Feature Request

Replace doctrine's deprecated fetchAll() with the new methods.
Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead.

Diff

        $result = $this->connection
            ->executeQuery($sql)
-            ->fetchAll(\PDO::FETCH_COLUMN);
+            ->fetchFirstColumn();
        $result = $qb->execute()
-			->fetchAll(\PDO::FETCH_ASSOC);
+        	->fetchAllAssociative();
        $result = $this->connection
            ->executeQuery($sql)
-            ->fetchColumn();
+            ->fetchOne();

getEntityManager from OnFlushEventArgs is depreacated since 2.13

getEntityManager from OnFlushEventArgs (and others) is depreacated since 2.13 see deprecated function:

    /**
     * Retrieve associated EntityManager.
     *
     * @deprecated 2.13. Use {@see getObjectManager} instead.
     *
     * @return EntityManagerInterface
     */
    public function getEntityManager()
    {
        Deprecation::trigger(
            'doctrine/orm',
            'https://github.com/doctrine/orm/issues/9875',
            'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
            __METHOD__
        );

        return $this->getObjectManager();
    }

I like to create a rule which will change function call from getEntityManager to getObjectManager and create a constant DOCTRINE_213 that will have this rule let me know if that is something we want

ManyToOne relations with JoinColumns are not being replaced with an array of JoinColumn

Looks like there's a bug on the ManyToOne relation with the JoinColumns annotation which ends out with the following error.

[Syntax Error] Expected PlainValue, got '(' at position 166 in property App\Entity\Product::$inventoryPosition.

The documentation says the @JoinColumns needs an array of JoinColumn:

An array of @joincolumn annotations for a @ManyToOne or @OneToOne relation with an entity that has multiple identifiers.

Take a look the code below removing the @Orm\JoinColumn annotation.

     /**
      * @var InventoryPosition
      *
      * @ORM\ManyToOne(targetEntity="App\Entity\InventoryPosition", inversedBy="products", cascade={"persist"})
-     * @ORM\JoinColumns({
-     *   @ORM\JoinColumn(name="inventory_position_id", referencedColumnName="id")
-     * })
+     * @ORM\JoinColumns({(name="inventory_position_id")})
      */
-    private $inventoryPosition;
+    private ?\App\Entity\InventoryPosition $inventoryPosition = null;

I'm using the DoctrineSetList::DOCTRINE_CODE_QUALITY setlist

ANNOTATIONS_TO_ATTRIBUTES set removes all annotations rather than only the converted to attributes

I have an entity:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
use SimpleThings\EntityAudit\Mapping\Annotation as Audit;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Table(name="products", indexes={
 *     @ORM\Index(columns={"updated_at"})
 * }))
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 * @Serializer\ExclusionPolicy("ALL")
 * @Audit\Auditable()
 */
class TestEntity
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id()
     * @Serializer\SerializedName("id")
     * @Serializer\Type("integer")
     * @Assert\NotBlank()
     */
    protected $id;
}

After running rector with only one set DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES, it turns into:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
use SimpleThings\EntityAudit\Mapping\Annotation as Audit;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Table(name: 'products')]
#[ORM\Index(columns: ['updated_at'])]
class TestEntity
{
    /**
     * @var int
     *
     * @Serializer\SerializedName("id")
     * @Serializer\Type("integer")
     * @Assert\NotBlank()
     */
    #[ORM\Column(name: 'id', type: 'integer')]
    #[ORM\Id]
    protected $id;
}

So these annotations have gone:

 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 * @Serializer\ExclusionPolicy("ALL")
 * @Audit\Auditable()

Whereas on the id property, the unprocessed annotations are in place.
Is that a bug or feature?


Rector 0.15.10

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.