phpdoctrine-ormdoctrinemezzionaming-strategy

Naming Strategy for table and column names (Doctrine ORM)


Is it possible to have a naming strategy take care of mapping table and column names in Doctrine ORM?

Right now all names are specified via annotation in the entity classes, e.g.

<?php

namespace App\Entity;

use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 * @ORM\Table(name="role")
 */
class Role
{
    /**
     * @ORM\Id()
     * @ORM\Column(name="id", type="guid")
     * @ORM\GeneratedValue(strategy="NONE")
     * @var string
     */
    private $id;

    /**
     * @ORM\Column(name="created_at", type="datetime")
     * @var \DateTimeImmutable
     */
    private $createdAt;

    /**
     * @ORM\Column(name="created_by", type="string")
     * @var string
     */
    private $createdBy;

    // [..]

}

Table and column names are all snake_case while class and property names are all camelCase.

I've tried to remove table and column name declarations in the entity classes and provided a naming strategy` via configuration, trying to set it in the following two ways.

<?php

use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;

return [
    'doctrine' => [
        'connection' => [
            // [..]
        ],
        'driver' => [
            // [..]
        ],
        'annotation' => [
            // [..]
        ],
        'entity_managers' => [
            'default' => [
                'naming_strategy' => UnderscoreNamingStrategy::class,
            ],
        ],
        'orm' => [
            'naming_strategy' => UnderscoreNamingStrategy::class,
        ],
    ],
];

When trying to retrieve an entity, an error is thrown.

Doctrine\DBAL\Exception\InvalidFieldNameException: An exception occurred while executing &#039;SELECT t0.id AS id_1, t0.createdAt AS createdAt_2, t0.createdBy AS createdBy_3, t0.updatedAt AS updatedAt_4, t0.updatedBy AS updatedBy_5, t0.name AS name_6, t0.desc AS desc_7, t0.isCore AS isCore_8 FROM Role t0&#039;:

SQLSTATE[42S22]: Column not found: 1054 Unknown column &#039;t0.createdAt&#039; in &#039;field list&#039; in file C:\project\path\vendor\doctrine\dbal\lib\Doctrine\DBAL\Driver\AbstractMySQLDriver.php on line 60

Solution

  • After a bit of studying and experimenting, I got the following solution to work in a Zend Expressive application.

    Configure naming strategy in doctrine.local.php

    <?php
    
    declare(strict_types = 1);
    
    use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
    
    return [
        'doctrine' => [
            'connection' => [
                // [..]
            ],
            'driver' => [
                // [..]
            ],
            'annotation' => [
                // [..]
            ],
            'configuration' => [
                'orm_default' => [
                    'naming_strategy' => UnderscoreNamingStrategy::class,
                ],
            ],
        ],
    ];
    

    Implement a factory for the naming strategy

    <?php
    
    namespace App;
    
    use Interop\Container\ContainerInterface;
    use Zend\ServiceManager\Factory\FactoryInterface;
    
    class NamingStrategyFactory implements FactoryInterface
    {
        public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
        {
            return new $requestedName();
        }
    }
    
    

    Register factory in ConfigProvider.php

    <?php
    
    declare(strict_types = 1);
    
    namespace App;
    
    use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
    
    class ConfigProvider
    {
        public function __invoke()
        {
            return [
                'dependencies' => $this->getDependencies(),
            ];
        }
    
        public function getDependencies(): array
        {
            return [
                'invokables' => [
                ],
                'factories' => [
                    // [..]
                    UnderscoreNamingStrategy::class => NamingStrategyFactory::class,
                ],
            ];
        }
    
    }