Yii CClientScriptの話

# CClientScriptの話

Yiiにはビューで扱うJavaScriptやCSSを管理するために CClientScript というクラスが用意されています。外部のJavaScriptやCSSファイルを指定してHTMLに組み込んだり、直接ビューにてコードを追加するときなどにこのクラスを利用します。
  
また CClientScript はコアのアプリケーションコンポーネントでもあるので、アプリケーション全体での設定を protected/config/main.php にて調整でき、Yiiのコアで宣言されているデフォルトの値を変更することも可能です。

## ファイルの組み込みについて

では、早速使ってみましょう。例として [Lightbox2](http://lokeshdhakar.com/projects/lightbox2/) を使います。`yiic webapp` でアプリケーションの雛形を生成して、protectedディレクトリと同階層にDLして解凍したlightboxディレクトリを置く。loading.gif, close.pngのパスを調整したいので lightbox/js/lightbox.js を以下のように書き換える。

```js:lightbox.js
this.fileLoadingImage = 'lightbox/images/loading.gif';
this.fileCloseImage = 'lightbox/images/close.png';
```

これで多分大丈夫なので protected/views/site/index.php を使ってコードを追加していきましょう。とりあえず以下のように書いてみてください。

```php:index.php
<?php
Yii::app()->clientScript->registerPackage('jquery');
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl.'/lightbox/js/lightbox.js');
Yii::app()->clientScript->registerCssFile(Yii::app()->baseUrl.'/lightbox/css/lightbox.css');
```

上記のようなコードを書くと、HTMLのソースは以下のようになります。headに書いたコードが組み込まれる感じですね。

```html
<head>
	...
	<link rel="stylesheet" type="text/css" href="/hoge/lightbox/css/lightbox.css" />
	<script type="text/javascript" src="/hoge/assets/f6e78aff/jquery.js"></script>
	<script type="text/javascript" src="/hoge/lightbox/js/lightbox.js"></script>
	<title>My Web Application - Site</title>
</head>
```

まず CClientScript は最初にも言いましたがアプリケーションコンポーネントなので Yii::app()->ComponentID でアクセスすることができます。それに続いてプロパティやメソッド名を書いていきます。

### CClientScript::registerPackage($name)

これはパッケージの登録です。[ここ] (https://github.com/yiisoft/yii/blob/master/framework/web/js/packages.php) にコアが保持しているパッケージリストがあります。例えば yiiactiveform を組み込ませたい場合は以下のように書きます。

```php:index.php
<?php
Yii::app()->clientScript->registerPackage('yiiactiveform');
//Yii::app()->clientScript->registerCoreScript('yiiactiveform'); でも同様
```

するとソースは以下のようになります。

```html
<script type="text/javascript" src="/hoge/assets/f6e78aff/jquery.js"></script>
<script type="text/javascript" src="/hoge/assets/f6e78aff/jquery.yiiactiveform.js"></script>
```

jquery.js も組み込まれているのは 'depends' で指定されているためです。'depends' で指定されたものはすべて一緒に組み込まれます。また YII_DEBUG の値によって、組み込まれるファイルに違いが出てくるので注意しましょう。例えば、YII_DEBUG が false の場合 jquery.min.js が組み込まれることになります。

### CClientScript::registerScriptFile($url, $position)

JavaScriptファイルを登録します。$positionはソースのどの部分に組み込むか、です。デフォルトでは NULL になっているので defaultScriptFilePosition プロパティで指定されている位置に組み込まれます。コードを見ると self::POS_HEAD と書かれているので、head部分がデフォルトの位置になります。変更したい場合は CClientScript::POS_HEAD, CClientScript::POS_BEGIN, CClientScript::POS_END などが用意されているので、詳しくはAPIを参考にしてみてください。

### CClientScript::registerCssFile($url, $media)

省略

---

では、実際ちゃんと動くか試してみましょう。Lightboxにはサンプルの画像も用意されているようなので、それを使ってみます。

```html+php:index.php
<?php
Yii::app()->clientScript->registerPackage('jquery');
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl.'/lightbox/js/lightbox.js');
Yii::app()->clientScript->registerCssFile(Yii::app()->baseUrl.'/lightbox/css/lightbox.css');
?>

<h1>CClientScript + Lightbox2</h1>

<?php $img = CHtml::image(Yii::app()->baseUrl.'/lightbox/images/examples/thumb-1.jpg'); ?>
<?php echo CHtml::link($img, Yii::app()->baseUrl.'/lightbox/images/examples/image-1.jpg', array('rel' => 'lightbox')); ?>
```

ちゃんと動きました？自分のはちゃんと動きました。Yiiのバージョン1.1.5以上を使ってる場合は以下のようにメソッドチェーンを利用できます。少しですがコード記述量が減ります。

```php:index.php
<?php
Yii::app()->clientScript
	->registerPackage('jquery')
	->registerScriptFile(Yii::app()->baseUrl.'/lightbox/js/lightbox.js')
	->registerCssFile(Yii::app()->baseUrl.'/lightbox/css/lightbox.css');
```

さて、ここでこの3つの登録、まとめて1行でシンプルに書けないかな？と自分は思ったんですが、皆さんはどうでしょうか。Yii::app()->baseUrl とかもなんかいちいち指定するのめんどくさいし。そこらへんの話を次でやります。その前に動的にパッケージを追加する話をします。

## 動的にパッケージを追加する

```php:index.php
<?php
$lightbox = array(
	'basePath' => 'webroot.lightbox',
	'baseUrl' => 'lightbox',
	'js' => array('js/lightbox.js'),
	'css' => array('css/lightbox.css'),
	'depends' => array('jquery'),
);

// パッケージを追加する
Yii::app()->clientScript->addPackage('lightbox', $lightbox);

// 追加したパッケージを登録する
Yii::app()->clientScript->registerPackage('lightbox');
```

CClientScript::addPackage() を使ってパッケージを追加します。このメソッドはYiiのバージョン1.1.9以降で使えるようになりました。それ以前だと以下のようになります。

```php:index.php
<?php
Yii::app()->clientScript->packages['lightbox'] = $lightbox;
```

これはYiiのバージョン1.1.7から利用できるものですが、これだとパッケージ追加以降の処理をメソッドチェーンで繋げられないですね。  
  
### CClientScript::addPackage($name, $definition) 

$name はパッケージ名です。$definition で basePath, baseUrl, js, css, depends などのオプションを指定します。$definitionの指定方法は上手く説明できないので [ここ](http://www.yiiframework.com/doc/api/1.1/CClientScript#packages-detail) を参考にしてみてください。

## パッケージを予め設定しておく

次に、パッケージを protected/config/main.php に設定しておくやり方です。アプリケーションコンポーネントなので 'components' 内に書きます。

```php:main.php
<?php
return array(
	...
	'components'=>array(
		...
		'clientScript' => array(
			'packages' => array(
				'lightbox' => array(
					'basePath' => 'webroot.lightbox',
					'baseUrl' => 'lightbox',
					'js' => array('js/lightbox.js'),
					'css' => array('css/lightbox.css'),
					'depends' => array('jquery'),
				),
			),
		),
		...
```

コードの雰囲気で書き方はわかるかと思います。あとはコントローラやビューなどで以下のように書くだけになります。1行でシンプルに書けるようになりましたね！

```php:index.php
<?php
Yii::app()->clientScript->registerPackage('lightbox');
```

また、パッケージの 'baseUrl' を指定しているので、以下のような感じでパッケージのベースurlを取得でき、CHtml::image や CHtml::link でもそれを利用できるようになります。これはYiiのバージョン1.1.8で実装されたものです。Yii::app()->baseUrl とかわざわざ書かなくていいし、 lightbox/ も省略できるようになりました！

```html+php:index.php
<?php $url = Yii::app()->clientScript->registerPackage('lightbox')->getPackageBaseUrl('lightbox'); ?>

<h1>CClientScript + Lightbox2</h1>

<?php $img = CHtml::image($url.'/images/examples/thumb-1.jpg'); ?>
<?php echo CHtml::link($img, $url.'/images/examples/image-1.jpg', array('rel' => 'lightbox')); ?>
```

## パッケージの依存

protected/config/main.php にパッケージを設定しておくやり方のときに 'depends' というオプションに array('jquery') と指定しましたが、これは lightbox パッケージを使うときは jquery パッケージも一緒に組み込むよって意味なんですが、この 'depends' を使えば、もう少し柔軟にパッケージを操ることができます。

```php:main.php
<?php
return array(
	...
	'components'=>array(
		...
		'clientScript' => array(
			'packages' => array(
				'lightb' => array(
					'basePath' => 'webroot.lightbox',
					'baseUrl' => 'lightbox',
					'js' => array('js/lightbox.js'),
				),
				'lightbo' => array(
					'baseUrl' => 'lightbox',
					'css' => array('css/lightbox.css'),
					'depends' => array('lightb'),
				),
				'lightbox' => array(
					'depends' => array('jquery', 'lightbo'),
				),
			),
		),
		...
```

```html+php:index.php
<?php $url = Yii::app()->clientScript->registerPackage('lightbox')->getPackageBaseUrl('lightb'); ?>

<h1>CClientScript + Lightbox2</h1>

<?php $img = CHtml::image($url.'/images/examples/thumb-1.jpg'); ?>
<?php echo CHtml::link($img, $url.'/images/examples/image-1.jpg', array('rel' => 'lightbox')); ?>
```

lightboxでやるとかなり強引な感じもしますが、ベースのパッケージを作って(上記の場合はlightb)、それに依存した新しいパッケージを作って(lightbo)、またそれに依存したパッケージを作る(lightbox)、という感じです。例えばベースのパッケージを普段のページで利用し、それに依存したパッケージを特定のページで利用したいときなんかに便利かなと思います。

## 最後に

今回の記事では主に CClientScript を使ってJavaScript, CSSの組み込み方や、パッケージの作り方と、その利用方法などについて書きました。本当は CClientScript と一緒に CAssetManager というものを絡めて書かないといけないのですが、自分もまだよくわかっていないのと、記事をシンプルに書きたいなと思ったのとで、あえて触れていません。ので、そこらへんも知りたいなって方は以下のリンクなども参考にしてみてください。日本語ブログの記事もいくつかあって自分も勉強になりました！

## 参考リンク

* [Yii API: CClientScript](http://www.yiiframework.com/doc/api/1.1/CClientScript)
* [Yii API: CAssetManager](http://www.yiiframework.com/doc/api/1.1/CAssetManager)
* [Yii Wiki: Javascript and AJAX with Yii](http://www.yiiframework.com/wiki/394/javascript-and-ajax-with-yii/)
* [Yii Wiki: Understanding "Assets"](http://www.yiiframework.com/wiki/148/understanding-assets/)
* [Adventures in Programming: Using Packages with the clientScript Component](http://danaluther.blogspot.jp/2012/03/using-packages-with-clientscript.html)
* [Yii JavaScriptソース、ファイルの組み込みについて | MT Systems](http://web.mt-systems.jp/archives/421)
* [RadioAgeCom:Yiiのassetsの仕組み](http://radio-age.com/dev/yii/yii-assets.html)
* [ユニークビジョン技術ブログ: Yiiフレームワークのテーマとレイアウト機能](http://blog.uniquevision.co.jp/2012/11/yii.html)