Symfony table prefix for Doctrine

Symfony table prefix for Doctrine

As a Web Developer you will work with many types of hostings and sometimes you have only one database to use. To avoid conflicts with names of tables, you need a different table prefix for each project. By default Symfony doesn’t support such a functionality, but of course it’s easy to implement when needed.

You can use Doctrine Prefix Bundle, but there would be no fun. If you’re not a fan of installing a new bunle for every single functionality, you can write your own TablePrefixSubscriber.

Let’s start

Inside your bundle you have many folders, like Controller, Resources etc. Create a new one and name it Subscriber. Now add a new php file named TablePrefixSubscriber.php and paste the contents bellow. Don’t forget to change the namespace matching your bundle.

<?php

namespace Picios\Bundle\LibBundle\Subscriber;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;

/**
 * Description of TablePrefixSubscriber
 *
 * @author avanzu
 */
class TablePrefixSubscriber implements \Doctrine\Common\EventSubscriber {

    protected $prefix = '';

    public function __construct($prefix = '') {
        $this->prefix = (string) $prefix;
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) {
        $classMetadata = $eventArgs->getClassMetadata();

        if(strlen($this->prefix)) {
            if(0 !== strpos($classMetadata->getTableName(), $this->prefix)) {
                $classMetadata->setTableName($this->prefix . $classMetadata->getTableName());
            }
        }
        foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
            if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY) {
                if(!isset($classMetadata->associationMappings[$fieldName]['joinTable'])) { continue; }
                $mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name'];
                if(0 !== strpos($mappedTableName, $this->prefix)) {
                    $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
                }
            }
        }
    }
    public function getSubscribedEvents() {
        return array('loadClassMetadata');
    }
}

Next we need to notice Doctrine to use our Subscriber. Find the file Resource/config/services.yml in your bundle directory and add such a declaration in services section.

  picios.tblprefix_subscriber:
    class: Picios\Bundle\LibBundle\Subscriber\TablePrefixSubscriber
    arguments: [%table_prefix%]
    tags:
      - { name: doctrine.event_subscriber }

or xml

        <service id="picios.tblprefix_subscriber" class="Picios\Bundle\LibBundle\Subscriber\TablePrefixSubscriber">
            <argument>%table_prefix%</argument>
            <tag name="doctrine.event_subscriber" />
        </service>

As you can see, there’s a table_prefix parameter, which hasn’t been defined yet. So let’s go to app/config/parameters.yml and add another parameter:

    table_prefix: foo_

We can’t forget to update app/config/parameters.yml.dist with the same parameter to prevent loosing it after a composer action.

As a result, we get a ready to go Doctrine using table prefixes. Now we can easily create many projects within one database. Which is not recommended by the way, but the circumstances sometimes force us to break the programming lows.

Leave a comment

Your email address will not be published. Required fields are marked *