Friday, December 3, 2010

YII » How to display a related HAS_MANY grid

In this example, we have a Cars table, as well as a Dealers table. A dealer has many cars.

I want to show the (single) Dealer view, but also all of the cars that belong to this dealer in a grid on the same page. Here's how:

In your Dealer model, you should have something like this:

public function relations()
{
return array('cars' => array(self::HAS_MANY, 'Cars', 'dealer_id'),);
}

In your view, you have to convert the related cars data to a CArrayDataProvider for it to work with the CGridview. You also need to adjust the button Urls in the CGridView.

In your Dealer view "view.php", below your CDetailView, add this:

$config = array();
$dataProvider = new CArrayDataProvider($rawData=$model->cars, $config);

$this->widget('zii.widgets.grid.CGridView', array(
    'dataProvider'=>$dataProvider
    , 'columns'=>array(
        'id'
        , 'name'
        , array(
            'class'=>'CButtonColumn'
            , 'viewButtonUrl'=>'Yii::app()->createUrl("/Cars/view", array("id"=>$data["id"]))'
            , 'updateButtonUrl'=>'Yii::app()->createUrl("/Cars/update", array("id"=>$data["id"]))'
            , 'deleteButtonUrl'=>'Yii::app()->createUrl("/Cars/delete", array("id"=>$data["id"]))'
            )
    )
));

Note that the viewButtonUrl is a PHP expression, but it's quoted. The $data field is the name of the row object inside the grid.

12 comments:

  1. Thanks McGuigan for this tutorial!

    fouss

    ReplyDelete
  2. Hello McGuigan,

    It works find but how to do if I want cars of dealers which category= 'some category' ?

    dealer(id,name,category)
    car(id,type,colour,dealer_id)

    thanks!

    fouss

    ReplyDelete
  3. It displays can't find cars.id field error.

    ReplyDelete
  4. If you experience cars.id field error, change
    $config = array();
    with
    $config = array('keyField' => 'dealer_id');
    and look at
    http://harrybailey.com/2011/07/yii-model-id-not-defined-for-carraydataprovider-and-csqldataprovider-etc/

    thanks 4 all!!!

    ReplyDelete
  5. updating... this is some good stuff should be easy for ppl to find...

    ReplyDelete
  6. how about adding a new car to a dealer? How should one setup the new/add button?

    ReplyDelete
  7. Found this page in my googling and found a slight improvment. Instead of using the CArrayDataProvider, a CActiveDataProvider will let the CGridView use the attributeLabel property in your relation. So, this example could be amended:

    -$dataProvider = new CArrayDataProvider($rawData=$model->cars, $config);
    +$dataProvider = new CActiveDataProvider('Cars', array('data' => $model->cars));

    ReplyDelete
    Replies
    1. Great man, you save a lot of work ;-)

      Delete
  8. its working good thnx.....

    ReplyDelete
  9. Perfecto funcionó, muy claro. Gracias.

    ReplyDelete
  10. Hi McGuigan,

    Thanks for the article. I am trying to get CListView to display items from 3 different models. I wanna make 3 separate queries (due to performance and other reasons) to 3 models and finally merge the data into one array and use this array for the view. I tried to use CArrayDataProvider to merge those arrays but not sure how to use them on the view. I wanna know how to deal with @var declaration in this case. Your help would be greatly appreciated.

    Thanks.

    ReplyDelete