Doctrine und Symfony2 ORM Entities aus Datenbank erzeugen

Sa, 21.06.2014 - 11:53 -- Daniel Espendiller

Normalweise nutzt man in Symfony2 und Doctrine Projekten Yaml oder Annotations um dann über doctrine:schema:update die Datenbankstruktur anzulegen bzw. aktualisieren. Wenn man allerdings auf eine fremde Datenbank angewiesen ist funktioniert dieses Vorgehen meist nicht mehr. Mittels doctrine:mapping:import besteht jedoch auch die Möglichkeit aus einer Datenbank die Doctrine Entities samt Konfiguration zu generieren. Alles geht hier allerdings nicht automatischen und einige Dinge gibt es noch zu beachten

Tabelle filtern

Nicht jede Datenbank mit allen Tabellen lassen sich direkt ins ORM Modell übertragen. Es gibt diverse Szenarien, wo kein automatischen umwandeln möglich ist. Doctrine parst alle Tabellen in einer Datenbank, kann hier nur eine Tabelle nicht konvertiert werden, so bricht der Importvorgang komplett ab. Möchte man diese Tabelle einfach ignorieren, kann man sie über schema_filter und eines Regulären Ausdruck überspringen lassen. Doctrine bietet war auch einen Paramater --filter, dieser greift aber erst nach dem Einlesen der Datenbank Struktur, also wenn der Fehler bereits aufgetreten ist.

Eine Konfiguration mit Filter für einer zweiter Doctrine EntityManager Instanz lässt dich dann über die Symfony2 Config wie folgt abbilden:

# app/config.yml
doctrine:
    dbal:
        default_connection:       default
        connections:
            default:
                dbname:           "%database_name%"
                [...]
                charset:          UTF8
            legacy:
                dbname:           "%database_desk_name%"
                dbname:           "%database_name%"
                [...]
                charset:          UTF8
 
                schema_filter: ~^(?invalid_table)~

Doctrine ORM Whitelist Tabellen

Man kann die Logik auch umdrehen und nur die Tabellen freigeben, die explizit von Doctrine genutzt werden sollen. Unbekannte Tabellen werden somit einfach übersprungen. Dazu dann einfach den Regulären Ausdruck von schema_filter anpassen.

# app/config.yml
doctrine:
    dbal:
        connections:
            legacy:
                schema_filter: ~^(my_table_name_1|my_table_name_1)$~

Enum Felder in Doctrine

Da Enum Felder nicht von allen SQL Datenbanken unterstützt wird, ist dieser Feldtyp in Doctrine erst einmal nicht aktiv. Durch setzen von mapping_types kann man Doctrine allerdings anweisen dieses Feld als String Typ zu nutzen. Man kann somit die Tabelle importieren.

Fatal error: Uncaught exception 'Doctrine\DBAL\DBALException' with message 'Unknown database type enum requested, Doctrine\DBAL\Platforms\MySqlPlatform may not support it.'

# app/config.yml
doctrine:
    dbal:
        connections:
            legacy:
                mapping_types:
                    enum: string

Tabellen ohne Primary Key

Nicht alle "Strukturelle Fehler" lassen sich übergeben. Tabellen ohne Primary Key werden von Doctrine nicht Unterstützt. Da es sich hierbei (hoffentlich) meist nur um ManyToMany Tabellen handelt, kann man das Mapping manuell anlegen und die Beziehungstabelle über die schema_filter ignorieren

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

Primär Key in Relation Mappings

Manchmal kann es auch vorkommen, dass "Primäre Schlüssel" einer Tabelle aus mehreren Felder besteht und diese zusätzlich Bestandteil einer ManyToOne oder OneToMany Beziehung sind. Das entsprechende Feld muss dazu einfach als associationKey definiert werden.

MyBundle\Entity\Foo:
    type: entity
    table: foo_table
    id:
        field_1:
            type: integer
        field_2:
            associationKey: true
    manyToOne:
        mlmLevel:
            targetEntity: Bar\ClassName
            joinColumn:
                name: field_2
                referencedColumnName: foreign_id

Doctrine Entity Klassen generieren

doctrine:mapping:import erstellt hier die reinen Konfigurationsdateien wenn mal Yaml auf Ausgabe nutzt und legt die entsprechenden Datei in einem definierten Bundle ab MyTargetBundle/Resource/config/doctrine/TableName.orm.yml. Eventuell müssen also noch die Klassen selber mittels Konsolenbefehl erzeugt werden.

php app/console doctrine:mapping:import --em=legacy MyTargetBundle yaml
---
php app/console doctrine:generate:entities MyTargetBundle