Yiiのassetsの仕組み

javascriptsやcss,imageを格納するyiiのassetsディレクトリ(パス)は独特の仕組みをもっていて、それについてのメモ。

CAssetManager

説明ページ

http://www.yiiframework.com/wiki/148/understanding-assets/ に説明がある。

  • webroot/assets/2472c2df/css/...
  • webroot/assets/2472c2df/images/...
  • webroot/assets/2472c2df/js/...

ようなかたちでパスが動的に生成される。

2472c2dfはユニックなもので、それを生成する「モジュール」や「コンポーネント」ごとに違う。

パス名の決まり方

http://www.yiiframework.com/doc/api/1.1/CAssetManager#hash-detail

protected function hash($path)
{
    return sprintf('%x',crc32($path.Yii::getVersion()));
}

ソースのフルパスとYiiのバージョンを加えたものをcrc32でハッシュ化されているので一意になる。

動作の仕組み

このユニックパスを、どのように生成させて、どのように指定するのかは、CAssetManagerクラスを用いる。

  1. まず、js,image,cssソースが入っているフルパスを指定する
  2. 同フルパス配下のディレクトリ、ファイルが公開用URLの/assets/ユニックパスに複写される。

具体的に言えば、

$assetUrl =Yii::app()->getAssetManager()->publish(パス));

とすればいい。

  • publishのパスは、webroot/assets配下に入れたいjs,image,cssソースが入っているフルパス
  • これでwebroot/assets/2744d4ef/にpublishフルパス以下のディレクトリ、ファイルがコピーされる。
  • 戻り値の$assetUrlには、/assets/2744d4ef/のようなURLパスが入る。

小規模サイトでの実装の仕方

というわけで上のgetAssetManager()->publish(パス)をどのタイミングで、どこで起動させればいいのかを理解しておけばassetsは使える。

モジュールよりはコンポーネントで

モジュールの場合は、モジュールの変数にassetUrlをつくっておけば、$this->module->assetUrlとしてViewなどでアクセス可能になる。http://www.yiiframework.com/wiki/148/understanding-assets/でもモジュールを例にあげて解説している。

ただ、モジュールは一種の独立アプリケーションなので、単純なものであっても、複数アプリケーションを作るのと同じ程度の気を使わなければならない。グループで開発する場合は疎結合なのでいいのだろうが、小規模少機能のものを一人で作るにはオーバースペックだと思う。

というわけで、単一アプリのコンポーネント機能を使って管理したほうが、使いやすそうである。一番簡単なのは既にあるwebroot/protected/components/Controller.phpの中に記載することかな、と思う(*1)。

assets用ソースパスを指定する。

とりあえず、views/assetsとする。

mkdir -p webroot/protected/views/assets/js
mkdir -p webroot/protected/views/assets/css
mkdir -p webroot/protected/views/assets/images

Controller.phpの設定

http://twitter.github.com/bootstrap/エクステンションのコンポーネント:BootStrap.phpを参照した。BootStrap.phpではユニックIDを処理するassetManagerに加えて、そのjs/cssスクリプトのURLをHTMLに登録表示するclientScriptが用いられている(*2)。なお、set/getPathAliasについてはhttp://www.yiiframework.com/doc/guide/1.1/ja/basics.namespace参照。

protected $_assetsUrl;
public function setCss($filename)
{
  Yii::app()->clientScript->registerCssFile($this->getAssetsUrl().'/css/'.$filename);
}
public function setJs($fileName, $position=CClientScript::POS_HEAD)
{
  Yii::app()->clientScript->registerScriptFile($this->getAssetsUrl().'/js/'.$fileName, $position);
}
public function siteImages($filename)
{
  return CHtml::image($this->assetsUrl.'/images/'.$filename);
}
protected function getAssetsUrl()
{
  if ($this->_assetsUrl !== null)
  return $this->_assetsUrl;
  else
  {
  $assetsPath = Yii::getPathOfAlias('application.views.assets');
  if (YII_DEBUG)
    $assetsUrl = Yii::app()->assetManager->publish($assetsPath, false, -1, true);
  else
    $assetsUrl = Yii::app()->assetManager->publish($assetsPath);
  return $this->_assetsUrl = $assetsUrl;
  }
}

views/layout/main.phpの記述方法

<head>
....
  $this->setCss('test.css');
  $this->setJs('test.js');
....
</head>
<body>
....
<?php echo $this->>siteImages('test.jpg');?>
....
<//body>

HTML出力結果

<link rel="stylesheet" type="text/css" href="/assets/519c78d7/css/test.css" />
<script type="text/javascript" src="/assets/519c78d7/js/test.js"></script>
<img src="/assets/519c78d7/images/test.jpg" alt="" /> 

img要素の属性が美しくないのはテストなのでお許しを。


独立コンポーネントにする

動作の仕組みは分かったので、Controller.phpからは分離してみる。

独立のコンポーネントを作るには、configを弄る必要がある。

クラス名 AssetsFile

CApplicationComponentを継承する。

webroot/components/AssetsFile.phpをつくり、class AssetsFile extends CApplicationComponent として上のController.phpの該当部分を移行する。

config/main.php

componentsの場所に、

'assets'=>array('class'=>'AssetsFile'),

を加える。

views/layout/main.phpの記述方法

上のconfigで設定したアプリケーションコンポーネントIDはassetsなので、

Yii::app()->assets->siteImages('a.png');

とすればアクセス出来る。

*1: Controllerクラスは、ベースのCControllerの拡張で、webroot/protected/controller/以下のコントローラーの親クラス

*2: いずれも初期にロードされるコアアプリケーションコンポーネントをなす。

this file --> last modified:2012-05-24 14:09:11