Twigで作るテンプレート兼モックアップ

# 概要
- Q. モックアップHTMLはモックとしての機能を維持したまま、テンプレートとして動的ページを生成出来るのか？
- A. 出来る　出来るのだ　そう、Twigならね
- 用意するもの：[Laravel 5.8](https://readouble.com/laravel/5.8/ja/)と [rcrowe/TwigBridge 0.11.0](https://github.com/rcrowe/TwigBridge/blob/master/README.md)を組み合わせてTwigを表示できる環境と知識

# HTMLファイルをTwig処理する設定

Twigテンプレートエンジンで処理する拡張子は通常だと`twig`だが、変更できる。

```php:/foo/config/twigbridge.php
        // 'extension' => 'twig',
        'extension' => 'twig.html',
```

# モックアップ

（比較用。読み飛ばしてOK）

- 適当に `php artisan make:controller` してビューを指定
- `/routes/web.php` でルーティングを指定
- ビューファイルを作成 `/foo/resources/views/student/detail.twig.html`

```php:/foo/app/Http/Controllers/StudentDetail.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Student;

class StudentDetail extends Controller
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function __invoke(int $id)
    {
        $st = [];
        return view('student/detail', ['student' => $st]);
    }
}

```

```twig:/foo/resources/views/student/detail.twig.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel</title>
    </head>
    <body>
        <p>home URL</p>
        <p>current URL</p>
        <table border="1">
            <tr>
                <th>ID</th>
                <td>12345</td>
            </tr>
            <tr>
                <th>Name名前</th>
                <td>田中　太郎</td>
            </tr>
            <tr>
                <th>Birthday誕生日</th>
                <td>2001/01/30</td>
            </tr>
        </table>
    </body>
</html>
```

はい、モック　一丁！
![スクリーンショット 2019-03-25 2.40.38.png](https://qiita-image-store.s3.amazonaws.com/0/368897/cba42b16-0902-d0d4-954e-77e37b442734.png)


# 標準的なTwigテンプレート

（比較用。読み飛ばしてOK）

標準的なTwigテンプレートの文法で、上記のモックアップを動的ページに書き換えた例。

```twig:/foo/resources/views/student/detail-1.twig.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
    </head>
    <body>
        <p>{{ url('/home') }}</p>
        <p>{{ url().current() }}</p>
        <table border="1">
            <tr>
                <th>ID</th>
                <td>{{ student.id }}</td>
            </tr>
            <tr>
                <th>Name名前</th>
                <td>{{ student.name }}</td>
            </tr>
            <tr>
                <th>Birthday誕生日</th>
                <td>{{ student.birthday|date("Y/m/d") }}</td>
            </tr>
        </table>
    </body>
</html>

```

```php:/foo/app/Http/Controllers/StudentDetail.php
    public function __invoke(int $id)
    {
        $st = ['id' = 2, 'name' => '田中', 'birthday' => '2000-01-01'];
        // Eloquent使ってDBから取得しても、ええんやで
        // $st = Student::findOrFail($id);
        return view('student/detail-1', ['student' => $st]);
    }
```

はい、動的ページ　一丁！
![スクリーンショット 2019-03-25 2.57.55.png](https://qiita-image-store.s3.amazonaws.com/0/368897/cfa6f37b-3e9a-e9d7-a458-c90f63ffab43.png)

# テンプレート兼モックアップ

- 要するに（１）HTMLコメントでTwigを制御して（２）TwigコメントをHTML出力すればいい
- [Twig Lexerを変更]( https://twig.symfony.com/doc/2.x/recipes.html#customizing-the-syntax)すれば可能

```php:/foo/app/Http/Controllers/StudentDetail.php

    public function __invoke(int $id)
    {
        $st = Student::findOrFail($id);

        $twig = \Twig::getFacadeApplication()->get('twig');
        $lexer = new \Twig\Lexer($twig, [
            // 本来のdelimiter
            // 'tag_comment'   => ['{#', '#}'],
            // 'tag_block'     => ['{%', '%}'],
            // 'tag_variable'  => ['{{', '}}'],
            // 'interpolation' => ['#{', '}'],
            // 変更したdelimiter
            'tag_comment'   => ['<!-- {# -->', '<!-- #} -->'],
            'tag_block'     => ['<!-- {%', '%} -->'],
            'tag_variable'  => ['<!-- {{', '}} -->'],
            'interpolation' => ['<!-- #{', '} -->'],
        ]);
        $twig->setLexer($lexer);

        return view('student/detail-2', ['student' => $st]);
    }
```

```twig:/foo/resources/views/student/detail-2.twig.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
    </head>
    <body>
        <p><!-- {# -->home URL<!-- #} --><!-- {{ url('/home') }} --></p>
        <p><!-- {# -->current URL<!-- #} --><!-- {{ url().current() }} --></p>
        <table border="1">
            <tr>
                <th>ID</th>
                <td><!-- {# -->12345<!-- #} --><!-- {{ student.id }} --></td>
            </tr>
            <tr>
                <th>Name名前</th>
                <td><!-- {# -->田中　太郎<!-- #} --><!-- {{ student.name }} --></td>
            </tr>
            <tr>
                <th>Birthday誕生日</th>
                <td><!-- {# -->2001/01/30<!-- #} --><!-- {{ student.birthday|date("Y/m/d") }} --></td>
            </tr>
        </table>
    </body>
</html>

```

テンプレートエンジンを通さない場合、[モックアップ](#モックアップ)と同様に見える。
![スクリーンショット 2019-03-25 3.06.39.png](https://qiita-image-store.s3.amazonaws.com/0/368897/4767230e-0bb5-5590-c836-ef4abd4888f8.png)

テンプレートエンジンを通した場合、[標準的なTwig](#標準的なtwigテンプレート)の出力と同様に見える。
![スクリーンショット 2019-03-25 3.03.17.png](https://qiita-image-store.s3.amazonaws.com/0/368897/e88496b4-0e26-0f0d-1a92-6b8d87d99cbc.png)


# 注意

__Lexerを変更した後は `php artisan twig:clean` で[キャッシュを削除](php artisan twig:clean)すること。__
　Twigはテンプレートファイルにアクセスした時に、phpキャッシュを作成してHTMLレンダリングに使用する。テンプレートファイルが変更されていたらphpキャッシュを作り直してレンダリングする。
　上述の方法でLexerを変更しても、キャッシュは再生成されず、Lexerが変更されていない状態のキャッシュでHTMLレンダリングが行われるので、Lexerを何回変更しても変更が反映されない、ように見える。

# 雑感
Twig is神

Hope this helps.