Example site built with Yii2: NFT Viewer

10. Models

As noted, models are your gateway to the database. This is where you will construct your database queries.

Yii uses something called Active Record. This allows you to accesses your database tables as objects.

Let's talk about an example table in our database. The table will be called 'customers' and will have the following schema:

Field Type
Primary Key customerNumber int(11) NOT NULL
companyName varchar(50) NOT NULL
contactLastName varchar(50) NOT NULL
contactFirstName varchar(50) NOT NULL
phone varchar(50) NOT NULL
addressLine1 varchar(50) NOT NULL
addressLine2 varchar(50) NULL
city varchar(50) NOT NULL
state varchar(50) NULL
postalCode varchar(15) NULL
country varchar(50) NOT NULL
salesRepEmployeeNumber int(11) NULL
creditLimit double NULL

This table can be created with the following sql statement:

CREATE TABLE `Customers` (
  `customerNumber` int(11) NOT NULL,
  `companyName` varchar(50) NOT NULL,
  `contactLastName` varchar(50) NOT NULL,
  `contactFirstName` varchar(50) NOT NULL,
  `phone` varchar(50) NOT NULL,
  `addressLine1` varchar(50) NOT NULL,
  `addressLine2` varchar(50) DEFAULT NULL,
  `city` varchar(50) NOT NULL,
  `state` varchar(50) DEFAULT NULL,
  `postalCode` varchar(15) DEFAULT NULL,
  `country` varchar(50) NOT NULL,
  `salesRepEmployeeNumber` int(11) DEFAULT NULL,
  `creditLimit` double DEFAULT NULL,
  PRIMARY KEY (`customerNumber`)
)

Download SQL to create table and insert test data.

So, now that we have a table, how do we generate a Model for that table so that we can access the records as objects? Introducing Gii - The Yii tool to automatically generate code.

10.1 Gii Code Generation Tool

If you are using Pretty URLs, you will access the Gii tool as follows: http://yii-basic.loc/gii

(yii-basic.loc would be replaced with your domain.)

Here is a snapshot of what you will see at that page:

We are currently only interested in the Model Generator and the CRUD Generator. (Remember CRUD stands for Create, Read, Update, Delete database functions.)

10.1.1 Generate Model Uisng Gii

Let's start by clicking the Start button for Model Generator. We will generate a Model for our Customers table as follows:

We have filled in the Database table name of Customers and the Model Class of Customers as well (Model Class will generally be the same name as the associated table for simplicity sake.)

Now click Preview at the bottom.

Now clicking Generate will create the appropriate files. Let's do that now.

Open the models directory in your Yii application and you will see a new file called Customers.php. This is the Model that was generated for you. Let's take a look at it.

<?php

namespace app\models;

use Yii;

class Customers extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'Customers';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['companyName', 'contactLastName', 'contactFirstName', 'phone', 'addressLine1', 'city', 'country'], 'required'],
            [['customerNumber', 'salesRepEmployeeNumber'], 'integer'],
            [['creditLimit'], 'number'],
            [['companyName', 'contactLastName', 'contactFirstName', 'phone', 'addressLine1', 'addressLine2', 'city', 'state', 'country'], 'string', 'max' => 50],
            [['postalCode'], 'string', 'max' => 15]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'customerNumber' => 'Customer Number',
            'companyName' => 'Company Name',
            'contactLastName' => 'Contact Last Name',
            'contactFirstName' => 'Contact First Name',
            'phone' => 'Phone',
            'addressLine1' => 'Address Line1',
            'addressLine2' => 'Address Line2',
            'city' => 'City',
            'state' => 'State',
            'postalCode' => 'Postal Code',
            'country' => 'Country',
            'salesRepEmployeeNumber' => 'Sales Rep Employee Number',
            'creditLimit' => 'Credit Limit',
        ];
    }

}

Let's examine this file and see what the various parts are.

Line 3 is setting the appropriate namespace and line 5 is specifying that the Yii class should be used. Note that 'app' is the root namespace for your Yii application.

Notice line 7, the Customers class extends the Active Record class. In this example, the class name matches our table name, however, that is not required.

Line 12 is where the actual database table name is specified and may or may not match the class name. Generally, it will match.

Now in line 20, we have a function called rules(). These are rules that are applied when interacting with the model. All input saved to the database is validated using these rules.

On line 34 we have the attributeLabels() function. This returns an array mapping the table field names to labels. Yii tries to guess the best label for a field based on the field name. However, you are free to alter these labels. The labels come into play when generating forms related to this model.

10.1.2 Generate CRUD Using Gii

Now let's generate the CRUD functions. Click the Start button for CRUD Generator.

You will see a page similar to this:

The required inputs for the form fields on the CRUD Generator are a little more arcane. What we are generating here doing here is three things:

  1. Create a controller to implement the CRUD functions for the Customers model.
  2. Create another model used for data searching of the Customers table.
  3. Create the View folder with default view files for the controller.

To create the CRUD functions for our Customers model, fill in the fields as follows. (Note: I have filled in the fields already in the screenshot above.)

Model Class

Enter the fully qualified namespace of your model generated in the previous step. In this case, enter the following: app\models\Customers

Remember, 'app' is the application root. You are working with the models namespace and the specific model is Customers.

