Sunday, February 24, 2008

Model.find output with recursive hasMany/belongTo

Though many parts of CakePHP are intuitive, I often find myself guessing at how the array I get back from Model.find will be formatted. In the interest of spending less time looking through the output of debug($this->Model->find()) statements, I've put together a breakdown of the structures returned by find for recursive hasMany/belongTo relationships. After looking at a few examples side by side, it becomes relatively clear what form the data structure takes based on model relationship and level of recursion.

The model hierarchy used in these examples is: User hasMany Stream, Stream belongsTo User, Stream hasMany Item, Item belongsTo Stream. To put it briefly, User <-> Stream <-> Item.

Basic find('all')

For the query

$streams = $this->User->find('all', array(
'conditions'=>array(
'User.id'=>'5'),
'recursive'=>0));
debug( $streams );


The generic structure is
{n}.Model.id
And the output is

Array
(
[0] => Array
(
[User] => Array
(
[id] => 5
[username] => donkey
)
)
)


Find with recursion

Notice how even though Stream is below User in the heirarchy, the Stream array key is on the same level as User.

For the query

$streams = $this->User->find('all', array(
'conditions'=>array(
'User.id'=>'5'),
'recursive'=>1,
));
debug( $streams );


The generic structure is
{n}.Model.id
{n}.ChildModel.{n}.id
And the output is

Array
(
[0] => Array
(
[User] => Array
(
[id] => 5
[username] => donkey
)
[Stream] => Array
(

[0] => Array
(
[id] => 3
[user_id] => 5
[name] => Google News - World
)
... snip ...
)
)
)


This query fails because User table query doesnt join Stream table. Stream table would be queried separately


$streams = $this->User->find('all', array(
'conditions'=>array(
'User.id'=>'5',
'Stream.id' => '3'),
'recursive'=>1,
));


Joining models

Using this form, the User and Stream tables are joined, as opposed to a query first being done on User then separate queries sent for each Stream.

For the query

$streams = $this->User->Stream->find('all', array(
'conditions'=>array(
'User.id'=>'5'),
'recursive'=>0,
));
debug( $streams );


The generic structure is
{n}.Model.id
{n}.ParentModel.id
And the output is

Array
(
[0] => Array
(
[Stream] => Array
(
[id] => 11
[user_id] => 5
[name] => Google News - Business
)
[User] => Array
(
[id] => 5
[username] => donkey
)
)
[1] => Array
(
[Stream] => Array
(
[id] => 2
[user_id] => 5
[name] => Google News - World
)
[User] => Array
(
[id] => 5
[username] => donkey
)
)
... snip ...
)


Joining models with criteria on child model

Joins allow us to include criteria for joined models. User shows up in the query even though recursion = 0, I guess because we are joining the User table.

For the query

$streams = $this->User->Stream->find('all', array(
'conditions'=>array(
'User.id'=>'5',
'Stream.id' => '3'),
'recursive'=>0,
));
debug( $streams );


The generic structure is
{n}.Model.id
{n}.ParentModel.id
And the output is

Array
(
[0] => Array
(
[Stream] => Array
(
[id] => 3
[user_id] => 5
[name] => Google News - World
)

[User] => Array
(
[id] => 5
[username] => donkey
)
)
)


Joining models with recursion

Notice how the Stream.id criteria did not apply to the second level.

For the query

$streams = $this->User->Stream->find('all', array(
'conditions'=>array(
'User.id'=>'5',
'Stream.id' => '3'),
'recursive'=>2,
));
debug( $streams );


The generic structure is
{n}.Model.id
{n}.ParentModel.id
{n}.ParentModel.Model.{n}.id
{n}.ChildModel.{n}.id
{n}.ChildModel.{n}.Model.id
And the output is

Array
(
[0] => Array
(
[Stream] => Array
(
[id] => 3
[user_id] => 5
[name] => Google News - World
)

[User] => Array
(
[id] => 5
[username] => donkey2
[Stream] => Array
(
[0] => Array
(
[id] => 3
[user_id] => 5
[name] => Google News - World
)
... snip. All streams were in this array ...
)
)
[Item] => Array
(
[0] => Array
(
[id] => 302
[stream_id] => 3
[name] => Rockets fired at Green Zone - United Press International
[Stream] => Array
(
[id] => 3
[user_id] => 5
[name] => Google News - World
)
)
... snip ...
)
)
)

Sunday, January 13, 2008

Inflo.us Support Thread

Please post any problems or questions in this thread.