How to setup table prefix in symfony2

后端 未结 6 1022
[愿得一人]
[愿得一人] 2020-11-27 16:41

Like in question topic, how can I setup default table prefix in symfony2?

The best if it can be set by default for all entities, but with option to override for indi

6条回答
  •  春和景丽
    2020-11-27 17:11

    @simshaun answer is good, but there is a problem with Many-to-Many relationships and inheritance.

    If you have a parent class User and a child class Employee, and the Employee own a Many-to-Many field $addresses, this field's table will not have a prefix. That is because of:

    if ($classMetadata->isInheritanceTypeSingleTable() && !$classMetadata->isRootEntity()) {
        // if we are in an inheritance hierarchy, only apply this once
        return;
    }
    

    User class (parent)

    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 {
    
    }
    

    Employee class (child)

    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;
    }
    

    Address class (relation with Employee)

    namespace FooBundle\Bar\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * User
     *
     * @ORM\Entity()
     * @ORM\Table(name="address")
     */
    class Address {
    
    }
    

    With the original solution, if you apply pref_ prefixe to this mapping, you will end up with tables :

    • pref_user
    • pref_address
    • employee_address

    Solution

    A solution can be to modify, in the answer of @simshaun, the point 4 like this:

    1. Create MyBundle\Subscriber\TablePrefixSubscriber.php

      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());
          }        
      }
      

    Here we handle the Many-to-Many relationship before verifying if the class is the child of an inheritance, and we add $mapping['sourceEntity'] == $classMetadata->getName() to add the prefix only one time, on the owning entity of the field.

提交回复
热议问题