How to save a model from a form

Let's now look at how to save a model from a form, which could be a new or an updated model.

The steps you need to follow are:

  1. In the action method, create a new model or get an existing model.
  2. In the action method, check whether there is data in the $_POST array.
  3. If there is data in $_POST, fill in the attributes property of the model with data from $_POST and call the save() method of the model; if save() returns true, redirect the user to another page (the details page, for example).

From now on, we will continue to use widgets and helper classes provided by the framework. In this case, the HTML form will be rendered using the yiiwidgetActiveForm class.

The most simple form we can write is the following:

<?php
use yiiwidgetsActiveForm;

$form = ActiveForm::begin([
    'id' => 'login-form',
]) ?>
    …
    …
    …
<?php ActiveForm::end() ?>

This code generates a form HTML tag with login-form as the id attribute and empty content; the method and action attributes are respectively, by default, the post and same action URL that generated the form. Other properties about AJAX validation and client validation can be set, as you will see further on.

The widget $form is created by employing a static method ActiveForm::begin, passing as an array that contains attributes of a form HTML tag (id, action, method, and so on) a configuration parameter and a key named options to specify all the extra options that we want to pass to form the HTML tag. Finally, the form will be completed when we call the static method ActiveForm::end(). Between the begin() and end() methods of the form, we can insert all the content needed.

In particular, the input fields of the form can be managed using the ActiveField widget. The ActiveField widget related to an attribute of model is created by calling the field() method of the $form object:

$field = $form->field($model, 'attribute');

The object returned from the field() method is a generic field that we can specialize by simply applying other methods to generate all the common kinds of input fields: hidden, text, password, file, and so on. This returns the same ActiveField $field object, and consequently other methods can be applied in a cascade.

A text field input is created with:

$textInputField = $field->textInput();

Or can be created simply like this:

$textInputField = $form->field($model, 'attribute')->textInput();

This variable $textInputField is again an ActiveField (the same object of $field), so we can apply all the other methods required to complete our input field; for example, if we need to place a hint in input field, we can use:

$textInputField->hint('Enter value');

Or we can simply use:

$textInputField = $form->field($model, 'attribute')->textInput()->hint('Enter value');

Additional framework in addition automatically takes into account the attribute's validation rules, which are defined in the rules() method of the model class. For example, if an attribute is required and we click on it and pass it to another field without typing anything, an error alert will be displayed reminding us that the field is required.

When an input field is created using the ActiveField widget, the id and name properties of this input will have this format: model-class-name_attribute-name for id and model-class-name[attribute-name] for name. This means that all the attributes of the model will be passed to the controller action when we submit the form grouped in a container array named the same as the model class.

For example, if the $model class is Room and the attribute is floor whose content is 12, create a text field from the $form object:

<?php echo $floorInputField = $form->field($model, 'floor')
->textInput()->hint('Enter value for floor');

This outputs the following HTML:

<input id="Room_floor" name="Room[floor]" value="12" placeholder="Enter value for floor" />

Example – creating and updating a room from a form

Just from following the instructions in the previous paragraph, we will try to create and update a room from the HTML form.

We now update the previously created actionCreate() method in RoomsController with some code to instantiate a new model object, check the content of the $_POST array, and if it is set, we call save() on the model:

    public function actionCreate()
    {
        // 1. Create a new Room instance;
        $model = new Room();
        
        // 2. Check if $_POST['Room'] contains data;
        if(isset($_POST['Room']))
        {
            $model->attributes = $_POST['Room'];
            
            // Save model
            if($model->save())
            {
             // If save() success, redirect user to action view.
             return $this->redirect(['view', 'id' => $model->id]);
            }
        }

        return $this->render('create', ['model' => $model]);
    }

To update the view in basic/views/rooms/create.php, pass:

<?php
use yiiwidgetsActiveForm;
use yiihelpersHtml;
?>
 
<div class="row">

    <div class="col-lg-6">
        
        <h2>Create a new room</h2>
            
        <?php $form = ActiveForm::begin(['id' => 'room-form']) ?>

        <?php echo $form->field($model, 'floor')->textInput(); ?>
        <?php echo $form->field($model, 'room_number')->textInput(); ?>
        <?php echo $form->field($model, 'has_conditioner')->checkbox(); ?>
        <?php echo $form->field($model, 'has_tv')->checkbox(); ?>
        <?php echo $form->field($model, 'has_phone')->checkbox(); ?>
        <?php echo $form->field($model, 'available_from')->textInput(); ?>
        <?php echo $form->field($model, 'price_per_day')->textInput(); ?>
        <?php echo $form->field($model, 'description')->textArea(); ?>
        <?php echo Html::submitButton('Save', ['class' => 'btn btn-primary']); ?>
        <?php ActiveForm::end() ?>
    </div>
</div>

