Before diving into Yii Framework 2, we need to take a look at how it is installed, how it is configured, and what the core building blocks of the framework are. In this chapter, we'll go over how to install the framework itself and prebuilt applications via a package management tool called Composer. We'll also cover some common configurations of both Yii Framework 2 and our web server, including making our applications aware of the environment they are running on and responding appropriately to that environment.
There are several different ways to install Yii2, ranging from downloading the framework from source control (typically, from GitHub at https://github.com/yiisoft/yii2) to using a package manager such as Composer. With modern web applications, Composer is the preferred method to install Yii2 as it enables us to install, update, and manage all dependencies and extensions for our application in an automated fashion. Additionally, using Composer, we can ensure that Yii Framework 2 is kept up to date with the latest security and bug fixes. Composer can be installed by following the instructions on https://getcomposer.org. Typically, this process looks as follows:
curl -sS https://getcomposer.org/installer | php
Alternatively, if you don't have cURL available on your system, it can be installed through PHP itself:
php -r "readfile('https://getcomposer.org/installer');" | php
Once installed, we should move Composer to a more centralized directory so that we can call it from any directory on our system. Installing Composer from a centralized directory rather than on a per-project basis has several advantages:
It can be called anywhere from any project. When working with multiple projects, we can ensure that we use the same dependency manager each time and for every project.
In a centralized directory, Composer only needs to be updated once rather than in every project we are working on.
Dependency managers are rarely considered code that should be pushed to your DCVS repository. Keeping the
composer.phar
file out of your repository reduces the amount of code you need to commit and push and ensures that your source code remains isolated from your package manager code.By installing Composer from a centralized directory, we can ensure that Composer is always available, which saves us a step each time we clone a project that depends on Composer.
A good directory to move Composer to is /usr/local/bin,
as shown in the following example:
mv composer.phar /usr/local/bin/composer chmod a+x /usr/local/bin/composer
Tip
Throughout this book, we'll be using Unix-style commands when referencing command-line arguments. Consequently, some commands may not work on Windows. If you decide to set up a Windows environment, you might need to use Composer-Setup.exe
(available at https://getcomposer.org/Composer-Setup.exe) to get Composer configured for your system. If you have any issues getting Composer to run on your system, ensure that you check out the Composer documentation available at https://getcomposer.org/doc/.
Alternatively, if you have Composer installed on your system already, ensure that you update it to the latest version by running this:
composer self-update
Tip
The commands that we use through this book are based on the assumption that you have sufficient privileges to run them. On Unix-like systems, you may need to preface some commands with sudo
in order to execute the command with a high permissions set. Alternatively if you are running these commands on Windows, you should ensure that you are running the listed commands in a command prompt that has elevated privileges. Ensure that you follow best practices when using sudo
and when using elevated command prompts in order to ensure your system stays secure.
Once Composer is installed, we'll need to install a global plugin called The Composer Asset Plugin (available at https://github.com/francoispluchino/composer-asset-plugin). This plugin enables Composer to manage asset files for us without the need to install additional software (these programs are Bower, an asset dependency manager created by Twitter, and Node Package Manager, or NPM, which is a JavaScript dependency manager).
composer global require "fxp/composer-asset-plugin:1.0.0"
Tip
Due to the GitHub API's rate limiting, during installation, Composer may ask you to enter your GitHub credentials. After entering your credentials, Composer will request a dedicated API key from GitHub that can be used for future installations. Ensure that you check out the Composer documentation at https://getcomposer.org/doc/ for more information.
With Composer installed, we can now instantiate our application. If we want to install an existing Yii2 package, we can simply run the following:
composer create-project --prefer-dist <package/name> <foldername>
Using the Yii2 basic app as an example, this command will look like this:
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
After running the command, you should see output similar to the following:
Installing yiisoft/yii2-app-basic (2.0.6) - Installing yiisoft/yii2-app-basic (2.0.6) Downloading: 100% Created project in basic Loading composer repositories with package information Installing dependencies (including require-dev) - Installing yiisoft/yii2-composer (2.0.3) - Installing ezyang/htmlpurifier (v4.6.0) - Installing bower-asset/jquery (2.1.4) - Installing bower-asset/yii2-pjax (v2.0.4) - Installing bower-asset/punycode (v1.3.2) - Installing bower-asset/jquery.inputmask (3.1.63) - Installing cebe/markdown (1.1.0) - Installing yiisoft/yii2 (2.0.6) - Installing swiftmailer/swiftmailer (v5.4.1) - Installing yiisoft/yii2-swiftmailer (2.0.4) - Installing yiisoft/yii2-codeception (2.0.4) - Installing bower-asset/bootstrap (v3.3.5) - Installing yiisoft/yii2-bootstrap (2.0.5) - Installing yiisoft/yii2-debug (2.0.5) - Installing bower-asset/typeahead.js (v0.10.5) - Installing phpspec/php-diff (v1.0.2) - Installing yiisoft/yii2-gii (2.0.4) - Installing fzaninotto/faker (v1.5.0) - Installing yiisoft/yii2-faker (2.0.3) Writing lock file Generating autoload files > yii\composer\Installer::postCreateProject chmod('runtime', 0777)...done. chmod('web/assets', 0777)...done. chmod('yii', 0755)...done.
Note
Your output may differ slightly due to the data cached on your system and versions of subpackages.
This command will install the Yii2 basic app to a folder called basic. When creating a new Yii2 project, you'll typically want to use the create-project command to clone "yii2-app-basic" and then develop your application from there as the basic app comes prepopulated with just about everything you need to start a new project. However, you can also create a Yii2 project from scratch that, while more complicated, gives you more control over your application's structure.
Let's take a look at the composer.json
file that was created when we ran the create-project
command:
{ "name": "yiisoft/yii2-app-basic", "description": "Yii 2 Basic Application Template", "keywords": ["yii2", "framework", "basic", "application template"], "homepage": "http://www.yiiframework.com/", "type": "project", "license": "BSD-3-Clause", "support": { "issues": "https://github.com/yiisoft/yii2/issues?state=open", "forum": "http://www.yiiframework.com/forum/", "wiki": "http://www.yiiframework.com/wiki/", "irc": "irc://irc.freenode.net/yii", "source": "https://github.com/yiisoft/yii2" }, "minimum-stability": "stable", "require": { "php": ">=5.4.0", "yiisoft/yii2": "*", "yiisoft/yii2-bootstrap": "*", "yiisoft/yii2-swiftmailer": "*" }, "require-dev": { "yiisoft/yii2-codeception": "*", "yiisoft/yii2-debug": "*", "yiisoft/yii2-gii": "*", "yiisoft/yii2-faker": "*" }, "config": { "process-timeout": 1800 }, "scripts": { "post-create-project-cmd": [ "yii\\composer\\Installer::postCreateProject" ] }, "extra": { "yii\\composer\\Installer::postCreateProject": { "setPermission": [ { "runtime": "0777", "web/assets": "0777", "yii": "0755" } ], "generateCookieValidationKey": [ "config/web.php" ] }, "asset-installer-paths": { "npm-asset-library": "vendor/npm", "bower-asset-library": "vendor/bower" } } }
While most of these items (such as the name, description, license, and require blocks) are rather self-explanatory, there are a few Yii2-specific items in here that we should take note of. The first section we want to look at is the "scripts"
section:
"scripts": { "post-create-project-cmd": [ "yii\\composer\\Installer::postCreateProject" ] }
This script tells Composer that when the create-project
command is run, it should run the postCreateProject
static function. Looking at the the framework source code, we see that this file is referenced in the yii2-composer
package (refer to https://github.com/yiisoft/yii2-composer/blob/master/Installer.php#L232). This command then runs several post-project creation actions, namely setting the local disk permissions, generating a unique cookie validation key, and setting some asset installer paths for composer-asset-plugin.
Next, we have the "extra"
block:
"extra": { "yii\\composer\\Installer::postCreateProject": { "setPermission": [ { "runtime": "0777", "web/assets": "0777", "yii": "0755" } ], "generateCookieValidationKey": [ "config/web.php" ] }, "asset-installer-paths": { "npm-asset-library": "vendor/npm", "bower-asset-library": "vendor/bower" } }
This section tells Composer to use these options when it runs the postCreateProject
command. These preconfigured options give us a good starting point to create our applications.
With our basic application now installed, let's take a look at a few basic configuration and bootstrap files that Yii2 automatically generated for us.
Projects created from yii2-app-basic
now come with a built-in requirements script called requirements.php
. This script checks several different values in order to ensure that Yii2 can run on our application server. Before running our application, let's run the requirements checker:
php requirements.php
You'll get output similar to the following:
Yii Application Requirement Checker This script checks if your server configuration meets the requirements for running Yii application. It checks if the server is running the right version of PHP, if appropriate PHP extensions have been loaded, and if php.ini file settings are correct. Check conclusion: ----------------- PHP version: OK [... more checks here ...] ----------------------------------------- Errors: 0 Warnings: 6 Total checks: 21
In general, as long as the error count is set to 0
, we'll be good to move forward. If the requirements checker notices an error, it will report it in the Check conclusion
section for you to rectify.
Like its predecessor, Yii Framework 2 comes with two separate entry scripts: one for web applications and the other for console applications.
In Yii2, the entry script for web applications has been moved from the root (/
) folder to the web/
folder. In Yii1, our PHP files were stored in the protected/
directory. By moving our entry scripts to the web/
directory, Yii2 has increased the security of our application by reducing the amount of web server configuration we need to run our application. Furthermore, all public asset (JavaScript and CSS) files are now completely isolated from our source code directories. If we open up web/index.php
, our entry script now looks as follows:
<?php // comment out the following two lines when deployed to production defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); $config = require(__DIR__ . '/../config/web.php'); (new yii\web\Application($config))->run();
Tip
Downloading the example code
The latest and most up to date copies of source code for this book is maintained on the Packt Publishing website, http://www.packtpub.com, and on GitHub at https://github.com/masteringyii, for each chapter where applicable.
While suitable for basic applications, the default entry script requires us to manually comment out and change the code when moving to different environments. Since changing the code in a nondevelopment environment doesn't follow best practices, we should change this code block so that we don't have to touch our code to move it to a different environment.
We'll start by creating a new application-wide constant called APPLICATION_ENV
. This variable will be defined by either our web server or our console environment and will allow us to dynamically load different configuration files depending upon the environment that we're working in:
After the opening
<?php
tag inweb/index.php
, add the following code block:// Define our application_env variable as provided by nginx/apache/console if (!defined('APPLICATION_ENV')) { if (getenv('APPLICATION_ENV') != false) define('APPLICATION_ENV', getenv('APPLICATION_ENV')); else define('APPLICATION_ENV', 'prod'); }
Our application now knows how to read the
APPLCATTION_ENV
variable from the environment variable, which will be passed either though our command line or our web server configuration. By default, if no environment is set, theAPPLICATION_ENV
variable will be set to prod.Next, we'll want to load a separate environment file that contains several environmental constants that we'll use to dynamically change how our application runs in different environments:
$env = require(__DIR__ . '/../config/env.php');
Next, we'll configure Yii to set the
YII_DEBUG
andYII_ENV
variables according to our application:defined('YII_DEBUG') or define('YII_DEBUG', $env['debug']); defined('YII_ENV') or define('YII_ENV', APPLICATION_ENV);
Then, follow the rest of our
index.php
file underweb/
:require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); (new yii\web\Application($config))->run();
With these changes, our web application is now configured to be aware of its environment and load the appropriate configuration files.
In Yii2, configuration files are still split into console- and web-specific configurations. As there are many commonalities between these two files (such as our database and environment configuration), we'll store common elements in their own files and include those files in both our web and console configurations. This will help us follow the DRY standard, and reduce duplicate code within our application.
Note
The DRY (don't repeat yourself) principle in software development states that we should avoid having the same code block appear in multiple places in our application. By keeping our application DRY, we can ensure that our application is performant and can reduce bugs in our application. By moving our database and parameters' configuration to their own file, we can reuse that same code in both our web and console configuration files.
Yii2 supports two different kinds of configuration files: one for web applications and another for console applications. In Yii2, our web configuration file is stored in config/web.php
and our console configuration file is stored in config/console.php
. If you're familiar with Yii1, you'll see that the basic structure of both of these files hasn't changed all that much.
The next file we'll want to look at is our database configuration file stored in config/db.php
. This file contains all the information our web and console applications will need in order to connect to the database.
In our basic application, this file looks as follows:
<?php return [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=yii2basic', 'username' => 'root', 'password' => '', 'charset' => 'utf8', ];
For an application that is aware of its environment, however, we should replace this file with a configuration that will use the APPLICATION_ENV
variable that we defined earlier:
<?php return require __DIR__ . '/env/' . APPLICATION_ENV . '/db.php';
Tip
Right now, we're just setting things up. We'll cover how to set up our directories in the next section.
With this change, our application now knows that it needs to look in a file called db.php
under config/env/<APPLICATION_ENV>/
to pull the correct configuration environment for that file.
In a manner similar to our database configuration file, Yii also lets us use a parameter file where we can store all of the noncomponent parameters for our application. This file is located at config/params.php
. Since the basic app doesn't make this file aware of its environment, we'll change it to do that as follows:
<?php return require __DIR__ . '/env/' . APPLICATION_ENV . '/params.php';
Finally, we have the environment configuration that we defined earlier when working with our entry scripts. We'll store this file in config/env.php, and it should be written as follows:
<?php return require __DIR__ . '/env/' . APPLICATION_ENV . '/env.php';
Most modern applications have several different environments depending upon their requirements. Typically, we'd break them down into four distinct environments:
The first environment we typically have is called DEV. This environment is where all of our local development occurs. Typically, developers have complete control over this environment and can change it, as required, to build their applications.
The second environment that we typically have is a testing environment called TEST. Normally, we'd deploy our application to this environment in order to make sure that our code works in a production-like setting; however, we normally would still have high log levels and debug information available to us when using this environment.
The third environment we typically have is called UAT, or the User Acceptance Testing environment. This is a separate environment that we'd provide to our client or business stakeholders for them to test the application to verify that it does what they want it to do.
Finally, in our typical setup, we'd have our PROD or production environment. This is where our code finally gets deployed to and where all of our users ultimately interact with our application.
As outlined in the previous sections, we've been pointing all of our environment configuration files to the config/env/<env>
folder. Since our local environment is going to be called DEV
, we'll create it first:
We'll start by creating our
DEV
environment folder from the command line:mkdir –p config/env/dev
Next, we'll create our
dev
database configuration file indb.php
underconfig/env/dev/
. For now, we'll stick with a basic SQLite database:<?php return [ 'dsn' => 'sqlite:/' . __DIR__ . '/../../../runtime/db.sqlite', 'class' => 'yii\db\Connection', 'charset' => 'utf8' ];
Next, we'll create our environment configuration file in
env.php
underconfig/env/dev
. If you recall from earlier in the chapter, this is where ourdebug
flag was stored, so this file will look as follows:<?php return [ 'debug' => true ];
Finally, we'll create our
params.php
file underconfig/env/dev/
. As of now, this file will simply return an empty array:<?php return [];
Now, for simplicity, let's copy over this configuration to our other environments. From the command line, we can do that as follows:
cp –R config/env/dev config/env/test cp –R config/env/dev config/env/uat cp –R config/env/dev config/env/prod
Now that we've told Yii what files and configurations it needs to use for each environment, we need to tell it what environment to use. To do this, we'll set custom variables in our web server configuration that will pass this option to Yii.
With our console application properly configured, we now need to configure our web server to pass the APPLICATION_ENV
variable to our application. In a typical NGINX configuration, we have a location block that looks as follows:
location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_pass 127.0.0.1:9000; #fastcgi_pass unix:/var/run/php5-fpm.sock; try_files $uri =404; }
To pass the APPLICATION_ENV
variable to our application, all we need to do is define a new fastcgi_param
as follows:
fastcgi_param APPLICATION_ENV "dev";
We can also easily configure Apache to pass the APPLICATION_ENV
variable to our application. With Apache, we typically have a VirtualHost block that looks as follows:
# Set document root to be "basic/web" DocumentRoot "path/to/basic/web" <Directory "path/to/basic/web"> # use mod_rewrite for pretty URL support RewriteEngine on # If a directory or a file exists, use the request directly RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # Otherwise forward the request to index.php RewriteRule . index.php # ...other settings... </Directory>
To pass the APPLICATION_ENV
variable to our application, all we need to do is use the SetEnv
command as follows, which can be placed anywhere in our VirtualHost block:
SetEnv APPLICATION_ENV dev
After making this change, simply restart Apache and navigate to your application.
At the most basic level, our application isn't doing anything different from what it was when we first ran the composer create-project
command. Despite not doing anything different, our application is now significantly more powerful and flexible than it was before our changes. Later on in the book, we'll take a look at how these changes in particular can make automated deployments of our application a seamless and simple process.
There are two base classes that almost everything in Yii2 extends from: the Component
class and the Object
class.
In Yii2, the Component
class has replaced the CComponent
class from Yii1. In Yii1, components act as service locators that host a specific set of application components that provide different services for the processing of requests. Each component in Yii2 can be accessed using the following syntax:
Yii::$app->componentID
For example, the database component can be accessed using this:
Yii::$app->db
The cache component can be accessed using this:
Yii::$app->cache
Yii2 automatically registers each component at runtime via the application configuration that we mentioned in the previous section by name.
To improve performance in Yii2 applications, components are lazy-loaded or only instantiated the first time they are accessed. This means that if the cache component is never used in your application code, the cache component will never be loaded. At times, however, this can be nonideal, so to force load a component, you can bootstrap it by adding it to the bootstrap configuration option in either config/web.php
or config/console.php
. For instance, if we want to bootstrap the log component, we can do that as follows:
<?php return [ 'bootstrap' => [ 'log' ], […] ]
The bootstrap
option behaves in a manner similar to the preload option in Yii1—any component that you want or need to be instantiated on bootstrap will be loaded if it is in the bootstrap
section of your configuration file.
Note
For more information on service locators and components, ensure that you read the Definitive Guide to Yii guide located at http://www.yiiframework.com/doc-2.0/guide-concept-service-locator.html and http://www.yiiframework.com/doc-2.0/guide-structure-application-components.html.
In Yii2, almost every class that doesn't extend from the Component
class extends from the Object
class. The Object
class is the base class that implements the property feature. In Yii2, the property feature allows you to access a lot of information about an object, such as the __get
and __set
magic methods, as well as other utility functions, such as hasProperty()
, canGetProperty()
, and canSetProperty()
. Combined, this makes objects in Yii2 extremely powerful.
Tip
The object
class is extremely powerful, and many classes in Yii extend from it. Despite this, using the magic methods __get
and __set
yourself is not considered best practice as it is slower than a native PHP method and doesn't integrate well with your IDE's autocomplete tool and documentation tools.
In Yii2, path aliases are used to represent file paths or URL paths so that we don't hardcode paths or URLs directly into our application. In Yii2, aliases always start with the @
symbol so that Yii knows how to differentiate it from a file path or URL.
Aliases can be defined in several ways. The most basic way to define a new alias is to call \Yii::setAlias()
:
\Yii::setAlias('@path', '/path/to/example'); \Yii::setAlias('@example, 'https://www.example.com');
Aliases can also be defined in the application configuration file by setting the alias option as follows:
return [ // ... 'aliases' => [ '@path => '/path/to/example, '@example' => 'https://www.example.com', ], ];
Also, aliases can be easily retrieved using \Yii::getAlias()
:
\Yii::getAlias('@path') // returns /path/to/example \Yii::getAlias('@example') // returns https://www.example.com
Several places in Yii are alias-aware and will accept aliases as inputs. For example, yii\caching\FileCache
accepts a file alias as an alias for the $cachePath
parameter:
$cache = new FileCache([ 'cachePath' => '@runtime/cache', ]);
Note
For more information on path aliases, check out the Yii documentation at http://www.yiiframework.com/doc-2.0/guide-concept-aliases.html.
In this chapter, we went over how to create new Yii2 applications via composer. We also went over the basic configuration files that come with Yii2 as well as how to configure our web application to load environment-specific configuration files. Finally, we also covered components, objects, and path aliases, which are fundamental to gaining mastery over Yii.
In the next chapter, we'll cover everything you need to know in order to become a master of console commands and applications.