Repeated Partial View

Hi everyone,

I have an online shop website and I need to output a lot of products almost in every page on the website.

Each product is inside a bordered box, like here .

I want to have a partial template of a single box so all I will have to do is

just duplicate the template and replace the params inside it.

I think the best way to do this is to make a component that:

  1. get products query results as an argument.

  2. duplicate the product template and replace params for each product.

  3. return HTML code.

What do you think? Is there a better way to do that?

Thanks!

Sounds like you want to take a look at CListView ((http://www.yiiframework.com/doc/api/1.1/CListView). That will take care of step two from your list without having to write a custom component. :)

Thank you, it is exactly what I need…

But CListView accept only CActiveDataProvider object as dataProvider.

Is there a way to make it work with my ActiveRecord results (products query)?

Thanks again!

I think it doesn’t matter which data provider you pass to the CListView. They are all implemented from the same IDataProvider interface.

All components which use a data provider call the same data provider methods defined in the interface. Cause each data provider is different also the implementation of these methods are different but the result is always the same.

Somebody may correct me if I’m wrong.

The docs say CActiveDataProvider is preferred, but you can use any dataprovider I think, like kokomo said. You would probably need to show some code for a more detailed answer, but if you are using a custum SQL string, you might consider the CSqlDataProvider. That uses a regular SQL statement so it probably works for most very custom cases. I haven’t used CSqlDataProvider myself yet, so you will need to figure out how suitable it is for yourself.

Alternatively, it might be that your code is easily refactorable to use CActiveDataprovider. By the way, the CActiveDataProdiver uses ActiveRecord to query the database. So again, maybe some code might help you get a more detailed answer.

I’m not sure how helpful this answer was, my thoughts don’t translate to words too well at the moment it seems, but I hope you have some points to go on.

Hi guys thank you for trying to help me.

I tried to pass the CActiveRecord Object to CListView:

Controller:


$dataProvider = Product::model()->with(array(

				'family:published',

				'family.brand',

				'family.subSection:published',

				))->findAll(array('group'=>'family.family_id')); // I checked and this query is working fine


$this->render('index', array('dataProvider'=>$dataProvider));

View:


$this->widget('zii.widgets.CListView', array(

	    'dataProvider'=>$dataProvider,

	    'itemView'=>'../product/_product',

	));

The error I get:

Call to a member function getData() on a non-object in …\framework\zii\widgets\CBaseListView.php on line 105

Anything wrong?

BTW: It is working when I use DB criteria…

Thanks :)

There are probably no returned rows, you could remove the conditions and see if it works (only findAll()) and then add the conditions one by one

Not the problem…I checked thisa again to make sure.

I think I know what is the problem.

Any criteria/activerecord I’m doing in the conroller and pass it to the view doesn’t work.

But if I use criteria/activerecord (same code) in the view, the widget is working.

Any object supplied to a view is changing it’s type…

The listview code is correct, So it must be the dataprovider, if you use this, does it return the same error?


$dataProvider = Product::model()->findAll()

This should output the amount of returned (limited) rows


echo count($dataProvider->getData());

OK, I tried what you said in the controller:


$dataProvider = Product::model()->findAll();

echo count($dataProvider->getData());

The error I get is the same:

"Fatal error: Call to a member function getData() on a non-object…"

That makes sense as…


$dataProvider = Product::model()->findAll()

… does not return a data provider object, but an array. What you need is to make $dataProvider something like this (untested, but you can fine-tune where needed):




$dataProvider = new CActiveDataProvider('Product', array(

    'criteria' => array(

        'with' => array(

            'family:published',

            'family.brand',

            'family.subSection:published',

        ),

        'condition' => 'group = family.family_id',

    )

));



Check CDbCriteria for details, as I am not 100% sure I correctly implemented it, but it should be close enough for the general idea.

Also note that rather than pre-fetching the query results (as you attempt to do now), CListView will call the findAll() method for you, supplying it dataprovider. You won’t need to use the getData() call yourself, as it is being done for you.

Hope this helps.

Oh that’s right, and even makes sense,

I tried it and its working!

Thank you!

Glad you got it working. :)

Lol that’s right sorry, glad you got it working