現在開いてるページへのリンクを判別できるHtmlHelperを作る。CakePHP1.3
CakePHP の HtmlHelper は、名前の通り html を生成します。
Baker暦の浅い自分は、何で html を普通に書かずわざわざHelperを介するのか、よく分からなかったりします。
でも、組み込みだし、どうも CakePHP 関連の情報を調べてると、HtmlHelper は使うのが当たり前っぽい。
変に自分流でやっちゃうよりは、CakePHP のルールに従ったほうがトラブルも少ないと思うので、一応使います。
<ul> <li><a href="/">ホーム</a></li ><li><a href="/product" class="current">プロダクト</a></li ><li><a href="/faq">よくある質問</a></li ><li><a href="/contact">お問い合わせ</a></li> </ul>
で、ナビゲーションにリンクを作ってる時に、開いてるページへのリンクには、こんな感じで current とかの class属性を付けたりしたい。
ですが、HtmlHelper を使ってるとこれが出来そうにないです。
しょうがないので HtmlHelper を継承して ExHtmlHelper を作り、HtmlHelper->link() をオーバーライドしました。
コード
APP/views/helpers/ex_html.php
<?php /** * Extended HtmlHelper * @author kanonji */ class ExHtmlHelper extends HtmlHelper { /** * Extended HtmlHelper->link() to understand the url is current or not. * * $options['current'] is additional option key. * If no value set, 'current' is set as default. * example: * $this->ExHtml->link('foo', 'bar', array('class'=>'baz', 'current'=>'qux')) * result: * <a href="/foo/" class="baz qux">bar</a> * * @param string $title The content to be wrapped by <a> tags. * @param mixed $url Cake-relative URL or array of URL parameters, or external URL (starts with http://) * @param array $options Array of HTML attributes. * @param string $confirmMessage JavaScript confirmation message. * @return string An `<a />` element. * @access public * @link http://book.cakephp.org/view/1442/link */ public function link($title, $url = null, $options = array(), $confirmMessage = false) { $current = 'current'; if(isset($options['current'])) $current = $options['current']; unset($options['current']); if ($url === null) $str = Router::url($title); else $str = Router::url($url); list($str) = explode('?', $str); if(rtrim($str, '/') === rtrim(Router::url(""), '/')) $options['class'] = isset($options['class']) ? "{$options['class']} {$current}" : $current; return parent::link($title, $url, $options, $confirmMessage); } }ex_html.php · GitHub
https://gist.github.com/571144/e345173f09e776ce4d179c1c977a374340984775
コードに間違いがあったので修正しました。
APP/app_controller.php
<?php class AppController extends Controller { public $helpers = array('Session', 'Html', 'Form', 'ExHtml'); }
View内で $this->ExHtmlHelper->link() の様に使います。
基本的に HtmlHelper->link() と同じように使えますが、第3引数に渡す配列に $options['current'] を追加してあります。
$options['current']に、現在開いてるページへのa要素に付けたいclass属性を指定できます。
難点
作ってから思ったんですが、これは HtmlHelper を拡張するより、JavaScriptでDOMとか使ってやったほうが良いかもしれません。
今時JavaScriptが動かない環境は少ないですし、もし現在のページへのリンクが判別できなくても、そんなに困らないですし。
ExHtmlHelperという名前が微妙
やってることが HtmlHelper の1つのメソッドに、ちょっとした改良を加えるだけなので、正直適切なHelper名が思いつきません。
名前から機能が予想できない ExHtmlHelper はあんまり良いネーミングじゃないですし。
CakePHP のコアにあるHtmlHelper CAKE/libs/view/helpers/html.php を APP/views/helpers/html.php にコピーすると、APPのほうからロードされるので、コピーしてからlink()メソッドを改造するという手もあります。
この方法なら、HtmlHelper という名前のままに出来ますが、CakePHP本体のマイナーアップデートで、もし HtmlHelper のバグが修正されたら、ちょっと面倒なことになります。
もしくは HtmlHelper だけ更新し忘れたり。
そう考えると、JavaScriptで対応した方が良いかなぁと。折角なので消さずに書くけど。