Search code examples
phpdoctrine-orm

Automatically generate sub-models for new OneToOne columns?


Say I have a Doctrine entity like so:

#[ORM\Entity]
#[ORM\Table(name: 'product')]
class Product
{
    #[ORM\Id]
    #[ORM\Column(type: DBALTYPES::INTEGER)]
    #[ORM\GeneratedValue]
    private int $id;
    #[ORM\Column(type: DBALTYPES::STRING, length: 50)]
    private string $sku;
    
    ...
}

I update the DB to match, and it goes into production. Now imagine I want to add a new OneToOne column, like so:

#[ORM\Entity]
#[ORM\Table(name: 'product')]
class Product
{
    #[ORM\Id]
    #[ORM\Column(type: DBALTYPES::INTEGER)]
    #[ORM\GeneratedValue]
    private int $id;
    #[ORM\Column(type: DBALTYPES::STRING, length: 50)]
    private string $sku;
    #[ORM\OneToOne(targetEntity: Attribute::class)]
    private Attribute $name;
    
    public function __construct()
    {
        $this->name = new Attribute();
    }
    
    ...
}

All existing Products were created before the $name property was added, so updating the DB adds the name_id column but leaves it defaulted to null. This is a problem because $name is a non-nullable property but it will be undefined except for newly-created products.

Is there a way to have Doctrine generate the required sub-models automatically when updating the DB with orm:schema-tool:update? Or do I have to do this manually somehow?


Solution

  • I would suggest you create a migration console make:mig

    final class Version20230613081942 extends AbstractMigration
    {
        public function getDescription(): string
        {
            return '';
        }
    
        public function up(Schema $schema): void
        {
            // this up() migration is auto-generated, please modify it to your needs
            $this->addSql('UPDATE product SET name = (SELECT id FROM attribute LIMIT 1) WHERE name IS NULL;');
        }
    
        public function down(Schema $schema): void
        {
            // this down() migration is auto-generated, please modify it to your needs
            $this->addSql('UPDATE product SET name = NULL');
        }
    }
    

    Adding an index to that column will also make the update faster

    #[ORM\Table(indexes: new Index(name: 'index_name', columns: ['attribute_id']))]