Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SonataAdminBundle with translatable fields (doctrine extensions)

I'm having a table with all translations in a "ext_translations" table.

The translating works great. The problem is now: I want to manage those translations via sonata-admin bundle.

I have already found a documentation, how to get work doctrine extensions with sonata admin. But in my case I have ONE table/entity for all my translations (for multiple entities).

So according to this documentation: http://www.elao.com/blog/symfony-2/doctrine-2/how-to-manage-translations-for-your-object-using-sonataadminbundle.html what should be my mappedBy attribute (see below)?

ext_translations table:

mysql> show columns from ext_translations; +--------------+--------------+------+-----+---------+----------------+ | Field        | Type         | Null | Key | Default | Extra          | +--------------+--------------+------+-----+---------+----------------+ | id           | int(11)      | NO   | PRI | NULL    | auto_increment | | locale       | varchar(8)   | NO   | MUL | NULL    |                | | object_class | varchar(255) | NO   |     | NULL    |                | | field        | varchar(32)  | NO   |     | NULL    |                | | foreign_key  | varchar(64)  | NO   |     | NULL    |                | | content      | longtext     | YES  |     | NULL    |                | +--------------+--------------+------+-----+---------+----------------+ 

MappedBy:

   /**      * @ORM\OneToMany(targetEntity="ProfileTranslation", mappedBy="object", cascade={"persist", "remove"})      */     protected $translations; 

As far as I understood the problem here: "I have a composite key (objectclass (the entity) + name (of the attribute) + foreignKey (id of entity)), so how should the 'mappedBy' refer to this?

I don't want to create an extra class for each translatable entity (like in the tutorial from above)

like image 447
eav Avatar asked Oct 27 '13 22:10

eav


1 Answers

Your situation is quite complex. Probably the best could be if you dont use any anotation, override the repository class, and build all your own logic.

We can try to leverage the new ability since Doctrine 2.1 of creating composite Composite Keys as Primary Key, as Feras said in his comment.

Doctrine 2 supports composite primary keys natively. Composite keys are a very powerful relational database concept and we took good care to make sure Doctrine 2 supports as many of the composite primary key use-cases. For Doctrine 2.0 composite keys of primitive data-types are supported, for Doctrine 2.1 even foreign keys as primary keys are supported.

In the docs, we have a good example to a use case that is more or less similar to yours:

Dynamic Attributes of an Entity (for example Article). Each Article has many attributes with primary key “article_id” and “attribute_name”.

You can see the example here: http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes

But since that approach only considers one entity, we have to adapt it to your needs. We can follow this steps:

  1. Create a sort of views of your ext_translations table

    CREATE VIEW profile_ext_translations AS  SELECT *  FROM ext_translations WHERE  object_class = 'Profile' 
  2. Then create different entities, for that views, so i.e. you would have an entity ProfileExtTranslations with a composite primary key, as follows:

    ** * @Entity */ class ProfileExtTranslations {    /**   * @ORM\ManyToOne(targetEntity="Profile", inversedBy="translations")      * @ORM\JoinColumn(name="foreign_key", referencedColumnName="id", onDelete="CASCADE")*/    private $profile;   /** @Id @Column(type="string") */  private $field;   //Other fields and methods   } 
  3. And now, the code of the Profile entity, in the mappedBy of the translations, you just use:

    /** * @ORM\OneToMany(targetEntity="ProfileExtTranslation", mappedBy="profile", cascade={"persist", "remove"}) */ protected $translations; 

And with this and probably a litle tunning, you should have it working.

like image 146
Carlos Robles Avatar answered Oct 13 '22 08:10

Carlos Robles