AJAX access control

The goal is to post to an action using AJAX from a foreign domain.

Here is the error:
Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

You need specifically allow other domains to access your actions through AJAX and also allow POST method. Add the following to the Controller in question:

  1. public function beforeAction($action)
  2. {
  3.     $this->enableCsrfValidation = false;
  4.     header("access-control-allow-origin: *");
  5.     header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
  6.     header("Access-Control-Allow-Headers: Content-Type");
  7.  
  8.     if (!parent::beforeAction($action)) {
  9.         return false;
  10.     }
  11.  
  12.     return true;
  13. }

Notice that to receive POST data you need disabled Csrf verification. The Csrf system will not work in this scenario.

gii 404 Not Found and 403 Forbidden

If you are getting a 404 not found error when trying to access gii, you probably don’t have gii set up in your config. This may happen if you initialize your advanced template in prod environment instead of dev.

To activate Gii, modify your web/index.php file as follows:

Change: defined(‘YII_ENV’) or define(‘YII_ENV’, ‘prod’);
To: defined(‘YII_ENV’) or define(‘YII_ENV’, ‘dev’);

Add the following:

  1. if (YII_ENV_DEV) {
  2.     $config['bootstrap'][] = 'gii';
  3.     $config['modules']['gii'] = [
  4.         'class' => 'yii\gii\Module',
  5.         'allowedIPs' => ['XXX.XX.XX.XX']
  6.     ];
  7. }

Replace XXX.XX.XX.XX with the IP address you are accessing the gii module from.
whatismyip.com

Advanced Template Directory Structure

  • backend
  • As mentioned, with the advanced template, you actually have two Yii installs. The backend directory is a complete Yii structure, similar to what you will
    find in the Basic Template. You will find the following subdirectories:

    • assets
    • config
    • controllers
    • models
    • runtime
    • views
    • web

    Each of these directories offers the same functionality as the corresponding directories as explained in the Basic Template above.

    One item to make note of here though is the config directory. Any configurations included in this config directory will apply only to web requests invoking
    the backend.

  • common
  • The purpose of the common directory is to have it accessed by both backend and frontend. You will see the following subdirectories:

    • config
    • Config files in this directory will apply to both backend and frontend.

    • mail
    • Functions same as the mail found in the Basic Template described above.

    • models
    • If you are using both backend and frontend, this is an important directory. The models directory in common allows you to access the same database functions
      from backend and frontend. If you are pulling the same data in particular instances, it makes sense to have just one model set up for that.

    • widgets
    • The widgets directory is a handy place to put snippets of code that you want to access anywhere, frontend or backend. By default, there is one widget
      already included that you will surely make use of: Alert.php

      A nice feature of Yii is the flash messaging. You can set a message that will be displayed on the next page loaded. You may have an alert that says there
      was an error submitting some info or a message saying info was successfully saved. These messages can be displayed simply using the following:

      <?php Alert::begin(); ?>

  • console
  • The console directory provides similar functionality to the command directory in the Basic Template, with some added features.

    As with the command directory, you can execute scripts from the command line. The scripts that will be executed are put in the controllers subdirectory.
    Here is an example of the same console file that will output “hello world” when executing the following on command line: php yii hello

    <?php
    
    namespace console\controllers;
    
    use yii\console\Controller;
    
    class HelloController extends Controller
    {
        public function actionIndex($message = 'hello world')
        {
            echo $message . "\n";
        }
    }
    

    In addition to the controller subdirectory, you have the following:

    • config
    • Set up specific config settings that apply only to using the console in command line terminal

    • migrations
    • Migrations is a powerful feature of Yii that enhances it portability. You can put full database schemas into the migrations folder and it will create the
      database tables for you as needed by executing the following command:


      php yii migrate

      You can even set the migrations up so that they can easily be reverted if need be.

    • models
    • Database functions specifically for command line functions.

    • runtime
    • This directory is for Yii internal use and can be ignored.

  • environments
  • The environments directory has two subdirectories:

    • dev
    • prod

    You can think of the environments as templates that can be applied by executing a command in terminal environment.

    Both these subdirectories have the following additional subdirectories:

    • backend
    • common
    • console
    • frontend

    If you set up Yii using the advanced template above, you made use of the environment function when you typed the following in command line terminal:


    php init

    and selected Development or Production.

    When you run the init command and select one of the above, it overwrites the various corresponding files with the template files for dev or prod.

  • frontend
  • The directory structure and functionality of the frontend directory is identical to the backend.

  • tests
  • The tests folder is set up to facilitate functional testing using Codeception.

  • vendor
  • Again, vendor is where all the source files for Yii reside. Refer to the Basic Template explanation above for details.

