Creating ReadPost Page

The ReadPost page shows the detailed content of a blog post. For authorized users, it also shows link buttons that would allow them to edit or delete the post.

We create two files protected/pages/posts/ReadPost.page and protected/pages/posts/ReadPost.php to save the page template and page class, respectively.

Creating Page Template

The ReadPost page template is very similar to the PostRenderer template, both presenting the content of a post. The difference is that ReadPost needs to display two link buttons when the current user is authorized to edit or delete the post.

<com:TContent ID="Main">

<h2>
<com:TLiteral Text="<%= $this->Post->title %>" />
</h2>

<com:TControl Visible="<%= $this->canEdit() %>">
	<a href="<%= $this->Service->constructUrl('posts.EditPost',array('id'=>$this->Post->post_id))%>">Edit</a> |
	<com:TLinkButton Text="Delete"
		OnClick="deletePost"
		Attributes.onclick="javascript:if(!confirm('Are you sure?')) return false;" />
</com:TControl>

<p>
Author:
<com:TLiteral Text="<%= $this->Post->author->username %>" /><br/>
Time:
<com:TLiteral Text="<%= date('m/d/Y h:m:sa', $this->Post->create_time) %>" />
</p>

<p>
<com:TLiteral Text="<%= $this->Post->content %>" />
</p>

</com:TContent>

Many PHP expressions are used in the above template. The expression $this->Post refers to a property defined in the ReadPost page class. It represents the PostRecord object corresponding to the post currently being viewed.

Info: Although we use expressions widely in templates, we do not overuse them. A major guideline in determining whether we should use an expression in a template is that the expression should be a property or a simple presentational transformation of the property. By following this guideline, we ensure content and presentation are well separated without losing sufficient flexibility.

We also notice in the above template that two link buttons are enclosed within a TControl whose visibility is determined by the expression $this->canEdit(). For the Delete link button, we use javascript confirmation dialog to obtain user's confirmation when he clicks to delete the post.

Info: All PRADO controls have a very useful property named Attributes which can accept arbitrary name-value pairs. Most PRADO controls will render the name-value pairs in Attributes literally in the corresponding HTML tag. For example, in the Delete link button above, we define an onclick which is rendered as the onclick attribute in the resulting <a> tag.

Creating Page Class

From the above page template, we see that we need to write a page class that implements the event handler: deletePost() (attached to the Delete button's OnClick event). We also need to retrieve the post data specified by the post ID passed via the id GET parameter.

Info: We implement the post deletion feature in the ReadPost page because it is so natural to do so here. When the user clicks on the Delete button, a javascript confirmation dialog will pop up. If the user confirms it, the deletion will be carried in response to the OnClick event of the Delete button.
class ReadPost extends TPage
{
	private $_post;
	/**
	 * Fetches the post data.
	 * This method is invoked by the framework when initializing the page
	 * @param mixed event parameter
	 */
	public function onInit($param)
	{
		parent::onInit($param);
		// post id is passed via the 'id' GET parameter
		$postID=(int)$this->Request['id'];
		// retrieves PostRecord with author information filled in
		$this->_post=PostRecord::finder()->withAuthor()->findByPk($postID);
		if($this->_post===null)  // if post id is invalid
			throw new THttpException(500,'Unable to find the specified post.');
		// set the page title as the post title
		$this->Title=$this->_post->title;
	}

	/**
	 * @return PostRecord the PostRecord currently being viewed
	 */
	public function getPost()
	{
		return $this->_post;
	}

	/**
	 * Deletes the post currently being viewed
	 * This method is invoked when the user clicks on the "Delete" button
	 */
	public function deletePost($sender,$param)
	{
		// only the author or the administrator can delete a post
		if(!$this->canEdit())
			throw new THttpException('You are not allowed to perform this action.');
		// delete it from DB
		$this->_post->delete();
		// redirect the browser to the homepage
		$this->Response->redirect($this->Service->DefaultPageUrl);
	}

	/**
	 * @return boolean whether the current user can edit/delete the post being viewed
	 */
	public function canEdit()
	{
		// only the author or the administrator can edit/delete a post
		return $this->User->Name===$this->Post->author_id || $this->User->IsAdmin;
	}
}

Testing

To test the ReadPost page, visit the URL http://hostname/blog/index.php and click on the title of the only post. Our browser will display the following result with the URL http://hostname/blog/index.php?page=ReadPost&id=1. Note, if we do not login, the two link buttons will be invisible.