Intereting Posts
Должен ли я создать новую таблицу в моей базе данных? Передача переменной FROM flash в HTML / php Автоматическое добавление товара в корзину, когда другой товар присутствует в пурпурной тележке Как я могу использовать php для заполнения файла manifest.json? Как получить значения post <td> </ td> Zend Framework 2: форматирование даты в представлении Отправить с бесплатной учетной записи Gmail через PHP Стиль неизученных связей с DOM и xpath Nginx: WordPress в качестве подкаталога на маршрутах Rails неправильно Лучший способ распознать файл в php AngularJS – перенаправление страницы на другую страницу в угловых js при попытке получить параметр из url Как я могу обойти отсутствие блока finally в PHP? Какова наилучшая практика для включения файлов PHP? как создать имя пользователя: пароль в файле .htpasswd на сервере Wamp, установленном на ОС Windows laravel eloquent сортировать по отношениям

Как настроить префикс таблицы в symfony2

Как в вопросе вопроса, как я могу настроить префикс таблицы по умолчанию в symfony2?

Лучше всего, если он может быть установлен по умолчанию для всех объектов, но с возможностью переопределения для отдельных.

Related of "Как настроить префикс таблицы в symfony2"

Только подумав об этом, я хотел бы пролить свет на то, как это сделать.

Symfony 2 & Doctrine 2.1
Примечание. Я использую YML для конфигурации, так что это то, что я покажу.

инструкции

  1. Откройте ресурсы своего ресурса / config / services.yml

  2. Определите префикс таблицы:
    Обязательно измените mybundle и myprefix_

    parameters: mybundle.db.table_prefix: myprefix_ 
  3. Добавить новую услугу:

     services: mybundle.tblprefix_subscriber: class: MyBundle\Subscriber\TablePrefixSubscriber arguments: [%mybundle.db.table_prefix%] tags: - { name: doctrine.event_subscriber } 
  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(); if ($classMetadata->isInheritanceTypeSingleTable() && !$classMetadata->isRootEntity()) { // if we are in an inheritance hierarchy, only apply this once return; } $classMetadata->setTableName($this->prefix . $classMetadata->getTableName()); 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 $mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name']; $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName; } } } } 
  5. Дополнительный шаг для пользователей postgres: сделать что-то похожее для последовательностей

  6. наслаждаться

Альтернативный ответ

Это обновление с учетом новых функций, доступных в Doctrine2.

Стратегия именования Doctrine2

Doctrine2 использует классы NamingStrategy которые реализуют преобразование из имени класса в имя таблицы или из имени свойства в имя столбца.

DefaultNamingStrategy просто находит «короткое имя класса» (без его пространства имен), чтобы вывести имя таблицы.

UnderscoreNamingStrategy делает то же самое, но также уменьшает и «сокращает» «короткое имя класса».

Класс CustomNamingStrategy может расширить один из указанных выше (по вашему усмотрению) и переопределить методы classToTableName и joinTableName чтобы вы могли указать, как должно быть построено имя таблицы (с использованием префикса).

Например, мой класс CustomNamingStrategy расширяет UnderscoreNamingStrategy и находит имя пакета на основе соглашений об именах и использует это как префикс для всех таблиц.


Стратегия именования Symfony2

Использование вышеприведенного в Symfony2 требует объявления класса CustomNamingStragery в качестве службы, а затем ссылки на него в вашем конфиге:

 doctrine: # ... orm: # ... #naming_strategy: doctrine.orm.naming_strategy.underscore naming_strategy: my_bundle.naming_strategy.prefixed_naming_strategy 

За и против

Плюсы:

  • запуск одного фрагмента кода для выполнения одной задачи – ваш класс стратегии именования вызывается напрямую и используется его выход;
  • ясность структуры – вы не используете события для запуска кода, которые изменяют вещи, которые уже были созданы другим кодом;
  • лучший доступ ко всем аспектам соглашений об именах;

Минусы:

  • нулевой доступ к метаданным сопоставления – у вас есть только тот контекст, который был предоставлен вам в качестве параметров (это тоже может быть хорошо, потому что оно приводит скорее конвенцию, чем исключение);
  • нуждается в доктрине 2.3 (не такая уж большая проблема теперь, возможно, в 2011 году, когда был задан этот вопрос :-));

