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:
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
CPortletclass by callingYii::import()before we refer to it the first time. This is becauseCPortletis part of theziiproject -- 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.
userMenu View ¶Next, we create the userMenu view which is saved in the file /wwwroot/blog/protected/components/views/userMenu.php:
<ul> <li> echo CHtml::link('Create New Post',array('post/create')); </li> <li> echo CHtml::link('Manage Posts',array('post/admin')); </li> <li> echo CHtml::link('Approve Comments',array('comment/index')) . ' (' . Comment::model()->pendingCommentCount . ')'; </li> <li> echo CHtml::link('Logout',array('site/logout')); </li> </ul>
Info: By default, view files for a widget should be placed under the
viewssub-directory of the directory containing the widget class file. The file name must be the same as the view name.
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"> 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).
UserMenu Portlet ¶Let's test what we have so far.
http://www.example.com/blog/index.php. Verify that there is nothing displayed in the side bar section of the page.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.UserMenu portlet. Verify that the logout action is successful and the UserMenu portlet disappears.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.
Found a typo, or you think this page needs improvement?
Edit it on GitHub !
What pendingCommentCount?
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); }pendingCommentCount, better way
Regarding Chris83 implementation of the method:
This is a much better way to implement the getPendingCommentCount() method
public function getPendingCommentCount() { return $this->count('status=:status', array(':status'=>self::STATUS_PENDING)); }The method is in the Comment model so we should use $this not Comment::, also we should use the defined constants to identify the comment status.
Using CDbCriteria to implement the count is overkill and uncalled for, possibly wasting cpu cycles.
here's an even cleaner, shorter way, if you're into making the code as succinct as possible without being cryptic:
public function getPendingCommentCount() { return $this->count('status='.self::STATUS_PENDING); }Where to put the getPendingCommentCount()
The described getPendingCommentCount() method is needed in the comment model file. It's located under /protected/models/comment.php
Signup or Login in order to comment.