YUI2.7.0+PHP5でメニューを自作する(その1)

YUI2.7.0とPHPを使って、以下のようなシンプルなメニューを作ってみたい。YUIに付属するメニューは、ちょっと好きになれない。

  • ログインしたユーザーに応じて、メニューの内容を変える。
  • 単純なツリー形式にする。
  • 画面にオーバーレイして出現する。

第1回目は、まず、最初の項についてプログラムを作ってみた。
「ユーザーに応じて」と書いたが、「ユーザーのロールに応じて」というのがありがちと思うので、まず、先のログインのサンプルで用いたusers.txtに「ロール」を追加した。

dummy@dummy.com,password,admin


これに応じて、先日のログで作成した、users.txtのためのPHPクラスを修正した。

<?php
/**
 * LoginTextDao.class.php
 * 
 * (C) 2009, tetsuya.odaka(EzoGP).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* 
 * users.txtのためのDao
 * 
 * 		author	;	t.odaka
 * 		date	;	2009/5/7
 * 
 * 		update	;	t.odaka users.txtへのRoleの追加による
 * 
 */
require_once('BaseTextDao.class.php');

class LoginTextDao extends BaseTextDao {
	/*
	* プロパティー 
	*/
	var $Email, $Password, $Role;

        /* 
	 * デフォルトのコンストラクタ 
	 */
	function __construct() {
		parent::__construct();
	}

	/* 
	 * Getter 
	 */
	function getEmail(){return $this->Email;}
	function getPassword(){return $this->Password;}
	function getRole(){return $this->Role;}
	
	/* 
	 * Setter 
	 */
	function setEmail($_str){$this->Email = $_str;}
	function setPassword($_str){$this->Password = $_str;}
	function setRole($_str){$this->Role = $_str;}
	
	/*
 	* findByUniqueKey
 	*   主キーをもとに、データを取得する。
	*   パラメータ
	*   $_fp	:	this->FileNameのファイルポインタ
 	*  	戻り値	:	見つかったらLoginTextDaoオブジェクト、なかったらnull.
 	*/
	function findByUniqueKey($_fp, $_key){
		
		while($_rarray = fgetcsv($_fp,1024)){
			if($_rarray[0] == $_key){
				$_retObj = new LoginTextDao();
				$_retObj->setEmail($_rarray[0]);
				$_retObj->setPassword($_rarray[1]);
				$_retObj->setRole($_rarray[2]);
				return $_retObj;
			}
		}
		return null;
	}
}
?>


前準備が終わったところで、スナップショット。以下は初期画面。


ログインした後は、そのログインユーザーのロールに応じたメニューを取得するようにする。メニューの内容はMarkup(リストとアンカー)で記述して、「ロール.txt」の名前でmenuディレクトリ下におく。ログイン前にメニューを表示する、ロールに応じたメニューの取得に失敗した場合にそなえて、default.txtというメニューファイルをおくことにした。以下は、default.txt。

<ul>
<li>DefaultList 0
	<ul>
		<li>List 0-0
			<ul>
				<li>item 0-0-0</li>
				<li>item 0-0-1</li>
			</ul>
		</li>
		<li>item 0-1
			<ul>
				<li><a target="_new" href="http://www.yahoo.co.jp" title="yahoo">Yahoo!</a>
					<ul>
						<li>item 0-1-0</li>
						<li>item 0-1-1</li>
					</ul>
				</li>
			</ul>
		</li>
	</ul>
</li>
</ul>


上にあるように、dummy@dummy.comには「admin」ロールを割り当てた。menu/admin.txtの内容は以下の通り。

<ul>
<li>AdminList 0
	<ul>
		<li>List 0-0
			<ul>
				<li>item 0-0-0</li>
				<li>item 0-0-1</li>
			</ul>
		</li>
	</ul>
</li>
<li>item 0-1
	<ul>
		<li><a target="_new" href="http://www.google.co.jp" title="google">Google</a>
			<ul>
				<li>item 0-1-0</li>
				<li>item 0-1-1</li>
			</ul>
		</li>
	</ul>
</li>
</ul>


以下は、dummy@dummy.comでログインする前に、Menuをクリックした際のスナップショット。このサンプルでは、「ロールごとのメニューを取得して、クライアントにフィードする」ことに主眼をおくので、画面下方に取得したメニューを表示する。


以下は、ログイン画面でdummy@dummy.comでログイン後、メニューを表示したもの。


以下にプログラムを掲載する。ここで作ったプログラムは3つ。

指定されたファイルを取得し、文字列として返却する TextPickup.class.php
Menuの表示要求をうけて、クライアントのログイン情報をもとに、Menu情報をクライアントにフィードする getMenu1.php
Menu取得のトリガーを引き、XHRで取得したメニューを表示する test_menu1.html


TextPickup.class.phpは、以前に作成した、BaseTextDao.class.phpをextendsして作成した。

<?php
/**
 * TextPickup.class.php
 * 
 * (C) 2009, tetsuya.odaka(EzoGP).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* 
 * Textファイルをピックアップするのためのクラス
 *   (注)ファイルのロック処理のため、呼び出し側から
 *       ファイルポインタをもらうことを前提にする。
 * 
 * 		author	;	t.odaka
 * 		date	;	2009/5/8
 * 
 */
require_once('BaseTextDao.class.php');

class TextPickup extends BaseTextDao {
        /*
	 * デフォルトのコンストラクタ 
	 */
	function __construct() {
		parent::__construct();
	}
	
	/*
 	* pickupText
 	*   指定されたテキストファイルを取得して、文字列にして戻す。
	*   パラメータ
	*   $_fp	:	this->FileNameのファイルポインタ
 	*  	戻り値	:	文字列に変換して返却.
 	*/
	function pickupText($_fp){
		require("../Myznala/debugLog.php");
		
		$_ret;
		while($_data = fgets($_fp,1024)){
			$m_log->debug('$_data: '.$_data); // Debugログ
			$_ret .= $_data;
		}
		$m_log->debug('$_ret: '.$_ret); // Debugログ
		return $_ret;
	}
}
?>


以下は、getMenu1.php

<?php
/* 
 * メニューの取得を行う
 *  メニューは、menu/下にユーザーロール別に存在する前提です。
 *      
 *		author	; t.odaka
 *		date	; 2009/5/7
*/
	require_once("TextPickup.class.php");
	require_once("LoginTextDao.class.php");
	
	// セッションの開始
	session_start();
	// SESSIONにEMailアドレスがあったらロールを取得する。
	if (isset($_SESSION['Email'])) {
		$pObj = new LoginTextDao();
		$pObj->setFileName('data/users.txt');
		// users.txtをopen.
		$fp = $pObj->fileOpen('r');
		$retObj = $pObj->findByUniqueKey($fp, $_SESSION['Email']);
		$pObj->fileClose($fp,'r');
		
		if($retObj == null) $role = 'default';	
		$role = $retObj->getRole();
	}else{
		$role = 'default';
	}
	
	// 取り出すメニューの名称
	$_menu = 'menu/'.$role.'.txt';
	if(!file_exists($_menu)) $_menu = 'menu/default.txt';
	
	// テキストの取り出し
	$ret = null;
	$tObj = new TextPickup();
	$tObj->setFileName($_menu);
	$fp = $tObj->fileOpen('r');
	$ret = $tObj->pickupText($fp);
	$tObj->fileClose($fp,'r');

	// 出力
	header("Content-Type:text/html");
	echo($ret);
	
	return;
?>


最後にJavascriptを含むHTMLの全文を示す。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> 
<head> 
	<meta http-equiv="Pragma" content="no-cache">
	<meta http-equiv="Cache-Control" content="no-cache">
	<meta http-equiv="Expires" content="Thu, 01 Dec 1994 16:00:00 GMT">
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
	<meta http-equiv="Content-Style-Type" content="text/css">
	<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>Login</title> 
 
<style type="text/css"> 
</style> 

<link rel="stylesheet" type="text/css" href="../scripts/lib/yui/build/fonts/fonts-min.css" /> 

<script type="text/javascript" src="../scripts/lib/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script> 
<script type="text/javascript" src="../scripts/lib/yui/build/connection/connection-min.js" ></script>

<style type="text/css" id="defaultstyle">
#main {
	margin: 2px;
	padding: 3px;
}

.ez_error {
	/* red(エラー用) */
	color:#ff0000;
}

</style>

<script type="text/javascript">

DisplayMenu = function() {
	var Event	= YAHOO.util.Event;
	var Dom		= YAHOO.util.Dom;

	/*
	* メニューリンクをクリックしたときのハンドラ
	*/
	var menuClickHdlr = function(){
		// メッセージのクリア
		Dom.get('msg').innerHTML = '';
		Dom.get('res').innerHTML = '';

		var _url	= 'getMenu1.php';
		var _arg ={
			'errId'	:	'msg',
			'resId'	: 	'res'
		};
		menuCallback.argument = _arg;
		// ajaxで検証
		YAHOO.util.Connect.asyncRequest('POST',_url,
						menuCallback);
	}
		
	/*
	* メニュー取得時のコールバック
	*/
	var menuCallback = {
    	        success : function(_obj) {
			var _resId = _obj.argument.resId;
			var _errId = _obj.argument.errId;

			// XHRの戻り値の取得(メニュー文字列)
			var _ret = _obj.responseText;

			// メニューの表示
			if(_ret.length > 0){
				Dom.get(_resId).innerHTML = _ret;
			}else{
	 			// エラーのハンドル(皆さん適当に)
				Dom.get(_errId).innerHTML = 'メニューの取得に失敗しました.';
			}
		},
		
     	        failure : function(_obj) {
 			var _errId = _obj.argument.errId;
 			var _ret = 'ステータス: ' + _obj.status + 'ステータステキスト: ' +
 						_obj.statusText + ' メニューの取得に失敗しました。';
 			// エラーのハンドル(皆さん適当に)
 			Dom.get(_errId).innerHTML = _ret;	     
 		}
	 };

	return{
    	init: function() {
		// ダイアログを表示するハンドラー
	        Event.on("menu", 
	    	       	"click", 
	    	       	menuClickHdlr);
		}
	};
}();

//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
	//DomReadyイベントで発火するハンドラ
	DisplayMenu.init,
	//ハンドラに渡すオブジェクト
	DisplayMenu,
	//ハンドラは、上記のオブジェクトのスコープをもつ。   
	true
);

</script>
</HEAD>

<BODY class="yui-skin-sam">
test_menu1.html
<br>
<div id="container">
<p>
ユーザーのロールに基づいてMenuを取得するサンプルです。<br/>
</p>
<a id="menu" href="#" class="my_menu">Menu</a>
<div id="msg" class=".ez_error"></div>
<div id="res"></div>

</div>
</BODY>
</HTML>