Cakephp3でPluginとThemeをつかってモバイルとPCのリソースやテンプレートを分ける

綺麗にわけられます。綺麗だね。

Cakephp3とmobiledetectのバージョンはこれです。

```composer.json
"cakephp/cakephp": "~3.2",
"mobiledetect/mobiledetectlib": "2.*",
```

## モバイルかどうかの分岐のライブラリ

Cakephp3では、Mobile Detectを標準で利用するようになっていて、すぐに使えるようになっている。
Mobile Detectの本体は、Packagistでここにあって、これが本体。
[mobiledetect/mobiledetectlib](https://packagist.org/packages/mobiledetect/mobiledetectlib)

githubでソースコードがあるこちら。
[serbanghita/Mobile-Detect](https://github.com/serbanghita/Mobile-Detect)

このMobile Detectは、cakephpのアプリではbootstrap.phpで既に読み込まれてあります。

```config/bootstrap.php
/**
 * Setup detectors for mobile and tablet.
 */
Request::addDetector('mobile', function ($request) {
    $detector = new \Detection\MobileDetect();
    return $detector->isMobile();
});
Request::addDetector('tablet', function ($request) {
    $detector = new \Detection\MobileDetect();
    return $detector->isTablet();
});
```

``Request::addDetector``ちゅうのは、Controllerの中で触れる``$this->request->is('XXXXX')``を動かすための宣言です。
Controllerの中での利用方法は、こんな感じ。

```
if ($this->request->is('mobile')) {
    if ($this->request->is('tablet')) {
        debug("タブレットです");
    } else {
        debug("タブレットじゃないモバイルです");
    }
} else {
	debug("PCです");
}
```
タブレットはモバイルの一部であるってところには気をつけてください。

## プラグインThemeってものは、Controller内でtemplateの切り替えができる

Cakephp3にデフォルトで入っているプラグインであるところの「テーマプラグイン」を利用してテンプレートの切り替えをします。

参考：[テーマ｜CakePHP 3.2 Red Velvet Cookbook](http://book.cakephp.org/3.0/ja/views/themes.html)

こんな風にアプリのsrcの中にテンプレートが宣言されているとして、

```
src/Template/
├── Common
├── Element
│   ├── Flash
│   │   ├── default.ctp
│   │   ├── error.ctp
│   │   └── success.ctp
│   ├── footer.ctp
│   └── header.ctp
├── Email
│   ├── html
│   │   └── default.ctp
│   └── text
│       └── default.ctp
├── Error
│   ├── error400.ctp
│   └── error500.ctp
└── Layout
    ├── Email
    │   ├── html
    │   │   └── default.ctp
    │   └── text
    │       └── default.ctp
    ├── ajax.ctp
    ├── default.ctp
    ├── error.ctp
    └── rss
        └── default.ctp

```


Mobileという名前のPluginに上書きするようにファイルを用意すると

```
plugins/Mobile/src/Template/
├── Element
│   ├── footer.ctp
│   └── header.ctp
└── Layout
    ├── default.ctp
    └── error.ctp
```

ControllerのbeforeRenderでこれを呼べば、テンプレートが呼び替えられplugin/Mobile/...側のテンプレートファイルを参照するようになります。モバイルの方にテンプレファイルがなかったらPCのほうが読まれます。

```
$this->viewBuilder()->theme('Mobile');
```



## では実際に切り替えの例を

いままでのを組み合わせると素敵にモバイルとPCのリソースを切り分けられます。

### モバイル用のテーマプラグインを用意

```
plugins/Mobile/src/Template/
├── Element
│   ├── footer.ctp
│   └── header.ctp
└── Layout
    ├── default.ctp
    └── error.ctp
```

```
plugins/Tablet/src/Template/
├── Element
│   ├── footer.ctp
│   └── header.ctp
└── Layout
    ├── default.ctp
    └── error.ctp
```

### モバイル用のテーマプラグインをロードする

テンプレート自体がロードされていないと動かないので、このようにロードしておいてください。

```generic/config/bootstrap.php
Plugin::load('Mobile');
Plugin::load('Tablet');
```

### AppControllerで、mobiledetectをつかって自動的にThemeを切り替え

```src/Controller/AppController.php
// 省略

class AppController extends Controller
{
	// 省略
	
    public function beforeRender(Event $event)
    {
        if ($this->request->is('mobile')) {
            if ($this->request->is('tablet')) {
                $this->viewBuilder()->theme('Tablet'); 
            } else {
                $this->viewBuilder()->theme('Mobile');
            }
        }
    }
}
```
テーマを指定しない場合は、applicationの``src/Template``がデフォルトです。

### モバイル用画像、JS、CSSなどの置き場所

プラグインテーマには、プラグインアセットってのがあって、
アプリと同じように、``plugin/プラグイン名``のディレクトリの下に、``webroot/``というディレクトリが置けます。

```
plugins/Mobile/webroot/
├── css
│   └── application.css
├── images
│   ├── close.png
│   ├── logo.png
│   ├── next.png
│   └── prev.png
└── js
    └── application.js
```

ほんでこのプラグインディレクトリのリソースへのリンクは、普通にこう ↓ 書くと、指定されたテーマ内にファイルがあるかチェックして、あったらプラグイン内のwebrootのパスを出力。なかったら通常のwebrootのパスを出力してくれるみたいです。

```
<?= $this->Html->script('application.js') ?>
```

ってやっておくと、パスを解釈してくれます。

```
<script src="/mobile/js/application.js"></script>
```

本体に同じ名前のもの``webroot/js/application.js``があっても、mobile側が優先されてパス展開されます。

一方で、mobileのplugin/webroot/js/application.jsにこのファイルがなかったら、/mobileを抜いてパス展開されます。

```
<script src="/js/application.js"></script>
```

「モバイル用だけロゴをちっちゃくして欲しいんだよね…。」とか言われた時のために、こんなふうに書いておけば、

```
<?= $this->Html->image('logo.png');?>
```

こんなふうに出力されます。

```
<img src="/mobile/img/logo.png"/>
```

でも画像はテンプレにimgタグで書いて起きたさ溢れますね。
コーダーの方々はHTMLでわたしてくれますし。
最初っからmobileのパスを付けて用意してもらうようにするのもいいかもしれません。

#### 最後に

あと、プラグインアセットのリンクのコマンドがcakeのコマンドに用意されていて、本番のパフォーマンスアップ用の設定なのですが、実稼働でもテストでも先に、以下のコマンドは開発中もやっといたほうが無難です。本番リリースの時にわすれないので。

```
bin/cake plugin assets symlink
```

実際はシンボリックリンクが張られます。

```
$ cd cakeapp
$ ls -l webroot/mobile 
lrwxr-xr-x  1 me  staff  46  5 31 12:17 webroot/mobile -> /var/www/cakeapp/plugins/Mobile/webroot
```

以上でした。

参考にしたドキュメント

http://book.cakephp.org/3.0/en/views/themes.html
http://book.cakephp.org/3.0/ja/plugins.html#id10
http://book.cakephp.org/3.0/ja/plugins.html#plugin-assets
http://book.cakephp.org/3.0/en/views/helpers/html.html#linking-to-images
http://book.cakephp.org/3.0/ja/deployment.html#symlink-assets

mobile detectとcakeのプラグイン
https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin