Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

View

以下を参照して勉強したメモ
ビュー - 3.x

役割

HTML, XML, JSON, PDF生成等
XMLJSONビューは
JSON と XML ビュー - 3.x

AppView アプリのベースのView

主にヘルパーを読み込むように使用する。

<?php
namespace App\View;

use Cake\View\View;

class AppView extends View
{

    public function initialize()
    {
        $this->loadHelper('MyUtils');
    }

}

テンプレート ctp

両者は同じ意味

<?php echo $variable; ?>
<?= $variable ?>

テンプレート内での制御構文 (やりたくない。。)
if 、 for 、 foreach 、 switch 、そして while

<ul>
<?php foreach ($todo as $item): ?>
  <li><?= $item ?></li>
<?php endforeach; ?>
</ul>

このように":"で書いて、end***で閉じる。

ifの例

<?php if ($username === 'a'): ?>
   <h3>a</h3>
<?php elseif ($username === 'b'): ?>
   <h3>b</h3>
<?php else: ?>
   <h3>unknown</h3>
<?php endif; ?>

ビューレイヤーのパーツ

  1. ビュー(テンプレート)
  2. エレメント 描画時にビューのテンプレートに埋め込まれる
  3. レイアウト ビューのテンプレートを包む
  4. ヘルパー ビューロジックのカプセル化
  5. cells   自己完結型のUI部品

ビューへコントローラから値を渡す

コントローラのset

エスケープ

h()

ビューからレイアウトやエレメントに値を渡す

ビューのset

$this->set('activeMenuButton', 'posts');

ビューのテンプレートを継承したい。

$this->extendを用いる。入れ子にできる。これとビューブロックを用いて親テンプレートと子テンプレートをつくり継承関係をつくる。

ビューブロック

使用メソッド
start() 、 append() 、 prepend() 、 assign() 、 fetch() 、 そして end()

サイドバーブロックを定義する。

// sidebar ブロックを作成する。
$this->start('sidebar');
echo $this->element('sidebar/recent_topics');
echo $this->element('sidebar/recent_comments');
$this->end();

これでサイドバーブロックが定義されたので、
使う場合、

<?= $this->fetch('sidebar') ?>

とすれば使えるようになる。

ビューブロックが定義されていない場合も考慮する場合

<?php if ($this->fetch('sidebar')): ?>
<?= $this->fetch('sidebar') ?>
<?php endif; ?>

fetchの第2引数を定義すると、ビューブロックがない場合の既定値にできる。

    <?= $this->fetch('sidebar', 'サイドバーがない') ?>

ビューテンプレートの継承

親 src/Template/Common/view.ctp

<h1><?= $this->fetch('title') ?></h1>
<?= $this->fetch('content') ?>

<div class="actions">
    <h3>サイドバー</h3>
    <ul>
    <?= $this->fetch('sidebar') ?>
    </ul>
</div>

子  src/Template/Posts/view.ctp

<?php
// 親のビューを継承する
$this->extend('/Common/view');

// 親の`title`に$postの値を入れる。
$this->assign('title', $post);

// 親のサイドバーの部分を定義
$this->start('sidebar');
?>
<li>
<?php
echo $this->Html->link('edit', [
    'action' => 'edit',
    $post->id
]); ?>
</li>
<?php $this->end(); ?>

// 他はすべて親のcontetのところになる。(contentは特殊)
<?= h($post->body) ?>

ビューブロックの列挙

$list = $this->blocks();

ビューブロックの詳細

既存ブロックへの追加

$this->append('sidebar');
echo $this->element('sidebar/popular_topics');
$this->end();
$this->append('sidebar', $this->element('sidebar/popular_topics'));

既存ブロックの手前に追加

$this->prepend('sidebar', 'このコンテンツはサイドバーの先頭に来ます');

ブロックの消去

$this->reset('sidebar');
// or 
$this->assign('sidebar', '');

レイアウト

デフォルトレイアウト
src/Template/Layout/default.ctp

<!DOCTYPE html>
<html lang="en">
<head>
<title><?= h($this->fetch('title')) ?></title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<!-- 外部ファイルとスクリプトファイルがここに入れます (詳しくは HTML ヘルパーを参照。) -->
<?php
echo $this->fetch('meta');
echo $this->fetch('css');
echo $this->fetch('script');
?>
</head>
<body>

<!-- もしすべてのビューでメニューを表示したい場合、ここに入れます -->
<div id="header">
    <div id="menu">...</div>
</div>

<!-- ここがビューで表示されるようにしたい場所です -->
<?= $this->fetch('content') ?>

<!-- 表示される各ページにフッターを追加します -->
<div id="footer">...</div>

</body>
</html>

fetchが使われているので子で色々値を入れたりすることがわかる(ビューの継承と同じ)。

デフォルトレイアウトからの変更はControler->viewBuilder()->setLayout

3.4以前は違うらしい。

ビューからも変えられる? View->layout

エレメント

エレメントをテンプレートに埋め込む

echo $this->element('helpbox');

データを渡す。

echo $this->element('helpbox', [
    "helptext" => "hoge!"
]);

エレメントはキャッシュとコールバックを定義できる。

echo $this->element('helpbox', [
        "helptext" => "help!",
        "foobar" => "hogehoge",
    ],
    [
        "cache" => true,
        // エレメントから before/afterRender が呼び出されるには true に設定してください
        "callbacks" => true
    ]
);

キャッシュの詳細は
ビュー - 3.x
をみよ。

しかし、callbackとかでロジックがいるようならビューセルを検討する。

ビューイベント

