パンくずリスト

やっつけで作った。
なお、

  • controller側でのページタイトルの指定と一致

……する仕組みは用意していない。疲れた。

APPPATH/classes/bread.php

<?php

class Bread
{
	static function wordlist($seg = null)
	{
		switch($seg)
		{
			case 'manual':
				//パンくずにリンクを付ける場合
				$word = Html::anchor('manual/','MANUAL');
				break;
			case 'prep':
				//つけない場合は単語だけ
				$word = '準備編';
				break;

			//省略!!!

			default:
				$word = null;
				break;
		}
		
		return $word;
	}
	
	public static function generate($title)
	{
		//urlセグメントを全て配列で取得
		$url = Uri::segments();

		//パンくずの先頭「TOP >」は必ず表示
		$crumb = '
  • ' . Html::anchor('/','TOP') . '
  • '; //パンくず末尾はそのページのタイトルを表示させたい //つまりforeachでの最後の処理を別にしなければならない //最後であるかどうか判断するため最後の要素のキーを取得する //foreach+end()+each()じゃなくてfor+count()でもいいのかも、そっちの方が単純 end($url); $url_last_element = each($url); //現在のキーと値のペアを返して、最後なのでカーソルが進まない $url_last_key = $url_last_element["key"]; //キー取得 foreach($url as $key => $seg) { if($key == $url_last_key || self::wordlist($seg) == null) //最後ならば(なんかもっとましな書き方ありそう) { $crumb .= '
  • ' . $title . '
  • '; //パンくずリスト末尾にページタイトルをつける } else { $crumb .= '
  • ' . self::wordlist($seg) . '
  • '; //パンくずリスト末尾にURLに対応した要素をつける } } return $crumb; } }

    controller例(template利用)

    <?php
    
    class Controller_ほげー extends Controller_Template
    {
    	public function before()
    	{
    		parent::before();
    	}
    
    	public function action_ほげー()
    	{
    		$data = array();
    		$title = 'パンくず~';
    		//template.php中の変数はset_globalを利用
    		$this->template->set_global('bread',Bread::generate($title));
    		$this->template->set_global('title',$title);
    		$this->template->content = View::forge('ほげほげー', $data);
    	}
    

    template.phpでの使用例(CSSは最小限のHTMLとCSSで作る、最もシンプルなパンくずリスト┃degicoの完全パクリです)

      <?php echo htmlspecialchars_decode($bread); ?>
    #bread li {
        display: inline-block;
    }
     
    #bread li + li:before {
        margin: 0 5px;
        content: ">";
    }
    

    苦労した所があったのでここに記録しておくことにする。
    FuelPHPでの関数の作り方に関してはhttp://w.terminal-end.net/?p=218を参考にしてほしい。

    static function wordlist()について

    正直連想配列でもよかった気がする。まあ、複雑なURLになったり、先述の「controllerとの対応」を考えると関数か。

    public static function generate()について

    //urlセグメントを全て配列で取得
    $url = Uri::segments();
    

    例えばこのページ(http://mn.terminal-end.net/parts/fuelphp/breadcrumb/)でUri::segments()をダンプすると

    array(3) {
      [0]=>
      string(5) "parts"
      [1]=>
      string(7) "fuelphp"
      [2]=>
      string(10) "breadcrumb"
    }
    

    要するに配列でURLを取得できる。今回のパンくずリストはURLを読み取ってそれをパンくずリストに変換するというものなので、これを使った。

    パンくずリスト末尾に表示させるページタイトルはwordlist()ではなくcontroller側から取りたかったので、foreachにおいて最後だけ処理を変える必要があった。
    end()はポインタを配列の最後の要素を指すようにするものである。cf.reset()
    ここでeach()を実行すると、each()は「今指している要素のキー・値を返し次の要素へポインタを移す、ただし最後を指している場合はポインタを移さない」というものなので、最後のキーを取得するのに利用することが出来る。(別にその後まだポインタ操作が続くわけではないのでどこを指しているかはどうでもいいのだが) この話は【PHP】foreachで配列の最初と最後を判別する方法 - ysklogからのパクリ。多謝。

    こうして今配列の最後を指しているのかいないのかの判定が出来るようになり、foreach文が意図した処理をしてくれる。

    template.phpについて

    wordlist()内にある
    //パンくずにリンクを付ける場合
    $word = Html::anchor('manual/','MANUAL');
    

    だが、これを単純にtemplate.phpでechoした場合aタグがそのまま表示されてしまう。aタグの<や>が&lt;・&gt;として出力されてしまうからである。
    そこでhtmlspecialchars_decode()を利用して元に戻す。こうすることでaタグがaタグであると認識される。