An ability to manage assets is one of the greatest parts of Yii. It is especially useful in the following cases:
While the first two cases could be considered as bonuses, the third one solves many widget reusing problems.
Let's create a simple widget using sample API, which will publish and use its own CSS, JavaScript, and an image.
yiic webapp
as described in the official guide.assets
directory under application's webroot
(where index.php
is) has write permissions; assets will be written there.Let's do some planning first. In Yii, you can place your widgets virtually inside any directory, and often, it is protected/components
. It is acceptable to have one or two classes inside, but when the number of classes increases, it can create problems. Therefore, let's place our widget into protected/extensions/yiicookbook
. Create an assets
directory inside the widget
folder and put inside the ajax-loader.gif
image you have just downloaded. Also, create yiicookbook.css
and yiicookbook.js
in the same directory.
widget
class itself, protected/extensions/yiicookbook/EYiiCookbook.php
:<?php class EYiiCookbook extends CWidget { public $object; private $loadingImageUrl; protected $url = "http://yiicookbook.org/api/%s?callback=?"; protected function getUrl() { return sprintf($this->url, urlencode($this->object)); } public function init() { $assetsDir = dirname(__FILE__).'/assets'; $cs = Yii::app()->getClientScript(); $cs->registerCoreScript("jquery"); // Publishing and registering JavaScript file $cs->registerScriptFile( Yii::app()->assetManager->publish( $assetsDir.'/yiicookbook.js' ), CClientScript::POS_END ); // Publishing and registering CSS file $cs->registerCssFile( Yii::app()->assetManager->publish( $assetsDir.'/yiicookbook.css' ) ); // Publishing image. publish returns the actual URL // asset can be accessed with $this->loadingImageUrl = Yii::app()->assetManager->publish( $assetsDir.'/ajax-loader.gif' ); } public function run() { $this->render("body", array( 'url' => $this->getUrl(), 'loadingImageUrl' => $this->loadingImageUrl, 'object' => $this->object, )); } }
body
view we are using inside the run
method protected/extensions/yiicookbook/views/body.php
:<div class="results" data-url="<?php echo $url?>"> <h2><?php echo $keyword?> events</h2> <div class="data"> <?php echo CHtml::image($loadingImageUrl)?> </div> </div>
We will need to put the following into yiicookbook.js
:
jQuery(function($){ $(".results").each(function(){ var url = $(this).data("url"); var container = $(".data", this); $.getJSON(url,function(json){ var html = "<ul>"; $.each(json.data,function(){ html += "<li>"; html += '<a href="'+this.url+'">'+this.name+'</a>'; if(this.author) { html += '<br />by '+this.author; } html += "</li>"; }); html += "</ul>"; container.html(html); }); }); });
yiicookbook.css
created previously:.results { padding: 10px; width: 400px; float: left; } .results ul { padding: 0; } .results li { list-style: none; border: 1px solid #ccc; padding: 10px; margin: 2px; }
protected/views/site/index.php
file and add the following code to it:<?php $this->widget("ext.yiicookbook. EYiiCookbook", array( 'object' => 'book', ))?> <?php $this->widget("ext.yiicookbook. EYiiCookbook", array( 'object' => 'website', ))?>
When we use $this->widget
in the site/index
view, two EYiiCookbook
methods are called: init
, which publishes assets and connects them to the page, and run
which renders widget HTML. First, we use CAssetManager::publish
to copy our file into the assets
directory visible from the Web. It returns a URL that can be used to access the resource. In the case of JavaScript and CSS, we use the CClientScript
methods that add the necessary <script>
and <style>
tags and prevent duplication. As for an image, we pass its URL to the body view that uses it to render a placeholder with CHtml::image
. When JavaScript is loaded, it makes requests to the sample API (described at http://yiicookbook.org/api/) and replaces placeholder with the actual data received.
There is more about working with assets.
Let's check our
assets
directory. It should look similar to the following:
assets 1a6630a0 main.css 2bb97318 pager.css 4ab2ffe jquery.js …
Directories such as 1a6630a0
are used to prevent collisions of files with similar names from different directories. The name of the directory is a hash of complete paths to the published assets
directory. Therefore, assets from the same directory are copied to the same place. This means that if you publish both the image and the CSS file, you can reference images from CSS using relative paths.
Using CAssetManager::publish
, you can publish an entire directory recursively. The difference is that single files are monitored after being published, whereas directories are not.
For further information, refer to the following URLs:
3.134.78.106