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:
action
method, create a new model or get an existing model.action
method, check whether there is data in the $_POST
array.$_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" />
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:
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]); ?>
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.
52.14.8.34