Basic Template Directory Structure

When installing the basic version of Yii2, you will see the following directory structure:

    • assets

Yii2 does a lot of asset management and caching. You create asset bundles that are used to include style sheets and Javascript files. Part of the advantage is that dependencies are handled and the scripts are properly included at the correct place.

There is a second assets folder under web. This folder is used by Yii as a cache for the assets. You need not concern yourself with this folder. If you are using git as version control repository, you will notice .gitignore is in that second assets folder. Nothing in that folder should be committed to the repository.

This folder needs to be writable by the web server. If you update JavaScript files or CSS files, you may need to delete all the folders in this directory. These can be safely deleted at any time. They are auto-generated by Yii as cache files.

    • commands

The commands directory allows you to create Yii management scripts that run under command line. You execute these commands by navigating to the Yii root folder in command line terminal and typing php yii or just ./yii. If you type either of those by themselves in a command line environment, you will get a list of commands that are available by default.

In the basic template, there is one example included that you can access through command line like this: php yii hello

That will output ‘Hello World’ to your terminal.

    • config

This folder holds the configuration files that include things like connecting Yii with your database, setting up e-mail sending, reformatting URLs and setting globally available parameter values.

    • controllers

‘C’ of MVC. Controllers are the heart of Yii. Controllers are the traffic directors of an MVC framework. When you make a web request to a Yii powered site, the controller is what processes that request.

    • mail

The mail folder contains the templates that Yii uses to construct an e-mail message.

    • models

‘M’ of MVC. The models folder is where all the database functionality goes. If you need to query the database or perform any other database manipulation, the code will go in the models folder.

    • runtime

The runtime folder is used by Yii when processing web requests. It needs to be writable and should be excluded from any Git repository (you will see a .gitignore file in this directory). You can safely ignore this directory.

    • tests

The tests folder is set up to facilitate functional testing using Codeception.

    • vendor

This directory is where the Yii source files reside. It is also where any additional third party modules that you install will be included. It is generally a very bad idea to alter the code in the vendor directory. The reason being that when you run any upgrades, the customized code you created will be overwritten.

The upgrade process is very easy using Composer. In command line terminal while in the Yii directory enter the following:

composer require yiisoft/yii2 2.0.6

(2.0.6 is the current version as of this writing.)

To update all third party plugins installed via Composer, execute the following command:

composer update

    • views

‘V’ of MVC. The views folder holds the pages that are displayed upon a web request. These files contain the HTML markup that renders the pages that display the queried data.

    • web

This is the document root directory that the web server points to. The primary function is index.php, which launches the Yii processes when called. Note that in this file, you can turn on or off the Yii debugging code. This enables the debug bar viewable at the bottom of the page, as mentioned in section 3.7.3.

You can set the Yii environment to ‘dev’ or ‘prod’ in the index.php file as well.

This folder is where you would put any files, images or other assets that you want to be accessible from the web. Only files in this folder can be accessed. You may want to have the following subdirectories:

        • css

    Containing all external style sheets.

        • js

    Containing all external Javascript files.

        • images

    All images to be used in any views.

