apelliciari
apelliciari

Reputation: 8501

CakePHP containable doesn't filter in a proper way

Like the example in cakephp manual, http://book.cakephp.org/view/1323/Containable#Containing-deeper-associations-1325, i need to fetch data from a model through a condition on its association model.

I have:

Model Language:

class Language extends AppModel {

    var $name = 'Language';
    var $actsAs = array('Containable');

        var $hasMany = array(
        'LanguageTranslation' => array(
            'className' => 'LanguageTranslation',
            'foreignKey' => 'language_id'
        )
    );

}

And the association, ModelTranslation

class LanguageTranslation extends AppModel {

    var $name = 'LanguageTranslation';

    var $belongsTo = array(
        'Language'
    );
}

when i do:

$language_array = $this->controller->Language->find('all', array(
            'contain' => "LanguageTranslation.id = 1" 
        ));

i receive all the languages, not only one (because id in LanguageTranslation is unique). The result need to be one!

SO, with

debug($language_array);

result is:

Array
(
    [0] => Array
        (
            [Language] => Array
                (
                    [id] => 1
                    [code] => it
                    [locale] => ita
                )

            [LanguageTranslation] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [language_id] => 1
                            [language] => italiano
                        )

                )

        )

    [1] => Array
        (
            [Language] => Array
                (
                    [id] => 2
                    [code] => en
                    [locale] => eng
                )

            [LanguageTranslation] => Array
                (
                )

        )

    [2] => Array
        (
            [Language] => Array
                (
                    [id] => 3
                    [code] => de
                    [locale] => ger
                )

            [LanguageTranslation] => Array
                (
                )

        )
)

Why i don't catch only the Language with id = 1?

Upvotes: 0

Views: 1050

Answers (3)

Andrew Senner
Andrew Senner

Reputation: 2509

In regards to Juhana's answer: (which initially calls find on the Language Model), You can supply conditions for the parent model which target child models.

Contain in a separate call.

<?php

$this->Language->contain(array(
    'LanguageTranslation'
));
$lang = $this->Language->find('first', array(
    'conditions' => array('LanguageTranslation.id' => 1)
));

?>

Contain in one call.

<?php

$lang = $this->Language->find('first', array(
    'conditions' => array('LanguageTranslation.id' => 1),
    'contain' => array('LanguageTranslation')
));

?>

If you need to apply conditions to the child models just add the conditions array to the child model's index in the contain call. For example:

<?php

$this->Language->contain(array(
    'LanguageTranslation' => array(
        'conditions' => array('<LanguageTranslationConditionHere>')
    )
));

?>

Hope this helps!

-Andrew

Upvotes: 0

Tal
Tal

Reputation: 529

linkable behavior will do the trick.

You can download it on: https://github.com/rafaelbandeira3/linkable

MODEL

var $actsAs = array('Linkable');

CONTROLLER

$language_array = $this->Language->find('all', array(
    'link' => array('LanguageTranslation'),
    'conditions' => array("LanguageTranslation.id = 1")
));

Upvotes: 2

JJJ
JJJ

Reputation: 33163

The conditions in containable apply only to the models inside the containment. Because the main query doesn't have any conditions it fetches every row in the table. In general you don't use containable to restrict the main query but to limit the way the query goes through the containment tree (very handy when you need to go through 3-4 levels of recursiveness where the results can get quite bloated if not contained).

In this case in particular if you are trying to get the data of a certain Language/LanguageTranslation pair, you can just pull the data from the LanguageTranslation model.

$this->Language->LanguageTranslation->find( 
    'first',
    array( 
        'conditions' => array( 'LanguageTranslation.id' => 1 ),
        'recursive'  => 1
    )
);

Upvotes: 1

Related Questions