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.

Sunday, December 16, 2007

Dell Vostro 1500 Working With 64-bit Ubuntu Gusty

Thanks to the Ubuntu forums, I knew before ordering my new Vostro 1500 that it was possible to get everything working on 32-bit Gusty. Being blessed with a free evening and the determination to take full advantage of my first 64-bit processor, I decided to try the 64-bit version of Gusty. Most things worked right out of the box but, as frequently reported, wifi and sound did not work. Vostro-owning Ubuntu fans fear not, it only took me about 10 minutes to get my system working 100%.

Wifi

Followed ndiswrapper setup instructions available here. Connection speed is 54 Mb/s; range is excellent. Haven't tested WEP yet.

For the record, lspci -v shows:
0c:00.0 Network controller: Broadcom Corporation BCM94311MCG wlan mini-PCI (rev 01)
Subsystem: Dell Unknown device 0007
Flags: bus master, fast devsel, latency 0, IRQ 17
Memory at fe8fc000 (32-bit, non-prefetchable) [size=16K]
Drivers for the Vostro 1500's Broadcom 4311 card are distributed with Gusty and can easily be installed with the Restricted Drivers Manager. However, these native drivers have very poor range and only connect at a max of 24 Mb/s. bcm43xx drivers are deprecated at this point according to this wiki page and will be replaced in kernel 2.6.24 by the b43 project. If you're intent on going as open-source as possible, follow instructions available here.

Sound

I did the fix described here. Works perfectly though others, including the guy that proposed the fix in the first place, have reported problems with the headphone jack working correctly.

Power

The Vostro 1500 is affected by the now notorious hard drive churn problem. This isn't really a bug, but rather the product of a series of unfortunate choices on the part of hardware manufacturers, integrators and distro developers.

Since I'm willing to trade shorter periods on battery power for longer hardware life, I changed the power saving settings following instructions here. I made one major change to avoid repeated spindown, so my 99-hdd-ugly-fix.sh looked like:


#!/bin/bash
if on_ac_power; then
# on AC so don't do any head parking
hdparm -B 254 -S 0 /dev/sda
else
# either on battery or power status could not be determined
# so quickly park the head to protect the disk
hdparm -B 128 -S 60 /dev/sda
fi


Setting -B controls how quickly the heads will be parked. Parking the heads protects your drive from bumps. This setting effects how often Load_Cycle_Count in SMART gets incremented. A value of 254 basically stops auto-parking the heads.

Setting -S controls when the hd spins down. Drive spin-down is designed to save energy. This controls how often SMART's Start_Stop_Count gets incremented. A value of 60 causes it to spin down after 5 minutes. If you want another interval, multiply the desired number of minutes by 12.

If you'd like to see all the gritty details of your harddrives health that I'm refering to, you'll need a utility to access the SMART data. Just run:


sudo apt-get install smartmontools
sudo smartctl -a /dev/sda


Goodies
Just sudo apt-get install ubuntu-restricted-extras libxine1-plugins to get all the good illegal stuff.

Well thats it for now. I'll be updating this post with anything else interesting I run into.