Ответ Simshaun работает нормально, но имеет проблему, когда у вас есть однонаправленное наследование, с ассоциациями над дочерним объектом. Первый if-statement возвращает, когда объект не является rootEntity, в то время как этот объект может все еще иметь ассоциации, которые должны быть префиксом.

Я исправил это, настроив подписчика на следующее:

 <?php namespace MyBundle\Subscriber; use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Event\LoadClassMetadataEventArgs; use Doctrine\ORM\Mapping\ClassMetadataInfo; class TablePrefixSubscriber implements EventSubscriber { protected $prefix = ''; /** * Constructor * * @param string $prefix */ public function __construct($prefix) { $this->prefix = (string) $prefix; } /** * Get subscribed events * * @return array */ public function getSubscribedEvents() { return array('loadClassMetadata'); } /** * Load class meta data event * * @param LoadClassMetadataEventArgs $args * * @return void */ public function loadClassMetadata(LoadClassMetadataEventArgs $args) { $classMetadata = $args->getClassMetadata(); // Only add the prefixes to our own entities. if (FALSE !== strpos($classMetadata->namespace, 'Some\Namespace\Part')) { // Do not re-apply the prefix when the table is already prefixed if (false === strpos($classMetadata->getTableName(), $this->prefix)) { $tableName = $this->prefix . $classMetadata->getTableName(); $classMetadata->setPrimaryTable(['name' => $tableName]); } foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) { if ($mapping['type'] == ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide'] == true) { $mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name']; // Do not re-apply the prefix when the association is already prefixed if (false !== strpos($mappedTableName, $this->prefix)) { continue; } $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName; } } } } } 

Однако это имеет недостаток; Неправильно выбранный префикс может вызвать конфликты, когда он фактически уже является частью имени таблицы. Например, используя префикс 'co', когда theres table, называемый «content», приведет к таблице без префикса, поэтому использование подчеркивания типа «co_» уменьшит этот риск.

Ответ @simshaun хорош, но есть проблема с отношениями «Много-ко-многим» и наследованием.

Если у вас есть родительский класс « User и дочерний класс « Employee , а « Employee владеет полем « Много-ко-многим» , то в таблице этого поля не будет префикса. Это из-за:

 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_ к этому сопоставлению, вы получите таблицы:

  • pref_user
  • pref_address
  • employee_address

Решение

Решением может быть изменение в ответе @simshaun точки 4 следующим образом:

  1. Создать 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()); } } 

Здесь мы обрабатываем отношения Many-to-Many, прежде чем проверять, является ли класс дочерним наследование, и добавляем $mapping['sourceEntity'] == $classMetadata->getName() чтобы добавить префикс только один раз, на владеющей субъектом поля.

Я не собираюсь реализовывать решение, которое связано с событием ловли (проблема с производительностью), поэтому я попробовал альтернативное решение, но оно не работает для меня. Я добавлял JMSPaymentCoreBundle и хотел добавить префикс в таблицы платежей. В этом пакете определение таблиц содержится в каталоге ресурсов \ config \ doctrine (формат xml). Я наконец нашел это решение:

1) скопируйте каталог доктрины, содержащий определения в таблице, и вставьте его в мой основной пакет

2) измените имя таблиц в определениях, чтобы добавить префикс

3) объявите его в свой config.yml в разделе doctrine / orm / entity manager / mapping (каталог – это каталог, в который были помещены измененные определения):

 doctrine: orm: ... entity_managers: default: mappings: ... JMSPaymentCoreBundle: mapping: true type: xml dir: "%kernel.root_dir%/Resources/JMSPayment/doctrine" alias: ~ prefix: JMS\Payment\CoreBundle\Entity is_bundle: false