By default, ActiveForm::begin() creates a form that has client validation enabled; therefore, the form will be submitted only when all the validation rules are satisfied as the submit button is rendered using yiihelpersHtml.

Pay attention to the top of view that contains the use keyword to define the complete path of the classes Html and ActiveForm:

use yiiwidgetsActiveForm;
use yiihelpersHtml;

Point your browser to http://hostname/basic/rooms/create to display the form to create a new room. The following screenshot shows what you should display, reporting in it some particular conditions:

Example – creating and updating a room from a form

The form to create a new room

This screenshot presents different states of fields: the floor input has a red border because it has the wrong type of content (it must be an integer!), the room number has a green border to indicate that is correct, and the Available From field has a red border because it is required but the user left it blank. The framework provides a more concise form to fill in attributes if $_POST data is available:

$model->load(Yii::$app->request->post());

This fills in the attributes of the model if the $_POST[model-class] content is available, and with this suggestion we can change the actionCreate content as follows:

    public function actionCreate()
    {
        // 1. Create a new Room instance;
        $model = new Room();
        
        // 2. Check if $_POST['Room'] contains data and save model;
        if( $model->load(Yii::$app->request->post()) && ($model->save()) )
        {
            return $this->redirect(['detail', 'id' => $model->id]);
        }
        
        return $this->render('create', ['model' => $model]);
    }

This is extraordinarily concise! Similarly, we can handle the update action to save changes to an existing model.

We can make a reusable form by putting its content in an external. Create a new file in basic/views/rooms/_form.php (the first underscore indicates that this is a view that is includable in other views) and cut and paste the code about form generation from the create view to this new _form view:

<?php
use yiiwidgetsActiveForm;
use yiihelpersHtml;
?>
<?php $form = ActiveForm::begin(['id' => 'room-form']) ?>

<?php echo $form->field($model, 'floor')->textInput(); ?>
<?php echo $form->field($model, 'room_number')->textInput(); ?>
<?php echo $form->field($model, 'has_conditioner')->checkbox(); ?>
<?php echo $form->field($model, 'has_tv')->checkbox(); ?>
<?php echo $form->field($model, 'has_phone')->checkbox(); ?>
<?php echo $form->field($model, 'available_from')->textInput(); ?>
<?php echo $form->field($model, 'price_per_day')->textInput(); ?>
<?php echo $form->field($model, 'description')->textArea(); ?>

<?php echo Html::submitButton('Create', ['class' => 'btn btn-primary']); ?>

<?php ActiveForm::end() ?>

In the basic/views/rooms/create.php file, instead of the form code, just put the code to render the _form view in it:

<?php echo $this->render('_form', ['model' => $model]); ?>

Note

When we modify the create view, remember to pass $model as the second parameter to render the _form view.

We are ready to build the update flow in order to update the room content from a form. Firstly, create an action in basic/controllers/RoomsController.php named actionUpdate, passing $id as a parameter that identifies the primary key to find the model.

In this action, we will put some code to get the model based on the id primary key, check whether the $_POST array contains data, and then save the model:

    public function actionUpdate($id)
    {
        // 1. Create a new Room instance;
        $model = Room::findOne($id);
        
        // 2. Check if $_POST['Room'] contains data and save model;
        if( ($model!=null) && $model->load(Yii::$app->request->post()) && ($model->save()) )
        {
            return $this->redirect(['detail', 'id' => $model->id]);
        }
        
        return $this->render('update', ['model' => $model]);
    }

This is basically equivalent to the code for the create action. Now, create the update view in basic/views/rooms/update.php with the following content:

<div class="row">

    <div class="col-lg-6">
        
        <h2>Update a room</h2>
        <?php echo $this->render('_form', ['model' => $model]); ?>
    </div>

</div>

From the database, check for one existing room and type the id value of this URL in your browser: http://hostname/basic/rooms/update?id=id-found.

For example, if id of an existing room is 1, type this URL in your browser:

http://hostname/basic/rooms/update?id=1

This will show a form with the filled in field based on the model attributes' content.

This example is complete, having built the detail view, which shows the content of model attributes. Create an action named actionDetail, passing $id as a parameter, which identifies the primary key to find the model:

    public function actionDetail($id)
    {
        // 1. Create a new Room instance;
        $model = Room::findOne($id);
        
        return $this->render('detail', ['model' => $model]);
    }

Then, create the detail view to display some of the model attributes' values in basic/views/rooms/detail.php:

<table class="table">
    <tr>
        <th>ID</th>
        <td><?php echo $model['id'] ?></td>
    </tr>
    <tr>
        <th>Floor</th>
        <td><?php echo $model['floor'] ?></td>
    </tr>
    <tr>
        <th>Room number</th>
        <td><?php echo $model['room_number'] ?></td>
    </tr>
</table>

Now after successfully creating or updating model, the detail view will be displayed with the content of some attributes of the model.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.8.34