doctrine / orm

Doctrine Object Relational Mapper (ORM)
https://www.doctrine-project.org/projects/orm.html
MIT License
9.93k stars 2.52k forks source link

Commands using DisconnectedClassMetadataFactory fails with embedded type without columnPrefix #7897

Open denissolomkin opened 4 years ago

denissolomkin commented 4 years ago

Bug Report

Commands using DisconnectedClassMetadataFactory fails with embedded type without columnPrefix. Actual for commands: GenerateEntitiesCommand, ConvertMappingCommand, ImportMappingDoctrineCommand

Q A
BC Break no
Version 2.6.3

Summary

Fails in commands, like as doctrine:mapping:convert, which using DisconnectedClassMetadataFactory (it always returns StaticReflectionService with dummy public function getClass($class) { return null; }), when Entity has embedded field without prefixColumn (if you want use fully auto-generated column name), because reflection is not object

\Doctrine\ORM\Mapping\ClassMetadataInfo:

    public function inlineEmbeddable($property, ClassMetadataInfo $embeddable)
    {
        foreach ($embeddable->fieldMappings as $fieldMapping) {
            $fieldMapping['originalClass'] = isset($fieldMapping['originalClass'])
                ? $fieldMapping['originalClass']
                : $embeddable->name;
            $fieldMapping['declaredField'] = isset($fieldMapping['declaredField'])
                ? $property . '.' . $fieldMapping['declaredField']
                : $property;
            $fieldMapping['originalField'] = isset($fieldMapping['originalField'])
                ? $fieldMapping['originalField']
                : $fieldMapping['fieldName'];
            $fieldMapping['fieldName'] = $property . "." . $fieldMapping['fieldName'];

            if (! empty($this->embeddedClasses[$property]['columnPrefix'])) {
                $fieldMapping['columnName'] = $this->embeddedClasses[$property]['columnPrefix'] . $fieldMapping['columnName'];
            } elseif ($this->embeddedClasses[$property]['columnPrefix'] !== false) {
                $fieldMapping['columnName'] = $this->namingStrategy
                    ->embeddedFieldToColumnName(
                        $property,
                        $fieldMapping['columnName'],
         >>>>>>>>>>>>   $this->reflClass->name,   <<<<<<<<< 
                        $embeddable->reflClass->name
                    );
            }

            $this->mapField($fieldMapping);
        }
    }

Current behavior


In ClassMetadataInfo.php line 3257:

  [Symfony\Component\Debug\Exception\ContextErrorException]  
  Notice: Trying to get property of non-object               

Exception trace:
 () at /www/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php:3257
 Doctrine\ORM\Mapping\ClassMetadataInfo->inlineEmbeddable() at /www/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php:200
 Doctrine\ORM\Mapping\ClassMetadataFactory->doLoadMetadata() at /www/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php:332
 Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->loadMetadata() at /www/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php:78
 Doctrine\ORM\Mapping\ClassMetadataFactory->loadMetadata() at /www/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php:225
 Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->getMetadataFor() at /www/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php:115
 Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->getAllMetadata() at /www/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php:135
 Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand->execute() at /www/vendor/doctrine/doctrine-bundle/Command/Proxy/ConvertMappingDoctrineCommand.php:37
 Doctrine\Bundle\DoctrineBundle\Command\Proxy\ConvertMappingDoctrineCommand->execute() at /www/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:255
 Symfony\Component\Console\Command\Command->run() at /www/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:971
 Symfony\Component\Console\Application->doRunCommand() at /www/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:86
 Symfony\Bundle\FrameworkBundle\Console\Application->doRunCommand() at /www/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:248
 Symfony\Component\Console\Application->doRun() at /www/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:74
 Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /www/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:148
 Symfony\Component\Console\Application->run() at /www/bin/console:49

How to reproduce

Add:

/** @Entity */
class User
{
    /** @Embedded(class = "Address") */
    private $address;
}

/** @Embeddable */
class Address
{
    /** @Column(type = "string") */
    private $street;

    /** @Column(type = "string") */
    private $city;
}

Run: php bin/console doctrine:mapping:convert yml folder-to-dist

How to reproduce

Command execution without exception

Ocramius commented 4 years ago

Does this also affect 2.6.x?

denissolomkin commented 4 years ago

Yes, for 2.6.3 is actual too

frank9999 commented 4 years ago

I also have this issue on 2.7.0

./bin/console doctrine:mapping:convert xml ./config/doctrine

In ClassMetadataInfo.php line 3328:

Notice: Trying to get property 'name' of non-object

I upgraded my projects to Symfony 5, which give me the following deprecation warnings:

YAML mapping driver is deprecated and will be removed in Doctrine ORM 3.0, please migrate to annotation or XML driver.

More people willl probably encounter this issue as soon as they start upgrading to Symfony 5 en start fixing their deprecation warnings.

ruudk commented 4 years ago

For anybody encountering this same issue after upgrading to ORM 2.7.0, this worked for me: Open vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php and remove:

/**
     * @return \Doctrine\Common\Persistence\Mapping\StaticReflectionService
     */
    public function getReflectionService()
    {
        return new StaticReflectionService();
    }

Run the command. Only downside is that you'll have to manually fix all the embeddables as the converter doesn't support that correctly.