0 follower

Displaying Posts

In our blog application, a post may be displayed among a list of posts or by itself. The former is implemented as the list operation while the latter the show operation. In this section, we customize both operations to fulfill our initial requirements.

1. Customizing show Operation

The show operation is implemented by the actionShow() method in PostController. Its display is generated by the show view with the view file /wwwroot/blog/protected/views/post/show.php.

Below is the relevant code implementing the show operation in PostController:

public function actionShow()
{
    $this->render('show',array(
        'post'=>$this->loadPost(),
    ));
}
 
private $_post;
 
protected function loadPost($id=null)
{
    if($this->_post===null)
    {
        if($id!==null || isset($_GET['id']))
            $this->_post=Post::model()->findbyPk($id!==null ? $id : $_GET['id']);
        if($this->_post===null || Yii::app()->user->isGuest &&
            $this->_post->status!=Post::STATUS_PUBLISHED)
            throw new CHttpException(404,'The requested post does not exist.');
    }
    return $this->_post;
}

Our change mainly lies in the loadPost() method. In this method, we query the Post table according to the id GET parameter. If the post is not found or if it is not published (when the user is a guest), we will throw a 404 HTTP error. Otherwise the post object is returned to actionShow() which in turn passes the post object to the show view for further display.

Tip: Yii captures HTTP exceptions (instances of CHttpException) and displays them in error pages using some predefined templates. These templates can be customized per application, which we will describe in detail at the end of this tutorial.

The change in the show view is mainly about ajdusting the formatting and styles of the post display. We will not go into details here.

2. Customizing list Operation

Like the show operation, we customize the list operation in two places: the actionList() method in PostController and the view file /wwwroot/blog/protected/views/post/list.php. We mainly need to add the support for displaying a list of posts that are associated with a specified tag.

Below is the modified actionList() method in PostController:

public function actionList()
{
    $criteria=new CDbCriteria;
    $criteria->condition='status='.Post::STATUS_PUBLISHED;
    $criteria->order='createTime DESC';
 
    $withOption=array('author');
    if(!empty($_GET['tag']))
    {
        $withOption['tagFilter']['params'][':tag']=$_GET['tag'];
        $postCount=Post::model()->with($withOption)->count($criteria);
    }
    else
        $postCount=Post::model()->count($criteria);
 
    $pages=new CPagination($postCount);
    $pages->applyLimit($criteria);
 
    $posts=Post::model()->with($withOption)->findAll($criteria);
 
    $this->render('list',array(
        'posts'=>$posts,
        'pages'=>$pages,
    ));
}

In the above, we first create a query criteria which specifies only published posts should be listed and they should be sorted according to their creation time in descending order. We then compute the total number of posts satisfying the criteria. The number is used by the pagination component to correctly compute how many pages the posts should be displayed in. Finally, we retrieve the post data from the database and send them to the list view for display.

Notice that when there is tag GET parameter, we would query with the tagFilter using the corresponding GET parameter value. Including tagFilter in the relational query will ensure that only a single SQL JOIN statement is used to retrieve the posts with the specified tag. Without this call, Yii would break the query into two separate SQL statements (for efficiency concern) and would return incorrect results.

Two variables are passed to the list view: $posts and $pages. The former refers to the list of posts be displayed, while the latter contains pagination information (e.g. how many pages in total, what is the current page). The list view contains a pagination widget that can automatically display posts in separate pages if there are too many of them.