CakePHPでRails Tutorialをやってみる〜その３ レイアウトの作成〜

# はじめに

* [その１ Cloud9の設定](http://qiita.com/naoki85/items/f4bfabc941381ca5ff35)
* [その２ ほぼ静的なページの作成](http://qiita.com/naoki85/items/0b7e7ea106a1c661ed35)

前回の続きです。
今回は[Rails Tutorial](https://railstutorial.jp/)の4章と5章をやりたいと思います。
大部分省略していますが、ご了承ください。

また、CakePHPっぽくない、というご指摘ありましたらコメントいただけますと幸いです。
# ヘルパーの作成
[ヘルパー](https://book.cakephp.org/3.0/ja/views/helpers.html)
[前回](http://qiita.com/naoki85/items/0b7e7ea106a1c661ed35)作成した、タイトルタグの生成部分をヘルパーにします。
ヘルパーを作成する場合は、`src/View/Helper`の中にファイルを作成します。
`Util`というヘルパーはすでにCakePHPに存在するので、`MyUtilHelper`という名前で作成します。

**9/8 追記**
`$title`が渡されなかった場合を考慮していなかったので、渡されなかった場合はデフォルト文字列を入れるようにしました。
合わせてテストコードも作成しました。

```php:src/View/Helper/MyUtilHelper.php
<?php
namespace App\View\Helper;

use Cake\View\Helper;

/**
 * MyUtil Helper
 *
 * These methods are used with many files.
 */
class MyUtilHelper extends Helper
{
    /**
     * Return full title for the title tag. 
     * @param  [String]
     * @return [String]
     */
    public function fullTitle($title)
    {
        if (empty($title)) $title = 'Sample App';
        $base_title = "Ruby on Rails Tutorial Sample App";
        return "{$title} | {$base_title}";
    }
}
```
ヘルパーを作成したら、`src/View/AppView.php`に追記してロードさせる必要があります。
（ビューごとに読み込む場合は、テンプレートに記載しますが。）

```diff:src/View/AppView.php
public function initialize()
{
+   parent::initialize();
+   $this->loadHelper('MyUtil');
}
```
これでテンプレート側でも呼ぶことができるので、`default.ctp`を書き換えます。

```diff:src/Template/Layout/default.ctp
<title>
-   <?= "{$title} | Ruby on Rails Tutorial Sample App" ?>
+   <?= $this->MyUtil->fullTitle($title); ?>
</title>
```
テストコードも作成してみます。
ヘルパーのテストは`tests/TestCase/View/Helper`に作成します。

```php:tests/TestCase/View/Helper/MyUtilHelperTest.php
<?php
namespace App\Test\TestCase\View\Helper;

use App\View\Helper\MyUtilHelper;
use Cake\TestSuite\TestCase;
use Cake\View\View;

class MyUtilHelperTest extends TestCase
{
    public $helper = null;

    public function setUp()
    {
        parent::setUp();
        $View = new View();
        $this->helper = new MyUtilHelper($View);
    }
    
    public function testFullTitle()
    {
        $base_title = 'Ruby on Rails Tutorial Sample App';
        // $titleが渡されなかった場合、Sample Appが代わりに入る
        $title = '';
        $this->assertEquals("Sample App | {$base_title}", $this->helper->fullTitle($title));
        
        // $titleが渡された場合、その文字が入る
        $title = 'Home';
        $this->assertEquals("{$title} | {$base_title}", $this->helper->fullTitle($title));
    }
}
```

これで再度テストを実行し、GREENならOKです。
# レイアウトにBootstrapを入れる
[Rails Tutorial](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.0#sec-custom_css)では、スタイリングにBootstrapを使用しています。
CakePHPはデフォルトでCSSがあり、個人的にはそちらの色合いが好きなので、使おうと試みましたが、CSSで時間をとられそうなので、Bootstrapを導入することにしました。

導入に際し、下記の記事を参考にさせていただきました。
[CakePHP3でtwitter bootstrapを使う（導入編）](http://qiita.com/milano/items/f244f9ac5514f0e6b213)

また、カスタムCSSも[Rails Tutorial](https://railstutorial.jp/)のものをほぼそのまま使用させていただきました。
（一部、私の方で修正しております。ヘッダー色はどうしても気にいらなかったので、CakePHPの色合いを使用させていただきました。）
コードを全て載せると記事が冗長になってしまうので、Githubの差分をご参考ください。
[https://github.com/naoki85/cakephp_de_rails_tutorial/commit/de366d40e8e79e6ce206e170328e9b272bbd6575](https://github.com/naoki85/cakephp_de_rails_tutorial/commit/de366d40e8e79e6ce206e170328e9b272bbd6575)

下図のようになるかと思います。

![スクリーンショット 2017-08-31 14.40.53.png](https://qiita-image-store.s3.amazonaws.com/0/118817/e11ac61e-1387-ed33-0523-a2fc4e663715.png)

# エレメントで部分テンプレートを作成してみる
部分的に再利用可能なテンプレートを切り出して使用するための、エレメントを使用してみます。
まだ再利用するような箇所はないのですが、ヘッダーとフッターを切り出します。
[エレメント](https://book.cakephp.org/3.0/ja/views.html#view-elements)

エレメントは`src/Template/Element`に作成します。
すでに`Flash`用のエレメントが存在しているかと思います。
分かりやすいように、その中に`Layout`というディレクトリを作成して、その中に`header.ctp`と`footer.ctp`を作成したいと思います。

```php:src/Template/Element/Layout/header.ctp
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="container">
    <?= $this->Html->link("sample app",
        ['controller' => 'StaticPages', 'action' => 'home'],
        ['id' => "logo"]); ?>
    <nav>
      <ul class="nav navbar-nav navbar-right">
        <li><?= $this->Html->link("Home",
            ['controller' => 'StaticPages', 'action' => 'home']); ?></li>
        <li><?= $this->Html->link("Help",
            ['controller' => 'StaticPages', 'action' => 'help']); ?></li>
        <li><?= $this->Html->link("Log in", '#'); ?></li>
      </ul>
    </nav>
  </div>
</header>
```
```php:src/Template/Element/Layout/footer.ctp
<footer class="footer">
  <small>
    The <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
    by <a href="http://www.michaelhartl.com/">Michael Hartl</a>
  </small>
  <nav>
    <ul>
      <li><?= $this->Html->link("About",
              ['controller' => 'StaticPages', 'action' => 'about']); ?></li>
      <li><?= $this->Html->link("Contact",
              ['controller' => 'StaticPages', 'action' => 'contact']); ?></li>
      <li><a href="http://news.railstutorial.org/">News</a></li>
    </ul>
  </nav>
</footer>
```
合わせて、リンク先も修正しています。
（まだログインは作成していないので、`#`のままです。）
`routes.php`で登録しておくと、よしなにリンクタグを生成してくれるそうです。

CakePHPは名前付きルーティングはそんなに使用しないのでしょうか？
とりあえず、コントローラーとアクションを指定するよう記述しました。

作成したエレメントで`default.ctp`を差し替えます。

```diff:src/Template/Layout/default.ctp
<!-- ... -->

- <header class="navbar navbar-fixed-top navbar-inverse">
-   <div class="container">
-     <?= $this->Html->link("sample app", '#',['id' => "logo"]); ?>
-     <nav>
-       <ul class="nav navbar-nav navbar-right">
-         <li><?= $this->Html->link("Home",   '#'); ?></li>
-         <li><?= $this->Html->link("Help",   '#'); ?></li>
-         <li><?= $this->Html->link("Log in", '#'); ?></li>
-       </ul>
-     </nav>
-   </div>
- </header>
+ <?= $this->element('Layout/header'); ?>

<!-- ... -->

- <footer class="footer">
-   <small>
-     The <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
-     by <a href="http://www.michaelhartl.com/">Michael Hartl</a>
-   </small>
-   <nav>
-     <ul>
-       <li><?= $this->Html->link("About",   '#'); ?></li>
-       <li><?= $this->Html->link("Contact", '#'); ?></li>
-       <li><a href="http://news.railstutorial.org/">News</a></li>
-     </ul>
-   </nav>
- </footer>
+ <?= $this->element('Layout/footer'); ?>

<!-- ... -->
```
本当はここでレイアウトのテストをした方が良いのかもしれませんが、うまく`a`タグの数や属性を取得する方法が思いつかないので省略してしまいました。。。
# さいごに
次回は、ユーザーモデルを作成していきたいと思います。
次回：[その４ ユーザーのモデルを作成する](http://qiita.com/naoki85/items/29e8576b694a5bc89015)