CakePHP2.7にBootstrap3をLessで導入してみた

※この記事自体ははてなブログの過去記事（2015年）から移転しました。内容古めなのでご注意ください。

# 背景

n番煎じで、今からやるならCakePHP3系の方が良いことは重々承知の上で、
現時点で情報が多いCakePHP2系にBootstrap3をLessで導入するため、色んなPluginを導入してみました。
出来る限り手動で構築しています。

ちなみに、Bootstrapも4が出るので、実はそっちの方が良いかもしれません。


# 基本構成

- CakePHP2.7.3
- CakePHPプラグイン
    - cakephp/debug_kit 2.2
    - Hyra/less 1.0
    - leafo/lessphp v0.5.0
    - oyejorge/less.php 1.7.0.5
- フレームワーク
    - Bootstrap  v3.3.5
    - JQuery  1.11.3
    - Simple Sidebar 1.0.4
    - html5shiv.js
    - respond.js
- 開発環境
    - Windows 8.1
    - Xampp 5.6.11

# CakePHP初期セットアップ

ひとまず、下記のURLからDLして解凍。Xamppのhtdocs配下に格納する。

[https://github.com/cakephp/cakephp/releases/tag/2.7.3:embed:cite]

とりあえずブラウザからアクセスすると、CakePHPの画面が出ます。
いくつかエラーが出ているのでこれをpassするように設定していきます。
やることは3点。

- core.phpのSecurity.saltとSecurity.cipherSeedを作成し、書き換える
- MySQLなどに新しいDBとログイン用アカウントを作成する
- database.php.defaultをdatabase.phpにリネームし、データベース接続情報を記載する


ネット上に分かりやすいサイトがこれでもかとあるので、参考サイトを挙げておきます。



[http://qiita.com/nvtomo1029/items/3eec132248c86d93b24f:embed:cite]

[http://blog.shiten.info/2013/03/cakephp-security-salt-%E3%81%A8-security-cipherseed-%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B.html:title]


個人的な感覚ですが、Security.saltとSecurity.cipherSeedは数文字変えるだけでなく、ちゃんとローカル環境で生成したものを使った方が良いような気がします。Web上で生成ツールもあるのですが、セキュリティを担保するなら他人が作ったものは使わないのが吉かも。もし元々の値を少し変更したもののリストや、Webサイトで生成したもののリストを使って総当たりされたら怖いような。…まぁ、こだわりすぎなんですが、別に難しくもないのでローカルで生成することをオススメします。


## DebugKit導入

DebugkitはCakePHP2.2向けのものを使う。Trunkは3系になっているため、使えないので注意。

[https://github.com/cakephp/debug_kit/tree/2.2:embed:cite]

zipで落としてきて、解凍し、DebugKitにフォルダをリネームし、app/Plugin/配下に配置します。
そして、app/Config/bootstrap.phpに下記1行を追記し、呼び出します。

```php
CakePlugin::load('DebugKit');
```

さらに、app/Controller/AppController.phpにあるAppControllerクラスで、DebugKitを読み込みます。
DebugKit.Toolbar以外にも読み込むcomponentsがあれば、そこに追記してください((AuthとかCookieとか))。

```php
class AppController extends Controller {
  public $components = array(
    'DebugKit.Toolbar'
  );
}
```



ここまでで、CakePHPの準備は完了です。


# LESSの導入

LESSを導入するにはいくつか方法があります。

- less.jsを使う
- デプロイ前にコンパイルしてから組み込む
- CakePHP pluginを使う


less.jsを使うと、毎回ブラウザ上でコンパイルすることになります。サーバー側の負荷は減りますが、クライアント側で負荷がかかります。Bootstrap3だとコンパイルに1秒以上かかることもあるので、あまりオススメではありません。

デプロイ前にコンパイルして使うのは最善の手段ですが、デプロイ時に毎回LESSの変更がないか気にしなければならず、個人や小規模のプロジェクトで回すのは面倒です。

CakePHP pluginを使うと、サーバー側でコンパイルすることになります。コンパイルには負荷が伴いますが、キャッシュを持つことが出来るのである程度軽減が出来ます。

[前回の記事](http://inspez.hateblo.jp/entry/2015/08/30/185214)でless.jsを使ったコンパイルは扱いましたので、今回はCakePHP pluginを使っていきます。


今回はHyra/lessを使います。Hyra/lessはleafo/lessphpのv0.3.8を使用しています。
まだ互換性調査が済んでいないのですが、とりあえずleafo/lessphp v0.5.0を使っていきます。


[https://github.com/Hyra/less:embed:cite]

[https://github.com/leafo/lessphp:embed:cite]

Hyra/lessとleafo/lessphpをZipで落とし、下記のフォルダ構成にします((関係ないものは端折ってます))。


```
CakePHP (ここがroot)
└ app
    └ Plugin
        └ Less（ここにHyra/lessを置く）
            └ Vendor
                └ lessphp（ここにleafo/lessphpを置く）

```

DebugKitと同じように、CakePHPのapp/Config/bootstrap.phpに下記1行を追記します。

```php
CakePlugin::load('Less');
```

さらに、app/Controller/AppController.phpにあるAppControllerクラスで、Lessヘルパーを読み込みます。



```php
class AppController extends Controller {
  public $components = array(
    'DebugKit.Toolbar'
  );
  public $helpers = array(
    'Less.Less'
  );
}
```

この時点でCakePHPをブラウザで見ると、下記のエラーが出ます。

```
Declaration of lessify::parse() should be compatible with lessc::parse($str = NULL, $initialVariables = NULL) [APP\Plugin\Less\Vendor\lessphp\lessify.inc.php, line 361]
```

これは、下記のようにプルリされています。ただ、v0.5.0では反映されていません。該当部分は2010年のコミットで止まっているようです。

[https://github.com/leafo/lessphp/pull/351:embed:cite]

ひとまず、第2引数を加えて先に進みます((コードも追ったのですが、加えて問題無さそうです。))。


最後に下記のlessフォルダを作成します。

```
CakePHP (ここがroot)
└ app
    ├ webroot
    │   └ less（ここにlessを置いていく）
    └ tmp
         └ cache
             └ less（ここにlessのキャッシュが格納される）

```

# Bootstrap3を導入する

まず、[前回の記事](http://inspez.hateblo.jp/entry/2015/08/30/185214)で作ったサイドバーのページを表示してみましょう。

手順は下記です。

- 初期表示ページの設定（app/Config/routes.php）
- Controllerの作成（app/Controller/SimpleSidebarController.php）
- Viewの作成
    - Layoutsの編集（app/View/Layouts/default.ctp）
    - 個別Viewの作成（app/Controller/SimpleSidebarController.php）
- Bootstrap3の配置


## 初期表示ページの設定

app/Config/routes.phpのRouterを下記のように変更し、SimpleSidebarのindexを初期表示させます。

```php
Router::connect('/', array('controller' => 'SimpleSidebar', 'action' => 'index'));
```


## Controllerの作成

app/Controller/SimpleSidebarController.phpを作成し、下記を記入します。


```php

<?php
App::uses('AppController', 'Controller');
class SimpleSidebarController extends AppController {
  public function index() {

  }
}

```

## Viewの作成

app/View/Layouts/default.ctpを下記に置換します。

```php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>test</title>
	<?php //bootstrap.lessを呼び出す。bootstrap.jsは遅延読み込みさせるために</body>直前に記載する ?>
  <?php echo $this->Less->css('bootstrap/bootstrap'); ?>

</head>
<body>

<?php //Viewファイルを呼び出します。 ?>
<?php echo $content_for_layout ?>

<!-- Javascriptは可能な限り遅延読み込みさせて、Javascriptを読み込む前にページが表示されるようにする -->
<?php echo $this->Html->script('jquery-1.11.3.min'); ?> <? //bootstrapはJQuery依存 ?>
<?php echo $this->Html->script('bootstrap.min'); ?>

<?php // ここから以下はIE9以下のバージョン用の設定。HTML5を認識させるために必要 ?>
<!--[if lt IE 9]>
  <script src="js/html5shiv/3.7.2/html5shiv.min.js"></script>
  <script src="js/respond/1.4.2/respond.min.js"></script>
<![endif]-->

<?php //サイドバー表示を切り替えるのに使用。必ずJQueryの後に記載すること ?>
<script>
$("#menu-toggle").click(function(e) {
    e.preventDefault();
    $("#wrapper").toggleClass("toggled");
});
</script>

</body>
</html>

```

app/View/SimpleSidebar/index.ctpを作成し、[前回の記事](http://inspez.hateblo.jp/entry/2015/08/30/185214)の<body>～</body>部分を記入します。


## Bootstrap3の配置

Bootstrap3のLESSを配置します。
下記ページから、Source codeをダウンロードし、bootstrap-3.3.5.zip/bootstrap-3.3.5/less内のファイルを全てapp/webroot/lessに配置します。
この時、bootstrapというフォルダを作成し、他のLESSと分けておくと便利です。その場合はapp/webroot/less/bootstrapに配置します。

[http://getbootstrap.com/getting-started/#download:embed:cite]

さらに、app/webroot/jsにjquery-1.11.3.min.jsとbootstrap.min.jsを配置します。
bootstrap.min.jsは先ほどダウンロードしたbootstrap-3.3.5.zip/bootstrap-3.3.5/dist/js内に、
jquery-1.11.3.min.jsは下記のサイトからダウンロードしてきます。

[https://jquery.com/:embed:cite]


どうせなので、html5shiv.jsとrespond.jsもapp/webroot/jsに配置しておきましょう。


[https://github.com/aFarkas/html5shiv:embed:cite]

[https://github.com/scottjehl/Respond:embed:cite]





# parse error対策でoyejorge/less.phpを導入

この時点でparse errorが出るようになります。


parse error: failed at `&:extend(.clearfix all);` 


結論から言うと、oyejorge/less.phpを使えば解決します。

[https://github.com/oyejorge/less.php#transitioning-from-leafolessphp:embed:cite]


上記のページの「Download the less.php source code」からless.php-master.zipをダウンロードし、
app/Plugin/Less/Vendor/lessphpにless.php-master.zip内からbin、libのフォルダを配置し、lessc.inc.phpを上書きします。


ただ、この辺り色々と話があるようで、どうもoyejorge/less.phpは遅いとか、leafo/lessphpはBootstrap3をサポートする気ないとか、
OSSっぽい議論が交わされているようです。


[https://github.com/leafo/lessphp/issues/520:embed:cite]

[https://github.com/leafo/lessphp/issues/543:embed:cite]


# 動作テスト

ここまで来れば、Bootstrap3が動くようになります。


## LESSの書き換えテスト

[前回の記事](http://inspez.hateblo.jp/entry/2015/08/30/185214)のSimple SidebarもLESS化してBootstrap.lessでimportしてみましょう。
ダウンロードしてきたsimple-sidebar.cssをリネームしてsimple-sidebar.lessに変え、bootstrap.lessの最下部に下記を追記するだけです。

```
// 外部ライブラリ
@import "simple-sidebar.less";
```

[http://startbootstrap.com/template-overviews/simple-sidebar/:embed:cite]

importした後にアクセスすると、コンパイルする時間分、レスポンスが遅くなります。
2回目以降のアクセスはキャッシュを使用しているため、この時間はほぼなくなります。

手元の環境でTTFBがキャッシュ有りで114ms、キャッシュ無しで1560ms、LESS無しで108msです。
確かにキャッシュが無い場合、結構時間がかかってしまっていますが、キャッシュが効いている限り、特に問題はなさそうです。
msのレベルで勝負し始めるなら、ちゃんとデプロイ前にコンパイルすべきですし、小規模のプロジェクトなら導入にすら気が付かないレベルかと思います。