eZ Publish 5.4 デザインバンドル作成手順

## 概要
[Beginner Tutorial](https://doc.ez.no/display/TECHDOC/Beginner+Tutorial) を簡略化して日本語訳したものになります。eZ Publish 5.4 に合わせています。eZ Platform ではパスや記述が変更になっている箇所があるのでご注意ください。

## Part 1: Step 1 eZ Publish のセットアップ
「[eZ Publish 5.4 インストールガイド](http://qiita.com/bezeklik/items/95cf590a267d3c848185)」などを参考に eZ Publish 5.4 をセットアップしてください。

## Part 1: Step 2 コンテンツモデルの作成
### コンテンツタイプ（クラス）の作成
#### Point of interest コンテンツタイプ
**名前**: Point of interest
**識別子**: point_of_interest
**オブジェクトの名前生成パターン**: `<name>`

| 名前        | 識別子      | 属性                     | 備考 |
|-------------|-------------|--------------------------|------|
| Name        | name        | テキスト                 |      |
| Description | description | XMLブロック              |      |
| Image       | Image       | 画像                     |      |
| Legend      | legend      | XMLブロック              |      |
| Place       | place       | Googleマップロケーション |      |

#### Ride コンテンツタイプ
**名前**: Ride
**識別子**: ride
**オブジェクトの名前生成パターン**: `<name>`

| 名前               | 識別子             | 属性                     | 備考                                                                              |
|--------------------|--------------------|--------------------------|-----------------------------------------------------------------------------------|
| Name               | name               | テキスト                 |                                                                                   |
| Image              | image              | 画像                     |                                                                                   |
| Description        | description        | XMLブロック              |                                                                                   |
| Difficulty level   | level              | 選択リスト               | オプション：beginner, intermediate, advanced                                      |
| Starting point     | starting_point     | Googleマップロケーション |                                                                                   |
| Ending point       | ending_point       | Googleマップロケーション |                                                                                   |
| Length             | length             | 整数                     |                                                                                   |
| Author             | author             | 作成者                   |                                                                                   |
| Points of interest | points_of_interest | 関連オブジェクト（複数） | セクションメソッド：チェックボックスのリスト、許可されたクラス：Point of interest |

### コンテンツツリーの投入（コンテンツ（オブジェクト）の作成）
コンテンツツリーに戻り、新規作成ボタンで 2 つの Folder を作成する。1つは Points of interest を、もう1つは Rides を作成する。
それぞれのフォルダーに Point of interest コンテンツと、それを関連オブジェクトで指定した Ride コンテンツをそれぞれ1件以上作成する。


## Part 2: Step 1 最初のテンプレートのカスタマイズ：ページレイアウト

### バンドルの作成 *
以下のコマンドを実行してバンドルを作成する。`php ezpublish/console g:b` と省略することもできる。

```bash
cd /opt/rh/httpd24/root/var/www/ezpublish5
php ezpublish/console generate:bundle --namespace=Ez/TutorialBikeBundle --bundle-name=EzTutorialBikeBundle --dir=/opt/rh/httpd24/root/var/www/ezpublish5/src --format=yml --no-interaction
```
### Assetic バンドルへの追加 *
```bash
cd /opt/rh/httpd24/root/var/www/ezpublish5
sed -i 's/eZDemoBundle/eZDemoBundle, EzTutorialBikeBundle/' ezpublish/config/config.yml
ln -s ../../src/Ez/TutorialBikeBundle/Resources/public/ web/bundles/eztutorialbike
```

### 独自のページレイアウトの作成
```bash:pagelayout.html.twig
yum install vim rh-php56-php-pecl-xdebug
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/pagelayout.html.twig
<!DOCTYPE html>
<!--[if lt IE 9 ]><html class="unsupported-ie ie" lang="{{ app.request.locale }}"><![endif]-->
<!--[if IE 9 ]><html class="ie ie9" lang="{{ app.request.locale }}"><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--><html lang="{{ app.request.locale }}"><!--<![endif]-->
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
 
    {% block page_head %}
        {% include 'EzTutorialBikeBundle::page_head.html.twig' %}
    {% endblock %}
    {% include 'EzTutorialBikeBundle::page_head_style.html.twig' %}
    {% include 'EzTutorialBikeBundle::page_head_script.html.twig' %}
</head>
 
<body>
<!-- Navigation -->
<nav class="navbar navbar-default navbar-fixed-top" id="total-navbar">
    {% block navbar %}
        {% include 'EzTutorialBikeBundle::page_topmenu.html.twig' %}
    {% endblock %}
</nav>
 
<!-- Header start -->
{% block header %}{% endblock %}
<!-- Header end -->
 
<section class="buttons">
    <div class="container">
        {% block content %}{% endblock %}
    </div>
</section>
 
<!-- Footer -->
{% block footer %}
    {% include 'EzTutorialBikeBundle::page_footer.html.twig' %}
{% endblock %}
 
<!-- Footer script area: START -->
{% block footerScript %}
    {#% include 'EzTutorialBikeBundle::page_footer_script.html.twig' %#}
{% endblock %}
<!-- Footer script area: END -->
 
</body>
</html>
_EOF_
```
### 独自の CSS と JavaScript の使用
```bash:page_head_style.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/page_head_style.html.twig
{% stylesheets
    '@EzTutorialBikeBundle/Resources/public/css/bootstrap.min.css'
    '@EzTutorialBikeBundle/Resources/public/css/bootstrap-theme.css'
    '@EzTutorialBikeBundle/Resources/public/css/style.css'
    '@EzTutorialBikeBundle/Resources/public/css/normalize.css'
%}
<link rel="stylesheet" type="text/css" href="{{ asset_url }}"/>
{% endstylesheets %}
 
<!-- External CSS -->
<style type="text/css">
    @import url("//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css");
</style>
_EOF_
```
```bash:page_head_script.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/page_head_script.html.twig
{% javascripts
    '@EzTutorialBikeBundle/Resources/public/js/jquery.min.js'
    '@EzTutorialBikeBundle/Resources/public/js/bootstrap.min.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
_EOF_
```

#### CSS/JavaScript/画像ファイルの配置
```bash
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle/Resources/public
curl -LO https://github.com/ezsystems/ezsc2015-beginner-tutorial/raw/master/assets.zip
yum -y install unzip
unzip assets.zip && rm -f assets.zip
```

### ページレイアウトのサブテンプレートの作成
```bash:page_head.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/page_head.html.twig
<header class="below-navbar">
    <div class="container">
        <div class="row" id="banner">
            <div class="col-xs-12">
                <div class="banner-header-block">
                    <img src="{{ asset( "bundles/eztutorialbike/images/logo_just_letters.png" ) }}" style="width: 100%;">
                    <h3 class="banner-header">{{ "Discover new rides! Go Bike!" | trans }}</h3>
                </div>
            </div>
        </div>
    </div>
</header>
_EOF_
```

```bash:page_footer.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/page_footer.html.twig
<footer class="text-center">
    <div class="footer-color-one">
        <div class="container">
            <div class="col-xs-10 col-xs-offset-1 text-center" id="intouch">
            </div>
        </div>
    </div>
    <div class="footer-color-two">
        <div class="container">
            <div class="row regular-content-size">
                <div class="col-xs-8 col-xs-offset-2 footer-links-block">
                    <ul class="list-inline footer-links">
                        <li><a href="#">About Us</a></li>
                        <li><a href="map.html">All Rides</a></li>
                        <li><a href="find.html">Submit a Ride</a></li>
                        <li><a href="#">FAQ</a></li>
                    </ul>
                </div>
                <div class="col-xs-8 col-xs-offset-2 footer-links-block">
                    <ul class="list-inline footer-links">
                        <li><a href="#">Contact Us</a></li>
                        <li><a href="#">My Account</a></li>
                        <li><a href="#">Language</a></li>
                        <li><a href="#">Support</a></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
    <div class="footer-color-three">
        <div class="container">
            <div class="row">
                <div class="col-xs-12">
                    <p class="small">Website design &#38; content &copy; copyright 2016 eZ Systems. This website was made with eZ Publish 5.4 Platform</p>
                </div>
            </div>
        </div>
    </div>
</footer>
_EOF_
```

### メニューのカスタマイズ
```bash:page_topmenu.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/page_topmenu.html.twig
<!-- Navigation -->
        <nav class="navbar navbar-default navbar-fixed-top" id="total-navbar">
            <div class="container">
                <!-- Brand and toggle -->
                <div class="navbar-header page-scroll">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#go-bike-navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="/">
                        <img alt="Brand" src="{{ asset( "bundles/eztutorialbike/images/128_bike_white_avenir.png" ) }}">
                    </a>
                </div>
 
                <!-- nav links -->
                <div id="go-bike-navbar" class="collapse navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="#">ALL RIDES</a></li>
                        <!--  <li><a href="#">SUBMIT A RIDE</a></li>
                         <li><a href="#">MY ACCOUNT</a></li> -->
                    </ul>
                    {#<ul class="nav navbar-nav navbar-right">#}
                        {#<li><a href="#">EN</a></li>#}
                        {#<li><a href="#">FR</a></li>#}
                        {#<li><a href="#">NO</a></li>#}
                    {#</ul>#}
                </div><!--/.nav-collapse -->
            </div><!-- /.container -->
        </nav>
_EOF_
```

## Part 2: Step 3 ホームページに Ride の一覧を表示する

### オーバーライドファイルの作成
```bash:ezpublish.yml
cd /opt/rh/httpd24/root/var/www/ezpublish5
cat << "_EOF_" >> ezpublish/config/ezpublish.yml
imports:
    - { resource: override.yml }
    - { resource: image_variations.yml }
_EOF_
```
```bash:override.yml
cd /opt/rh/httpd24/root/var/www/ezpublish5
cat << "_EOF_" > ezpublish/config/override.yml
ezpublish:
    system:
        default:
            location_view:
                full:
                    frontpage:
                        template: "EzTutorialBikeBundle:full:welcome.html.twig"
                        match:
                            Id\Location: 2
                    ride:
                        template: "EzTutorialBikeBundle:full:ride.html.twig"
                        controller: "EzTutorialBikeBundle:Ride:viewRideWithPOI"
                        match:
                            Identifier\ContentType: "ride"
                line:
                    ride:
                        template: "EzTutorialBikeBundle:line:ride.html.twig"
                        match:
                            Identifier\ContentType: "ride"
                    point_of_interest:
                        template: 'EzTutorialBikeBundle:line:point_of_interest.html.twig'
                        match:
                            Identifier\ContentType: "point_of_interest"
_EOF_
```

### ホームページテンプレートの作成
```bash:full/welcome.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
mkdir Resources/views/full
cat << "_EOF_" > Resources/views/full/welcome.html.twig
{% extends "EzTutorialBikeBundle::pagelayout.html.twig" %}
 
{% block content %}
    <script src="//maps.google.com/maps/api/js?sensor=false"></script>
    {{ render( controller( "EzTutorialBikeBundle:Homepage:getAllRides" ) ) }}
{% endblock %}
_EOF_
```

### Ride 一覧を表示するサブコントローラーの作成
```bash:HomepageController.php
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Controller/HomepageController.php
<?php

namespace Ez\TutorialBikeBundle\Controller;

use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\Core\MVC\Symfony\Controller\Controller;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
use eZ\Publish\Core\Pagination\Pagerfanta\ContentSearchAdapter;
use Pagerfanta\Pagerfanta;
use Symfony\Component\HttpFoundation\Request;

class HomepageController extends Controller
{
    public function getAllRidesAction( Request $request )
    {
        $repository = $this->getRepository();
        $locationService = $repository->getLocationService();
        $contentService = $repository->getContentService();
 
        $rootLocationId = $this->getConfigResolver()->getParameter( 'content.tree_root.location_id' );
        $rootLocation = $locationService->loadLocation( $rootLocationId );
 
        $currentLocationId = 2;// $request->get('location_id');
        $currentLocation = $locationService->loadLocation( $currentLocationId );
        $currentContent = $contentService->loadContentByContentInfo( $currentLocation->contentInfo );
 
        $query = new Query();
        $query->query = new Criterion\LogicalAnd(
            array(
                new Criterion\Subtree( $rootLocation->pathString ),
                new Criterion\Visibility( Criterion\Visibility::VISIBLE ),
                new Criterion\ContentTypeIdentifier( array('ride') )
            )
        );
        $query->sortClauses = array(
            new SortClause\DatePublished( Query::SORT_ASC )
        );
 
        $pager = new Pagerfanta(
            new ContentSearchAdapter($query, $this->getRepository()->getSearchService())
        );
        //FIXME : get $limit value from a custom parameter
        $limit = 10;
        $pager->setMaxPerPage( $limit );
        $pager->setCurrentPage($request->get('page', 1));
 
        return $this->render(
            'EzTutorialBikeBundle:list:rides.html.twig',
            array(
                'location' => $currentLocation,
                'content' => $currentContent,
                'pagerRides' => $pager,
            )
        );
    }
}
_EOF_
```

### Ride 一覧を表示するテンプレートの作成
```bash:list/rides.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
mkdir Resources/views/list
cat << "_EOF_" > Resources/views/list/rides.html.twig
{#Only display pagerfanta navigator if needed.#}
{% if pagerRides.haveToPaginate() %}
    <div class="pagerfanta">
        {{ pagerfanta( pagerRides, 'twitter_bootstrap_translated', {'routeName': location } ) }}
    </div>
{% endif %}
 
<div class="row regular-content-size">
    <div class="col-xs-10 col-xs-offset-1 box-style">
        <h3 class="center bottom-plus new-header">{{ 'List of all Rides' | trans }}</h3>
        {# Loop over the page results #}
        {% for ride in pagerRides %}
            {% if loop.first %}
            <table class="table table-hover">
                <thead>
                <tr class="table-header">
                    <th>{{ 'Ride' | trans }}</th>
                    <th></th>
                    <th>{{ 'From - To' | trans }}</th>
                    <th>{{ 'Distance' | trans }}</th>
                    <th>{{ 'Level' | trans }}</th>
                </tr>
                </thead>
                <tbody>
            {% endif %}
            {{ render( controller( 'ez_content:viewLocation', { 'locationId': ride.versionInfo.contentInfo.mainLocationId, 'viewType': 'line' } )) }}
            {% if loop.last %}
                </tbody>
            </table>
            {% endif %}
        {% endfor %}
    </div>
</div>
 
{#Only display pagerfanta navigator if needed.#}
{% if pagerRides.haveToPaginate() %}
    <div class="pagerfanta">
        {{ pagerfanta( pagerRides, 'twitter_bootstrap_translated', {'routeName': location } ) }}
    </div>
{% endif %}
_EOF_
```

### Ride の view line を表示するカスタムテンプレートの使用
```bash:line/ride.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
mkdir Resources/views/line
cat << "_EOF_" > Resources/views/line/ride.html.twig
<tr>
    <td>
        {{ ez_render_field( content, 'image', { parameters: { 'alias': 'small' }} ) }}
    </td>
    <td>
        <h3 class="header-link-table">
            <strong>
                <a href="{{ path( "ez_urlalias", { 'locationId': content.contentInfo.mainLocationId } ) }}" target="_self">
                    {{ ez_content_name( content ) }}
                </a>
            </strong>
        </h3>
        <p class="pre-small">
            {{ ez_render_field( content, 'author') }}
        </p>
    </td>
    <td>
        <div id="googleMap{{ content.id }}" style="min-height: 250px; min-width: 250px"></div>
    </td>
    <td>
        <p>{{ ez_render_field( content, 'length' ) }} Km</p>
    </td>
    <td>
        <p>{{ ez_render_field( content, 'level' ) }}</p>
    </td>
</tr>
 
<script type="text/javascript">
    function initialize{{ content.id }}(){
        var centreMap = new google.maps.LatLng({{ ez_field_value(content, "starting_point").latitude}}, {{ ez_field_value(content, "starting_point").longitude }});
 
        var optionsMap = {
            zoom: 4,
            center: centreMap,
            keyboardShortcuts: true,
            scrollwheel: true,
            panControl: false,
            mapTypeControl: true,
            overviewMapControl: true,
            rotateControl: true,
            scaleControl: true,
            streetViewControl: true,
            zoomControl: true,
            mapTypeId: google.maps.MapTypeId.HYBRID
        };
 
        var divMap = document.getElementById("googleMap{{ content.id }}" );
 
        var Map = new google.maps.Map(divMap, optionsMap);
 
        var imageStartMarqueur = new google.maps.MarkerImage("//maps.google.com/mapfiles/marker_green.png", new google.maps.Size(24, 24), new google.maps.Point(0,0), new google.maps.Point(12, 12));
        var imageEndMarqueur = new google.maps.MarkerImage("//maps.google.com/mapfiles/marker.png", new google.maps.Size(24, 24), new google.maps.Point(0,0), new google.maps.Point(12, 12));
 
        // starting point
        new google.maps.Marker({
            position: new google.maps.LatLng({{ ez_field_value(content, "starting_point").latitude }}, {{ ez_field_value(content, "starting_point").longitude }}),
            map: Map,
            title: "Marker-start",
            icon: imageStartMarqueur
        });
 
        // end point
        new google.maps.Marker({
            position: new google.maps.LatLng({{ ez_field_value(content, "ending_point").latitude }}, {{ ez_field_value(content, "ending_point").longitude }}),
            map: Map,
            title: "Marker-end",
            icon: imageEndMarqueur
        });
    }
    $( document ).ready(function() { initialize{{ content.id }}(); });
</script>
_EOF_
```

## Part 2: Step2 Ride のコンテンツの表示

### Ride full view

#### Ride のオーバーライドルールの作成
override.yml に記載済み

#### Ride の full テンプレートの作成
```bash:full/ride.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/full/ride.html.twig
{% extends "EzTutorialBikeBundle::pagelayout.html.twig" %}
 
{% block content %}
    <section class="below-navbar">
        <div class="container">
            <div class="row regular-content-size">
                <div class="col-xs-10 col-xs-offset-1 row-padding">
                    <div class="col-xs-12">
                        <div class="col-xs-1 text-left">
                            <h2>Ride:</h2>
                        </div>
                        <div class="col-xs-11 text-left">
                            <h2 class="extra-padding-left">{{ ez_content_name( content ) }}</h2>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>
 
    <section>
        <div class="container">
            <div class="row regular-content-size">
                <div class="col-xs-10 col-xs-offset-1">
                    <div id="map-container"></div>
                </div>
            </div>
        </div>
    </section>
 
    <section class="first-below-navbar">
        <div class="container">
            <div class="row regular-content-size">
                <div class="col-xs-10 col-xs-offset-1 padding-box">
                    <div class="col-xs-2">
                        <div class="box-ride">
                            <h3 class="special-number">{{ ez_render_field( content, 'length') }} Km</h3>
                            <p class="pre-small special-number special-number-margin"><strong>{{ 'Level' | trans }}</strong></p>
                            <p class="text-center">
                                <i class="fa fa-star star-color"></i>
                                <i class="fa fa-star star-color"></i>
                                <i class="fa fa-star star-color"></i>
                            </p>
                        </div>
                    </div>
                    <div class="col-xs-10 bottom-extra">
                        <div class="col-xs-2 text-right">
                            <p>Name:</p>
                        </div>
                        <div class="col-xs-4">
                            {{ ez_render_field( content, 'author') }}
                        </div>
                        {#<div class="col-xs-1 text-right">#}
                            {#<p>Start:</p>#}
                            {#<p>End:</p>#}
                        {#</div>#}
                        {#<div class="col-xs-5">#}
                            {#<p class="strong">{{ ez_render_field }}</p>#}
                            {#<p class="strong">Geneva, Switzerland</p>#}
                        {#</div>#}
                    </div>
                    <div class="col-xs-10">
                        <div class="col-xs-2 text-right">
                            <p>Description:</p>
                        </div>
                        <div class="col-xs-10 text-justify">
                            {{ ez_render_field( content, 'description') }}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>

{# Displaying Points of interest, injected via RideController.php, viewRideWithPOIAction function #}
{% for point in pointOfInterestList %}
    {% if loop.first %}
        <section class="photos">
        <div class="container">
        <div class="row regular-content-size">
        <div class="col-xs-10 col-xs-offset-1" id="wrapper">
        <div class="col-xs-12">
            <h4 class="underscore-green">Points of interest:</h4>
        </div>
    {% endif %}
 
    {{ render( controller( "ez_content:viewLocation", { 'locationId': point.contentInfo.mainLocationId, 'viewType': 'line'} )) }}
 
    {% if loop.last %}
        </div>
        </div>
        </div>
        </section>
    {% endif %}
{% endfor %}
<script src="//maps.google.com/maps/api/js?sensor=false"></script>
<script>
    // Define your locations: HTML content for the info window, latitude & longitude
    var locations = [
        [ '<p class="infowindow-text">Start!</p>', "{{ ez_field_value(content, "starting_point").latitude}}", "{{ ez_field_value(content, "starting_point").longitude }}", 'orange-dot.png']
        {% for point in pointOfInterestList %}
            ,['<p><span>{{ ez_render_field( point, 'image', { parameters: { 'alias': 'small' }}) }}</span></p>', '{{ ez_field_value( point, "place").latitude}}', '{{ ez_field_value( point, "place").longitude }}', 'green-dot.png']
        {% endfor %}
        ,[ '<p class="infowindow-text">End!</p>', "{{ ez_field_value(content, "ending_point").latitude}}", "{{ ez_field_value(content, "ending_point").longitude }}", 'blue-dot.png']
    ];
 
    var iconURLPrefix = '//maps.google.com/mapfiles/ms/icons/';
 
    var map = new google.maps.Map(document.getElementById('map-container'), {
        zoom: 8,
        center: new google.maps.LatLng("{{ ez_field_value(content, "starting_point").latitude}}", "{{ ez_field_value(content, "ending_point").latitude}}"),
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        mapTypeControl: false,
        streetViewControl: false,
        panControl: false,
        zoomControlOptions: {
            position: google.maps.ControlPosition.LEFT_BOTTOM
        }
    });
 
    var bikeLayer = new google.maps.BicyclingLayer();
    bikeLayer.setMap(map);
 
    var infowindow = new google.maps.InfoWindow({
        maxWidth: 200
    });
 
    var markers = [];
 
    var iconCounter = 0;
 
    // Add the markers and infowindows to the map
    for (var i = 0; i < locations.length; i++) {
        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(locations[i][1], locations[i][2]),
            map: map,
            icon:  iconURLPrefix + locations[i][3]
        });
 
        markers.push(marker);
 
        google.maps.event.addListener(marker, 'mouseover', (function(marker, i) {
            return function() {
                infowindow.setContent(locations[i][0]);
                infowindow.open(map, marker);
            }
        })(marker, i));
    }
 
    function autoCenter() {
        //  Create a new viewpoint bound
        var bounds = new google.maps.LatLngBounds();
        //  Go through each...
        for (var i = 0; i < markers.length; i++) {
            bounds.extend(markers[i].position);
        }
        //  Fit these bounds to the map
        map.fitBounds(bounds);
    }
    autoCenter();
</script>
{% endblock %}
_EOF_
```

### POI の一覧の表示

#### オーバーライドルールに新しいパラメーターを追加
override.yml に記載済み

#### Ride の full view の POI の一覧を挿入
```bash:RideController.php
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Controller/RideController.php
<?php
 
namespace Ez\TutorialBikeBundle\Controller;
 
use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Bundle\EzPublishCoreBundle\Controller;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
use eZ\Publish\Core\Pagination\Pagerfanta\ContentSearchAdapter;
use eZ\Publish\Core\Repository\Values\Content\Location;
use Pagerfanta\Pagerfanta;
use Symfony\Component\HttpFoundation\Request;
 
class RideController extends Controller
{
 
    /**
     * Action used to display a ride
     *  - Adds the list of all related Points of interest to the response.
     *
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location of the ride
     * @param $viewType
     * @param bool $layout
     * @param array $params
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function viewRideWithPOIAction( $locationId, $viewType, $layout = false, array $params = array())
    {
        $repository = $this->getRepository();
        $contentService = $repository->getContentService();
 
        $location = $repository->getLocationService()->loadLocation( $locationId );
        $currentLocation = $location;
        $currentContent = $contentService->loadContentByContentInfo( $currentLocation->contentInfo );
 
        $pointOfInterestListId = $currentContent->getFieldValue( 'points_of_interest' );
        $pointOfInterestList = array();
        foreach( $pointOfInterestListId->destinationContentIds as $pointId)
        {
            $pointOfInterestList[ $pointId ] = $contentService->loadContent( $pointId );
        }
 
        return $this->get('ez_content')->viewLocation(
            $location->id,
            $viewType,
            $layout,
            array('pointOfInterestList' => $pointOfInterestList) + $params
        );
    }
}
_EOF_
```

#### full view に挿入された一覧を表示する
full/ride.html.twig に記載済み

### 画像種別設定
```bash:image_variations.yml
cd /opt/rh/httpd24/root/var/www/ezpublish5
cat << "_EOF_" > ezpublish/config/image_variations.yml
ezpublish:
    system:
        site_group:
            image_variations:
                medium:
                    reference: null
                    filters:
                        - { name: geometry/scaledownonly, params: [200, 290] }
                large:
                    reference: null
                    filters:
                        - { name: geometry/scaledownonly, params: [360, 440] }
                # this is a new image's size used in the place template
                imageplacesize:
                    reference: null
                    filters:
                        - { name: geometry/scalewidthdownonly, params: [370] }
_EOF_
```

### Point of interest の line view の作成
```bash:line/point_of_interest.html.twig
cd /opt/rh/httpd24/root/var/www/ezpublish5
cd src/Ez/TutorialBikeBundle
cat << "_EOF_" > Resources/views/line/point_of_interest.html.twig
<div class="col-xs-4 photos-box">
    <a href="#bikeModal{{ content.id }}" class="portfolio-link" data-toggle="modal">
        <div class="caption">
            <div class="caption-content">
                <i class="fa fa-search-plus fa-3x"></i>
            </div>
        </div>
        {{ ez_render_field( content, 'image', { parameters: { 'alias': 'small'},
                                                attr: { 'class': 'img-responsive img-rounded' }}) }}
        {#<img src="images/lyon.png" class="img-responsive img-rounded" alt="">#}
    </a>
</div>
 
{# MODAL #}
<div class="bike-modal modal fade" id="bikeModal{{ content.id }}" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-content">
        <div class="close-modal" data-dismiss="modal">
            <div class="lr">
                <div class="rl">
                </div>
            </div>
        </div>
        <div class="container">
            <div class="row">
                <div class="col-xs-8 col-xs-offset-2">
                    <div class="modal-body text-center">
                        <h2>Photo: {{ ez_content_name( content ) }}</h2>
                        <hr class="featurette-divider">
                        {{ ez_render_field( content, 'image', { parameters: { 'alias': 'large'},
                                                                attr: { 'class': 'img-responsive img-rounded' }}) }}
                        {#<img src="images/lyon.png" class="img-responsive img-centered img-rounded" alt="">#}
                        {{ ez_render_field( content, 'description', { attr: { 'class': 'padding-box text-justify' }}) }}
 
                        {#<p class="padding-box text-justify"></p>#}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
_EOF_
```