Managing posts mainly refers to listing posts in an administrative view that allows us to see posts with all statuses, updating them and deleting them. They are accomplished by the admin
operation and the delete
operation, respectively. The code generated by Gii
does not need much modification. Below we mainly explain how these two operations are implemented.
The admin
operation shows posts with all statuses in a tabular view. The view supports sorting and pagination. The following is the actionAdmin()
method in PostController
:
public function actionAdmin()
{
$model=new Post('search');
if(isset($_GET['Post']))
$model->attributes=$_GET['Post'];
$this->render('admin',array(
'model'=>$model,
));
}
The above code is generated by the Gii
tool without any modification. It first creates a Post
model under the search
scenario. We will use this model to collect the search conditions that the user specifies. We then assign to the model the user-supplied data, if any. Finally, we render the admin
view with the model.
Below is the code for the admin
view:
$this->breadcrumbs=array( 'Manage Posts', ); <h1>Manage Posts</h1> $this->widget('zii.widgets.grid.CGridView', array( 'dataProvider'=>$model->search(), 'filter'=>$model, 'columns'=>array( array( 'name'=>'title', 'type'=>'raw', 'value'=>'CHtml::link(CHtml::encode($data->title), $data->url)' ), array( 'name'=>'status', 'value'=>'Lookup::item("PostStatus",$data->status)', 'filter'=>Lookup::items('PostStatus'), ), array( 'name'=>'create_time', 'type'=>'datetime', 'filter'=>false, ), array( 'class'=>'CButtonColumn', ), ), ));
We use CGridView to display the posts. It allows us to sort by a column and paginate through the posts if there are too many to be displayed in a single page. Our change is mainly about how to display each column. For example, for the title
column, we specify that it should be displayed as a hyperlink that points to the detailed view of the post. The expression $data->url
returns the value of the url
property that we define in the Post
class.
Tip: When displaying text, we call CHtml::encode() to encode HTML entities in it. This prevents from cross-site scripting attack.
In the admin
data grid, there is a delete button in each row. Clicking on the button should delete the corresponding post. Internally, this triggers the delete
action implemented as follows:
public function actionDelete()
{
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$this->loadModel()->delete();
if(!isset($_GET['ajax']))
$this->redirect(array('index'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
The above code is the one generated by the Gii
tool without any change. We would like to explain a little bit more about the checking on $_GET['ajax']
. The CGridView widget has a very nice feature that its sorting, pagination and deletion operations are all done in AJAX mode by default. That means, the whole page does not get reloaded if any of the above operations is performed. However, it is also possible that the widget runs in non-AJAX mode (by setting its ajaxUpdate
property to be false or disabling JavaScript on the client side). It is necessary for the delete
action to differentiate these two scenarios: if the delete request is made via AJAX, we should not redirect the user browser; otherwise, we should.
Deleting a post should also cause the deletion of all comments for that post. In addition, we should also update the tbl_tag
table regarding the tags for the deleted post. Both of these tasks can be achieved by writing an afterDelete
method in the Post
model class as follows,
protected function afterDelete()
{
parent::afterDelete();
Comment::model()->deleteAll('post_id='.$this->id);
Tag::model()->updateFrequency($this->tags, '');
}
The above code is very straightforward: it first deletes all those comments whose post_id
is the same as the ID of the deleted post; it then updates the tbl_tag
table for the tags
of the deleted post.
Tip: We have to explicitly delete all comments for the deleted post here because SQLite does not really support foreign key constraints. In a DBMS that supports this constraint (such as MySQL, PostgreSQL), the foreign key constraint can be set up such that the DBMS automatically deletes the related comments if the post is deleted. In that case, we no longer this explicit deletion call in our code.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.