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

Creating and Updating Posts

With the Post model ready, we need to fine-tune the actions and views for the controller PostController. In this section, we first customize the access control of CRUD operations; we then modify the code implementing the create and update operations.

Customizing Access Control

The first thing we want to do is to customize the access control because the code generated by yiic does not fit our needs.

We modify the accessRules() method in the file /wwwroot/blog/protected/controllers/PostController.php as follows,

public function accessRules()
{
    return array(
        array('allow',  // allow all users to perform 'list' and 'show' actions
            'actions'=>array('index', 'view'),
            'users'=>array('*'),
        ),
        array('allow', // allow authenticated users to perform any action
            'users'=>array('@'),
        ),
        array('deny',  // deny all users
            'users'=>array('*'),
        ),
    );
}

The above rules state that all users can access the index and view actions, and authenticated users can access any actions, including the admin action. The user should be denied access in any other scenario. Note that these rules are evaluated in the order they are listed here. The first rule matching the current context makes the access decision. For example, if the current user is the system owner who tries to visit the post creation page, the second rule will match and it will give the access to the user.

Customizing create and update Operations

The create and update operations are very similar. They both need to display an HTML form to collect user inputs, validate them, and save them into database. The main difference is that the update operation will pre-populate the form with the existing post data found in the database. For this reason, the yiic tool generates a partial view /wwwroot/blog/protected/views/post/_form.php that is embedded in both the create and update views to render the needed HTML form.

We first change the _form.php file so that the HTML form only collects the inputs we want: title, content, tags and status. We use plain text fields to collect inputs for the first three attributes, and a dropdown list to collect input for status. The dropdown list options are the text displays of the possible post statuses:

<?php echo $form->dropDownList($model,'status',Lookup::items('PostStatus')); ?>

In the above, we call Lookup::items('PostStatus') to bring back the list of post statuses.

We then modify the Post class so that it can automatically set some attributes (e.g. create_time, author_id) before a post is saved to the database. We override the beforeSave() method as follows,

protected function beforeSave()
{
    if(parent::beforeSave())
    {
        if($this->isNewRecord)
        {
            $this->create_time=$this->update_time=time();
            $this->author_id=Yii::app()->user->id;
        }
        else
            $this->update_time=time();
        return true;
    }
    else
        return false;
}

When we save a post, we want to update the tbl_tag table to reflect the change of tag frequencies. We can do this work in the afterSave() method, which is automatically invoked by Yii after a post is successfully saved into the database.

protected function afterSave()
{
    parent::afterSave();
    Tag::model()->updateFrequency($this->_oldTags, $this->tags);
}
 
private $_oldTags;
 
protected function afterFind()
{
    parent::afterFind();
    $this->_oldTags=$this->tags;
}

In the implementation, because we want to detect if the user changes the tags in case he is updating an existing post, we need to know what the old tags are. For this reason, we also write the afterFind() method to keep the old tags in the variable _oldTags. The method afterFind() is invoked automatically by Yii when an AR record is populated with the data from database.

We are not going to give details of the Tag::updateFrequency() method here. Interested readers may refer to the file /wwwroot/yii/demos/blog/protected/models/Tag.php.

$Id: post.create.txt 2120 2010-05-10 01:29:41Z 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 12 comments:

#101
Transactions
by cmorinico at 3:59am on March 2, 2009.

Hello, thanks for this wonderful tutorial. How can we implement saving the data in one transaction, so we are free of orphan or missing records in case of a server failure? This applies here and on many other cases where you have to update or insert data in multiple tables.

Thanks again. Claudio.

#107
Re: Transactions
by olafure at 3:23am on March 9, 2009.

See the Using Transactions in the Guide.

#148
missing informations ?
by thomas.mery at 3:43am on March 28, 2009.

Hello,

first of all Thanks for Yii (TFY) !

As for my comment :

Maybe i ovelooked part of this tutorial so far but should it not specify that you need to add the tags input field in the form view for the saving of the tags to work ?

And also add a name attribute to the submit button in the form view for the changes to the PostController to work ?

CHtml::submitButton($update ? 'Save' : 'Create', array('name' => 'submitPost'));

Thank you for letting us know if this is intentional (or if I actually have not read correctly)

#250
HELP - date/time problems
by backgammon at 4:25pm on April 29, 2009.
  • am getting this error when I try to manage a blog post:

A non well formed numeric value encountered

And it is singling out this line as being the source of the error:

00024:

<?php echo date('F j, Y',$post->createTime); ?>

Also worth noting:

When the date/time value is being submitted to the database, it is going in as all 0's - 0000-00-00 00:00:00

Any help or suggestions would be helpful.

Thanks.

Peace

#296
Missing a Query Object
by alfanhui at 5:58pm on May 16, 2009.

I've been missing a Query Object to avoiding SQL hardcoding

#318
Why not a transaction for post related tags saving action?
by skyblaze at 5:41am on May 25, 2009.

I wonder if it is better to use a transaction for the post and relative tag associations rows instead of using the beforeSave method

#368
Correction
by Luiz at 6:11pm on June 9, 2009.

Change $post to $model in the 1.0.6 release: <?php echo CHtml::activeDropDownList($post,'status',Post::model()->statusOptions); ?>

<?php echo CHtml::activeDropDownList($model,'status',Post::model()->statusOptions); ?>

#460
When adding the Preview button, you also need to name the submit button
by nutshell at 7:29am on July 9, 2009.

The new code for the actionCreate function, checks which button (Submit or Preview) has been pressed by looking at:

$_POST'previewPost' or $_POST'submitPost'

This means you'll have to name both buttons. The code for the new Preview button looks like:

<?php echo CHtml::submitButton('Preview',array('name'=>'previewPost')); ?>

Doing the same for submit button would result in:

<?php echo CHtml::submitButton($update ? 'Save' : 'Create', array('name'=>**'submitPost'**)); ?>
#532
Error with beforeValidate()
by Backslider at 8:07pm on August 2, 2009.

I get this far with the tutorial, then when I try to post a comment I get the following error:

Missing argument 1 for Post::beforeValidate(), called in C:\wamp\www\yii\framework\base\CModel.php on line 147 and defined

#652
model name ?
by mech7 at 9:02pm on September 11, 2009.

Am not sure if i skipped something but the CRUD generates with me $model... but all references here use $post

#662
mysql...
by mech7 at 9:58pm on September 17, 2009.

beforeValidate timestamps do not work in mysql...

#688
mysql
by Mungo at 9:37am on September 29, 2009.

This helped me with the 00000 timestamp problem:

http://www.yiiframework.com/doc/cookbook/10/

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.