Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine 1.2 auto-join i18n?


I would like to extend the i18n behavior, so that it joins the translation table automatically, on any type of query (DQL, relations, getTable).
Additionally it needs to define the default language parameter, so when I do a query without the language set, it falls back to the the default language.
Note: I'm looking for a generalized behavior, so that is applies to all i18n model objects, not to write and override for each of the classes.

Here is an example:
table product -> id, category_id, price...
table product_translation -> id, lang, name, description...

With the current solution when I do something like this: Doctrine_Core::getTable('Product')->findAll(), it gets all the products without joining the translations.
So in the controller I have to loop trough all the records and reapply translated values, with $product->name = $product->Translation['en']->name

I would like something like this:

  • Doctrine_Core::getTable('Product')->findAll() it should get the joined values for lang='en'
  • Doctrine_Core::getTable('Product)->findAll('en') same as above
  • It should also work with relations, so for instance if I have a class User which has many products $user->Products it should return a collection with translations included.
  • Also something like $user->Products('en') should return the collection for other (non-default) languages
  • Magic functions would also be nice (if possible)...something like Doctrine_Core::getTable('Product')->getByCategoryAndLang(1,'en')

Can anyone help? I'm looking at templates and behaviors, I think that is the way to go, but have no clue how to implement this

EDIT: I see there is not much interest in this, so let me try with a simpler question. How do you usually get i18n fields via relations. For instance how can I call $user->Products and get the products with loaded translations?

like image 966
ZolaKt Avatar asked Mar 25 '11 17:03

ZolaKt


1 Answers

I think that You do not need to extend the standard Doctrine behavior unless You want this fully automatic. But still You can try to do this like we do - we use a DAO (Data Access Object) that returns us concrete Doctrine entity (Doctrine table representation):

\DAO::get('Some\Namespace\Classname')

where Classname stands for table described by PHP class model. Our DAO class creates the instance of Classname that is encapsulated into proxy (see Design Patterns).

Beyond table class model we create another class for this table that stands above the table model and manipulates with this model. Within this class we write methods like getProducts($args), getProduct($id), getProductsByCategory($catId) etc.

I think that this is what You are looking for...

In method getProducts($args) You can then implement ->leftJoin() within DQL that will join the translations table by given $lang identificator in $args parameter. Simple example (not tested):

class Products extends \DAO {
    public function save($item) {
        $item->save();
    }

    public function getProducts($args = array()) {
        $order = array('p.id');

        $result = \Doctrine_Query::create()
            ->from('Some\Namespace\Product p')
            ->where('1 = 1');

        if(!empty($args['lang'])) {
            $result = $result->leftJoin('Some\Namespace\ProductTranslation pt ON pt.product_id = p.id AND pt.language = ?', $args['lang']);
        }

        $result = $result->orderBy($order);

        $result = $result->execute();

        return $result;
    }
}

Then by calling

$products = DAO::get('Some\Namespace\Product')->getProducts(array('lang' => 1));

You obtain all the products with english translations loaded...

It is not so much automaticated and You have to write Your own DAO class for every model but it is good approach as You have different data definition class (model) and data manipulation class (controller) that needed for MVC/MVP object oriented application architecture...

like image 107
shadyyx Avatar answered Oct 05 '22 07:10

shadyyx