views:

37

answers:

1

Hello. I have such a model

Designer:
  tableName: designers
  actAs:
    I18n:
      fields: [name]
  columns:
    id:
      type: integer(2)
      unsigned: true
      primary: true
      autoincrement: true
    name:
      type: string(30)
      notnull: true

While default I18n behavior must be used like this

$d = Doctrine_Query::create()
                ->select('id, t.name')
                ->from('Designer d')
                ->leftJoin('d.Translation t')
                ->where("t.lang = 'en'")
                ->execute();

I would be faaar more convenient to set some constant to the current language, say en, and have every i18nable field correspond to it, thus having such query

$d = Doctrine_Query::create()
            ->select('id, name')
            ->from('Designer d')
            ->execute();

equivalent to the above one.

I'm trying to make a new behavior, extending the default one, which could provide such things, but I need your help.

Getting the needed language is easy, so let's just say there is define('LANGUAGE', 'en'). The basic behavior class is

class TransparentI18N extends Doctrine_Template
{
    private $_translation = NULL;

    public function setUp()
    {
        $this->addListener(new TransparentI18NListener());

        $this->actAs(new Doctrine_Template_I18n($this->_options));
    }
}

So the idea is to add a listener, that would modify the query to set joins and select needed fields whenever such fields are present in the select clause. The TransparentI18NListener contains the preDqlSelect, which receives the Doctrine_Event object. And I can get the relevant Doctrine_Query and even getDqlPart('select') works, but the latter returns the raw select string, like id, t.name, how can I get, to which table each clause corresponds?

Then I'd have to set fields of the Doctrine_Record instance. Is it possible without making models extend some custom class which would give such functionality? I'm really reluctant to add such a class, but in case everything other fails, I should be able to make it save these fields and override the __get method to show translated fields if they are requested.

I was too scared to think about the insert/update/delete part, but hopefully if I deal with the above problems, I'd be able to add hooks to dql and get the job done.

Do you think such a think is possible in general without messing with core doctrine libraries? Having to use it in the default way would be a huge pain in the *...

A: 

I don't have a good, non-hacky solution for your actual problem but have an alternative to try.

You could put all your find/get queries in the models corresponding table class.
So you still have to do the Translation-Joints but all you queries are at one place and are easy to maintain.

class DesignerTable extends Doctrine_Table
{
    protected $_lang = LANGUAGE;

    public function findAll()
    {
        return Doctrine_Query::create()
                ->select('id, t.name')
                ->from('Designer d')
                ->leftJoin('d.Translation t')
                ->where("t.lang = ?", $this->_lang)
                ->execute();
    }

    public function findOneById($id)
    {
        return Doctrine_Query::create()
                ->select('id, t.name')
                ->from('Designer d')
                ->leftJoin('d.Translation t')
                ->where('.lang = ?', $this->_lang)
                ->andWhere('id = ?', $id) 
                ->execute();
    }
    ...
}

// In your controllers:

// Find all designers
$designers = Doctrine_Core::getTable('Designer')->findAll();

// Find one designer by id
$designers = Doctrine_Core::getTable('Designer')->findOneById(13);
Benjamin Cremer
I guess that will not work for creating custom `Doctrine_Queries` :(
roddik
@roddik why not? you can define as many methods as you need. you don't have to use the doctrine inbuild find*-querynames.
Benjamin Cremer
yes, but the problem is, if some other developer wants to use `Doctrine_Query::create()->...`, he won't be able to use the easy accessors a-la `$designer->name`, right?
roddik