How to process AR objects

I'm fairly new to AR way of working with db-data, and I've run into some difficulties when processing the results of CActiveRecords functions. To illustrate, I will state a scenario wit two tables:

Table 1 'categories' has fields 'cat_id', 'cat_name'

Table 2 'items' has fields 'item_id', 'cat_id', 'item_name'

All items must belong to a category. So now I want to make a "manage" page for all records. This is what i would normally without AR (with SQL):

  • Get all data from 'categories' and 'items' and store in an array like this:


  $items['cat_one'][] = 'item_one'


  $items['cat_one'][] = 'item_two'


  $items['cat_one'][] = 'item_three'


  $items['cat_two'][] = 'item_four'


  $items['cat_two'][] = 'item_five'


  $items['cat_three'][] = 'item_six'


  $items['cat_four'][] = 'item_seven'


Then when handeling it i would do it with two foreach loops:



foreach ($items as $cat_name => $array) {


  // do something with category


  foreach ($array as $item_name) {


    // do something with item


  }


}


Now, when I tried this with AR i ran into some problems. I did a findAll() on both AR models. Then when doing a foreach on the result of the categories model I couldn’t find a way to pick out only the items belonging to the category i was handling, without doing a foreach on all the items and an if to disregard those that didnt belong to the current category.

This seems like an awful lot of loops working with AR objects as oppose to arrays.

So (at last) my question is: Are there some functions that can process returned AR objects in a way that is efficient? Or any other way to solve this scenario with AR objects instead of SQL/array way?

I would suggest something like:

I am assuming your sending the cat_id you want to show records for via the url (controller/action/cat_id/1).



<?php


$criteria = new CDbCriteria;


$criteria->condition = 'cat_id = :cat_id';


$criteria->params = array(':cat_id' => $_GET['cat_id']);


$rows = Items::model()->findAll($criteria);


foreach($rows as $x => $row) {


  // do somthing eg print($row->item_name);


}


I think this is what you might be after?

Chris

No, I'm afraid your suggestion only gets the items for one category at a time. I want to get all categories and process each items in each category… My controller looks something like this:

<?php>


$criteria=new CDbCriteria;


$categories=categories::model()->findAll($criteria);





$criteria=new CDbCriteria;


$items=items::model()->findAll($criteria);


?>

Then I send both of $categories and $items to render the view. In the view I do a foreach on the categories, and further I want to do something with each items belonging to that category.

But since $items is an object of CActiveRecord I have hard time to process it optimal. I'm used to an array, which is really easy to manipulate.

Maby in my case, I should just shouldn't use AR?

I guess what I'm looking for is some CActiveRecord function that takes an cat_id as argument and brings back all items for it…

This is a typical relational query problem that you can exploit AR.

In your categories model, you need to declare a relation 'items' using HAS_MANY.

Then you can do



$categories=categories::model()->with('items')->findAll($criteria);


foreach($categories as $category) {


    foreach($category->items as $item)


       ...


}


That worked very well, thanks!

What if I want to find an item (lets say item_id=5) under a category (lets say cat_id=2) without going through all the data in a foreach? With an array it would be like this:

$res = $categories[2]['items'][5];

Can I for example use something like $categories->find(cat_id, item_id), or will find always fetch from database? (Im thinking that maybe the find function dont contact the db, if it allready got all the objects)