@ simshaun ответ хороший, но есть проблема с отношениями «многие ко многим» и наследованием.
Если у вас есть родительский класс User
и дочерний класс Employee
, а Employee
принадлежит поле Many-to-Many $addresses
, таблица этого поля не будет иметь префикс.
Это из-за:
if ($classMetadata->isInheritanceTypeSingleTable() && !$classMetadata->isRootEntity()) {
// if we are in an inheritance hierarchy, only apply this once
return;
}
Класс пользователя (родитель)
namespace FooBundle\Bar\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* @ORM\Entity()
* @ORM\Table(name="user")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="type", type="string")
* @ORM\DiscriminatorMap({"user" = "User", "employee" = "\FooBundle\Bar\Entity\Employee"})
*/
class User extends User {
}
Класс работника (ребенок)
namespace FooBundle\Bar\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* @ORM\Entity()
*/
class Employee extends FooBundle\Bar\Entity\User {
/**
* @var ArrayCollection $addresses
*
* @ORM\ManyToMany(targetEntity="\FooBundle\Bar\Entity\Adress")
* @ORM\JoinTable(name="employee_address",
* joinColumns={@ORM\JoinColumn(name="employee_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="address_id", referencedColumnName="id")}
* )
*/
private $addresses;
}
Адресный класс (связь с Сотрудником)
namespace FooBundle\Bar\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* @ORM\Entity()
* @ORM\Table(name="address")
*/
class Address {
}
В исходном решении, если вы примените префикс pref_
к этому отображению, вы получите таблицы:
pref_user
pref_address
employee_address
Решение
Решением может быть изменение в ответе @simshaun пункта 4 следующим образом:
Создать MyBundle \ Subscriber \ TablePrefixSubscriber.php
<?php
namespace MyBundle\Subscriber;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class TablePrefixSubscriber implements \Doctrine\Common\EventSubscriber
{
protected $prefix = '';
public function __construct($prefix)
{
$this->prefix = (string) $prefix;
}
public function getSubscribedEvents()
{
return array('loadClassMetadata');
}
public function loadClassMetadata(LoadClassMetadataEventArgs $args)
{
$classMetadata = $args->getClassMetadata();
// Put the Many-yo-Many verification before the "inheritance" verification. Else fields of the child entity are not taken into account
foreach($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
if($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY
&& array_key_exists('name', $classMetadata->associationMappings[$fieldName]['joinTable']) // Check if "joinTable" exists, it can be null if this field is the reverse side of a ManyToMany relationship
&& $mapping['sourceEntity'] == $classMetadata->getName() // If this is not the root entity of an inheritance mapping, but the "child" entity is owning the field, prefix the table.
) {
$mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name'];
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
}
}
if($classMetadata->isInheritanceTypeSingleTable() && !$classMetadata->isRootEntity()) {
// if we are in an inheritance hierarchy, only apply this once
return;
}
$classMetadata->setTableName($this->prefix . $classMetadata->getTableName());
}
}
Здесь мы обрабатываем отношение Многие-ко-многим , прежде чем проверять, является ли класс дочерним для наследования, и мы добавляем $mapping['sourceEntity'] == $classMetadata->getName()
, чтобы добавить префикс только один раз, для объекта-владельца. поле.