Making CGridView Display Different Values From Different Models

I have a model of a particular table which is running fine and works great with CGridView. The main issue I have is that I need to display information from other models based on values from the main model.

For example, lets say I have a "main model" called "Customers." They have some kind of field that indicates a kind of ice cream they got with a number. So, in the model -


class Customer extends CActiveRecord {

    ...

    private $iceCreamType; //stores a number (0/1/2) to determine the column to look at

    ...

}



In another model, "IceCream", it defines what each kind of ice cream is:




class IceCream extends CActiveRecord {

    ...

    private $iceCreamType-1;  //Chocolate

    private $iceCreamType-2;  //Vanilla

    private $iceCreamType-3;  //Strawberry

    ...

}



In this case, CGridView is using “Customer” as its main model as that’s where most of the data comes from. My question is, how do I tell CGridView to use Customer::iceCreamType in the data set from the IceCream model to obtain its output value? I guess I’m looking for something like this:




<?php $this->widget( 'zii.widgets.grid.CGridView', array(

    'dataProvider' => $dataProvider,

    'columns' => array(

        array( 

            'name' => 'iceCreamType',

            'header' => 'Type of Ice Cream',

            'value' => '$iceCreamData[ "iceCreamType-" . $data->iceCreamType ]',

        ),

        ...

    ),

);



Are there any ideas on this? I tried something like this to no avail:


'value' => 'IceCream::model()->findBySQL( "SELECT iceCreamType-" . $data->iceCreamType . " FROM IceCream WHERE ...'" ),

In addition to not working properly, it looks very ugly and isn’t super usable. Any ideas? Thanks!

I realize your example is an illustration, but it doesn’t make sense for IceCream to have three attributes to define three types, as though they were constants. One attribute ought to do it.

At any rate, you need to define a relation in each model that reflects this. Then you can call on these relations in constructing your data provider.

Customer will have:




public function relations()

{

    return array(

        'iceCream'=>array(self::BELONGS_TO,'IceCream','iceCreamType'),

    );

}



IceCream will have:




public function relations()

{

    return array(

        'customers'=>array(self::HAS_MANY,'Customer','type'), // if you rename IceCream's attribute to 'type'

    );

}



And the data provider:




<?php $this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider'=>new CActiveDataProvider('Customer',array(

        'criteria'=>array(

            'with'=>array( 

                'iceCream'=>array(

                    'select'= 'type',

                ),

            ),

        ),

    )),

));



While I know my example seems completely wrong due to the fact that the table design is not very great, you don’t always get to choose what you’re working with and you just have to run with it :)

Thanks a bunch for the example. That looks like it’ll work out, or at least I’ll be able to give it a shot!

Understood! In that case you’ll need three separate relations each way. Ughh, what if they go to Baskin-Robbins and you have to add 54 more attributes? (I suppose I’m showing my age with that one.)

More info.

Hahah! That’s hilarious. And frankly, very true… eek.

I think, though, it might be a fixed number of “types” of “ice cream” in my actual case (the Ice Cream analogy is a little flawed in this way) but that doesn’t make it anymore logical really… especially when you’re trying to do things in a clean fashion.

Thanks for the link! The relations never really made much sense to me from working through the blog tutorial or reading things in the API but this looks like it’ll clear stuff up. Awesome.