List View Grouping

How can I group restaurant menu items by their category? So I end up with: (see set up below)

Category Title 1

  • Menu Item Title 1

  • Menu Item Title 2

  • Menu Item Title 3

Category Title 2

  • Menu Item Title 4

  • Menu Item Title 5

  • Menu Item Title 6

ie-

Breakfast

  • Fried Eggs

  • Pancakes

  • Waffles

Lunch

  • Hamburger

  • Sandwich

  • Soup

I have two tables: menu_item (id, title, menu_category_id) and menu_category (id, title)

Each menu item is assigned a menu category

I have a relationship in my Menu model called "category" that links Menu and MenuCategory




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

    'criteria'=>array(

        'with'=>array('category'),

    ),

));



Everything works fine but the default CListView displays like this:

Category Title 1

  • Menu Item Title 1

Category Title 1

  • Menu Item Title 2

Category Title 1

  • Menu Item Title 3

Category Title 2

  • Menu Item Title 4

Category Title 2

  • Menu Item Title 5

Category Title 2

  • Menu Item Title 6

I also have same problem and I solved it in this way. Don’t know if it is an appropriate way but it works.




<?php

/* get all categories */

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

foreach ($categories as $category) 

{

    echo '<div class="title-style">';

    echo $category->name;

    echo '</div>';

    

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

        'data' => $model->findByAttributes(array('category_id' => $category->id)),

        'attributes' => array(

            'menu_name',

        ),

    ));

}

?>



Thanks for the example Mohsin. I ended up doing something very similar but… but it does seem like there should be a better way.

This is what I did:




public function actionIndex()

{

    $criteria=new CDbCriteria;

    $criteria->select='DISTINCT t.title';

    $criteria->condition='t.active=1';

    $criteria->order='menu_position ASC';

    $criteria->join='INNER JOIN menu ON menu.menu_category_id=t.id';


    $category=new CActiveDataProvider('MenuCategory', array(

        'criteria'=>$criteria,

    ));


    $criteria=new CDbCriteria;

    $criteria->condition='t.active=1';

    $criteria->order='category.menu_position ASC, category_position ASC';

    $criteria->with=array('category');


    $menu=new CActiveDataProvider('Menu', array(

        'criteria'=>$criteria,

     ));


    $this->render('index',array(

        'dataProvider'=>$menu,

        'categories'=>$category,

    ));

}



First I made a data provider with unique categories that have also been used in the menu table. Then made a data provider with my menu and their respective category.

Then in my view I looped like you.




<?php foreach ($categories->data as $category) { ?>

    <h2><?php echo CHtml::link(CHtml::encode($category->title),'',array('name'=>strtolower(CHtml::encode($category->title)))); ?></h2>


    <?php foreach ($dataProvider->data as $item) { ?>

        <?php if ($item->category->title == $category->title) { ?>

            <div class="view menuitem">

                <p class="price">

                    $<?php echo CHtml::encode($item->price); ?>

                </p>

                <h4><?php echo CHtml::link(CHtml::encode($item->title),Yii::app()->createUrl('menu/'.$item->id),array('name'=>strtolower(CHtml::encode($item->title)))); ?></h4>

                <p><?php echo $item->description; ?></p>

            </div>

        <?php } ?>

    <?php } ?>

<?php } ?>



Nothing wrong with this solution. Only thing I’d add is a with(), and maybe a together(), in with the find. That way it only performs one SQL query rather than one per category. As this can avoid some query overhead and be quicker, more noticeable if you connect over TCP though.

I am doing something similar to this problem. I have a table Comic in which I stores: ComicID (PK) and Comic_Title. And I want to display all available comics grouped by the first letter of comic’s title like this:

A.

Air Craft [specific space] Alibaba [specific space] Amma

B.

Boys [specific space] Boys and Girls [specific space] BBB

Can anyone suggest me a way to display comics like that?

Dear Friend

If you have model Book and a field name as title, then we can do the following.




$books=Book::model()->findAll(array(

'order'=>"title ASC"

));



Then the following code will serve the purpose




$alphabet="";






foreach($books as $book)

{

    $bookFirstLetter=strtoupper(substr($book->title,0,1));

    if($bookFirstLetter!==$alphabet)

    {   

         echo "</br>".$bookFirstLetter."</br>";

         $alphabet=$bookFirstLetter;

    }


    echo $book->title." </t> ";

}



The code is very nascent; apply your own aesthetics.

Regards.

Ok thanks :). I got the idea. I am working on CSS to display my comics as my expected way.