0
votes

I have simple model relationship in CakePHP 1.3 with Categories -> Products

Category hasMany Products

There is slight difference between the data arrays which I get in the different controllers. The Product data is in the main product array when getting as associated model in the Categories controller and is separated when getting it in Products.

For Example to get 'Product1'

in Categories - $category['Product'][0]['title']

and in Products - $product[0]['Product']['title']

I would like to use same element for displaying the products. It does not matter which array scheme will be used just to be the same. And where is the right place to make the modification? I can modify those arrays after getting them, but don't think that it is the best option.

When I am in the Categories controller and get a category I get this:

// $this->Category->findById('12');
Array
(
[ProductCategory] => Array
    (
        [id] => 12
        [title] => Category 1
        [updated] => 2013-02-24 10:06:15
        [created] => 2013-02-24 10:06:15
    )
[Product] => Array
    (
        [0] => Array
            (
                [id] => 4
                [parent_id] => 12
                [title] => Product1
                [updated] => 2013-02-24 10:17:01
                [created] => 2013-02-24 09:12:59

            )

        [1] => Array
            (
                [id] => 6
                [parent_id] => 12
                [title] => Product2
                [updated] => 2013-02-24 10:16:54
                [created] => 2013-02-24 09:13:53

            )
)

And when getting all the products inside the Products controller:

// $this->Product->find('all');
Array
(
    [0] => Array
        (
            [Product] => Array
                (
                    [id] => 10
                    [parent_id] => 12
                    [title] => Product1
                    [updated] => 2013-02-24 10:16:42
                    [created] => 2013-02-24 09:16:35
                )

        )

    [1] => Array
        (
            [Product] => Array
                (
                    [id] => 8
                    [parent_id] => 12
                    [title] => Product2
                    [updated] => 2013-02-24 10:16:47
                    [created] => 2013-02-24 09:15:39
                )

        )
    )
)
3

3 Answers

1
votes

One of your finds is a find('all') and the other is a findById() (which uses find('first')).

Both of these return data in a different format, since find('first') knows you only want one item, and find('all') is an unknown set of item(s).

Just use find('all') for both, but set your limit based on whether you need only one or more than one. Then, your data will be returned exactly the same.

Which Controller you retrieve your data from has no effect on the data returned. Which MODEL however, does - so just make sure you're doing your find from the same model.

Eg.

//in your ProductsController
$this->Product->find('all');

//in your CategoriesController
$this->Category->Product->find('all');

// in some other controller
$this->loadModel('Product);
$this->Product->find('all');

PS - BUT it's better if you don't do your "finds" in your Controller - make a method in your Model, and call it from your Controller(s) so instead of $this->Product->find(), it would be $this->Product->getProducts() (or whatever you want to call it). (read more about "fat models, skinny controllers" for reasons/examples...etc).

0
votes

Dave is right, the difference is the method you're using... Even though you claim that associated data is always merged, your find on the 'Product' model is NOT associated data, so the format WILL always be different.

I've been here for a short while and I've already noticed that Dave knows his stuff. :) I agree with the fat models/skinny controllers paradigm for clean, efficient code.

If you changed:

<?php

$this->Category->contain(array(
    'Product'
));
$this->Category->find('all', 
    array(
        'conditions' => array(
            'Category.id' => $id // 12 for your OP.
        ),
        'limit' => 1
    )
);

?>

Should give you:

<?php

array
    (
    [0] => array
        (
        'Category' => array
            (
            [id] => 12
            [title] => Category 1
            [updated] => 2013-02-24 10:06:15
            [created] => 2013-02-24 10:06:15
            ),
        'Product' => array
            (
                [0] => array
                    (
                    ...
                    ),
                [1] => array
                    (
                    ...
                    )
            )
    )
)

?>

Please correct me if I am mistaken, thanks!

0
votes

Or if you want "Products" to look like:

<?php

'Product' => array
    (
        [0] => array
            (
                'Product' => array
                    (
                        ...
                    )
            )
    )

?>

when fetching data from the category model, you would need to fetch the associated data manually, e.g.:

<?php

$this->Category->contain();
$cats = $this->Category->find('all');
foreach ($cats as &$cat) {
    $this->Category->Product->contain();  // You have to contain for each find.
    $cat['Product'] = $this->Category->Product->find('all', 
        array(
            'conditions' => array(
                'Product.category_id' => $cat['Category']['id']
            )
        )
    );
}

?>