A quick tutorial on CakePHP Set class (Part 1)
March 4, 2008 – 12:56 am| Table of Content [Hide] |
Test data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | $data = array( 1 => array('Post' => array( 'id' => 1, 'post_comment_count' => 2, 'name' => 'My first title', 'body' => 'My first body' ), 'PostComment' => array( array( 'id' => 1, 'post_id' => 1, 'is_active' => 1, 'name' => 'My first comment', 'body' => 'My first comment'), array( 'id' => 2, 'post_id' => 2, 'is_active' => 1, 'name' => 'My second comment', 'body' => 'My second comment'), array( 'id' => 3, 'post_id' => 2, 'is_active' => 1, 'name' => 'My third comment', 'body' => 'My third comment') ) ), 2 => array('Post' => array( 'id' => 2, 'post_comment_count' => 1, 'name' => 'My second title', 'body' => 'My second title' ), 'PostComment' => array( array( 'id' => 4, 'post_id' => 2, 'is_active' => 1, 'name' => 'My fourth comment', 'body' => 'My fourth comment' ) ) ), 3 => array('Post' => array( 'id' => 3, 'post_comment_count' => 0, 'name' => 'My third title', 'body' => 'My third title' ), 'PostComment' => array( ) ) ); $dataExtra = array( 4 => array('Post' => array( 'id' => 4, 'post_comment_count' => 1, 'name' => 'My fourth title', 'body' => 'My fourth title' ), 'PostComment' => array( array( 'id' => 5, 'post_id' => 4, 'is_active' => 1, 'name' => 'My fifth comment', 'bdoy' => 'My fifth comment' ) ) ) ); |
Set::merge
PHP doc blcok
This function can be thought of as a hybrid between PHP's array_merge and array_merge_recursive. The difference to the two is that if an array key contains another array then the function behaves recursive (unlike array_merge) but does not do if for keys containing strings (unlike array_merge_recursive). See the unit test for more information. Note: This function will work with an unlimited amount of arguments and typecasts non-array parameters into arrays.
A bit like array_merge_recursive. Merge joins two arrays on their keys.
If we want to add the $extraData array into the $dat most people would probably think, hey, lets merge them using Set::merge… but.. no, dont, unless you know what your doing.
1 | pr(Set::merge($data, $dataExtra)); |
The above cod will only produce the ‘expected’(?) result because I have added the numeric key 4 in the $extraData array (Line 40). If I had, as I did the first time around, just let php auto-increment the keys for me, both $datad and $extraData would contain the numeric index key 0, and since Set::merge works on keys, $extraData’s Fourth post would overwrite $data’s First post where they had anything in common (id, name, post_comment_count, body and everything in the first PostComment (My first comment)).
In case I had let php handle the index keys, I would have to use Set::insert to append the fourth comment to the list.
A better use of Set::merge is in CAKE/libs/model/model.php where is automagic merges ‘actsAs’ from your current model (PostComment) and your AppModel, so you automagic inherit the global behaviors from AppModel:
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | // model.php if (is_subclass_of($this, 'AppModel')) { $appVars = get_class_vars('AppModel'); $merge = array(); if ($this->actsAs !== null || $this->actsAs !== false) { $merge[] = 'actsAs'; } foreach ($merge as $var) { if (isset($appVars[$var]) && !empty($appVars[$var]) && is_array($this->{$var})) { $this->{$var} = Set::merge($appVars[$var], $this->{$var}); } } } |
A funny thing is that Set::merge is still rarely used in the core code yet. Probably because array_merge (or am()) is faster for simple operations like just merging two simple 1 level arrays like a config array.
Set::filter
PHP doc blcok
Filters empty elements out of a route array, excluding '0'.
This method is not recursive. So doing
1 2 | < ?php pr(Set::filter($data, true)); |
wont change anything in the array sinc no elements in first level is empty.
1 2 3 4 5 6 7 8 9 | pr(Set::filter($data[3], true)); array('Post' => array( 'id' => 3, 'post_comment_count' => 0, 'name' => 'My third title', 'body' => 'My third title' ) ); |
We will notice that the PostComment array is gone, since its empty
Set::pushDiff
PHP doc blcok
Pushes the differences in $array2 onto the end of $array
That sounds simple enough, and it really is.
1 | pr(Set::pushDiff($data, $dataExtra)); |
just pushes the $dataExtra on the end of $data, since they have nothing in common. Again, this method operates on the array keys when comparing arrays.
Set::map
PHP doc block
Maps the contents of the Set object to an object hierarchy. Maintains numeric keys as arrays of objects
That sounds very fancy, and it is! A lot of people migrating to CakePHP from Symfony (PHPDoctrine, Propel) will probably be confused at first that all model data in CakePHP is arrays, and not objects like other frameworks. This method attemps to ‘fix’ this issue by converting a model data array to a set of objects (StdClass). StdClass is a build-in dummy class in PHP, and it doesnt really do anything but contain data, no methods or fancy magic there.
1 2 3 4 5 6 7 8 9 | < ?php // Convert to objects $map = Set::map($data); // id of first post (Object style) echo $map[0]->id; // name of first comment to first post (Object style) echo $map[0]->PostComment[0]->name; // name of first comment to first post (array style) echo $map[0]['PostComment'][0]['name']; // WONT WORK, Cannot access StdClass as an array |
As you can see above, its important to decide what method you want to use, Object or Array style, since they cannot be mixed.
Also, the return from Set::map is a mix of arrays and StdClass, thats why I can access $map[0] as array, but not access $map[0]['name'].
Set::numeric
PHP doc blcok
Checks to see if all the values in the array are numeric
Not much to say on this one, because it doesnt do more or less than the name implies.
1 2 3 4 5 6 7 8 | // false var_dump(Set::numeric($data)); // false var_dump(Set::numeric($data[1])); // false var_dump(Set::numeric($data[1]['PostComment'])); // true var_dump(Set::numeric(array(1,2,3))); |
——-
Thats it for now, next time I will look at:
Set::enum, Set::format, Set::extract, Set::insert, Set::remove, Set::check, Set::diff, Set::isEqual, Set::contains, Set::countDim, Set::normalize, Set::combine and Set::reverse.
Look forward to it
4 Responses to “A quick tutorial on CakePHP Set class (Part 1)”
Great, thanks for doing this! Looking forward to seeing the rest of the functions explained too.
By Sean on Mar 4, 2008
Great Stuff I look forward to the next piece thx
By Sam S on Jul 17, 2008
Thank you very much for the useful blog posts. One little detail I thought I’d point out is that the example code here seems to have > encoded as > but there’s a space before the ; and so it’s not displaying as > but rather as > ; which makes copy and paste pretty much impossible. Not really a big deal, as I’m just using this information to learn from, but it would be easier to read if these characters were displayed as intended.
By Silver Knight on Jun 6, 2009