大分前ですが、駅で電車を待っていたら事故か何かでダイヤが乱れてました。その時遅れている事をアナウンスしていた(おそらく新入社員の)女性駅員さんが、アナウンスする度に駅名を噛んでました。
...駅員が駅名噛んだらマズイだろ。と思ってました。そしてついでに萌えてました(*´ω`*)
layoutを改造する
グローバルナビが欲しい今日この頃
レイアウトのguest.ctpを作ってきましたが、やっぱりナビが欲しいと思いました。しかもBootstrapのナビバーがいいなぁ~と思いました。かっこいいですよねあれ。
まあ、Bootstrap用のサイト作るなら必須だなと後から気づいた訳ですけども。
やっぱりBootstrapのサンプルページからナビバーの部分だけコピペします。
app/View/Layout/guest.ctpを変更
...
<div id="header">
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#">Bootstrap コピペ場</a>
<div class="nav-collapse">
<ul class="nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
...
こういうCSSフレームワークを使うとどうしても、上のような感じに入れ子&クラス名が多くなるんですよね。そこはまあ、納得してお付き合いしてかなければいけないんですけども。
助っ人
前回書いたViewこと美優さんは健気に頑張っています。あまりに大変そうなのでControllerさんが気を利かせて助っ人を付けてます。HtmlHelperです。前回美優さんの隠し玉とかいてたHelperの1つです。
HtmlHelperはすでに何回も出てきています。guest.ctpを確認すると以下の箇所があります。
$this->Html->charset()
すなわち$this(=美優さん)のHtml助っ人(=HtmlHelper)のcharset()という仕事を実行していた訳です。文字列を返し例えばcharset()なら以下の文字列返します。
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
助っ人さんは他にいます。FormHelperとかですが、今は出番が無いので放置します。
助っ人さんの役目は、複数のビューやエレメント、レイアウトで共有する処理を目的別にまとめておく事です。HtmlHelperなら、htmlタグを返すメソッドがそろってます。
後でHtmlHelperのメソッドをまとめたいです。
自作の助っ人
助っ人は自作出来ます。今後Bootstrapの関連のタグをたくさん使いそうなので、Bootstrap用の助っ人を作ってみようとおもいます。
約束事があります。
- ファイル作成場所は「app/View/Helper」の下
- AppHelperを継承する。
- Viewで使用するHelperはController内で設定する
取り敢えずシンプルなナビバーを返すところから始めます。以下コード。
app/View/Helper/B99TwitterBootstrapHelper.phpを新たに作成。
<?php
/**
* Twitter Bootstrap用のヘルパー
*/
App::uses('AppHelper', 'View/Helper');
class B99TwitterBootstrapHelper extends AppHelper {
public $helpers = array('Html');
/**
*
* @return String navbar tag string
*/
public function simpleNavbar(){
$result = <<<NAV
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#">Bootstrap コピペ場</a>
<div class="nav-collapse">
<ul class="nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
</div>
</div>
</div>
NAV;
return $result;
}
}
app/Controller/PagesControllerに追加
public $helpers = array('B99TwitterBootstrap');
そのままナビバーを表示しても見た目が変わらないのでデバッグ出力します。
app/View/Pages/index.ctpに追加
<?php
$this->layout = "guest";
debug($this->B99TwitterBootstrap->simpleNavbar());
?>
...
ブラウザでアクセスします。

自作した助っ人がちゃんと動作しているようです。
さらに自作の助っ人
B99TwitterBootstrapHelperを作ってみましたが、固定の文字列を返すだけでこのままでは使い勝手が良くありません。下のリストのようにさらに改造します。
- プロジェクト名を引数で渡す
- リンク先を引数で渡す
- 「class="active"」って所を自動で判別して差し込む
app/View/Helper/B99TwitterBootstrapHelper.phpを修正
...
/**
*
* シンプルなナビバーを作って返す
* @param array $brand array( 'title' => 'Bootstrap コピペ場', 'url' => '/')titleはaタグに挟まれる文字列、urlはAタグのリンク先
* @param array $links $links = array('index' => array( 'title' => 'Home', 'url' => '/'))keyは$active_strと合う文字列、titleはaタグに挟まれる文字列、urlはAタグのリンク先
* @param string $$active_str
* @return String navbar tag string
*/
public function simpleNavbar($brand, $links, $active_str){
$link_li_tag = "";
$brand_a_tag = "";
//このfor文の中でactiveなclassの値を設定する
foreach ($links as $key => $val) {
//classがあるかチェック無ければ追加する
if (!isset($val['class'])) {
$val['class'] = "";
}
//activeなliタグかチェック
if ($key==$active_str){
//classに「active」文字列を追加
$val['class'] .= " active";
}
//配列の値を設定し直す
$links[$key] = $val;
}
//liタグを作る
foreach ($links as $key => $val){
$link_li_tag .= " " . $this->Html->tag('li', $this->Html->link($val['title'] , $val['url']), $val['class']) . "
";
}
//プロジェクト名のaタグを作る
$brand_a_tag = $this->Html->link($brand['title'], $brand['url'], array('class'=>'brand'));
//ナビバーの文字列を返す
return <<<NAV
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
{$brand_a_tag}
<div class="nav-collapse">
<ul class="nav">
{$link_li_tag}
</ul>
</div>
</div>
</div>
</div>
NAV;
}
...
app/View/Pages/index.ctpからコメントアウト(もしくは削除)
<?php
$this->layout = "guest";
//debug($this->B99TwitterBootstrap->simpleNavbar());
?>
...
app/View/Layout/guest.ctpへ追加
<?php
$brand = array( 'title' => 'Bootstrap コピペ場', 'url' => '/');
$links = array(
'index' => array( 'title' => 'Home', 'url' => '/'),
'scaffolding' => array( 'title' => 'Scaffolding', 'url' => '/pages/scaffolding'),
'base-css' => array( 'title' => 'Base Css', 'url' => '/pages/base-css'),
'components' => array( 'title' => 'Components', 'url' => '/pages/components'),
'javascript' => array( 'title' => 'Javascript Plugins', 'url' => '/pages/javascript'),
'about' => array( 'title' => 'About', 'url' => '/pages/about'),
);
debug($this->B99TwitterBootstrap->simpleNavbar($brand, $links, $this->request->params['action']));
...
<div id="header">
<?php echo $this->B99TwitterBootstrap->simpleNavbar($brand, $links, $this->request->params['action']);?>
</div>
...
ブラウザでアクセスする。

オッケーのようなのでguest.ctpからdebug()メソッドを削除する。
これで晴れてグローバルで動的にactiveが変化するナビバーの出来上がり...のはず。
simpleNavbar()メソッドの第3引数が「$this->request->params['action']」となってますが、これは現在のurlからアクションに当たる文字列を格納しています。この値を渡すことでどこのliタグがactiveなのかを判断してます。
まとめ
- 美優さんことViewには助っ人ことHelperという仕組みがある。
- Helperを使うには色々と決まりがある。
- 変数の中身がわからない場合はdebug()メソッドを使う
環境とか
項目 | 内容 |
PHPフレームワーク | Cakephp 2.2.0 |
IDE | Eclipse 3.6 |
開発環境? | MAMP |
PC | Macmini |
OS | Mac OS Lion |