Commit 976abcd7 by funson86

english

parent 353625b7
Assets
======
An asset in Yii is a file that may be referenced in a Web page. It can be a CSS file, a JavaScript file, an image
or video file, etc. Assets are located in Web-accessible directories and are directly served by Web servers.
It is often preferable to manage assets programmatically. For example, when you use the [[yii\jui\DatePicker]] widget
in a page, it will automatically include the required CSS and JavaScript files, instead of asking you to manually
find these files and include them. And when you upgrade the widget to a new version, it will automatically use
the new version of the asset files. In this tutorial, we will describe the powerful asset management capability
provided in Yii.
## Asset Bundles <a name="asset-bundles"></a>
Yii manages assets in the unit of *asset bundle*. An asset bundle is simply a collection of assets located
in a directory. When you register an asset bundle in a [view](structure-views.md), it will include the CSS and
JavaScript files in the bundle in the rendered Web page.
## Defining Asset Bundles <a name="defining-asset-bundles"></a>
Asset bundles are specified as PHP classes extending from [[yii\web\AssetBundle]]. The name of a bundle is simply
its corresponding PHP class name which should be [autoloadable](concept-autoloading.md). In an asset bundle class,
you would typically specify where the assets are located, what CSS and JavaScript files the bundle contains, and
how the bundle depends on other bundles.
The following code defines the main asset bundle used by [the basic application template](start-installation.md):
```php
<?php
namespace app\assets;
use yii\web\AssetBundle;
class AppAsset extends AssetBundle
{
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'css/site.css',
];
public $js = [
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}
```
The above `AppAsset` class specifies that the asset files are located under the `@webroot` directory which
is corresponding to the URL `@web`; the bundle contains a single CSS file `css/site.css` and no JavaScript file;
the bundle depends on two other bundles: [[yii\web\YiiAsset]] and [[yii\bootstrap\BootstrapAsset]]. More detailed
explanation about the properties of [[yii\web\AssetBundle]] can be found in the following:
* [[yii\web\AssetBundle::sourcePath|sourcePath]]: specifies the root directory that contains the asset files in
this bundle. This property should be set if the root directory is not Web accessible. Otherwise, you should
set the [[yii\web\AssetBundle::basePath|basePath]] property and [[yii\web\AssetBundle::baseUrl|baseUrl]], instead.
[Path aliases](concept-aliases.md) can be used here.
* [[yii\web\AssetBundle::basePath|basePath]]: specifies a Web-accessible directory that contains the asset files in
this bundle. When you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property,
the [asset manager](#asset-manager) will publish the assets in this bundle to a Web-accessible directory
and overwrite this property accordingly. You should set this property if your asset files are already in
a Web-accessible directory and do not need asset publishing. [Path aliases](concept-aliases.md) can be used here.
* [[yii\web\AssetBundle::baseUrl|baseUrl]]: specifies the URL corresponding to the directory
[[yii\web\AssetBundle::basePath|basePath]]. Like [[yii\web\AssetBundle::basePath|basePath]],
if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property, the [asset manager](#asset-manager)
will publish the assets and overwrite this property accordingly. [Path aliases](concept-aliases.md) can be used here.
* [[yii\web\AssetBundle::js|js]]: an array listing the JavaScript files contained in this bundle. Note that only
forward slash "/" should be used as directory separators. Each JavaScript file can be specified in one of the
following two formats:
- a relative path representing a local JavaScript file (e.g. `js/main.js`). The actual path of the file
can be determined by prepending [[yii\web\AssetManager::basePath]] to the relative path, and the actual URL
of the file can be determined by prepending [[yii\web\AssetManager::baseUrl]] to the relative path.
- an absolute URL representing an external JavaScript file. For example,
`http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` or
`//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
* [[yii\web\AssetBundle::css|css]]: an array listing the CSS files contained in this bundle. The format of this array
is the same as that of [[yii\web\AssetBundle::js|js]].
* [[yii\web\AssetBundle::depends|depends]]: an array listing the names of the asset bundles that this bundle depends on
(to be explained shortly).
* [[yii\web\AssetBundle::jsOptions|jsOptions]]: specifies the options that will be passed to the
[[yii\web\View::registerJsFile()]] method when it is called to register *every* JavaScript file in this bundle.
* [[yii\web\AssetBundle::cssOptions|cssOptions]]: specifies the options that will be passed to the
[[yii\web\View::registerCssFile()]] method when it is called to register *every* CSS file in this bundle.
* [[yii\web\AssetBundle::publishOptions|publishOptions]]: specifies the options that will be passed to the
[[yii\web\AssetManager::publish()]] method when it is called to publish source asset files to a Web directory.
This is only used if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property.
### Asset Locations <a name="asset-locations"></a>
Assets, based on their location, can be classified as:
* source assets: the asset files are located together with PHP source code which cannot be directly accessed via Web.
In order to use source assets in a page, they should be copied to a Web directory and turned into the so-called
published assets. This process is called *asset publishing* which will be described in detail shortly.
* published assets: the asset files are located in a Web directory and can thus be directly accessed via Web.
* external assets: the asset files are located on a Web server that is different from the one hosting your Web
application.
When defining an asset bundle class, if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property,
it means any assets listed using relative paths will be considered as source assets. If you do not specify this property,
it means those assets are published assets (you should therefore specify [[yii\web\AssetBundle::basePath|basePath]] and
[[yii\web\AssetBundle::baseUrl|baseUrl]] to let Yii know where they are located.)
It is recommended that you place assets belonging to an application in a Web directory to avoid the unnecessary asset
publishing process. This is why `AppAsset` in the prior example specifies [[yii\web\AssetBundle::basePath|basePath]]
instead of [[yii\web\AssetBundle::sourcePath|sourcePath]].
For [extensions](structure-extensions.md), because their assets are located together with their source code
in directories that are not Web accessible, you have to specify the [[yii\web\AssetBundle::sourcePath|sourcePath]]
property when defining asset bundle classes for them.
> Note: Do not use `@webroot/assets` as the [[yii\web\AssetBundle::sourcePath|source path]].
This directory is used by default by the [[yii\web\AssetManager|asset manager]] to save the asset files
published from their source location. Any content in this directory are considered temporarily and may be subject
to removal.
### Asset Dependencies <a name="asset-dependencies"></a>
When you include multiple CSS or JavaScript files in a Web page, they have to follow certain orders to avoid
overriding issues. For example, if you are using a jQuery UI widget in a Web page, you have to make sure
the jQuery JavaScript file is included before the jQuery UI JavaScript file. We call such ordering the dependencies
among assets.
Asset dependencies are mainly specified through the [[yii\web\AssetBundle::depends]] property.
In the `AppAsset` example, the asset bundle depends on two other asset bundles: [[yii\web\YiiAsset]] and
[[yii\bootstrap\BootstrapAsset]], which means the CSS and JavaScript files in `AppAsset` will be included *after*
those files in the two dependent bundles.
Asset dependencies are transitive. This means if bundle A depends on B which depends on C, A will depend on C, too.
### Asset Options <a name="asset-options"></a>
You can specify the [[yii\web\AssetBundle::cssOptions|cssOptions]] and [[yii\web\AssetBundle::jsOptions|jsOptions]]
properties to customize the way that CSS and JavaScript files are included in a page. The values of these properties
will be passed to the [[yii\web\View::registerCssFile()]] and [[yii\web\View::registerJsFile()]] methods, respectively, when
they are called by the [view](structure-views.md) to include CSS and JavaScript files.
> Note: The options you set in a bundle class apply to *every* CSS/JavaScript file in the bundle. If you want to
use different options for different files, you should create separate asset bundles, and use one set of options
in each bundle.
For example, to conditionally include a CSS file for browsers that are IE9 or above, you can use the following option:
```php
public $cssOptions = ['condition' => 'lte IE9'];
```
This will cause a CSS file in the bundle to be included using the following HTML tags:
```html
<!--[if lte IE9]>
<link rel="stylesheet" href="path/to/foo.css">
<![endif]-->
```
To wrap link tag with `<noscript>` the following can be used:
```php
public $cssOptions = ['noscript' => true];
```
To include a JavaScript file in the head section of a page (by default, JavaScript files are included at the end
of the body section), use the following option:
```php
public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
```
### Bower and NPM Assets <a name="bower-npm-assets"></a>
Most JavaScript/CSS package are managed by [Bower](http://bower.io/) and/or [NPM](https://www.npmjs.org/).
If your application or extension is using such a package, it is recommended that you follow these steps to manage
the assets in the library:
1. Modify the `composer.json` file of your application or extension and list the package in the `require` entry.
You should use `bower-asset/PackageName` (for Bower packages) or `npm-asset/PackageName` (for NPM packages)
to refer to the library.
2. Create an asset bundle class and list the JavaScript/CSS files that you plan to use in your application or extension.
You should specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property as `@bower/PackageName` or `@npm/PackageName`.
This is because Composer will install the Bower or NPM package in the directory corresponding to this alias.
> Note: Some packages may put all their distributed files in a subdirectory. If this is the case, you should specify
the subdirectory as the value of [[yii\web\AssetBundle::sourcePath|sourcePath]]. For example, [[yii\web\JqueryAsset]]
uses `@bower/jquery/dist` instead of `@bower/jquery`.
## Using Asset Bundles <a name="using-asset-bundles"></a>
To use an asset bundle, register it with a [view](structure-views.md) by calling the [[yii\web\AssetBundle::register()]]
method. For example, in a view template you can register an asset bundle like the following:
```php
use app\assets\AppAsset;
AppAsset::register($this); // $this represents the view object
```
If you are registering an asset bundle in other places, you should provide the needed view object. For example,
to register an asset bundle in a [widget](structure-widgets.md) class, you can get the view object by `$this->view`.
When an asset bundle is registered with a view, behind the scene Yii will register all its dependent asset bundles.
And if an asset bundle is located in a directory inaccessible through the Web, it will be published to a Web directory.
Later when the view renders a page, it will generate `<link>` and `<script>` tags for the CSS and JavaScript files
listed in the registered bundles. The order of these tags is determined by the dependencies among
the registered bundles and the order of the assets listed in the [[yii\web\AssetBundle::css]] and [[yii\web\AssetBundle::js]]
properties.
### Customizing Asset Bundles <a name="customizing-asset-bundles"></a>
Yii manages asset bundles through an application component named `assetManager` which is implemented by [[yii\web\AssetManager]].
By configuring the [[yii\web\AssetManager::bundles]] property, it is possible to customize the behavior of an asset bundle.
For example, the default [[yii\web\JqueryAsset]] asset bundle uses the `jquery.js` file from the installed
jquery Bower package. To improve the availability and performance, you may want to use a version hosted by Google.
This can be achieved by configuring `assetManager` in the application configuration like the following:
```php
return [
// ...
'components' => [
'assetManager' => [
'bundles' => [
'yii\web\JqueryAsset' => [
'sourcePath' => null, // do not publish the bundle
'js' => [
'//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
]
],
],
],
],
];
```
You can configure multiple asset bundles similarly through [[yii\web\AssetManager::bundles]]. The array keys
should be the class names (without the leading backslash) of the asset bundles, and the array values should
be the corresponding [configuration arrays](concept-configurations.md).
> Tip: You can conditionally choose which assets to use in an asset bundle. The following example shows how
> to use `jquery.js` in the development environment and `jquery.min.js` otherwise:
>
> ```php
> 'yii\web\JqueryAsset' => [
> 'js' => [
> YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
> ]
> ],
> ```
You can disable one or multiple asset bundles by associating `false` with the names of the asset bundles
that you want to disable. When you register a disabled asset bundle with a view, none of its dependent bundles
will be registered, and the view will also not include any of the assets in the bundle in the page it renders.
For example, to disable [[yii\web\JqueryAsset]], you can use the following configuration:
```php
return [
// ...
'components' => [
'assetManager' => [
'bundles' => [
'yii\web\JqueryAsset' => false,
],
],
],
];
```
You can also disable *all* asset bundles by setting [[yii\web\AssetManager::bundles]] as `false`.
### Asset Mapping <a name="asset-mapping"></a>
Sometimes you want to "fix" incorrect/incompatible asset file paths used in multiple asset bundles. For example,
bundle A uses `jquery.min.js` of version 1.11.1, and bundle B uses `jquery.js` of version 2.1.1. While you can
fix the problem by customizing each bundle, an easier way is to use the *asset map* feature to map incorrect assets
to the desired ones. To do so, configure the [[yii\web\AssetManager::assetMap]] property like the following:
```php
return [
// ...
'components' => [
'assetManager' => [
'assetMap' => [
'jquery.js' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
],
],
],
];
```
The keys of [[yii\web\AssetManager::assetMap|assetMap]] are the asset names that you want to fix, and the values
are the desired asset paths. When you register an asset bundle with a view, each relative asset file in its
[[yii\web\AssetBundle::css|css]] and [[yii\web\AssetBundle::js|js]] arrays will be examined against this map.
If any of the keys is found to be the last part of an asset file (which is prefixed with [[yii\web\AssetBundle::sourcePath]]
if available), the corresponding value will replace the asset and be registered with the view.
For example, an asset file `my/path/to/jquery.js` matches a key `jquery.js`.
> Note: Only assets specified using relative paths are subject to asset mapping. And the target asset paths
should be either absolute URLs or paths relative to [[yii\web\AssetManager::basePath]].
### Asset Publishing <a name="asset-publishing"></a>
As aforementioned, if an asset bundle is located in a directory that is not Web accessible, its assets will be copied
to a Web directory when the bundle is being registered with a view. This process is called *asset publishing*, and is done
automatically by the [[yii\web\AssetManager|asset manager]].
By default, assets are published to the directory `@webroot/assets` which corresponds to the URL `@web/assets`.
You may customize this location by configuring the [[yii\web\AssetManager::basePath|basePath]] and
[[yii\web\AssetManager::baseUrl|baseUrl]] properties.
Instead of publishing assets by file copying, you may consider using symbolic links, if your OS and Web server allow.
This feature can be enabled by setting [[yii\web\AssetManager::linkAssets|linkAssets]] to be true.
```php
return [
// ...
'components' => [
'assetManager' => [
'linkAssets' => true,
],
],
];
```
With the above configuration, the asset manager will create a symbolic link to the source path of an asset bundle
when it is being published. This is faster than file copying and can also ensure that the published assets are
always up-to-date.
## Commonly Used Asset Bundles <a name="common-asset-bundles"></a>
The core Yii code has defined many asset bundles. Among them, the following bundles are commonly used and may
be referenced in your application or extension code.
- [[yii\web\YiiAsset]]: It mainly includes the `yii.js` file which implements a mechanism of organizing JavaScript code
in modules. It also provides special support for `data-method` and `data-confirm` attributes and other useful features.
- [[yii\web\JqueryAsset]]: It includes the `jquery.js` file from the jQuery bower package.
- [[yii\bootstrap\BootstrapAsset]]: It includes the CSS file from the Twitter Bootstrap framework.
- [[yii\bootstrap\BootstrapPluginAsset]]: It includes the JavaScript file from the Twitter Bootstrap framework for
supporting Bootstrap JavaScript plugins.
- [[yii\jui\JuiAsset]]: It includes the CSS and JavaScript files from the jQuery UI library.
If your code depends on jQuery, jQuery UI or Bootstrap, you should use these predefined asset bundles rather than
creating your own versions. If the default setting of these bundles do not satisfy your needs, you may customize them
as described in the [Customizing Asset Bundle](#customizing-asset-bundles) subsection.
## Asset Conversion <a name="asset-conversion"></a>
Instead of directly writing CSS and/or JavaScript code, developers often write them in some extended syntax and
use special tools to convert it into CSS/JavaScript. For example, for CSS code you may use [LESS](http://lesscss.org/)
or [SCSS](http://sass-lang.com/); and for JavaScript you may use [TypeScript](http://www.typescriptlang.org/).
You can list the asset files in extended syntax in [[yii\web\AssetBundle::css|css]] and [[yii\web\AssetBundle::js|js]]
in an asset bundle. For example,
```php
class AppAsset extends AssetBundle
{
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'css/site.less',
];
public $js = [
'js/site.ts',
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}
```
When you register such an asset bundle with a view, the [[yii\web\AssetManager|asset manager]] will automatically
run the pre-processor tools to convert assets in recognized extended syntax into CSS/JavaScript. When the view
finally renders a page, it will include the CSS/JavaScript files in the page, instead of the original assets
in extended syntax.
Yii uses the file name extensions to identify which extended syntax an asset is in. By default it recognizes
the following syntax and file name extensions:
- [LESS](http://lesscss.org/): `.less`
- [SCSS](http://sass-lang.com/): `.scss`
- [Stylus](http://learnboost.github.io/stylus/): `.styl`
- [CoffeeScript](http://coffeescript.org/): `.coffee`
- [TypeScript](http://www.typescriptlang.org/): `.ts`
Yii relies on the installed pre-processor tools to convert assets. For example, to use [LESS](http://lesscss.org/)
you should install the `lessc` pre-processor command.
You can customize the pre-processor commands and the supported extended syntax by configuring
[[yii\web\AssetManager::converter]] like the following:
```php
return [
'components' => [
'assetManager' => [
'converter' => [
'class' => 'yii\web\AssetConverter',
'commands' => [
'less' => ['css', 'lessc {from} {to} --no-color'],
'ts' => ['js', 'tsc --out {to} {from}'],
],
],
],
],
];
```
In the above we specify the supported extended syntax via the [[yii\web\AssetConverter::commands]] property.
The array keys are the file extension names (without leading dot), and the array values are the resulting
asset file extension names and the commands for performing the asset conversion. The tokens `{from}` and `{to}`
in the commands will be replaced with the source asset file paths and the target asset file paths.
> Info: There are other ways of working with assets in extended syntax, besides the one described above.
For example, you can use build tools such as [grunt](http://gruntjs.com/) to monitor and automatically
convert assets in extended syntax. In this case, you should list the resulting CSS/JavaScript files in
asset bundles rather than the original files.
## Combining and Compressing Assets <a name="combining-compressing-assets"></a>
A Web page can include many CSS and/or JavaScript files. To reduce the number of HTTP requests and the overall
download size of these files, a common practice is to combine and compress multiple CSS/JavaScript files into
one or very few files, and then include these compressed files instead of the original ones in the Web pages.
> Info: Combining and compressing assets is usually needed when an application is in production mode.
In development mode, using the original CSS/JavaScript files is often more convenient for debugging purpose.
In the following, we introduce an approach to combine and compress asset files without the need of modifying
your existing application code.
1. Find out all asset bundles in your application that you plan to combine and compress.
2. Divide these bundles into one or a few groups. Note that each bundle can only belong to a single group.
3. Combine/compress the CSS files in each group into a single file. Do this similarly for the JavaScript files.
4. Define a new asset bundle for each group:
* Set the [[yii\web\AssetBundle::css|css]] and [[yii\web\AssetBundle::js|js]] properties to be
the combined CSS and JavaScript files, respectively.
* Customize the asset bundles in each group by setting their [[yii\web\AssetBundle::css|css]] and
[[yii\web\AssetBundle::js|js]] properties to be empty, and setting their [[yii\web\AssetBundle::depends|depends]]
property to be the new asset bundle created for the group.
Using this approach, when you register an asset bundle in a view, it causes the automatic registration of
the new asset bundle for the group that the original bundle belongs to. And as a result, the combined/compressed
asset files are included in the page, instead of the original ones.
### An Example <a name="example"></a>
Let's use an example to further explain the above approach.
Assume your application has two pages X and Y. Page X uses asset bundle A, B and C, while Page Y uses asset bundle B, C and D.
You have two ways to divide these asset bundles. One is to use a single group to include all asset bundles, the
other is to put (A, B, C) in Group X, and (B, C, D) in Group Y. Which one is better? It depends. The first way
has the advantage that both pages share the same combined CSS and JavaScript files, which makes HTTP caching
more effective. On the other hand, because the single group contains all bundles, the size of the combined CSS and
JavaScript files will be bigger and thus increase the initial file transmission time. In this example, we will use
the first way, i.e., use a single group to contain all bundles.
> Info: Dividing asset bundles into groups is not trivial task. It usually requires analysis about the real world
traffic data of various assets on different pages. At the beginning, you may start with a single group for simplicity.
Use existing tools (e.g. [Closure Compiler](https://developers.google.com/closure/compiler/),
[YUI Compressor](https://github.com/yui/yuicompressor/)) to combine and compress CSS and JavaScript files in
all the bundles. Note that the files should be combined in the order that satisfies the dependencies among the bundles.
For example, if Bundle A depends on B which depends on both C and D, then you should list the asset files starting
from C and D, followed by B and finally A.
After combining and compressing, we get one CSS file and one JavaScript file. Assume they are named as
`all-xyz.css` and `all-xyz.js`, where `xyz` stands for a timestamp or a hash that is used to make the file name unique
to avoid HTTP caching problem.
We are at the last step now. Configure the [[yii\web\AssetManager|asset manager]] as follows in the application
configuration:
```php
return [
'components' => [
'assetManager' => [
'bundles' => [
'all' => [
'class' => 'yii\web\AssetBundle',
'basePath' => '@webroot/assets',
'baseUrl' => '@web/assets',
'css' => ['all-xyz.css'],
'js' => ['all-xyz.js'],
],
'A' => ['css' => [], 'js' => [], 'depends' => ['all']],
'B' => ['css' => [], 'js' => [], 'depends' => ['all']],
'C' => ['css' => [], 'js' => [], 'depends' => ['all']],
'D' => ['css' => [], 'js' => [], 'depends' => ['all']],
],
],
],
];
```
As explained in the [Customizing Asset Bundles](#customizing-asset-bundles) subsection, the above configuration
changes the default behavior of each bundle. In particular, Bundle A, B, C and D no longer have any asset files.
They now all depend on the `all` bundle which contains the combined `all-xyz.css` and `all-xyz.js` files.
Consequently, for Page X, instead of including the original source files from Bundle A, B and C, only these
two combined files will be included; the same thing happens to Page Y.
There is one final trick to make the above approach work more smoothly. Instead of directly modifying the
application configuration file, you may put the bundle customization array in a separate file and conditionally
include this file in the application configuration. For example,
```php
return [
'components' => [
'assetManager' => [
'bundles' => require(__DIR__ . '/' . (YII_ENV_PROD ? 'assets-prod.php' : 'assets-dev.php')),
],
],
];
```
That is, the asset bundle configuration array is saved in `assets-prod.php` for production mode, and
`assets-dev.php` for non-production mode.
### Using the `asset` Command <a name="using-asset-command"></a>
Yii provides a console command named `asset` to automate the approach that we just described.
To use this command, you should first create a configuration file to describe what asset bundles should
be combined and how they should be grouped. You can use the `asset/template` sub-command to generate
a template first and then modify it to fit for your needs.
```
yii asset/template assets.php
```
The command generates a file named `assets.php` in the current directory. The content of this file looks like the following:
```php
<?php
/**
* Configuration file for the "yii asset" console command.
* Note that in the console environment, some path aliases like '@webroot' and '@web' may not exist.
* Please define these missing path aliases.
*/
return [
// Adjust command/callback for JavaScript files compressing:
'jsCompressor' => 'java -jar compiler.jar --js {from} --js_output_file {to}',
// Adjust command/callback for CSS files compressing:
'cssCompressor' => 'java -jar yuicompressor.jar --type css {from} -o {to}',
// The list of asset bundles to compress:
'bundles' => [
// 'yii\web\YiiAsset',
// 'yii\web\JqueryAsset',
],
// Asset bundle for compression output:
'targets' => [
'all' => [
'class' => 'yii\web\AssetBundle',
'basePath' => '@webroot/assets',
'baseUrl' => '@web/assets',
'js' => 'js/all-{hash}.js',
'css' => 'css/all-{hash}.css',
],
],
// Asset manager configuration:
'assetManager' => [
],
];
```
You should modify this file and specify which bundles you plan to combine in the `bundles` option. In the `targets`
option you should specify how the bundles should be divided into groups. You can specify one or multiple groups,
as aforementioned.
> Note: Because the alias `@webroot` and `@web` are not available in the console application, you should
explicitly define them in the configuration.
JavaScript files are combined, compressed and written to `js/all-{hash}.js` where {hash} is replaced with the hash of
the resulting file.
The `jsCompressor` and `cssCompressor` options specify the console commands or PHP callbacks for performing
JavaScript and CSS combining/compressing. By default Yii uses [Closure Compiler](https://developers.google.com/closure/compiler/)
for combining JavaScript files and [YUI Compressor](https://github.com/yui/yuicompressor/) for combining CSS files.
You should install tools manually or adjust these options to use your favorite tools.
With the configuration file, you can run the `asset` command to combine and compress the asset files
and then generate a new asset bundle configuration file `assets-prod.php`:
```
yii asset assets.php config/assets-prod.php
```
The generated configuration file can be included in the application configuration, like described in
the last subsection.
> Info: Using the `asset` command is not the only option to automate the asset combining and compressing process.
You can use the excellent task runner tool [grunt](http://gruntjs.com/) to achieve the same goal.
Extensions
==========
Extensions are redistributable software packages specifically designed to be used in Yii applications and provide
ready-to-use features. For example, the [yiisoft/yii2-debug](tool-debugger.md) extension adds a handy debug toolbar
at the bottom of every page in your application to help you more easily grasp how the pages are generated. You can
use extensions to accelerate your development process. You can also package your code as extensions to share with
other people your great work.
> Info: We use the term "extension" to refer to Yii-specific software packages. For general purpose software packages
that can be used without Yii, we will refer to them using the term "package" or "library".
## Using Extensions <a name="using-extensions"></a>
To use an extension, you need to install it first. Most extensions are distributed as [Composer](https://getcomposer.org/)
packages which can be installed by taking the following two simple steps:
1. modify the `composer.json` file of your application and specify which extensions (Composer packages) you want to install.
2. run `composer install` to install the specified extensions.
Note that you may need to install [Composer](https://getcomposer.org/) if you do not have it.
By default, Composer installs packages registered on [Packagist](https://packagist.org/) - the biggest repository
for open source Composer packages. You can look for extensions on Packagist. You may also
[create your own repository](https://getcomposer.org/doc/05-repositories.md#repository) and configure Composer
to use it. This is useful if you are developing closed open extensions and want to share within your projects.
Extensions installed by Composer are stored in the `BasePath/vendor` directory, where `BasePath` refers to the
application's [base path](structure-applications.md#basePath). Because Composer is a dependency manager, when
it installs a package, it will also install all its dependent packages.
For example, to install the `yiisoft/yii2-imagine` extension, modify your `composer.json` like the following:
```json
{
// ...
"require": {
// ... other dependencies
"yiisoft/yii2-imagine": "*"
}
}
```
After the installation, you should see the directory `yiisoft/yii2-imagine` under `BasePath/vendor`. You should
also see another directory `imagine/imagine` which contains the installed dependent package.
> Info: The `yiisoft/yii2-imagine` is a core extension developed and maintained by the Yii developer team. All
core extensions are hosted on [Packagist](https://packagist.org/) and named like `yiisoft/yii2-xyz`, where `xyz`
varies for different extensions.
Now you can use the installed extensions like they are part of your application. The following example shows
how you can use the `yii\imagine\Image` class provided by the `yiisoft/yii2-imagine` extension:
```php
use Yii;
use yii\imagine\Image;
// generate a thumbnail image
Image::thumbnail('@webroot/img/test-image.jpg', 120, 120)
->save(Yii::getAlias('@runtime/thumb-test-image.jpg'), ['quality' => 50]);
```
> Info: Extension classes are autoloaded by the [Yii class autoloader](concept-autoloading.md).
### Installing Extensions Manually <a name="installing-extensions-manually"></a>
In some rare occasions, you may want to install some or all extensions manually, rather than relying on Composer.
To do so, you should
1. download the extension archive files and unpack them in the `vendor` directory.
2. install the class autoloaders provided by the extensions, if any.
3. download and install all dependent extensions as instructed.
If an extension does not have a class autoloader but follows the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/),
you may use the class autoloader provided by Yii to autoload the extension classes. All you need to do is just to
declare a [root alias](concept-aliases.md#defining-aliases) for the extension root directory. For example,
assuming you have installed an extension in the directory `vendor/mycompany/myext`, and the extension classes
are under the `myext` namespace, then you can include the following code in your application configuration:
```php
[
'aliases' => [
'@myext' => '@vendor/mycompany/myext',
],
]
```
## Creating Extensions <a name="creating-extensions"></a>
You may consider creating an extension when you feel the need to share with other people your great code.
An extension can contain any code you like, such as a helper class, a widget, a module, etc.
It is recommended that you create an extension in terms of a [Composer package](https://getcomposer.org/) so that
it can be more easily installed and used by other users, liked described in the last subsection.
Below are the basic steps you may follow to create an extension as a Composer package.
1. Create a project for your extension and host it on a VCS repository, such as [github.com](https://github.com).
The development and maintenance work about the extension should be done on this repository.
2. Under the root directory of the project, create a file named `composer.json` as required by Composer. Please
refer to the next subsection for more details.
3. Register your extension with a Composer repository, such as [Packagist](https://packagist.org/), so that
other users can find and install your extension using Composer.
### `composer.json` <a name="composer-json"></a>
Each Composer package must have a `composer.json` file in its root directory. The file contains the metadata about
the package. You may find complete specification about this file in the [Composer Manual](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup).
The following example shows the `composer.json` file for the `yiisoft/yii2-imagine` extension:
```json
{
// package name
"name": "yiisoft/yii2-imagine",
// package type
"type": "yii2-extension",
"description": "The Imagine integration for the Yii framework",
"keywords": ["yii2", "imagine", "image", "helper"],
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Aimagine",
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"authors": [
{
"name": "Antonio Ramirez",
"email": "amigo.cobos@gmail.com"
}
],
// package dependencies
"require": {
"yiisoft/yii2": "*",
"imagine/imagine": "v0.5.0"
},
// class autoloading specs
"autoload": {
"psr-4": {
"yii\\imagine\\": ""
}
}
}
```
#### Package Name <a name="package-name"></a>
Each Composer package should have a package name which uniquely identifies the package among all others.
The format of package names is `vendorName/projectName`. For example, in the package name `yiisoft/yii2-imagine`,
the vendor name and the project name are `yiisoft` and `yii2-imagine`, respectively.
Do NOT use `yiisoft` as vendor name as it is reserved for use by the Yii core code.
We recommend you prefix `yii2-` to the project name for packages representing Yii 2 extensions, for example,
`myname/yii2-mywidget`. This will allow users to more easily tell whether a package is a Yii 2 extension.
#### Package Type <a name="package-type"></a>
It is important that you specify the package type of your extension as `yii2-extension` so that the package can
be recognized as a Yii extension when being installed.
When a user runs `composer install` to install an extension, the file `vendor/yiisoft/extensions.php`
will be automatically updated to include the information about the new extension. From this file, Yii applications
can know which extensions are installed (the information can be accessed via [[yii\base\Application::extensions]].
#### Dependencies <a name="dependencies"></a>
Your extension depends on Yii (of course). So you should list it (`yiisoft/yii2`) in the `require` entry in `composer.json`.
If your extension also depends on other extensions or third-party libraries, you should list them as well.
Make sure you also list appropriate version constraints (e.g. `1.*`, `@stable`) for each dependent package. Use stable
dependencies when your extension is released in a stable version.
Most JavaScript/CSS packages are managed using [Bower](http://bower.io/) and/or [NPM](https://www.npmjs.org/),
instead of Composer. Yii uses the [Composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin)
to enable managing these kinds of packages through Composer. If your extension depends on a Bower package, you can
simply list the dependency in `composer.json` like the following:
```json
{
// package dependencies
"require": {
"bower-asset/jquery": ">=1.11.*"
}
}
```
The above code states that the extension depends on the `jquery` Bower package. In general, you can use
`bower-asset/PackageName` to refer to a Bower package in `composer.json`, and use `npm-asset/PackageName`
to refer to a NPM package. When Composer installs a Bower or NPM package, by default the package content will be
installed under the `@vendor/bower/PackageName` and `@vendor/npm/Packages` directories, respectively.
These two directories can also be referred to using the shorter aliases `@bower/PackageName` and `@npm/PackageName`.
For more details about asset management, please refer to the [Assets](structure-assets.md#bower-npm-assets) section.
#### Class Autoloading <a name="class-autoloading"></a>
In order for your classes to be autoloaded by the Yii class autoloader or the Composer class autoloader,
you should specify the `autoload` entry in the `composer.json` file, like shown below:
```json
{
// ....
"autoload": {
"psr-4": {
"yii\\imagine\\": ""
}
}
}
```
You may list one or multiple root namespaces and their corresponding file paths.
When the extension is installed in an application, Yii will create for each listed root namespace
an [alias](concept-aliases.md#extension-aliases) that refers to the directory corresponding to the namespace.
For example, the above `autoload` declaration will correspond to an alias named `@yii/imagine`.
### Recommended Practices <a name="recommended-practices"></a>
Because extensions are meant to be used by other people, you often need to take extra development effort. Below
we introduce some common and recommended practices in creating high quality extensions.
#### Namespaces <a name="namespaces"></a>
To avoid name collisions and make the classes in your extension autoloadable, you should use namespaces and
name the classes in your extension by following the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/) or
[PSR-0 standard](http://www.php-fig.org/psr/psr-0/).
You class namespaces should start with `vendorName\extensionName`, where `extensionName` is similar to the project name
in the package name except that it should not contain the `yii2-` prefix. For example, for the `yiisoft/yii2-imagine`
extension, we use `yii\imagine` as the namespace its classes.
Do not use `yii`, `yii2` or `yiisoft` as vendor name. These names are reserved for use by the Yii core code.
#### Bootstrapping Classes <a name="bootstrapping-classes"></a>
Sometimes, you may want your extension to execute some code during the [bootstrapping process](runtime-bootstrapping.md)
stage of an application. For example, your extension may want to respond to the application's `beginRequest` event
to adjust some environment settings. While you can instruct users of the extension to explicitly attach your event
handler in the extension to the `beginRequest` event, a better way is to do this automatically.
To achieve this goal, you can create a so-called *bootstrapping class* by implementing [[yii\base\BootstrapInterface]].
For example,
```php
namespace myname\mywidget;
use yii\base\BootstrapInterface;
use yii\base\Application;
class MyBootstrapClass implements BootstrapInterface
{
public function bootstrap($app)
{
$app->on(Application::EVENT_BEFORE_REQUEST, function () {
// do something here
});
}
}
```
You then list this class in the `composer.json` file of your extension like follows,
```json
{
// ...
"extra": {
"bootstrap": "myname\\mywidget\\MyBootstrapClass"
}
}
```
When the extension is installed in an application, Yii will automatically instantiate the bootstrapping class
and call its [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] method during the bootstrapping process for
every request.
#### Working with Databases <a name="working-with-databases"></a>
Your extension may need to access databases. Do not assume that the applications that use your extension will always
use `Yii::$db` as the DB connection. Instead, you should declare a `db` property for the classes that require DB access.
The property will allow users of your extension to customize which DB connection they would like your extension to use.
As an example, you may refer to the [[yii\caching\DbCache]] class and see how it declares and uses the `db` property.
If your extension needs to create specific DB tables or make changes to DB schema, you should
- provide [migrations](db-migrations.md) to manipulate DB schema, rather than using plain SQL files;
- try to make the migrations applicable to different DBMS;
- avoid using [Active Record](db-active-record.md) in the migrations.
#### Using Assets <a name="using-assets"></a>
If your extension is a widget or a module, chances are that it may require some [assets](structure-assets.md) to work.
For example, a module may display some pages which contain images, JavaScript, and CSS. Because the files of an
extension are all under the same directory which is not Web accessible when installed in an application, you have
two choices to make the asset files directly accessible via Web:
- ask users of the extension to manually copy the asset files to a specific Web-accessible folder;
- declare an [asset bundle](structure-assets.md) and rely on the asset publishing mechanism to automatically
copy the files listed in the asset bundle to a Web-accessible folder.
We recommend you use the second approach so that your extension can be more easily used by other people.
Please refer to the [Assets](structure-assets.md) section for more details about how to work with assets in general.
#### Internationalization and Localization <a name="i18n-l10n"></a>
Your extension may be used by applications supporting different languages! Therefore, if your extension displays
content to end users, you should try to [internationalize and localize](tutorial-i18n.md) it. In particular,
- If the extension displays messages intended for end users, the messages should be wrapped into `Yii::t()`
so that they can be translated. Messages meant for developers (such as internal exception messages) do not need
to be translated.
- If the extension displays numbers, dates, etc., they should be formatted using [[yii\i18n\Formatter]] with
appropriate formatting rules.
For more details, please refer to the [Internationalization](tutorial-i18n.md) section.
#### Testing <a name="testing"></a>
You want your extension to run flawlessly without bringing problems to other people. To reach this goal, you should
test your extension before releasing it to public.
It is recommended that you create various test cases to cover your extension code rather than relying on manual tests.
Each time before you release a new version of your extension, you may simply run these test cases to make sure
everything is in good shape. Yii provides testing support, which can help you to more easily write unit tests,
acceptance tests and functionality tests. For more details, please refer to the [Testing](test-overview.md) section.
#### Versioning <a name="versioning"></a>
You should give each release of your extension a version number (e.g. `1.0.1`). We recommend you follow the
[semantic versioning](http://semver.org) practice when determining what version numbers should be used.
#### Releasing <a name="releasing"></a>
To let other people know your extension, you need to release it to public.
If it is the first time you release an extension, you should register it on a Composer repository, such as
[Packagist](https://packagist.org/). After that, all you need to do is simply creating a release tag (e.g. `v1.0.1`)
on the VCS repository of your extension and notify the Composer repository about the new release. People will
then be able to find the new release, and install or update the extension through the Composer repository.
In the releases of your extension, besides code files you should also consider including the followings to
help other people learn about and use your extension:
* A readme file in the package root directory: it describes what your extension does and how to install and use it.
We recommend you write it in [Markdown](http://daringfireball.net/projects/markdown/) format and name the file
as `readme.md`.
* A changelog file in the package root directory: it lists what changes are made in each release. The file
may be written in Markdown format and named as `changelog.md`.
* An upgrade file in the package root directory: it gives the instructions on how to upgrade from older releases
of the extension. The file may be written in Markdown format and named as `upgrade.md`.
* Tutorials, demos, screenshots, etc.: these are needed if your extension provides many features that cannot be
fully covered in the readme file.
* API documentation: your code should be well documented to allow other people more easily read and understand it.
You may refer to the [Object class file](https://github.com/yiisoft/yii2/blob/master/framework/base/Object.php)
to learn how to document your code.
> Info: Your code comments can be written in Markdown format. The `yiisoft/yii2-apidoc` extension provides a tool
for you to generate pretty API documentation based on your code comments.
> Info: While not a requirement, we suggest your extension adhere to certain coding styles. You may refer to
the [core framework code style](https://github.com/yiisoft/yii2/wiki/Core-framework-code-style).
## Core Extensions <a name="core-extensions"></a>
Yii provides the following core extensions that are developed and maintained by the Yii developer team. They are all
registered on [Packagist](https://packagist.org/) and can be easily installed as described in the
[Using Extensions](#using-extensions) subsection.
- [yiisoft/yii2-apidoc](https://github.com/yiisoft/yii2-apidoc):
provides an extensible and high-performance API documentation generator. It is also used to generate the core
framework API documentation.
- [yiisoft/yii2-authclient](https://github.com/yiisoft/yii2-authclient):
provides a set of commonly used auth clients, such as Facebook OAuth2 client, GitHub OAuth2 client.
- [yiisoft/yii2-bootstrap](https://github.com/yiisoft/yii2-bootstrap):
provides a set of widgets that encapsulate the [Bootstrap](http://getbootstrap.com/) components and plugins.
- [yiisoft/yii2-codeception](https://github.com/yiisoft/yii2-codeception):
provides testing support based on [Codeception](http://codeception.com/).
- [yiisoft/yii2-debug](https://github.com/yiisoft/yii2-debug):
provides debugging support for Yii applications. When this extension is used, a debugger toolbar will appear
at the bottom of every page. The extension also provides a set of standalone pages to display more detailed
debug information.
- [yiisoft/yii2-elasticsearch](https://github.com/yiisoft/yii2-elasticsearch):
provides the support for using [Elasticsearch](http://www.elasticsearch.org/). It includes basic querying/search
support and also implements the [Active Record](db-active-record.md) pattern that allows you to store active records
in Elasticsearch.
- [yiisoft/yii2-faker](https://github.com/yiisoft/yii2-faker):
provides the support for using [Faker](https://github.com/fzaninotto/Faker) to generate fake data for you.
- [yiisoft/yii2-gii](https://github.com/yiisoft/yii2-gii):
provides a Web-based code generator that is highly extensible and can be used to quickly generate models,
forms, modules, CRUD, etc.
- [yiisoft/yii2-imagine](https://github.com/yiisoft/yii2-imagine):
provides commonly used image manipulation functions based on [Imagine](http://imagine.readthedocs.org/).
- [yiisoft/yii2-jui](https://github.com/yiisoft/yii2-jui):
provides a set of widgets that encapsulate the [JQuery UI](http://jqueryui.com/) interactions and widgets.
- [yiisoft/yii2-mongodb](https://github.com/yiisoft/yii2-mongodb):
provides the support for using [MongoDB](http://www.mongodb.org/). It includes features such as basic query,
Active Record, migrations, caching, code generation, etc.
- [yiisoft/yii2-redis](https://github.com/yiisoft/yii2-redis):
provides the support for using [redis](http://redis.io/). It includes features such as basic query,
Active Record, caching, etc.
- [yiisoft/yii2-smarty](https://github.com/yiisoft/yii2-smarty):
provides a template engine based on [Smarty](http://www.smarty.net/).
- [yiisoft/yii2-sphinx](https://github.com/yiisoft/yii2-sphinx):
provides the support for using [Sphinx](http://sphinxsearch.com). It includes features such as basic query,
Active Record, code generation, etc.
- [yiisoft/yii2-swiftmailer](https://github.com/yiisoft/yii2-swiftmailer):
provides email sending features based on [swiftmailer](http://swiftmailer.org/).
- [yiisoft/yii2-twig](https://github.com/yiisoft/yii2-twig):
provides a template engine based on [Twig](http://twig.sensiolabs.org/).
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment