tags:

views:

139

answers:

2

I have the output array from a $Model->find() query which also pulls data from a hasMany relationship:

Array(
[Parent] => Array
            (
                [id] => 1
            )

[Child] => Array
            (
                [0] => Array
                    (
                        [id] => aaa
                        [score] => 3
                        [src] => stage6/tn~4bbb38cc-0018-49bf-96a9-11a0f67883f5.jpg
                        [parent_id] => 1
                    )

                [1] => Array
                    (
                        [id] => bbb
                        [score] => 5
                        [src] => stage0/tn~4bbb38cc-00ac-4b25-b074-11a0f67883f5.jpg
                        [parent_id] => 1
                    )

                [2] => Array
                    (
                        [id] => ccc
                        [score] => 2
                        [src] => stage4/tn~4bbb38cc-01c8-44bd-b71d-11a0f67883f5.jpg
                        [parent_id] => 1
                    )

     )
)

I'd like to transform this output into something like this, where the child id is the key to additional child attributes:

Array(
[aaa] => Array
    (
        [score] => 3
        [src] => stage6/tn~4bbb38cc-0018-49bf-96a9-11a0f67883f5.jpg
    )
[bbb] => Array
    (
        [score] => 5
        [src] =>  stage0/tn~4bbb38cc-00ac-4b25-b074-11a0f67883f5.jpg
    )
[ccc] => Array
    (
        [score] => 2
        [src] => stage4/tn~4bbb38cc-01c8-44bd-b71d-11a0f67883f5.jpg
    )

}

Is there an easy way to use Set::extract, Set::combine, Set::insert, etc. to do this efficiently? I cannot figure it out.

+1  A: 

I've used Set::combine to do this a few times, but I can't make an argument for efficiency. As an example, I had a list of volunteers and each of those volunteers belonged to a group. I wanted to retrieve each committee and its volunteers, but as an associative array keyed by the committee name. Here's the code I used to do that:

$volunteers = Set::combine (
  $this->Volunteer->Committee->find (
    'all',
    array ( 'order' => 'display_order' )
  ),
  '{n}.Committee.title',
  '{n}.Volunteer'
);

Hopefully that helps. The documentation for Set::combine may help elaborate on the details.

Rob Wilkerson
Given a Committee with more than one Volunteer, won't your code obliterate all but one of the array elements?Did you mean to use the `$groupPath` parameter of `Set::combine`?
Daniel Wright
It's been a long (read: LOOONG) time since I've visited this code, but IIRC that's what the `{n}.Committee.title` bit is. Either way, this works great (1.2.x). In my view, I just have a nested loop that spits out "headers" (committee names) and volunteers.
Rob Wilkerson
I figured out why your code sample rang false. I learned the `Set` library mostly using the XPath syntax, which behaves differently than the `classicExtract` syntax. If I replaced the classic array path syntax in your code with XPath syntax, it throw an error. (As an aside: wow, talk about confusing function behaviour. Ah, the charms of PHP.)
Daniel Wright
A: 

As Rob says, Set::combine is the answer to your question. Here's a sample solution, using the XPath 2.0 syntax:

$parents = $this->Parent->find('all');
$assocChildren = Set::combine( $parents, '/Child/id', '/Child' );
Daniel Wright