There is one other subdirectory that you will find under web: assets. Like runtime, this directory is for use by Yii when responding to web requests. It needs to be writable by Yii and you can safely ignore it. This directory should also be excluded from any Git repo (hence the .gitignore file).

Setting unknown property: common\models\User::created_at timestamp

Yii2 models have a nifty feature related to timestamps. When you create a record or update a record, a timestamp is automatically generated and saved to the field created_at and updated_at respectively.

This is accomplished by adding the following to your model:

  1. public function behaviors()
  2. {
  3.     return [
  4.         TimestampBehavior::className(),
  5.     ];
  6. }

However, what if you do not have a created_at field in your table? Or, you have a timestamp field named something else, like date_created?

When you install Yii2 using advanced template, the code above is by default included in the User.php model. If you try to add a user, but you don’t have a created_at field in your user table, you will get the following error:

Setting unknown property: common\models\User::created_at

Fortunately, you can modify this behavior and specify a different field name. Here is the code to specify using date_created and date_updated:

  1. public function behaviors()
  2. {
  3.     return [
  4.         'timestamp' => [
  5.             'class' => '\yii\behaviors\TimestampBehavior',
  6.             'attributes' => [
  7.                 ActiveRecord::EVENT_BEFORE_INSERT => ['date_created', 'date_updated'],
  8.                 ActiveRecord::EVENT_BEFORE_UPDATE => ['date_updated'],
  9.             ],
  10.             'value' => new \yii\db\Expression('NOW()'),
  11.         ],
  12.     ];
  13. }

Setting the value property to new \yii\db\Expression(‘NOW()’) will create sql such as date_created = NOW().

Active form html5 input types such as email and number

HTML5 text input types are supported in YII2. These types include:

  • color
  • date
  • datetime
  • datetime-local
  • email
  • month
  • number
  • range
  • search
  • tel
  • time
  • url
  • week

With YII2 you can specify the input type as this:

  1. $form->field($model, 'email')->input('email')

This would set the input type to ’email’ which is useful for mobile apps. This will bring up the e-mail keyboard. The number keyboard can also be supported by using input(‘number’).

Class \models\DateTime not found global functions

Put a backslash in from of the class name to indicate it is in the global namespace:

$time = new \DateTime(‘now’, new \DateTimeZone(‘UTC’));

Timezone for Formatter

To set the default timezone in YII, use the following code in your main config file:

  1. return [  
  2.   'timeZone' => 'America/Phoenix',
  3.  ]

However, take note that YII assumes the datetime in the database is UTC. So, if you are inserting the data in the database already adjusted to current timezone, YII will adjust it again and it will be off.

One option is to set the YII timezone to UTC so that it does not adjust the time.

  1. return [  
  2.   'timeZone' => 'UTC',
  3.  ]

So now you set the default time zone, yet your GridView and DetailView don’t show in the updated time zone. Simple fix. Set the format of the item to datetime. So like ‘last_viewed:datetime’.

Query sum of database column using Active Record

You can use YII2 Active Record to query the sum of a database column.

Here is an example that gets total cost and total revenue for a given date range with status as CREDITED:

  1. $query = Ledger::find();
  2. $this->load($params);
  3.  
  4. $query->where(['status' => 'CREDITED']);
  5. $query->andWhere('date_created >= :begin_date',[':begin_date' => $this->begin_date]);
  6. $query->andWhere('date_created <= :end_date',[':end_date' => $this->end_date]);
  7. $cost = $query->sum('cost');
  8. $revenue = $query->sum('revenue');

Format GridView Footer as Currency

You can use YII2’s built in formatter to format any arbitrary value you like. For example, you may want to format the footer of a grid view as currency. When specifying the cell, you can set the format of that cell. However, while you can control what will be in the footer for that column, GridView does not have a method of formatting the footer values.

Here is a simple method to format any value.

  1. $formatter = new \yii\i18n\Formatter;
  2. $formatted_value = $formatter->asCurrency($value);