我定义了一个Doctrine实体,用于映射到我的数据库中的视图。一切正常,实体关系按预期工作。
现在的问题是,当在CLI上运行orm:schema-manager:update
时,将为此实体创建一个表,这是我想要避免的。已经有一个视图用于这个实体,没有必要再创建一个表。
我能否注释实体,以便不创建表,同时仍然保持对所有实体相关功能(关联等)的访问权?
我定义了一个Doctrine实体,用于映射到我的数据库中的视图。一切正常,实体关系按预期工作。
现在的问题是,当在CLI上运行orm:schema-manager:update
时,将为此实体创建一个表,这是我想要避免的。已经有一个视图用于这个实体,没有必要再创建一个表。
我能否注释实体,以便不创建表,同时仍然保持对所有实体相关功能(关联等)的访问权?
基于ChrisR的原始答案,受Marco Pivetta的帖子启发,如果您正在使用Symfony2,则在此处添加解决方案:
看起来Symfony2没有使用原始Doctrine命令: \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand
相反,它使用了bundle中的命令: \Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand
因此,基本上必须扩展该类,最终得到:
src/Acme/CoreBundle/Command/DoctrineUpdateCommand.php
:
<?php
namespace App\Command;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class DoctrineUpdateCommand extends UpdateSchemaDoctrineCommand
{
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui): ?int
{
$ignoredEntities = [
'App\Entity\EntityToIgnore',
];
$metadatas = array_filter($metadatas, static function (ClassMetadata $classMetadata) use ($ignoredEntities) {
return !in_array($classMetadata->getName(), $ignoredEntities, true);
});
return parent::executeSchemaCommand($input, $output, $schemaTool, $metadatas, $ui);
}
}
return parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadatas);
来取得更好的效果。 - Jugali Lakota\Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand
子类化为自己的CLI命令。在该子类中过滤传递给executeSchemaCommand()
的$metadatas
数组,然后将其传递给父函数。
只需将此新的子类命令附加到您在Doctrine CLI脚本中使用的ConsoleApplication上,就完成了!
下面是扩展命令,在生产环境中,您可能希望从配置文件或其他地方获取$ignoredEntities
属性,这应该能帮助您。
<?php
use Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand;
use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class My_Doctrine_Tools_UpdateCommand extends UpdateCommand
{
protected $name = 'orm:schema-tool:myupdate';
protected $ignoredEntities = array(
'Entity\Asset\Name'
);
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui)
{
/** @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
$newMetadata = [];
foreach ($metadatas as $metadata) {
if (!in_array($metadata->getName(), $this->ignoredEntities)) {
$newMetadata[] = $metadata;
}
}
return parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadata, $ui);
}
}
PS:感谢Marco Pivetta让我走上了正确的道路。https://groups.google.com/forum/?fromgroups=#!topic/doctrine-user/rwWXZ7faPsA
return parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadatas);
来取得更好的效果。 - Jugali Lakota虽然比较老,但也有一种值得注意的解决方案,使用 Doctrine2
的 postGenerateSchema
事件监听器 - 对我来说,这比重写 Doctrine
类更好:
namespace App\Doctrine\Listener;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
/**
* IgnoreTablesListener class
*/
class IgnoreTablesListener
{
private $ignoredTables = [
'table_name_to_ignore',
];
public function postGenerateSchema(GenerateSchemaEventArgs $args)
{
$schema = $args->getSchema();
$tableNames = $schema->getTableNames();
foreach ($tableNames as $tableName) {
if (in_array($tableName, $this->ignoredTables)) {
// remove table from schema
$schema->dropTable($tableName);
}
}
}
}
同时注册监听器:
# config/services.yaml
services:
ignore_tables_listener:
class: App\Doctrine\Listener\IgnoreTablesListener
tags:
- {name: doctrine.event_listener, event: postGenerateSchema }
Schema
实例 - 没有执行。在这种情况下,dropTable
表示从Schema
实例中取消设置表。如果您调用:d:s:u --dump-sql
,则会收到已生成模式SQL的忽略表。 - Kamil AdryjanekgetEntityManager
方法。 - Jugali LakotaSchemaIgnoreClasses
实体管理器配置选项,该选项基本上会忽略任何模式操作中配置的类。schema_ignore_classes
键,像这样:doctrine:
dbal:
# your dbal configuration
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Main'
prefix: 'App\Entity\Main'
alias: Main
schema_ignore_classes:
- Reference\To\My\Class
- Reference\To\My\OtherClass
$schema->getTableNames()
没有起作用(我不知道为什么)。
所以:
<?php
namespace AppBundle\EventListener;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
class IgnoreTablesListener extends UpdateSchemaDoctrineCommand
{
private $ignoredEntities = [
'YourBundle\Entity\EntityYouWantToIgnore',
];
/**
* Remove ignored tables /entities from Schema
*
* @param GenerateSchemaEventArgs $args
*/
public function postGenerateSchema(GenerateSchemaEventArgs $args)
{
$schema = $args->getSchema();
$em = $args->getEntityManager();
$ignoredTables = [];
foreach ($this->ignoredEntities as $entityName) {
$ignoredTables[] = $em->getClassMetadata($entityName)->getTableName();
}
foreach ($schema->getTables() as $table) {
if (in_array($table->getName(), $ignoredTables, true)) {
// remove table from schema
$schema->dropTable($table->getName());
}
}
}
}
并注册一个服务
# config/services.yaml
services:
ignore_tables_listener:
class: AppBundle\EventListener\IgnoreTablesListener
tags:
- {name: doctrine.event_listener, event: postGenerateSchema }
工作得很好! ;)