View
以下を参照して勉強したメモ
ビュー - 3.x
役割
HTML, XML, JSON, PDF生成等
XMLとJSONビューは
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; ?>
ビューレイヤーのパーツ
- ビュー(テンプレート)
- エレメント 描画時にビューのテンプレートに埋め込まれる
- レイアウト ビューのテンプレートを包む
- ヘルパー ビューロジックのカプセル化
- 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) { // カスタムロジック } }
ビューセル
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()
ヘルパーにある各種コールバック
- Helper::beforeRenderFile(Event $event, $viewFile)
- Helper::afterRenderFile(Event $event, $viewFile, $content)
- Helper::beforeRender(Event $event, $viewFile)
- Helper::afterRender(Event $event, $viewFile)
- Helper::beforeLayout(Event $event, $layoutFile)
- Helper::afterLayout(Event $event, $layoutFile)
テーマ
勉強中