SchemaTool: Create Table IF NOT EXISTS

Hallo,

Kennt Ihr einen Weg das SchemaTool so zu nützen, dass Tabellen nur neu angelegt werden, wenn Sie noch nicht existieren?

    /**
     * Creates the schemas for the additional models
     */
    public static function createSchemas()
    {
        $tool = new SchemaTool(Shopware()->Container()->get('models'));
        $classes = [
            Shopware()->Container()->get('models')->getClassMetadata(Discount::class),
            Shopware()->Container()->get('models')->getClassMetadata(AccessCode::class)
        ];
        $tool->createSchema($classes);
    }

Wenn ich die Tabellen beim Uninstall nicht löschen möchte führt das beim erneuten Install des Plugins aktuell zu einer Exception.
Eine $tool->hasTable() Methode oder einen entsprechenden Parameter beim Anlegen habe ich bislang leider nicht gefunden.

Kennt ihr hier einen Weg?

Danke & liebe Grüße

Versuch erstmal die Klassen zu löschen und dann zu erzeugen.

$tool->dropSchema($classes);
$tool->createSchema($classes);

 

Durch dropSchema würde der Table gelöscht werden, was Synonymous vermutlich auch bei der Installation nicht möchte („Wenn ich die Tabellen beim Uninstall nicht löschen möchte…“).
Ich habe ebenfalls ein Plugin, dessen Daten ich nicht verlieren möchte, wenn das Plugin deinstalliert oder neuinstalliert wird.

Ich habe das derzeit so gelöst, dass ich bei der Installation eine eigene PDO Connection öffne und das „CREATE TABLE IF NOT EXISTS“ statement absetze. 
Falls es einen bessere Lösung dafür gibt, wäre ich für Feedback dankbar.

Hallo Synonymous,

der SchemaManager von Doctrine bietet die Methode tablesExist(array $tableNames) (siehe: http://www.doctrine-project.org/api/dbal/2.4/class-Doctrine.DBAL.Schema.AbstractSchemaManager.html#_tablesExist ).

Deine Methode könnte damit in etwa so aussehen (ungetestet):

/**
 * Creates the schemas for the additional models
 */
public static function createSchemas() {
    $tool = new SchemaTool(Shopware()->Container()->get('models'));
    $classes = [
        Shopware()->Container()->get('models')->getClassMetadata(Discount::class),
        Shopware()->Container()->get('models')->getClassMetadata(AccessCode::class)
    ];

    // you could (and should) also implement a method which dynamically returns an array of
    // table names based on the ClassMetadata in $classes
    $tableNames = array("table1", "table2");

    $schemaManager = Shopware()->Container()->get('models')->getConnection()->getSchemaManager();
    if (!$schemaManager->tablesExist($tableNames)) {
        $tool->createSchema($classes);
    }
}

Viele Grüße

3 Likes

@pwagner du hast rechts, habe das nicht gelesen :D.

@kcon schrieb:

Hallo Synonymous,

der SchemaManager von Doctrine bietet die Methode tablesExist(array $tableNames) (siehe: http://www.doctrine-project.org/api/dbal/2.4/class-Doctrine.DBAL.Schema.AbstractSchemaManager.html#_tablesExist ).

Deine Methode könnte damit in etwa so aussehen (ungetestet):

/**

  • Creates the schemas for the additional models
    */
    public static function createSchemas() {
    $tool = new SchemaTool(Shopware()->Container()->get(‘models’));
    $classes = [
    Shopware()->Container()->get(‘models’)->getClassMetadata(Discount::class),
    Shopware()->Container()->get(‘models’)->getClassMetadata(AccessCode::class)
    ];

// you could (and should) also implement a method which dynamically returns an array of
// table names based on the ClassMetadata in $classes
$tableNames = array(“table1”, “table2”);

$schemaManager = Shopware()->Container()->get(‘models’)->getConnection()->getSchemaManager();
if (!$schemaManager->tablesExist($tableNames)) {
$tool->createSchema($classes);
}
}

Viele Grüße

 Man braucht vlt. eine Mischung von createSchema mit updateSchema. Wenn in der Zwischen eine neue Version des Plugins gibt, würde diese Funktion nicht mehr richtig funktionieren.

Deine Methode könnte damit in etwa so aussehen (ungetestet):

/**
 * Creates the schemas for the additional models
 */
public static function createSchemas() {
    $tool = new SchemaTool(Shopware()->Container()->get('models'));
    $tables = [
        "table1" => Shopware()->Container()->get('models')->getClassMetadata(Discount::class),
        "table2" => Shopware()->Container()->get('models')->getClassMetadata(AccessCode::class)
    ];

    $schemaManager = Shopware()->Container()->get('models')->getConnection()->getSchemaManager();
    foreach($tables as $tableName => $class){

    
      if (!$schemaManager->tablesExist($tableName)) {
          $tool->createSchema([$class]);
      }else{
          $tool->updateSchema([$class], true); //true - saveMode and not delete other schemas
      }
    }
}

 

2 Likes

Guten Morgen zusammen,

Eine ifTableExists Methode habe ich eigentlich gesucht. Die gibt es in meiner Version des SchemaTools (Doctrine\ORM\Tools) aber leider nicht!? :slight_smile:

Möglicherweise gibt es die in einer anderen Doctrine Version - in jener die bei Shopware genutzt wird fehlt sie aber. Oder ich bin gerade völlig am falschen Dampfer…

Liebe Grüße

@Synonymous schrieb:

Eine ifTableExists Methode habe ich eigentlich gesucht. Die gibt es in meiner Version des SchemaTools (Doctrine\ORM\Tools) aber leider nicht!?

Das ist richtig, denn die Methode heißt  tablesExist statt ifTableExists und ist im SchemaManager anstatt des SchemaTools implementiert.

Deswegen auch die Zeile

$schemaManager = Shopware()->Container()->get('models')->getConnection()->getSchemaManager();

Ansonsten tut sie aus meiner Sicht genau das, wonach Du gesucht hast: Man kann damit vor dem Erstellen von Schemata prüfen, ob die Tabellennamen schon existieren.

Viele Grüße

1 Like

Alles klar… hatte nicht gesehen, dass Du den Manager statt den Tools heranziehst…
Danke, werde ich gleich mal so umsetzen. Thumb-Up

Vielen Dank für eure Ideen @kcon und @alexxxbing. Mit “getTableName” kann man sich einfach den Tabellennamen aus der Klasse holen und muss diesen nicht manuell im Installer hinterlegen:

    private function createSchema()
    {
        $tool = new SchemaTool($this->modelManager);
        $classes = [
            $this->modelManager->getClassMetadata(Confirmation::class),
            $this->modelManager->getClassMetadata(Shipment::class),
            $this->modelManager->getClassMetadata(ShipmentDetail::class),
            $this->modelManager->getClassMetadata(StockList::class)
        ];

        /** @var \Doctrine\DBAL\Schema\AbstractSchemaManager $schemaManager */
        $schemaManager = $this->modelManager->getConnection()->getSchemaManager();

        /** @var \Doctrine\ORM\Mapping\ClassMetadata $class */
        foreach ($classes as $class) {
            if (!$schemaManager->tablesExist([$class->getTableName()])) {
                $tool->createSchema([$class]);
            } else {
                $tool->updateSchema([$class], true); //true - saveMode and not delete other schemas
            }
        }
    }