Search Model Class

This will be the fully qualified namespace of the Search Model that will be created. You can name the model anything, but the general convention is ModelnameSearch. Enter the following: app\models\CustomersSearch

Controller Class

This is the fully qualified namespace for the controller that will provide CRUD functions for this model. The format for the class name is ModelnameController, with the shown camel case. Use the name of the model with first letter capitalized followed by the word Controller, first letter also capitalized. Enter the following: app\controllers\CustomersController

View Path

You can leave this field empty. This specifies the file system path to the directory that will be used to hold the view files for this controller. It will default to /views/customers in this case. All the view files for the CustomersController will be located in the customers directory under the views directory.

Base Controller Class

Leave as is. No need to complicate it.

Widget Used in Index Page

By default, Yii will use GridView. If you click on the field, you can change it to ListView. This is the widget controlling how data from the model is displayed. GridView is the most common.

Enable I18N

This has to do with language translation. Yii supports multiple translations of your application using the following format: Yii::t() This will take the content passed to it and render the appropriate translation of it. Leave this unchecked for now.

Once all these fields are filled in, click the Preview button at the bottom. You should see the following result:

These are the files that will be created. Notice there is one controller file that will be created and one model, the search model that will be created as well. Then there are the view files that allow you to view, create and update data records. A form corresponding to the model attributes (the database table fields) will be generated as well.

10.2 Model Rules

Let's explore model rules in more depth.

The model rules are used to validate any input before it is saved to the database. The rules are arrays specifying the table field names as an array followed by the validation type.

When saving records to the associated table, all data must have a rule associated with it. If you try submitting a form and it contains a field that is not in the rules array, that data will be ignored. All data fields must have at least one rule associated. If you create a form and are submitting data, but that data seems to be ignored, having no associated rule is probably the cause.

10.2.1 Common Model Rules Explained

A common rule you will use is the 'required' rule. This specifies that the associated fields must be present and contain data or Yii will return an error.

An example of using the rules array is as follows:

['first_name','required']

This rule stipulates that the first_name field be present and not null when saving a record.

If you have multiple fields that are required, they can be passed as their own array in place of the first parameter.

[['first_name','last_name'],'required']

In addition to the required rule, some of the more common validation rules included by default are as follows:

  • string

[['first_name','last_name'], 'string', 'max'=>50, 'min'=>15]

This stipulates that the two fields are text strings and that they are at least 15 characters long and 50 characters maximum.

  • Integer

['age', 'integer', 'max'=>500, 'min'=>100]

The value passed for 'age' in this example must be an integer of 100 at the least and 500 at the most.

  • number

['salary', 'number', 'max'=>9.5, 'min'=>5]

The value passed for 'salary' must be a number, either an integer or floating point decimal of 5.0 at the least and 9.5 at the most.

  • unique

['username','unique']

This stipulates that the value passed as the username field must be unique compared to all current values of that field in the database.

  • compare

['password','compare','compareAttribute'=>'confirm_password', 'message' => 'Password does not match confirm password.']

This stipulates that the value of the password field must match the value of the confirm_password field. If it does not match, the message parameter will be set as the error message for the password field.

  • date

[['from_date', 'to_date'], 'date']

This requires the date fields 'from_date' and 'to_date' to be in the default format. Default example: Jun 30, 2016. If you would like to validate the date field in another format, such as 06/30/2016, you would include the format property.

[['from_date', 'to_date'], 'date', 'format' => 'MM/dd/yyyy']

The date format is in the ICU format. See that ICU manual under Date/Time Format Syntax for details: http://userguide.icu-project.org/formatparse/datetime

  • email

['email', 'email']

Verifies that the value in the email field is a valid e-mail address.

  • url

['website', 'url', 'defaultScheme' => 'http']

Verifies that the value passed in the 'website' field is a valid URL. The defaultScheme property will tag on the http:// if it is missing (e.g. www.website.com becomes http://www.website.com)

  • default

['country', 'default', 'value' => 'USA']

This validator does not validate data. Instead, it assigns a default value to the attributes being validated if the attributes are empty. The value property is the assigned default. In this case, the 'country' field would default to 'USA' if it was empty.

  • trim

[['username', 'email'], 'trim']

This validator does not perform data validation. Instead, it will trim the surrounding white spaces around the input value.

  • safe

['field', 'safe']

This validator does not perform data validation. Instead, is marks the field to be a safe attribute. Remember, any field data passed in must have an entry in the rules array or it will be ignored. The 'safe' validation would be used if no other validation would apply, but you still want to pass in that field data.

  • enableClientValidation

['first_name','required', 'enableClientValidation' => false]

This is not a validator, but a property. While Yii does server side validation using these rules, when you generate a form using the Yii Active Form method, these rules will also be created as client side Javascript validation. Setting this property to false will disable the Javascript validation for that field.

10.2.2 Generated Rules

You will notice the rules generated by Gii corresponded to the table fields. Fields that are Not Null are listed as required. Fields with a varchar of 50 are listed as being string fields with a maximum length of 50 characters. Integer fields are required to be integers and double fields are required to be numbers.

Yii does its best to determine from the table fields the rules that should be applied. However, you will probably need to tweak it a bit.