Генерация сущностей из таблиц базы данных в Doctrine2

К сожалению, способ описанный в официальной документации у меня выдал ошибку "failed to open stream: No such file or directory", поэтому можно воспользоваться официальными командами (о которых ниже) или спец. скриптом (который делает все тоже самое, но является более простым вариантом + генерирует гетеры и сетеры).

1. В файле config/packages/doctrine.yaml указываем:

doctrine:
    dbal:
        default_connection: connection_db
        connections:
            connection_db:
                host:     '%env(MYSQL_HOST)%'
                port:     '%env(MYSQL_PORT)%'
                dbname:   '%env(MYSQL_DATABASE)%'
                user:     '%env(MYSQL_USERNAME)%'
                password: '%env(MYSQL_PASSWORD)%'
                driver: 'pdo_mysql'
                server_version: '5'

    orm:
        auto_generate_proxy_classes: true
        default_entity_manager: entity_manager_db
        entity_managers:
            entity_manager_db:
                naming_strategy: doctrine.orm.naming_strategy.default
                default_repository_class:  Doctrine\ORM\EntityRepository
                auto_mapping: true
                mappings:
                    App:
                        is_bundle: false
                        type: xml
                        dir: '%kernel.project_dir%/EntityMapping'
                        prefix: 'App\Entity'
                        alias: App

2. Выполняем команду, которая в директории EntityMapping создаст xml-файлы с описанием сущностей:

bin/console doctrine:mapping:import "App\Entity" xml --path=EntityMapping

3. Выполняем команду, которая в директории src/App/Entity будут создаст классы сущностей:

bin/console doctrine:mapping:convert annotation ./src/

Генерируем по одной таблице

Согласно документации (кстати, может изменяться), для того, чтобы сгенерировать сущности из таблицы базы данных, нужно выполнить 2 шага:

1. сгенерировать yml из DDL таблиц, командой: 

app/console doctrine:mapping:import --force AccountBundle yml

где AccountBundle - директория по адресу src/AccountBundle, а yml - формат в котором будут сохранены данные

2. сгенерировать сущности из yml, командой:

app/console doctrine:generate:entities AccountBundle

Все вроде бы просто, и все должно сработать, но у меня возникли некоторые проблемы.

Итак, первая проблема - слишком большое кол-во таблиц (большой проект с шардированными таблицами), поэтому доктрина весела несколько часов, после чего мне это надоело и я начал разбираться, как мне исключить типичные таблицы и первым делом, я понял, что мне нужны базовые таблицы схемы public. Но, стоит обратить внимание, что если Вы используете PostgreSQL, то доктрина всем таблицам схемы public удаляет префикс public, именно поэтому регулярка в параметре schema_filter нацелена на проверку отсутствия точки:

# Doctrine Configuration
doctrine:
    dbal:
        default_connection: main
        connections:
            main:
                schema_filter: /^(?!.*\.).+$/

Если Вы использовали нестандартный тип данных, то Вы получите ошибку:

[Doctrine\DBAL\DBALException]                                                                            
Unknown database type _text requested, Doctrine\DBAL\Platforms\PostgreSQL92Platform may not support it.

В этом случае, в файле настроек app/config/app/config.yml нужно приравнять нестандартный тип (например your_type), к одному из стандартных, так:

doctrine:
    dbal:
        default_connection: main
        connections:
            main:
                mapping_types:
                    your_type: string

Если, Вы в какой-то таблице не используете PK, то получите ошибку:

[Doctrine\ORM\Mapping\MappingException]                                                                                             
Table balance_history has no primary key. Doctrine does not support reverse engineering from tables that don't have a primary key.

 Выход: добавить PK или игнорировать данную таблицу:

schema_filter: /^(?!.*table_witout_pk|.*\.).+$/

А что делать, если Вы не используете Symfony, то Вы можете задавать данный фильтр так:

/** @var \Doctrine\DBAL\Connection $connection */
$config = $connection->getConfiguration();

$config->setFilterSchemaAssetsExpression('/^(?!table_name_to_exclude).*$/');

Или наоборот, укажем только те таблицы, которые нам интересны:

$config->setFilterSchemaAssetsExpression('/^(recipes|ingredients).*$/');

В итоге, после выполнения 1-ой команды у Вас будут сгенерированы yml-файлы в директории:

src/AccountBundle/Resources/config/doctrine

p.s. для тех, кто хочет покопаться:

  • выборка схем и таблиц происходит в методе: \Doctrine\DBAL\Schema\AbstractSchemaManager::listTableNames
  • фильтрация заданная мной в конфигурации, происходит в методе: \Doctrine\DBAL\Schema\AbstractSchemaManager::filterAssetNames

Источники: 1 - 2


07.03.2011 17:52