- Background
- Asset Manager
- Example: Asset use by Gii
- CAssetManager class
- Maintenance of the assets folder
- Upgrading Yii
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, 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:
// 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 underassets/
, 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 underassets/
.
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.
Small tip about deleting/updating assets files.
Be careful deleting files under assets subfolders without deleting subfolders themselves. Yii checks if corresponding subfolder exists (/assets/2472c2df) and if it does, Yii does NOT copy files again into that subfolder, even if you deleted some files manually there.
This means that if you want to renew the published files of your module/extension/etc you have to delete whole subfolder (/2472c2df), so Yii republishes files from source.
Also i think good practice is to make forced publishing dependable of debug constant.
$baseJsUrl = Yii::app()->getAssetManager()->publish($baseJsPath, false, -1, YII_DEBUG);
This will force Yii to copy assets files every time you run the application in debug mode and such always have current runtime files. When you publish your application, you switch debug mode off and Yii will go into normal mode (publishing only when corresponding subfolder under /assets does not exist).
Re: how does it work for extensions ?
If you have let's say a XyzWidget (if your extension is a widget for example) and in your view code you create it:
$xyz = $this->widget('ext.xyz.XyzWidget', array( 'property' => 'initialValue', ));
And in your XyzWidget code you have method like above getAssetsUrl()
you simply call it:
For $this->module see documentation CController.getModule()
Tip for developing assets
In your development environment/configuration, use the linkAssets property:
http://www.yiiframework.com/doc/api/1.1/CAssetManager/#linkAssets-detail
Assets will be published as symbolic links to the source directory. You can 'directly' edit files from assets/ and don't need to republish after every change.
Be carefull with CAssetManager->linkAssets
CAssetManager->linkAssets is good only when you control your hosting environment (VPS or dedicated server). Otherwise you depend of too many conditions controlled by hoster (OS type/version, php version, web server configuration).
For example my main hoster for shared projects still has php 5.2.17 installed and you need at least 5.3
Re: Be carefull with CAssetManager->linkAssets
That's why I said: use in your development environment.
In a production environment not using symlinks is preferable.
(for expected support, again see: http://www.yiiframework.com/doc/api/1.1/CAssetManager/#linkAssets-detail)
Cloud-based hosting
I am trying to get my app onto EngineYard's Orchestra platform. It doesn't allow to write to the server expect in the system's tmp folder. It's no big deal for the 'runtime' folder, but for 'assets' I'm not sure what to do.
Re: Cloud-based hosting
Well, you must provide public accessible directory named eg
assets
because users (browsers) will need to access it in order to retrieve images, javascripts, stylesheets etc. Just put this directory under yourwebroot
directory (where yoursindex.php
file is) and that's all. You can tune up your directory structure anytime using CAssetManager.basePath and CAssetManager.baseUrl properties.Re: Cloud-based hosting
ManInTheBox, I think you misunderstood. I cannot write any file to the server. I can only write to Linux's 'tmp' directory.
Yii assets on Amazon S3
Nathan, please check this extension:
http://www.yiiframework.com/extension/s3assetmanager
Basically to use any js/css/image assets/files on EY's Orchestra you should upload them to Amazon S3. That extensions helps you to do this.
Re: Cloud-based hosting
Ok, sorry for bad answer. I'm not experienced with
EngineYard's Orchestra platform
so try with Johnatan's answer instead.[ASK]How to Disable Asset??
Hi..
i want to run a web application on cd, so im using "DWebPro".
But when i run the web, there are some error because of creating the asset (you know in CD you can't write, just read)
any ideas how to clear this problem? or there is a way to disable asset?
thanks anyway..
Small tips about removing asstes file from your frontend.
I have seen and faced myself that when you have a complex page they often need to include many external JavaScript and CSS files. This gives one extra round trip to your server and back, I tried setting a corn-job in my server to delete this files so i could increase the performance and decrease page loading time. I found we can do it in two ways,
FIRST
You can either minify them and compile them to a single file. Eg:
/assets/xxx/jquery.js
/assets/xxx/jquery.ajaxqueue.js
/assets/xxx/jquery.metadata.js
/assets/xxx/jquery.ba-bbq.js
/assets/xxx/jquery.yiilistview.
into a single file one-js.js or permanently removing them.
However, removing them permanently somehow can bring problem to your pages and contents
but if compiled to a single file it would boost performance and decrease loading time
You can compile them to one file by following the steps:
<?php echo $content; ?>
<?php
$cs=Yii::app()->clientScript;
$cs->scriptMap=array(
'jquery.js'=>'/js/one-js.js', 'jquery.ajaxqueue.js'=>'/js/one-js.js', 'jquery.metadata.js'=>'/js/one-js.js', 'jquery.ba-bbq.js'=>'/js/one-js.js', 'jquery.yiilistview.js'=>'/js/one-js.js',
);
You can remove them permanently by removing /js/one-js.js from the above code.
Cheers !
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.