zenstruck / foundry

A model factory library for creating expressive, auto-completable, on-demand dev/test fixtures with Symfony and Doctrine.
https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html
MIT License
608 stars 63 forks source link

[2.x] [rector] error thrown using `FoundrySetList` && `PersistenceResolver` w/ custom generator #581

Closed jrushlow closed 1 week ago

jrushlow commented 3 months ago

>> rector process -c ./rector.php --clear-cache --dry-run produces:

...

 [ERROR] Could not process "/home/jrdev/develop/php/big-desk/src/Factory/NoteFactory.php" file, due to:                 
         "System error: "Cannot instantiate custom generator : array (                                                  
           'class' => 'doctrine.uuid_generator',                                                                        
         )"                                                                                                             
         Run Rector with "--debug" option and post the report here: https://github.com/rectorphp/rector/issues/new". On line: 23

w/ --debug

 [ERROR] Could not process "/home/jrdev/develop/php/big-desk/src/Factory/NoteFactory.php" file, due to:                 
         "System error: "Cannot instantiate custom generator : array (                                                  
           'class' => 'doctrine.uuid_generator',                                                                        
         )"                                                                                                             

         Stack trace:                                                                                                   
         #0 vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php(604):                                              
         Doctrine\ORM\Mapping\Exception\InvalidCustomGenerator::onMissingClass(Array)                                   
         #1 vendor/doctrine/orm/src/Mapping/ClassMetadataFactory.php(174):                                              
         Doctrine\ORM\Mapping\ClassMetadataFactory->completeIdGeneratorMapping(Object(Doctrine\ORM\Mapping\ClassMetadat 
         a))                                                                                                            
         #2 vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php(343):                  
         Doctrine\ORM\Mapping\ClassMetadataFactory->doLoadMetadata(Object(Doctrine\ORM\Mapping\ClassMetadata), NULL,    
         false, Array)                                                                                                  
         #3 vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php(225):                  
         Doctrine\Persistence\Mapping\AbstractClassMetadataFactory->loadMetadata('App\\Entity\\Note')                   
         #4 tools/rector/vendor/phpstan/phpstan-doctrine/src/Type/Doctrine/ObjectMetadataResolver.php(129):             
         Doctrine\Persistence\Mapping\AbstractClassMetadataFactory->getMetadataFor('App\\Entity\\Note')                 
         #5 vendor/zenstruck/foundry/utils/rector/src/PersistenceResolver.php(109):                                     
         PHPStan\Type\Doctrine\ObjectMetadataResolver->getClassMetadata('App\\Entity\\Note')                            
         #6 vendor/zenstruck/foundry/utils/rector/src/PersistenceResolver.php(62):                                      
         Zenstruck\Foundry\Utils\Rector\PersistenceResolver->isPersisted('App\\Entity\\Note')                           
         #7 vendor/zenstruck/foundry/utils/rector/src/PersistenceResolver.php(54):                                      
         Zenstruck\Foundry\Utils\Rector\PersistenceResolver->shouldUseProxyFactory('App\\Entity\\Note')                 
         #8 vendor/zenstruck/foundry/utils/rector/src/RewriteFactoryPhpDoc/RewriteFactoryPhpDoc.php(97):                
         Zenstruck\Foundry\Utils\Rector\PersistenceResolver->shouldTransformFactoryIntoObjectFactory('App\\Factory\\Not 
         ...')                                                                                                          
         #9 tools/rector/vendor/rector/rector/src/Rector/AbstractRector.php(136):                                       
         Zenstruck\Foundry\Utils\Rector\RewriteFactoryPhpDoc\RewriteFactoryPhpDoc->refactor(Object(PhpParser\Node\Stmt\ 
         Class_))                                                                                                       
         #10 tools/rector/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(176):            
         Rector\Rector\AbstractRector->enterNode(Object(PhpParser\Node\Stmt\Class_))                                    
         #11 tools/rector/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(105):            
         PhpParser\NodeTraverser->traverseArray(Array)                                                                  
         #12 tools/rector/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(196):            
         PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node\Stmt\Namespace_))                                  
         #13 tools/rector/vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(85):             
         PhpParser\NodeTraverser->traverseArray(Array)                                                                  
         #14 tools/rector/vendor/rector/rector/src/PhpParser/NodeTraverser/RectorNodeTraverser.php(41):                 
         PhpParser\NodeTraverser->traverse(Array)                                                                       
         #15 tools/rector/vendor/rector/rector/src/Application/FileProcessor.php(105):                                  
         Rector\PhpParser\NodeTraverser\RectorNodeTraverser->traverse(Array)                                            
         #16 tools/rector/vendor/rector/rector/src/Application/ApplicationFileProcessor.php(184):                       
         Rector\Application\FileProcessor->processFile(Object(Rector\ValueObject\Application\File),                     
         Object(Rector\ValueObject\Configuration))                                                                      
         #17 tools/rector/vendor/rector/rector/src/Application/ApplicationFileProcessor.php(161):                       
         Rector\Application\ApplicationFileProcessor->processFile(Object(Rector\ValueObject\Application\File),          
         Object(Rector\ValueObject\Configuration))                                                                      
         #18 tools/rector/vendor/rector/rector/src/Console/Command/WorkerCommand.php(118):                              
         Rector\Application\ApplicationFileProcessor->processFiles(Array, Object(Rector\ValueObject\Configuration),     
         Object(Closure))                                                                                               
         #19 tools/rector/vendor/rector/rector/vendor/evenement/evenement/src/EventEmitterTrait.php(111):               
         Rector\Console\Command\WorkerCommand->Rector\Console\Command\{closure}(Array)                                  
         #20 tools/rector/vendor/rector/rector/vendor/clue/ndjson-react/src/Decoder.php(117):                           
         RectorPrefix202402\Evenement\EventEmitter->emit('data', Array)                                                 
         #21 tools/rector/vendor/rector/rector/vendor/evenement/evenement/src/EventEmitterTrait.php(111):               
         RectorPrefix202402\Clue\React\NDJson\Decoder->handleData(Array)                                                
         #22 tools/rector/vendor/rector/rector/vendor/react/stream/src/Util.php(62):                                    
         RectorPrefix202402\Evenement\EventEmitter->emit('data', Array)                                                 
         #23 tools/rector/vendor/rector/rector/vendor/evenement/evenement/src/EventEmitterTrait.php(111):               
         RectorPrefix202402\React\Stream\Util::RectorPrefix202402\React\Stream\{closure}('{"action":"main...')          
         #24 tools/rector/vendor/rector/rector/vendor/react/stream/src/DuplexResourceStream.php(154):                   
         RectorPrefix202402\Evenement\EventEmitter->emit('data', Array)                                                 
         #25 tools/rector/vendor/rector/rector/vendor/react/event-loop/src/StreamSelectLoop.php(201):                   
         RectorPrefix202402\React\Stream\DuplexResourceStream->handleData(Resource id #1970)                            
         #26 tools/rector/vendor/rector/rector/vendor/react/event-loop/src/StreamSelectLoop.php(173):                   
         RectorPrefix202402\React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)                               
         #27 tools/rector/vendor/rector/rector/src/Console/Command/WorkerCommand.php(89):                               
         RectorPrefix202402\React\EventLoop\StreamSelectLoop->run()                                                     
         #28 tools/rector/vendor/rector/rector/vendor/symfony/console/Command/Command.php(327):                         
         Rector\Console\Command\WorkerCommand->execute(Object(RectorPrefix202402\Symfony\Component\Console\Input\ArgvIn 
         put), Object(RectorPrefix202402\Symfony\Component\Console\Output\ConsoleOutput))                               
         #29 tools/rector/vendor/rector/rector/vendor/symfony/console/Application.php(960):                             
         RectorPrefix202402\Symfony\Component\Console\Command\Command->run(Object(RectorPrefix202402\Symfony\Component\ 
         Console\Input\ArgvInput), Object(RectorPrefix202402\Symfony\Component\Console\Output\ConsoleOutput))           
         #30 tools/rector/vendor/rector/rector/vendor/symfony/console/Application.php(333):                             
         RectorPrefix202402\Symfony\Component\Console\Application->doRunCommand(Object(Rector\Console\Command\WorkerCom 
         mand), Object(RectorPrefix202402\Symfony\Component\Console\Input\ArgvInput),                                   
         Object(RectorPrefix202402\Symfony\Component\Console\Output\ConsoleOutput))                                     
         #31 tools/rector/vendor/rector/rector/src/Console/ConsoleApplication.php(53):                                  
         RectorPrefix202402\Symfony\Component\Console\Application->doRun(Object(RectorPrefix202402\Symfony\Component\Co 
         nsole\Input\ArgvInput), Object(RectorPrefix202402\Symfony\Component\Console\Output\ConsoleOutput))             
         #32 tools/rector/vendor/rector/rector/vendor/symfony/console/Application.php(216):                             
         Rector\Console\ConsoleApplication->doRun(Object(RectorPrefix202402\Symfony\Component\Console\Input\ArgvInput), 
         Object(RectorPrefix202402\Symfony\Component\Console\Output\ConsoleOutput))                                     
         #33 tools/rector/vendor/rector/rector/bin/rector.php(130):                                                     
         RectorPrefix202402\Symfony\Component\Console\Application->run()                                                
         #34 tools/rector/vendor/rector/rector/bin/rector(5): require_once('/home/jrdev/dev...')                        
         #35 tools/rector/vendor/bin/rector(119): include('/home/jrdev/dev...')                                         
         #36 {main}". On line: 23

