This is the part 2 of the series, Inside Yii 2. Here we will be looking at Model in the MVC pattern, and how we can make use of it in Yii 2.

This post assumes that you read the part 1 of the series.

Models

The extract below from wikipedia tells us how we can reason about the M in the MVC pattern.

A model stores data that is retrieved according to commands from the controller and displayed in the view.

The code for this post can be found here. Just checkout branch models-part2.

Simple right?

To break it down a bit, the following highlights how we can use it:

  • I use Model to represent and accept user inputs e.g User details.

  • I can define some validation rules on the Model to ascertain a valid and expected user input.

  • I use the Model to store the valid user input data either in memory or persist the data to a storage e.g. MySQL, Redis e.t.c

  • When the user later asks for the saved information, we will retrieve the data from where it was stored via the model and present it to the user.

We can simply visualize it this way:

Storing: User -> View -> Controller -> Model -> Storage

Retrieving: User <- View <- Controller <- Model <- Storage

The data flows in the direction of the arrows.

Enough of the bla bla bla… let’s do some fun stuff.

Creating Models

There are two options, creating the file manually or using Yii 2 in-built gii command.

version output

The model generator takes two required options --tableName and --modelClass. We can get this by running php yii gii/model --help from the root of our application. The command also gives us details of other options and their default values.

  • --modelClass - This is the name of the ActiveRecord class that would be generated. AR provides an object-oriented solution, which helps us to interact with our DB tables. More details about AR implementation in Yii 2 is here - AR in Yii.

  • --tableName - Name of the database table that the ActiveRecord class is associated with.

Setup App DB

Before moving forward, we need to first create a DB and table. I expect you already have a MySQL server setup in your local environment. If not, you can get MySQL up and running from here.

I will assume you now have MySQL running, just create a database. I will call mine inside_yii2_db.

Create tables

We will go ahead and create our db tables. We will do that manually and you can use the sql query below to create yours, though Yii comes with a very nice way of creating our db structure using db migration feature, just like in most frameworks. But we wouldn’t do that now, may be in future posts.

CREATE TABLE `semesters` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `courses` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL DEFAULT '',
  `semester_id` int(11) unsigned NOT NULL,
  `total_registered` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `fk_courses_semester_id` (`semester_id`),
  CONSTRAINT `fk_courses_semester_id` FOREIGN KEY (`semester_id`) REFERENCES `semesters` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Update db credentials on the db config
  • Open the db config file - config/db.php
<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=127.0.0.1;dbname=inside_yii2_db',
    'username' => 'devuser',
    'password' => 'secret',
    'charset' => 'utf8',
];

You can update the credentials - dbname, username, password for your own environment.

Create Model with command

The commands below will create the corresponding models for our tables

  • php yii gii/model --tableName=semesters --modelClass=Semester

  • php yii gii/model --tableName=courses --modelClass=Course

One of benefits of model generator is that it reads the constraints, columns data types as defined in the table and generates rules for validation, relations based on foreign key constraints.

You can open the models classes

  • models/Semester.php

  • models/Course.php

Note:

The generator will generate the relations using the database names.

For example, check Course.php

/**
* @return \yii\db\ActiveQuery
*/
public function getSemester()
{
    return $this->hasOne(Semesters::className(), ['id' => 'semester_id']);
}

We can see in the method above, the relation class name is Semesters (plural) instead of Semester (singular) - this is the ideal naming convention for a model since the ActiveRecord class represents a single record in the semesters table.

The generator uses the table name of the related table via the foreign key to create the relations method. To avoid modifying the generated class, some preferred naming their db tables in singular noun.

Model rules
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['semester_id'], 'required'],
            [['semester_id', 'total_registered'], 'integer'],
            [['name'], 'string', 'max' => 50],
            [['semester_id'], 'exist', 'skipOnError' => true, 'targetClass' => Semester::className(), 'targetAttribute' => ['semester_id' => 'id']],
        ];
    }

Let’s look at the rules one by one. - required: As we can see, the generated rules defined semester_id as a required field, when we call method validate on course model and the semester_id is missing, it will fail with error message Semester ID cannot be blank..

  • integer: If you try to save any other value other than integer in any of the fields defined as integer, the validation will fail with message Total Registered must be an integer.

  • max: Here we defined that the maximun length for field name is 50.

  • exist: This is another interesting validator, this validator checks if the value in semester_id can be found in the target column of the table represented by the target class, i.e. is there is record in semesters table whose id is what we have in the semester_id.

There are many other useful validators that the framework provides.

Load, Validate and Save

Now let’s look at some basic methods that we can call on a model to successfully save it.

$data = [
  'Semester' => [
    'name' => 'Spring',
  ]
];

// create the instance of the model
$semester = new Semester();

// load the data (e.g. user input from the post data from the http request)
$semester->load($data);

// if validate is successful, save it
if ($semester->validate()) {
  $semester->save();
} else {
  var_dump($semester->getErrors());
}

If validation fails, we can get the errors by calling getErrors() on the model.

In the next post of the series Inside-Yii2 part 3, we will look at form models and how we can use it to take user inputs, clean it up, validate, load the cleaned input to the actual model and save.

WATCH OUT! for more.

You can get the application code on github - inside-yii2 repo, just checkout the models-part2 branch.