空の eZ Platform にデザインを組み込む

[eZ Platform Demo](https://github.com/ezsystems/ezplatform-demo/) を参考に、空の eZ Platform にオリジナルのデザインテンプレートを追加する手順を解説します。

## eZ Platform のセットアップ
[eZ Platform 1.8.0 インストール手順](http://qiita.com/bezeklik/items/af89d55d95db7dc7db2b) を参考に eZ Platform をセットアップします。

## ファイル構成
eZ Publish 5.x では src 配下に新しくバンドルを作成する方法が標準でしたが、eZ Platform からは Symfony 2.x の手順を踏襲し、 app 配下にテンプレートファイルを作成する手順が標準となります。

主なディレクトリーとファイルの構成は以下の通りです。

```
<ezroot>
├── app/
│   ├── Resources/
│   │   ├── translations/
│   │   │   └── messages.en.xlf
│   │   └── views/
│   │       ├── full/
│   │       │   ├── article.html.twig
│   │       │   └── home.html.twig
│   │       ├── layout/
│   │       │   ├── footer.html.twig
│   │       │   └── header.html.twig
│   │       └── pagelayout.html.twig
│   └── config/
│       ├── ezplatform.yml
│       └── views.yml
├── src/
│   └── AppBundle/
│       └── Controller
└── web/
    └── assets/
        ├── css/
        ├── fonts/
        ├── images/
        └── js/
```

### ディレクトリーの作成
```bash
mkdir -p app/Resources/{translations,views/{full,layout,user}}
mkdir -p web/assets/{css,fonts,images,js}
```

## コンテンツタイプの作成

初期インストールではコンテンツタイプが Article と Folder しかなく、トップページのコンテンツタイプが Folder になっている。
そのままでは柔軟性が低いので、[Create a frontpage content type](https://jira.ez.no/browse/COM-19888) を参考にトップページ専用の Frontpage コンテンツタイプを作成し、コンテンツアイテムを作成後にノードを差し替える。

### Frontpage コンテンツタイプの作成
Admin パネル > コンテンツタイプ > コンテンツタイプの作成 または /ez#/admin/pjax%2Fcontenttype%2Fgroup%2F1 へアクセスしてコンテンツタイプの作成画面から実施する。

#### コンテンツタイプ

| 項目               | 設定例 | 備考 |
|------------------:|:--|:--|
|名前                |Frontpage   |   |
|識別子              |frontpage   |   |
|説明文              |トップページ専用コンテンツタイプ   |   |
|コンテンツ名パターン   |&lt;title&gt;   |   |
|URLエイリアス名パターン|   |   |

#### フィールド
例では Title と Body だけですが、キービジュアルやサイト情報など必要に応じて項目を追加するといいでしょう。
##### Title
| 項目名 | 設定例 |
|--:|:--|
| フィールドタイプ  | Text Line (ezstring)  |
| Position  | 1  |
| 名前 | Title  |
| 識別子  | title  |
| 説明文  |   |
| 必須  | <i class="fa fa-check-square" aria-hidden="true"></i>  |
| 検索対象  | <i class="fa fa-check-square" aria-hidden="true"></i>  |
| 翻訳対象  | <i class="fa fa-check-square" aria-hidden="true"></i>  |
| カテゴリー  | Content  |
| 最小文字数  |   |
| 最大文字数  |   |
| デフォルト値  |   |

##### Body
| 項目名 | 設定例 |
|--:|:--|
| フィールドタイプ  | Rich Text (ezrichtext)  |
| Position  | 2  |
| 名前 | Body  |
| 識別子  | body  |
| 説明文  |   |
| 必須  | <i class="fa fa-square-o" aria-hidden="true"></i>  |
| 検索対象  | <i class="fa fa-check-square" aria-hidden="true"></i>  |
| 翻訳対象  | <i class="fa fa-check-square" aria-hidden="true"></i>  |
| カテゴリー  | Content  |
| エディター表示行数  | 10  |


## 設定ファイルの作成
### imports
views.yml を import する

```
sed -i "1iimports:\n    - { resource: views.yml }" app/config/ezplatform.yml
```

### テンプレート設定
```yaml:app/config/views.yml
ezpublish:
    system:
        default:
            pagelayout: pagelayout.html.twig
            content_view:
                full:
                    home:
                        template: full\home.html.twig
                        match:
                            Identifier\ContentType: [frontpage]
                    article:
                        template: full\article.html.twig
                        match:
                            Identifier\ContentType: [article]
```
### レイアウトファイルの作成
```jinja:app/Resources/views/pagelayout.html.twig
<!DOCTYPE html>
<html lang="{{ app.request.locale|replace('_', '-') }}">
<head>
<meta charset="utf-8">
{% if content is defined and title is not defined %}
{% set title = ez_content_name(content) %}
{% endif %}
{% block page_head %}
<title>{{ title }}</title>
{% endblock %}
<link rel="Shortcut icon" href="{{ asset('assets/images/favicon.ico') }}" type="image/x-icon" />
</head>
<body>
{% block header %}
{{ render_esi(controller('app.controller.menu:getChildNodesAction', { template: 'layout/header.html.twig' })) }}
{% endblock %}

{% block content %}{% endblock %}

{% block footer %}{% include 'layout/footer.html.twig' %}{% endblock %}
</body>
</html>
```

```jinja:app/Resources/views/layout/header.html.twig
  <header>
    <nav>
      <ul>
{% if menuItems is defined and menuItems is not empty %}
{% for item in menuItems %}
        <li><a href="{{ path(item) }}">{{ ez_content_name(item.contentInfo) }}</a></li>
{% endfor %}
{% endif %}
      </ul>
    </nav>
  </header>
```
```html:app/Resources/views/layout/footer.html.twig
  <footer>
  </footer>
```
```jinja:app/Resources/views/full/home_page.html.twig
{% block content %}
{% endblock %}
```
```jinja:app/Resources/views/full/article.html.twig
{% block content %}
{% endblock %}
```
```php:src/AppBundle/Controller/MenuController.php
<?php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\TwigBundle\TwigEngine;
use eZ\Publish\API\Repository\SearchService;
use AppBundle\QueryType\MenuQueryType;

class MenuController
{
    protected $templating;
    protected $searchService;
    protected $menuQueryType;
    protected $topMenuLocationId;

    public function __construct(TwigEngine $templating, SearchService $searchService, MenuQueryType $menuQueryType, $topMenuLocationId) {
        $this->templating = $templating;
        $this->searchService = $searchService;
        $this->menuQueryType = $menuQueryType;
        $this->topMenuLocationId = $topMenuLocationId;
    }

    public function getChildNodesAction($template) {
        $locationSearchResults = $this->searchService->findLocations($this->menuQueryType->getQuery());
        $menuItems = [];
        foreach ($locationSearchResults->searchHits as $hit) {
            $menuItems[] = $hit->valueObject;
        }
        return $this->templating->renderResponse($template, ['menuItems' => $menuItems], new Response());
    }
}
```