Entity Property:

// Symfony's UID Component

    #[
        ORM\Id,
        ORM\Column(type: UuidType::NAME),
        ORM\GeneratedValue(strategy: 'CUSTOM'),
        ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')
    ]
    protected Uuid $id;

Rector config:

<?php

use Rector\Config\RectorConfig;
use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector;
use Rector\PHPUnit\Set\PHPUnitSetList;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SymfonySetList;

return static function (RectorConfig $config): void {
    $config->paths([
        __DIR__.'/src',
        __DIR__.'/tests',
    ]);

    $config->bootstrapFiles([
        __DIR__.'/vendor/autoload.php',
        __DIR__.'/tools/rector/vendor/autoload.php',
    ]);

    $config->symfonyContainerXml(__DIR__.'/var/cache/test/App_KernelTestDebugContainer.xml');
    $config->symfonyContainerPhp(__DIR__.'/tests/rector-bootstrap.php');
    $config->singleton(\Zenstruck\Foundry\Utils\Rector\PersistenceResolver::class,
        static fn() => new \Zenstruck\Foundry\Utils\Rector\PersistenceResolver(
            // Note- rector-bootstrap returns a ContainerInterface for the symfonyContainerPhp() method above
            (require __DIR__.'/tests/rector-bootstrap.php')->get('doctrine')->getManager())
    );

    $config->sets([
        \Zenstruck\Foundry\Utils\Rector\FoundrySetList::UP_TO_FOUNDRY_2,
        LevelSetList::UP_TO_PHP_83,
        SetList::DEAD_CODE,
        SymfonySetList::SYMFONY_64,
        PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES,
        PHPUnitSetList::PHPUNIT_100,
    ]);

    $config->skip([
        PreferPHPUnitThisCallRector::class
    ]);
};

Temp. Workaround: Comment out the attribute(s) for the generator -> run rector -> remove comments.

// Symfony's UID Component

//    #[
//       ORM\Id,
//        ORM\Column(type: UuidType::NAME),
//        ORM\GeneratedValue(strategy: 'CUSTOM'),
//        ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')
//    ]
    protected Uuid $id;
nikophil commented 2 months ago

thank you to give a try to this whole upgrade path! I've tested it on several projects of mine, as well as @kbond did, but that's cool it gets tested on other projects before we release it

don't hesitate to post other problems you encounter, I'll fix them quickly

nikophil commented 2 months ago

Hi @jrushlow

could you show your rector-bootstrap.php file please?

it seems strange that you have the problem, because it seems you're passing the entity manager from Symfony's container, and based on what is said in the following issues, this seems enough :thinking:

https://github.com/phpstan/phpstan-doctrine/issues/297 https://github.com/rectorphp/rector/issues/7911

nikophil commented 1 week ago

I'm closing this, since it's kinda not related to Foundry