在Doctrine中,如何从更新模式命令中忽略特定的列?

时间:2018-11-23 13:56:36

标签: php doctrine-orm doctrine

我有一个名为产品映射实体,只有两列:idname

如果我手动添加另一列,即直接使用SQL语句stock_qty,那么模式更新工具将会远程

如何防止Doctrine删除未映射到我的实体的自定义列?

相关问题:https://github.com/doctrine/doctrine2/issues/6434

2 个答案:

答案 0 :(得分:0)

您可以定义onSchemaColumnDefinitiononSchemaAlterTableRemoveColumn事件,并忽略这些列。

使用onSchemaColumnDefinition事件

在捆绑包中,创建例如。 src / AppBundle / EventListener / MyEventListener.php:

namespace AppBundle\EventListener;

use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;

class MyEventListener
{
    public function onSchemaAlterTableRemoveColumn(SchemaAlterTableRemoveColumnEventArgs $args)
    {
        $tableColumn = $args->getColumn();
        $table = $args->getTableDiff();
        if($table->name == 'tableName' && $tableColumn->getName() == 'columnName') {
            $args->preventDefault();
        }
    }
}

然后,在您的服务中注册事件监听器:

services:
    AppBundle\EventListener\MyEventListener:
    tags:
        - { name: doctrine.event_listener, event: onSchemaAlterTableRemoveColumn }

类似,您可以这样做:

使用onSchemaAlterTableRemoveColumn事件

在捆绑包中,创建例如。 src / AppBundle / EventListener / MyEventListener.php:

namespace AppBundle\EventListener;

use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;

class MyEventListener
{
    public function onSchemaColumnDefinition(SchemaColumnDefinitionEventArgs $args)
    {
        $tableColumn = $args->getTableColumn();
        $table = $args->getTable();
        if($table == 'tableName' && $tableColumn['Field'] == 'columnName') {
            $args->preventDefault();
        }
    }
}

然后,在您的 services.yml 中注册事件监听器:

services:
    AppBundle\EventListener\MyEventListener:
    tags:
        - { name: doctrine.event_listener, event: onSchemaColumnDefinition }

运行时:

php bin/console doctrine:schema:update --force

应忽略指定的列。 (在这种情况下,“ tableName”。“ columnName”将不会被删除)

参考文献:

Doctrine schema events

Doctrine Event Listeners

答案 1 :(得分:0)

Jannes Botis的回答非常有帮助。我有一些额外的问题,即使该列被忽略,索引和外键也被删除。此外,向下迁移继续尝试重新添加相关列。

接下来是基于其他答案的扩展解决方案。

<?php
namespace App\Listener\Doctrine;

use Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs;
use Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs;

class DoctrineListener
{
    protected $ignoreFields;

    public function __construct($doctrineIgnoreFields)
    {
        $this->ignoreFields = $doctrineIgnoreFields;
    }

    public function onSchemaAlterTableAddColumn(SchemaAlterTableAddColumnEventArgs $args)
    {
        $tableDiff = $args->getTableDiff();
        if (in_array($tableDiff->name, array_keys($this->ignoreFields))) {
            $tableName = $tableDiff->name;
            $tableColumn = $args->getColumn();
            if (in_array($tableColumn->getName(), $this->ignoreFields[$tableName])) {
                $columnName = $tableColumn->getName();

                if ($tableColumn->getName() == $columnName) {
                    $tableDiff = $args->getTableDiff();
                    unset($tableDiff->addedColumns[$columnName]);
                    foreach ($args->getTableDiff()->addedIndexes as $index => $addedIndex) {
                        foreach ($addedIndex->getColumns() as $column) {
                            if ($column === $columnName) {
                                unset($tableDiff->addedIndexes[$index]);
                                $args->preventDefault();
                            }
                        }
                    }
                    foreach ($args->getTableDiff()->addedForeignKeys as $index => $foreignKey) {
                        foreach ($foreignKey->getColumns() as $column) {
                            if ($column === $columnName) {
                                unset($tableDiff->addedForeignKeys[$index]);
                                $args->preventDefault();
                            }
                        }
                    }
                }
            }
        }
    }

    public function onSchemaAlterTableRemoveColumn(SchemaAlterTableRemoveColumnEventArgs $args)
    {
        $tableDiff = $args->getTableDiff();

        if (in_array($tableDiff->name, array_keys($this->ignoreFields))) {

            $tableName = $tableDiff->name;
            $tableColumn = $args->getColumn();

            if(in_array($tableColumn->getName(), $this->ignoreFields[$tableName])) {
                $columnName = $tableColumn->getName();
                $args->preventDefault();

                unset($tableDiff->removedColumns[$columnName]);
                foreach ($args->getTableDiff()->removedIndexes as $index => $removedIndex) {
                    foreach ($removedIndex->getColumns() as $column) {
                        if ($column === $columnName) {
                            unset($tableDiff->removedIndexes[$index]);
                            $args->preventDefault();
                        }
                    }
                }
                foreach ($args->getTableDiff()->removedForeignKeys as $index => $removedForeignKey) {
                    foreach ($removedForeignKey->getColumns() as $column) {
                        if ($column === $columnName) {
                            unset($tableDiff->removedForeignKeys[$index]);
                            $args->preventDefault();
                        }
                    }
                }
            }
        }
    }
}

配置:

services:
    # default configuration for services in *this* file
    _defaults:
        ...
        bind:
            $doctrineIgnoreFields:
                'table_a':
                    - 'column_a'
                    - 'column_b'
                'table_b':
                    - 'column_c'
                    - 'column_d'

             

    App\Listener\Doctrine\DoctrineListener:
        tags:
            - { name: doctrine.event_listener, event: onSchemaAlterTableAddColumn }
            - { name: doctrine.event_listener, event: onSchemaAlterTableRemoveColumn }

此解决方案已在symfony 4.4上进行了测试