Question

I have created a Bundle (called MYBUNDLE) with just 2 entities: Menu and Group. Both were declared as mappedSuperclass because I need this bundle could be use for other projects. As a condition, projects will have to extend from these classes to customize them by setting the tables name or adding some fields. For instance:

Classes into MYBUNDLE:

class Group{        
    protected $id;
    protected $menus;
}
class Menu{        
    protected $id;
    protected $groups;
}

YML for mapping my entities from MYBUNDLE

Project\MYBUNDLE\Entity\Menu:
    type: mappedSuperclass    
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO

Project\MYBUNDLE\Entity\Group:
    type: mappedSuperclass
    fields:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    manyToMany:
        menus:
            targetEntity: Menu
            joinTable:
                name: sf_group_menu
                joinColumns:
                    sf_group_id:
                        referencedColumnName: id
                inverseJoinColumns:
                    sf_menu_id:
                        referencedColumnName: id

Classes into my child bundle:

use Project\MYBUNDLE\Entity\Group as TGroup;
/**
 * @ORM\Entity
 * @ORM\Table(name="sf_group")
 */
class Group extends TGroup
{ }

use Project\MYBUNDLE\Entity\Menu as TMenu;
/**
 * @ORM\Entity
 * @ORM\Table(name="sf_menu")
 */
class Menu extends TMenu
{ }

However each one of the two classes have a property to make a manytomany association between them (As mappedSuperclass doesn't allow an inverse side, my association is manytomany unidirectional).

I need to make a query inside MYBUNDLE. A query which join both tables with the manytomany association. The reason i want to make this query inside MYBUNDLE, is because this bundle has a service which draws the Menu deppending in the Group or Groups. This method should be facilitate from this bundle, so other bundles could use it and i dont have to implemment in every sub-bundle.

My partial solution was to make a config part for my MYBUNDLE, something like:

mybundle:
    menu_entity: 
        name: MyprojectChildBundle\Entity\Menu
    group_entity:
        name: MyprojectChildBundle\Entity\Group

With this configuration, I can use the repository of the child bundle inside MYBUNDLE, with this:

$this->em->getRepository("MyprojectChildBundle:Group")-findAll();

Everything works when I make a query without joins. On the other hand, when I do this:

$repo = $this->em->getRepository("MyprojectChildBundle:Group");
$result = $repo->createQueryBuilder("c")          
               ->select('c, d')
               ->join("c.menus", "d")->getQuery()->getResult();


return $result

Everything fails, because the SQL formed try to look for a table called "Menu" which does not exist because it is called "sf_menu". The table Group is correctly changed to "sf_group" because I am using the Repository of my child. However using this repository just change the name of that class, but not of joined tables.

How could I make this kind of query inside MYBUNDLE? Thanks a lot.

Was it helpful?

Solution

Finally i found the solution :)

I had to create 2 more classes as my model. This classes should have all mapping Database and shoud be declared as single inheritance like this:

#src\Myproject\MYBUNDLE\Model\Menu

/**
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"menu1" = "Myproject\MYBUNDLE\Entity\Menu", "menu2" = "Menu"})
 */
abstract class Menu {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    // Other fields
}

That you should do with both entities (Menu and Group). The advantage of this implementation is that you don't lose any associations as before, due to declare them as mappedSuperClasss.

Then you should declare one entity per each model class and declare them as MappedSuperClass. They should look like this:

#src\Myproject\MYBUNDLE\Entity\Menu

use Doctrine\ORM\Mapping as ORM;
use Tixpro\TMenuBundle\Model\Menu as BaseMenu;

/** @ORM\MappedSuperclass */
class Menu extends BaseMenu
{
}

With this implementation you make sure not to lose any association. In addition, any entity could extend from your entities class to add more fields and customize them. For instance:

#src\Project\ChildBundle\Entity\Menu

use Myproject\MYBUNDLE\Entity\Menu as TMenu;
/**
 * @ORM\Entity
 * @ORM\Table(name="sf_menu")
 */

class Menu extends TMenu{
    //put your code here
}

Don't forget to configure the params in the config.yml to use MYBUNDLE.

mybundle:
    menu_entity: 
        name: MyprojectChildBundle\Entity\Menu
    group_entity:
        name: MyprojectChildBundle\Entity\Group

if you dont do this, you couldn't know the repository inside MYBUNDLE and consequently you couldn't make joined queries into your MYBUNDLE.

Finally, after setting your params and making that implementation, you are able to use joined queries inside your MYBUNDLE, like this:

$repo = $this->em->getRepository("MyprojectChildBundle:Menu");
$result = $repo->createQueryBuilder("wa")          
    ->select('wa, da')
    ->join("wa.roles", "da")

That's all.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top