Also available in these languages:
English日本語polskiРусский简体中文

Creating User Menu Portlet

Based on the requirements analysis, we need three different portlets: the "user menu" portlet, the "tag cloud" portlet and the "recent comments" portlet. We will develop these portlets by extending the CPortlet widget provided by Yii.

In this section, we will develop our first concrete portlet - the user menu portlet which displays a list of menu items that are only available to authenticated users. The menu contains four items:

  • Approve Comments: a hyperlink that leads to a list of comments pending approval;
  • Create New Post: a hyperlink that leads to the post creation page;
  • Manage Posts: a hyperlink that leads to the post management page;
  • Logout: a link button that would log out the current user.

Creating UserMenu Class

We create the UserMenu class to represent the logic part of the user menu portlet. The class is saved in the file /wwwroot/blog/protected/components/UserMenu.php which has the following content:

Yii::import('zii.widgets.CPortlet');
 
class UserMenu extends CPortlet
{
    public function init()
    {
        $this->title=CHtml::encode(Yii::app()->user->name);
        parent::init();
    }
 
    protected function renderContent()
    {
        $this->render('userMenu');
    }
}

The UserMenu class extends from the CPortlet class from the zii library. It overrides both the init() method and the renderContent() method of CPortlet. The former sets the portlet title to be the name of the current user; the latter generates the portlet body content by rendering a view named userMenu.

Tip: Notice that we have to explicitly include the CPortlet class by calling Yii::import() before we refer to it the first time. This is because CPortlet is part of the zii project -- the official extension library for Yii. For performance consideration, classes in this project are not listed as core classes. Therefore, we have to import it before we use it the first time.

Creating userMenu View

Next, we create the userMenu view which is saved in the file /wwwroot/blog/protected/components/views/userMenu.php:

<ul>
    <li><?php echo CHtml::link('Create New Post',array('post/create')); ?></li>
    <li><?php echo CHtml::link('Manage Posts',array('post/admin')); ?></li>
    <li><?php echo CHtml::link('Approve Comments',array('comment/index'))
        . ' (' . Comment::model()->pendingCommentCount . ')'; ?></li>
    <li><?php echo CHtml::link('Logout',array('site/logout')); ?></li>
</ul>

Info: By default, view files for a widget should be placed under the views sub-directory of the directory containing the widget class file. The file name must be the same as the view name.

Using UserMenu Portlet

It is time for us to make use of our newly completed UserMenu portlet. We modify the layout view file /wwwroot/blog/protected/views/layouts/column2.php as follows:

......
<div id="sidebar">
    <?php if(!Yii::app()->user->isGuest) $this->widget('UserMenu'); ?>
</div>
......

In the above, we call the widget() method to generate and execute an instance of the UserMenu class. Because the portlet should only be displayed to authenticated users, we only call widget() when the isGuest property of the current user is false (meaning the user is authenticated).

Testing UserMenu Portlet

Let's test what we have so far.

  1. Open a browser window and enter the URL http://www.example.com/blog/index.php. Verify that there is nothing displayed in the side bar section of the page.
  2. Click on the Login hyperlink and fill out the login form to login. If successful, verify that the UserMenu portlet appears in the side bar and the portlet has the username as its title.
  3. Click on the 'Logout' hyperlink in the UserMenu portlet. Verify that the logout action is successful and the UserMenu portlet disappears.

Summary

What we have created is a portlet that is highly reusable. We can easily reuse it in a different project with little or no modification. Moreover, the design of this portlet follows closely the philosophy that logic and presentation should be separated. While we did not point this out in the previous sections, such practice is used nearly everywhere in a typical Yii application.

$Id: portlet.menu.txt 1739 2010-01-22 15:20:03Z qiang.xue $
If you find any typos or errors in the tutorial, please create a Yii ticket to report it. If it is a translation error, please create a Yiidoc ticket, instead. Thank you.

Total 8 comments:

#80
one remark
by jonah at 2:33am on February 17, 2009.

Personally I would rather do:

if (!Yii::app()->user->isGuest)
    $this->widget('UserMenu');

than

$this->widget('UserMenu',array('visible'=>!Yii::app()->user->isGuest));

#108
Re: one remark
by olafure at 3:14am on March 10, 2009.

That seems to work, but: You'll have trouble if later on you want the widget to do something (reserve space, display text, ...) when the user is not logged in. That won't be possible because it's never called.

Besides, it's likely that if there ever will be IDE for Yii, that your approach won't be recognized by the IDE.

Good point though - your way is probably a bit faster, since the object won't be created at all.

#175
Yelp!
by backgammon at 4:25pm on April 7, 2009.

Seem to be getting this error and I cannot determine why:

'Property "Comment.pendingCommentCount" is not defined.'

#186
Re : Yelp!
by thomas.mery at 4:28am on April 10, 2009.

You should have a look (if you have not already :) ) at the stack trace that is returned at the bottom of the rror page.

It says that at some point in userMenu.php there is a call to :

CActiveRecord->__get('pendingCommentC...')

this means that a model is trying to execute a function called :

getPendingCommentCount

if you look at line 3 in the userMenu.php you'll see this :

Comment::model()->pendingCommentCount

which is turned into Comment::model()->getPendingCommentCount() internally

So your Comment model lacks this function (have alook in the original Comment.php model file in the demos/blog/ dir in the yii release)

hope this helps

#425
getPendingCommentCount()
by juanmjimenezs at 6:05am on June 29, 2009.

Hi!, this is the function that you have to paste in the class Comment:

public function getPendingCommentCount() { $criteria = new CDbCriteria; $criteria->condition='status = 0';
return Comments::model()->count($criteria); }

#472
Menu Portlet in Yii 1.0.7?
by lsorgetz at 7:36pm on July 13, 2009.

Why when I use the example above, the user menu portlet does not work in version 1.0.7?

#503
pendingCommentCount, Portlet, etc.
by yii at 7:17am on July 27, 2009.

Hi, somebody has to rewrite this tutorial about Portlets, because there are a lot of problems with version 1.0.7

#1191
What pendingCommentCount?
by Chris83 at 2:30pm on February 27, 2010.

To clarify what juanmjimenezs said above you need an additional function in your Comment model in order for the portlet to work.

public function getPendingCommentCount()
{
   $criteria = new CDbCriteria; $criteria->condition='status = 0';
   return Comment::model()->count($criteria);
}

I corrected a typo and formatted the code so that it's a bit easier to read.

Your Comment:

You may enter comment using Markdown syntax.

Please login with your forum account.
Note: you must have at least ONE forum post with your account.