Difference between #4 and #3 of Understanding "Assets"

unchanged
Title
Understanding "Assets"
unchanged
Category
Tutorials
changed
Tags
assetsassets, understanding
unchanged
Content
Many newcomers to Yii ask about the `assets/` directory found under the webroot,
and this article means to explain why it's there and how to work with it.

Background
----------
Many applications are entirely self contained, and there's no trouble or
conflict putting necessary resources (images, CSS files, Javascript files, etc.)
under the webroot:

* `webroot/css/*`
* `webroot/js/*`
* `webroot/images/*`

and so on. If a module needs to add one more resources, it's added directly
and referenced by the path down from webroot.

But if one creates a module intended for widespread reuse elsewhere, naming
conflicts start to emerge: How do you insure that your filename `css/foo.css`
won't conflict with some unrelated application's attempt to use a file
of the same name? Likewise with Javascript, images, and all the rest. This gets
more difficult the more popular the module gets: it's going to eventually
conflict with **something**.

Asset Manager
-------------
Yii addresses this by use of
[CAssetManager](http://www.yiiframework.com/doc/api/1.1/CAssetManager),
available as `Yii::app()->assetManager`, which can take a module's
private resource files and automatically **publish** them to the web-visible
area (typically, `webroot/assets/`) on demand, giving the assets a
non-conflicting unique name that can be later referenced in the code.

This copying/publishing is done the first time a module's resources are
used, returning a URL to the application to use when generating HTML.

In addition to supporting resource publication by modules (both internal and for
user application), Yii uses assets internally for core resources, such as
jQuery.

Example: Asset use by Gii
-------------------------
A good example of asset publication is the Gii code generator, which can be
found in the framework directory. Looking here we see:

* `framework/gii/GiiModule.php`
* `framework/gii/models/...`
* `framework/gii/views/...`
* `framework/gii/controllers/...`
* `framework/gii/assets/css/...`
* `framework/gii/assets/js/...`
* `framework/gii/assets/images/...`
* etc

The models, views, and controllers (along with the module config file) are like
any other module, accessed at runtime by Yii just like the application code
itself.

But Yii needs additonal web resources -- CSS, JS, images -- at runtime, but
they're generally not available to the browser client from within the
framework directory.

So the Gii module arranges to **publish** these assets to an area under 
`webroot/`, and the first time Gii is used these new folders show up:

* `webroot/assets/2472c2df/css/...`
* `webroot/assets/2472c2df/images/...`
* `webroot/assets/2472c2df/js/...`

The `2472c2df` is a unique name created by Yii in a way that won't conflict
with any other module that publishes assets, but the particular numbers
don't mean anything. After publication, the Gii module knows that the path
`/assets/2472c2df/css/main.css` can be used in a URL to load the main CSS file.

CAssetManager class
-------------------
(Note: this section is just an overview, not a detailed howto.)

The application's asset manager is available as
`Yii::app()->assetManager`, and the main method is `publish()`. It's
given a pathname where to find the source material - either one file or a
directory to be published recursively - and it returns the URL base that can be
used to access the published material.

This trimmed-down example was adapted from Gii (1.1.6) with much extraneous
material removed:
~~~
[php]
// in the module initialization program
class XxiiModule extends CWebModule
{
    ...
    // getAssetsUrl()
    //    return the URL for this module's assets, performing the publish
operation
    //    the first time, and caching the result for subsequent use.
    private $_assetsUrl;

    public function getAssetsUrl()
    {
        if ($this->_assetsUrl === null)
            $this->_assetsUrl =
Yii::app()->getAssetManager()->publish(
                Yii::getPathOfAlias('xxii.assets') );
        return $this->_assetsUrl;
    }
    ....

// xxii/views/layouts/main.php

   <link rel="stylesheet"
         type="text/css"
         href="<?php echo $this->module->assetsUrl;
?>/css/main.css"/>
   ...
   <div id="logo">
   <?php echo CHtml::link(
                
CHtml::image($this->module->assetsUrl.'/images/logo.png'),
                 array('/xxii')); ?>
   </div>
~~~
The first time this is used in an application, the asset manager copies all the
files to the `webroot/assets/` folder, and then the module can use the
`$model->assetsUrl` property to form the base of generated URLs for each of
the particular resource files.

Using the example assets layout shown in the earlier section, these two uses
would generate the URLs:

* `/assets/2472c2df/css/main.css`
* `/assets/2472c2df/images/logo.png`

respectively.

Maintenance of the `assets` folder
----------------------------------
Many newcomers ask: "What do we do with the assets folder?", and the
answer is "Mostly nothing".

* It's important that the directory be writable by the webserver user so
that Yii can publish the resources there when needed.
* When a project has multiple versions (production, testing, development, etc.)
**do not** copy the `assets/` folders from one area to another; allow Yii to
deploy them automatically in each area.
* **Do not** manually edit any file under `assets/` - if you have a real need to
make a change, find the publishing module, edit the source, delete the subfolder
under `assets/`, and let Yii re-publish the updated files.
* **Do not** reference names under the `assets/` folder directly (say, to get at
some other module's assets). If you need to use that 
* **Do not** add the contents of the `assets/` folder to any source-code control
system; these files have master source in other places.
* It is safe to delete everything under `assets/`. Yii will re-publish the
assets if they are not found under `assets/`.

Upgrading Yii
-------------
When upgrading to a new release of Yii, you do not need to clean up the folders
under `assets/`. Yii will automatically re-publish assets to new folders based
on the Yii version number. The old folders will remain there and unused.

If you are using the SVN development branch of Yii and find any asset file
updated in the Yii framework after SVN update (e.g. `jquery.yiigridview.js` is
changed due to a bug fix), you should clean up your `assets` folder so that the
updated asset files can be re-published.