View.beforeRender
View.beforeRenderFile
View.afterRenderFile
View.afterRender
View.beforeLayout
View.afterLayout

イベントリスナーを登録する?
EventListenerInterface
勉強中
イベントシステム - 3.x

独自のビューロジックを持つビューをつくる

src/Viewに配置、参照の際はViewを除いた部分。

// src/View/HogeView.php の中で
namespace App\View;

use Cake\View\View;

class HogeView extends View
{
    public function render($view = null, $layout = null)
    {
        // カスタムロジック
    }
}

ビューセル

ビューセル - 3.x

src/Template/Cell/に置く。

namespace App\View\Cell;

use Cake\View\Cell;

class HogeCell extends Cell
{

    public function display()
    {
    }

}

bakeでも作れる

bin/cake bake cell Hoge

未読メッセージの数を出す。

namespace App\View\Cell;

use Cake\View\Cell;

class HogeCell extends Cell
{

    public function display()
    {
        $this->loadModel('Messages');
        $unread = $this->Messages->find('unread');
        $this->set('unread_count', $unread->count());
    }

   public function other()
  {
  }
}

ポイントはcellはコントローラと同じようにloadModelでき、setでセルテンプレートにsetできること。
セルテンプレート側では

<!-- src/Template/Cell/Hoge/display.ctp -->
<div class="notification-icon">
    未読メッセージが <?= $unread_count ?> 件あります。
</div>

このあたりもコントローラとの関係と近い。

そのセルをビューテンプレートで用いる

$cell = $this->cell('Hoge');

render() ?>
cellをechoすると__toString()を使用するために意味のあるエラーメッセージを読み取れなくなるらしいのでrenderする。

// HogeCellの他のメソッドを呼び出す

$cell = $this->cell('Hoge::other');

値をcellに渡す。

$cell = $this->cell('Hoge::other', ['ok']);

セル側は

   public function other($okString)
  {
  }


異なるセルテンプレートを用いる。

echo $this->cell('Hoge::other')->render('messages');

もしくは

$cell = $this->cell('Hoge::other');
$cell->template = 'messages';
echo $cell;

セルはキャッシュもできる。
ビューセル - 3.x

$cell = $this->cell('Hoge', [], ['cache' => true]);

コントローラからセルを使いたい

namespace App\Controller;

use App\Controller\AppController;
use Cake\View\CellTrait;

class FooController extends AppController
{
    use CellTrait;

    // 他のコード。
}

ヘルパー

以下を参照している。
ヘルパー - 3.x

使うヘルパーはビューでロードする。

class AppView extends View
{
    public function initialize()
    {
        parent::initialize();
        $this->loadHelper('Html');
        $this->loadHelper('Form');
        $this->loadHelper('Flash');
    }
}

CakePHPにビルトインされているヘルパーはロードしなくても使える。

条件付きでヘルパーを読み込みたい

class AppView extends View
{
    public function initialize()
    {
        parent::initialize();
        if ($this->request->getParam('action') === 'index') {
            $this->loadHelper('ListPage');
        }
    }
}

コントローラ側で読み込んでおきたいならビュービルダーで

class HogesController extends AppController
{
    public function beforeRender(Event $event)
    {
        parent::beforeRender($event);
        $this->viewBuilder()->helpers(['MyHelper']);
    }
}

ヘルパーにオプションを渡す。
3.2以降

namespace App\View\Helper;

use Cake\View\Helper;
use Cake\View\View;

class HogeHelper extends Helper
{
    public function initialize(array $config)
    {
        debug($config);
    }
}

渡す方は

namespace App\Controller;

use App\Controller\AppController;

class HogesController extends AppController
{
    public $helpers = ['Hoge' => ['option1' => 'value1']];
}

等としてやる。

オプションのデフォルト値は必ず定義がいる。

namespace App\View\Helper;

use Cake\View\Helper;
use Cake\View\StringTemplateTrait;

class HogeHelper extends Helper
{

    use StringTemplateTrait;

    protected $_defaultConfig = [
        'option1' => 'o',
    ];
}

設定の読み取り

$option1= $this->Hoge->config('option1');

ヘルパーの別名
勉強中

ヘルパーの使用
echo $this->Hoge->foo('styles');
既存ヘルパーにメソッド追加
/* src/View/Helper/HogeHelper.php (他のヘルパーを使用) */

namespace App\View\Helper;

use Cake\View\Helper;

class HogeHelper extends Helper
{
    public $helpers = ['Html'];

    public function makeEdit($title, $url)
    {
        // 出力に HTML ヘルパーを使用
        // 整形されたデータ:

        $link = $this->Html->link($title, $url, ['class' => 'edit']);

        return '<div class="editOuter">' . $link . '</div>';
    }
}
ヘルパー内からビューの変数にアクセスできる。。。

$this->_View->get()

class HogeHelper extends Helper
{

    public $helpers = ['Html'];

    public someMethod()
    {
        // meta description の設定
        echo $this->Html->meta(
            'description', $this->_View->get('metaDescription'), ['block' => 'meta']
        );
    }
}

エレメントも当然できる。
$this->_View->element()

ヘルパーにある各種コールバック
  1. Helper::beforeRenderFile(Event $event, $viewFile)
  2. Helper::afterRenderFile(Event $event, $viewFile, $content)
  3. Helper::beforeRender(Event $event, $viewFile)
  4. Helper::afterRender(Event $event, $viewFile)
  5. Helper::beforeLayout(Event $event, $layoutFile)
  6. Helper::afterLayout(Event $event, $layoutFile)

テーマ

勉強中