goo blog サービス終了のお知らせ 

ウィリアムのいたずらの、まちあるき、たべあるき

ウィリアムのいたずらが、街歩き、食べ物、音楽等の個人的見解を主に書くブログです(たま~にコンピューター関係も)

PHPでつくる、仕様書からのプログラム自動生成(その3:雛形ファイルの仕様)

2005-11-28 18:14:01 | PHP

前に書いた仕様書をCSVで書き出し、雛形ファイルを用意すると、仕様書の内容をいれて、プログラムが自動生成するという話。

■■ 手順的にはこんなかんじ
・仕様書をCSV書き出ししたものと、
・雛形を用意して、
   ↓
・このPHPを実行すると、
   ↓
・ブラウザ上に、雛形の指定したところへ、仕様書の値を入れて
 ソースを書き出す。

前のブログで、「このPHPを実行すると」のPHPと、それを呼び出す実行画面について、書いたので、今回は、「雛形を用意して」の雛形ファイルの書き方です




■■ 雛形ファイルのつくりかた

(1)てきとーにプログラムを書いてください
 もちろん、PHPプログラムでなくてもいいです。
 例には、SQLを示しましたが、JavaプログラムでもPHPプログラムでも、
 もちろん、一般的な文章、つまり、「あんたくび!」というドキュメントでもOKです。

(2)半角の< > &を、変換します
 雛形にある、< は <に > は >に & は &に変換したほうがいいです
 (なお、上の行の&は、本当は半角)
  
(3)ここで、あたまとおわりに、じゅもんをつけてください。
 頭に付ける呪文は、こんなかんじ
<?
//==============================//
//	文頭の呪文		//
//==============================//
	session_start();
	$data	=	$_SESSION['data'];
?>
<html>
<BODY>
<pre>

(上記の< >は、実際には半角です)

おわりにつける呪文はこんな感じ
</pre>
</BODY>
</HTML>

(上記の< >は、実際には半角です)

(4)CSVファイルのデータが入るところを指定します

・値が直接入るところには、
  <?=$data[0][1]?>のように
<?=$data[行番号][列番号]?>を指定してください
(どこも空白を空けないでください)

なお、はじめの行は0行目、列も0列目からはじまります
(1スタートでなく、0スタートです)


・繰り返しのところは
<?for($i = 開始行; $i < count($data) ; $i++){ ?>
<?}?>

で囲ってください。開始行のところは、データファイルで、繰り返し部分のところが
はじまる行を指定します。つまり、見出し行の次の行です。
(上記のなかで、実際に指定するのは、開始行だけです)

・繰り返しの中で、ある列の値を表示するには
 <?=$data[$i][列番号]?>
 として、行のところに$iを書きます。

・条件のときは、
<?if (条件文) { ?>
<?}else { ?>
<?}?>
でかきます。そうすると、条件文が成立したときに、かきだします。
(elseの行は、なくてもOK)
 条件式の中で、データファイルの値を利用するときは、$data[行番号][列番号]、繰り返しの中で利用するときは$data[$i][列番号]となります。

基本的にはこうなのですが、実は<? ?>のなかでは、好きにPHPプログラムを書いていただいて問題ありません

(5)そして、このファイルを保存して拡張子をPHPにします。




今、じかんがないので、データファイルの構造と、なぜこれで、自動生成するのかについて、この方法のメリットについては、今度の機会に書きます。



  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHPでつくる、仕様書からのプログラム自動生成(その2:操作画面の内容と、実行プログラム)

2005-11-28 17:35:07 | PHP

 先ほど書いた、仕様書をCSVで書き出し、雛形ファイルを用意すると、仕様書の内容をいれて、プログラムが自動生成するという話。

■■ 手順的にはこんなかんじ
・仕様書をCSV書き出ししたものと、
・雛形を用意して、
   ↓
・このPHPを実行すると、
   ↓
・ブラウザ上に、雛形の指定したところへ、仕様書の値を入れて
 ソースを書き出す。

ここで、「このPHPを実行すると」のPHPと、それを呼び出す実行画面について、以下に書きます。




■■ 実行画面について
 実行画面の様子は、こんなかんじ。
<form method="POST" action="makepro.php">
CSVファイル名:<input type="text" name="csvfname">  1行のバイト数:<input type="text" name="gyolen" value=1000><BR>
雛形ファイル名:<input type="text" name="hinafname">                
<input type="submit" name="submit" value="実行">
</form>

(上記の < > ¥ は、実際には半角です)

で、画面の様子は、ここの。。。と書こうと思ったら(>_<!!)

gooやってくれるな(^^;)

前のブログの例その1 の実行画面、
 編集画面では、フォームの形になっていたのに、それをエントリしたとたんに、ソースが書かれてる(>_<!) 

 これじゃ、みなさんには、実行画面のイメージがわかんないですよね。。

 具体的には、CSVファイル名、雛形ファイル名 1行のバイト数の入力エリアがあります。

 ここでCSVファイル名は(実際にはタブ区切りですけど)データファイル名、

 雛形ファイル名は、雛形として用意したファイル名を入れてください。

 1行のバイト数は、データファイルの最大の1行のバイト数なのですが、実際のものより、大きい分には問題ありません。




 ということで、実行画面は、入力フォームです。ここで、makepro.phpというのを呼び出しています。
makepro.phpというのは、何をやっているかというと、こんな感じのことをしてます
(といって、以下、ソースプログラムです)

<?
//======================================//
//	コントロール部分		//
//======================================//
	session_start();

		//======================//
		//	処理実行	//
		//======================//
	$VO = shori($VO);

		//======================//
		//	次の画面表示	//
		//======================//
	if ( $VO['nextJob']	==	"ERROR" )
	{	//	エラー時は、エラー画面
		$_SESSION['errmsg'] = $VO['errmsg'];
		header("Location:errmsg.php¥n¥n");
	}
	else
	{	//	正常時、雛形ファイルへ
		$_SESSION['data'] = $VO['data'];
		header("Location:".$VO['hinafname']."¥n¥n");
	}

//=======ここまで:以降は、関数を書いてます===============================//

?>

<?
//======================================//
//	処理部分			//
//======================================//
function shori($VO)
{
		//======================//
		//	データセット	//
		//======================//
	$VO['csvfname']	=	$_POST['csvfname'];
	$VO['gyolen']	=	$_POST['gyolen'];
	$VO['hinafname']=	$_POST['hinafname'];

		//======================//
		//	エラーチェック	//
		//======================//
	$VO['nextJob']	=	"OK";
	if ( $VO['csvfname']	==	"" )
	{
		$VO['nextJob']	=	"ERROR";
		$VO['errmsg']	=	"CSVファイル名の指定がありません";
		return $VO;
	}
	elseif ( $VO['hinafname']	==	"" )
	{
		$VO['nextJob']	=	"ERROR";
		$VO['errmsg']	=	"雛形ファイル名の指定がありません";
		return $VO;
	}
	elseif ( $VO['gyolen']	<=	0 )
	{
		$VO['nextJob']	=	"ERROR";
		$VO['errmsg']	=	"1行のバイト数の指定をしてないか、不正値";
		return $VO;
	}

		//======================//
		//	データ取得	//
		//======================//
	$file = fopen($VO['csvfname'],"r");
	if ( $file == "" )
	{
		$VO['nextJob']	=	"ERROR";
		$VO['errmsg']	=	"CSVファイルのオープンに失敗しました";
		return $VO;
	}

	$i = 0;
	while (($rec =fgetcsv($file,$VO['gyolen'],"¥t") ) != "" )
	{
		if ( count($rec) > 1 )
		{		//	セルが1つよりおおく存在
			$data[$i] = $rec;
			$i ++;
		}
		elseif ( ( count($rec) == 1 ) && ($rec[0] != "" ) )
		{		//	セルが1つだが、そのセルは空でない
			$data[$i] = $rec;
			$i ++;
		} 
	}
	fclose($file);
	$VO['data']	=	$data;

	return $VO;
}
?>

(上記の < > ¥ は、実際には半角です)

 つまり、shoriというところで、CSVファイルを読み込み(fgetcsvのところ、そこでいろいろやってるのは、改行だけの行があったときは、無視する処理)、それを'data'というところにいれて、最終的には、エラーならエラー画面に、そうでなければ、dataをセッションに入れて、雛形ファイル(じつはこのファイル、PHP形式で書くので、呼び出せる)を呼び出しているだけです。

 ??なんで、自動生成するのか?

っていう話ですが、それは、雛形ファイルの仕様について書いた後で、説明します。

 今回は、とりあえずここまで。

 次回、気が向いたら書く内容は、雛形ファイルの仕様についてです。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHPでつくる、仕様書からのプログラム自動生成(その1:操作方法と具体例)

2005-11-28 17:03:45 | PHP

 仕様書から自動生成を行うプログラムについて、前のブログでとりあげましたけど、今回(から?)、具体的に、その内容を書きます。
 今回は、はじめに、操作内容と具体例について。




■■ どういった内容か?
 こんな感じのことをします。

・仕様書をCSV書き出ししたものと、
・雛形を用意して、
   ↓
・このPHPを実行すると、
   ↓
・ブラウザ上に、雛形の指定したところへ、仕様書の値を入れて
 ソースを書き出す。




■■ わけわかんないので、例その1

・こんな、テーブル仕様書(CSVファイル)を用意します
テーブル名	HELLO_WORLD_TABLE	PRIMARY KEY	NO
名前	型	桁数(文字のとき)	NOT NULL
NO	INTEGER		NOT NULL
LANGUAGE	VARCHAR	50
MESSAGE	VARCHAR	100


で、こんな雛形ファイルを用意します。
<?
//==============================//
//	文頭の呪文		//
//==============================//
	session_start();
	$data	=	$_SESSION['data'];
?>
<html>
<BODY>
<pre>
CREATE TABLE <?=$data[0][1]?> (
<? for($i=2 ; $i < count($data);$i++){ ?>
<?	switch($data[$i][1])
	{
	case	"INTEGER":
		print("	" . $data[$i][0] ."	INTEGER	" .  $data[$i][3] . ",");
		break;
	case	"VARCHAR":
		print("	" . $data[$i][0] ."	VARCHAR(" .  $data[$i][2] . ") " . $data[$i][3] . ",");
		break;
	//	今回は、これ以外ないので省略
   	}
?>

<?}?>
	PRIMARY KEY(<?=$data[0][3]?>)

); 
</pre>
</body>
</html>

(上記 < > ¥ は、本当は、半角)

で、これらの雛形ファイルと、CSVファイル(本当はタブ区切りだけど)をサーバーにおきます。

そして、以下の実行画面で

値設定と実行


<form method="POST">
CSVファイル名:<input type="text" name="csvfname">  1行のバイト数:<input type="text" name="gyolen" value=1000>
雛形ファイル名:<input type="text" name="hinafname">                
<input type="submit" name="submit" value="実行">
</form>

で雛形ファイルと、CSVファイルを指定すると、

こんなもんが、画面にあらわれます。
CREATE TABLE HELLO_WORLD_TABLE (
	NO	INTEGER	NOT NULL,
	LANGUAGE	VARCHAR(50) ,
	MESSAGE	VARCHAR(100) ,
	PRIMARY KEY(NO)

); 


あとは、これを貼りこんで実行してください。
仕様書を、上記の形式で書くと、雛形は変えなくても、CREATE文が、同じように自動生成されます。
(つーことは、仕様書が何百もある場合は、「値を設定して、このプログラムを呼び出し、結果を保存する」というJAVAプログラムを書いてしまえば、どんなにあろうとも、ボタン1発、JAVAプログラムをよべばいいということ)




■■ 例その2:

で、こんどは、データをINSERTしましょう。

CSVファイルは、テストデータとして、こんな感じで用意しておきます
テーブル	HELLO_WORLD_TABLE
名称	NO	LANGUAGE	MESSAGE
型	INTEGER	VARCHAR	VARCHAR
1	1	"日本語"	"こんにちわ 世界"
2	2	"英語"	"Hello World"


で、雛形ファイルは、こんなかんじ
<?
//==============================//
//	文頭の呪文		//
//==============================//
	session_start();
	$data	=	$_SESSION['data'];
?>
<html>
<BODY>
<pre>
<? for($i=3 ; $i < count($data);$i++){ ?>
INSERT INTO <?=$data[0][1]?> ( <?
	for($j=1 ; $j < count($data[1]);$j++)
	{ 
		print $data[1][$j];
		if ( $j != count($data[1]) - 1 )
		{
			print ",";
		}
	}
?> ) VALUES( <?
	for($j = 1 ; $j < count($data[$i]) ; $j ++)
	{
		if ( $data[2][$j]	==	"VARCHAR")
		{
			print "'" . $data[$i][$j] . "'" ;
		}
		else
		{
			print $data[$i][$j];
		}
		if ( $j != count($data[1]) - 1 )
		{
			print ",";
		}
	}
?>);
<? } ?>
</pre>
</body>
</html>

(上記 < > ¥ は、本当は、半角)

で、さっきのプログラムを実行すると、こんなかんじで、データができる
INSERT INTO HELLO_WORLD_TABLE ( NO,LANGUAGE,MESSAGE ) VALUES( 1,'日本語','こんにちわ 世界');
INSERT INTO HELLO_WORLD_TABLE ( NO,LANGUAGE,MESSAGE ) VALUES( 2,'英語','Hello World');


あとはいれればいいだけ。
これは、CSVデータ部分を変えると(きまりはあるが)、
・このテーブルの一部のデータの自動生成はもちろんOKだし、
・それ以外のテーブルのデータの自動生成も、OKです。
(雛形は変えなくていい)




■■ 例その3
 じつは、さっきのブログのinsertToTbl($db,$data)、selectTbl($db)は、この方式で、例1のCSVファイル(テーブル定義)と、ある雛形を使って、自動的に作っている。
 ここでは、INSERT文とselect文しかないけど、delete,Update、selectもwhere句を使ったものなども、雛形を作って自動生成できる。




 あとは、同じように、ドライバ部分も雛形を作れば、自動生成して、すぐに、テーブル定義、DBアクセス関数、ドライバができて、テストできる。

 という話で、では、
・その実行画面と、
・そこから呼ばれるPHPプログラムと
・雛形の書き方
は、どーなっているのというのが、ここでのお話。

ただ、話がながくなったので、このへんでおしまい。

気が向いたら、第二話で実行画面と、そこから呼ばれるPHPを公開します。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHPのmysqliを使った、SQL文実行(prepareで)と検索実行(commitの話も)

2005-11-28 16:25:48 | PHP

 この話書きましたっけ?今、調べたら、このブログには引っかかるんだけど、ぜんぜん違うページがひっかかるので、ここに書いておきます。

■■ 前提となるテーブル
ここのテーブルを使わせてもらいます
SQL文を引用すると、こんなかんじ
CREATE TABLE HELLO_WORLD_TABLE (
	NO	INTEGER	NOT NULL,
	LANGUAGE	VARCHAR(50) ,
	MESSAGE	VARCHAR(100) ,
	PRIMARY KEY(NO)
); 


■■ やること
 以下のPHPプログラムを実行します。
 ここでは、
(1)DBをオープンします

(2)データをセットしてINSERTします
 →insertToTblという関数を呼び出します

(3)その結果を取得します
 →selectTblという関数を呼び出します

(4)DBをクローズします

(5)結果を表示します

これらを、PHPで書くと、以下のとおり
<HTML>
<BODY>
<?
	include("hello.php");

	//--------------------------------------//
	//	DB操作部分			//
	//--------------------------------------//

	//	DBのオープン
	//	ユーザー名などは、実際にあわせて、書き換える
	$db = mysqli_connect("localhost", "ユーザー名", "パスワード", "使用DB");
	if (!$db)
	{
		print("接続できませんでした");
		exit();
	}
	
	//	INSERTしてみる
	$data['NO']		=	3;
	$data['LANGUAGE']	=	"テスト語";
	$data['MESSAGE']	=	"Insertのテスト";
	insertToTbl($db,$data);

	//	結果を取得してみる
	$kekka = selectTbl($db);

	//	クローズ
	mysqli_close($db);

	//--------------------------------------//
	//	結果表示部分			//
	//--------------------------------------//
	print "<table border = 1>";
	for($i = 0 ; $i < count($kekka); $i ++ )
	{
		print "<tr>";
		for ($j = 0 ; $j < count($kekka[$i]) ; $j ++ )
		{
			print "<td>" . $kekka[$i][$j] . " </td>";
		}
		print "</tr>";
	}
	print "</table>"; 

?>
</BODY>
</HTML>

(上記中 < > ¥ は実際には、半角です)




■■それらを実現する関数
 prepareステートメントを使って、Insert実行の例が、
 insertToTbl($db,$data);のほう。

 検索のほうが
 selectTbl($db);

どちらも、利用前に、
$db = mysqli_connect(ホスト名, "ユーザー名", "パスワード", "使用DB");
で、DBのハンドルを取得しておく必要有(それを引数$dbとして渡している)
また、最後に
mysqli_close($db);
を行う。

プログラムは、このとおり
<?
	function insertToTbl($db,$data)
	{
		//	ステートメントの設定
		$sql = 'INSERT INTO HELLO_WORLD_TABLE (NO,LANGUAGE,MESSAGE) VALUES(?,?,?)';
		$stmt = mysqli_prepare($db,$sql);
		mysqli_stmt_bind_param( $stmt,"iss",$NO,$LANGUAGE,$MESSAGE);

		//	値設定
		$NO 	=	$data["NO"];
		$LANGUAGE 	=	$data["LANGUAGE"];
		$MESSAGE 	=	$data["MESSAGE"];
	
		//SQL文を実行する
		mysqli_stmt_execute($stmt);

		//ステートメントクローズ
		mysqli_stmt_close($stmt);

	}

	function selectTbl($db)
	{
		//SQL作成
		$sql = 'select * from HELLO_WORLD_TABLE';

		//SQL文を実行する
		$rs = mysqli_query($db, $sql);
		if (!$rs)
		{
			return $kekka;
		}

		$i = 0;
		while($row=mysqli_fetch_array($rs))
		{
			for($j=0;$j < count($row) ; $j++) 
			{
				$kekka[$i][$j] = $row[$j];
			}
			$i++;
		}

		//結果レコードをメモリから開放
		mysqli_free_result($rs);

		return $kekka;
	}
?>

(上記中 < > ¥ は実際には、半角です)




■■ つけたし
今回は、commit処理を行っていない。
する場合は、DBのハンドルを取得したのち

//オートコミットOFF
mysqli_autocommit($db, FALSE);

をして、コミットする場合は、
mysqli_commit($db);
ロールバックのときは
mysqli_rollback($db);
を発行する。




■■ なんで、こんなことをかくのか
 insertToTbl($db,$data);と、selectTbl($db);のテーブルごとの自動生成プログラムを例として、今度書くかもしれないので(このブログに)


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHPをWebだけでなく業務システムへ応用するケースと、その問題点と可能性

2005-11-26 12:20:46 | PHP

 日経システム構築の2005年12月号(最近きた、「緊急点検!Webアプリ・セキュリティ」の号)の128ページにヤナセの方が、

ユーザーが語るWebアプリケーション基盤の最適解 J2EEとPHPを適所で使う

 というのが出ています。

 で、そこによると(以下斜体部分は上記記事からの引用)

サーバー環境をUNIX/Linuxに絞った結果、大規模システムはJ2EE、中小規模の開発はPHPという判断に落ち着きました。

(中略)

 利用経験から言えば、PHPは画面(HTML)テンプレートで一歩優位、素早い開発に向く。その反面、高いレベルの情報が必要だし、技術者に不足感があります。


 ウィリアムのいたずらが、ちょこっとPHPを使った結果からみても、PHPは、Webだけではなく、業務システムの開発に向いていると思います。
 中小規模の開発(中小企業の開発ではない。あとで理由を述べる)ならば、Webで公開するためでなく、社内利用での業務システム開発のために使うのでも、向いていると思います。

 そういう意味では、将来的には、PHPベースでの業務システム開発というのも、あり!というか、結構使われるかもしれません。




 しかし、PHPで業務システムを今、開発するには、問題があると思います。

 ひとつは、PHPが、オープンなゆえの相性とバージョンアップの問題です。

 つまり、PHPをApache上で動かすとするとすると、Apacheが、かりに、5.0とか10.0とかバージョンアップしていったとき、PHPも、Apacheとの連携部分のモジュールを変えていかなければなりません(具体的にはphp5apache2.dllのことをさしてます。これが、php7apache10とかになるかもしれないということです)。

 さてこのとき、apacheの最新版に対して、PHPのすべてのバージョン(PHP3,PHP4...)が対応してくれるかどうか?ということです。

 もし、対応してくれないとすると、

・Apacheに何か問題があって、バージョンを上げないといけない(かりに10にしよう)。
・でも、今PHP3で開発していて、そのバージョンに対応するものが出ていない(PHP3apache10.dllがサポート外で開発されなくなった)。
・なので、PHPもバージョンアップということになった(ここでPHP6としましょう)
・しかしPHP3からPHP6へのバージョンアップは、(バグも含めた)完全な互換があるように作るかどうかわからない(とくにオープンシステムだと)
・そのため、PHP3ではうまくいくのに、PHP6では動かない!となってしまったとき、

急にプログラム修正が発生してしまいます。

費用発生です。でも、中小企業だと、その費用を急に出せといわれてもねえ。。

って問題です。




 この問題は、どこかのメーカーが、商用でPHPモジュールをつくってしまい(たとえば、InterStage PHPとかいって、富士通がPHP互換モジュールを自社で開発するとか)、下位互換を保つとか、あらかじめ、情報をサーチしておいて、サポート対象外になりそうだったら、バージョンアップ開発をしてしまうとかすれば、ある程度解消します。

 ただ、前者のように、どこかメーカーがだすとなると、結構なお金がかかりそうだし、後者の「情報をサーチして」というのは、中小企業の場合、自社にそういう部隊を作れないでしょう。

 じゃあ、ソフト屋さんと、顧問契約??っていうのもねえ。。あんまりなさそうだし。。

 そんなときこそ中小企業診断士と思うかもしれませんが、診断士でPHPを組む人がはたして何人いるか(ゼロではないことは、確信する。なぜなら、ここに1人いるから)。。。

 つーと、中小企業の開発向きのはずのPHPが、中小企業で採用すると、一番危険になってしまうのです(>_<!)

 ただ、大手企業の1部門でのちょっとした開発などでは、使われてくるかもしれません。

 あとは、PHPベースのパッケージソフトとかでてくれば、状況は変わると思いますけどね。。




 人の問題は、高いレベルを求めないのであれば、状況は、変わってくる可能性はあると思います。はじめ、食えないWeb系のプログラマさんやフリーの人(=ウィリアムのいたずら?)がはいっていき、それが広まれば、派遣会社でも、対応してくるんじゃないでしょーか?

 で、じゃあ、そうなる可能性は?というと、上記にもかいたように、PHPのパッケージソフト(有償のものでも無償のものでも)が出てくると、かなり違ってくると思います。

 そのパッケージソフトとして考えられるものは
・Accessのように、DB定義と作成、DB操作、帳票出力ができるソフト
 (DBはSQLLiteでPHPベースで記述)
・PHPから呼び出す、帳票作成SDK(PHPのクラス提供かなあ。。)
  →雛形とデータをいれて、PDFで出力
・ユニットテスト環境

ただ、これらのものが、PHPベースだと作りやすいこともたしかで、フリーで出る可能性もたかいですよね。。

え、「お前作れ」って

。。。形勢わるくなってきたんで、このへんで(^^;)


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

仕様書からのプログラム自動生成って、VBAで書くと大変だけど、PHPなら、楽勝かもお?

2005-11-25 17:32:14 | PHP

 現在実験中!のお話。

 Excelの仕様書から、Excel VBAで、Javaなり、いろいろな設定ファイルなり、テストデータなりを自動生成させるっていうことは、良くあると思います。というか、ウィリアムのいたずらの仕事の大半は、それです。

 で、この作業は、基本的にはこうなります。

(1)元データとなる、仕様書をExcelファイルで用意する

(2)自動生成する雛形(プログラムなり、スクリプトなり)を用意する。
  そこに、元データのどこがはいるかを、タグで指定する

(3)Excelで、雛形をよみこみ、タグが出てきたら、そのタグを解釈し、
   繰り返しなら繰り返す
   条件なら条件判定して、OKなら書き出す、NGなら書かない
   値をとってくる場合は、元データからとってくる
 というプログラムをマクロ(VBA)でつくる

(4)Excelの上記マクロを実行する。




 でもでもでも、ですよ。。。

(1)の元データって、実は、CSVでもぜんぜんOKなんですよ。

で、

(2)の雛形ファイル、これを、PHPでかく。

つまり、ソースコードのあたまに、
<?
//==============================//
//	文頭の呪文	  //
//==============================//
	session_start();
	$data	=	$_SESSION['data'];
?>
<html>
<BODY>
<pre>

(実際の<>は、半角)

って、かいちゃうわけよ。で、ソースプログラムを書く。
で、最後に
</pre>
</body>
</html>

(実際の<>は、半角)

 ってかくと、中身は、JavaやCなんかのソースプログラムなんだけど、PHPで扱える形式になるよねえ。。。
 なので、PHPファイルとして(拡張子phpで)保存しておく。

 もちろん、このとき、(Java等の)ソース中の(半角の)< > &は、 &lt; &gt; &amp;(&は、本当は小文字)に、「すべて置換」しておくこと。(じゃないと、タグと思われて、異常終了になってしまう)

そうすると

(3)のプログラムは、CSVファイルを読み込み、雛形PHPファイルを解釈して、ソースを書き出すっていうことだよねえ。。。

 ところが、PHPを使えば
 ・CSVファイルを読み込んで、
 ・今まで説明したように、その内容をセッションに入れる。
 ・そして、雛形ファイルをLocationで設定して呼び出すと。。。
 ・呼ばれた雛形ファイルは、
    セッションの中に入っている元データをもとに、
    ソースを(展開して)作成するよねえ
    →つまり、プログラムを自動生成する。。よねえ。。




おお、そうすると、
(1)元データをCSVで用意して、
(2)雛形ファイルをPHPで、
    上記呪文部分と、
    値を出力する部分を<?=data[1][2]?>のように指定
    条件部分(IF文を書く)
    繰り返し部分
     <?for($i = 5 ; $i <count($data) ; $i++){?>とか書くのと    を指定して用意し、
(3)はじめのフォームからCSVと雛形のありかを指定し、
(4)サーバーで、CSVファイルを読んで、雛形をLocationで呼び出すPHPプログラム(これは汎用的に使える)を書けば、

もう、なんでも、自動生成できるじゃん!

 すげー、Excelなんかだと、このタグを解釈する部分のプログラムが難しい(IF文や繰り返し処理などが難しい)んだけど、PHPなら、そこの部分を書く必要がない(PHPのエンジンがやってくれるので)から。。。数十行でかけちゃう!(Excelだと、数百行、や千行以上になってくる)

 おおおお




 というのを、今実験中です。上の意味がわかんなかった人でも、実験結果をみれば、分かってもらえると思います。現在、普通のファイルの自動生成はOKなんですけど、今度は、実際のプログラムを雛形にして、テストしてみるつもりです(実際の説明のときのサンプルは、この実験したものと異なり、もっとわけりやすいのにすると思いますけど)

以上、現在ウィリアムのいたずらが、研究中の中間報告でした

P.S 本当のことを言うと、今日、これを書こうと思って、つくってたんだけど、テストが終わらなかったのです。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

コントローラーに、起動するプログラムの情報を持たせる方法

2005-11-24 15:29:59 | PHP

 きのうのブログで、PHPなどでMVCを行う方法について書きました。
 PHPなど、と書いたのは、実はこのやりかた、PHPじゃなくってもかまいません。
 画面表示部にあたるVIEWをJSPで書いて、処理部分をサーブレットやCGIでも、OKです。

 で、昨日までのやり方だと、コントローラーは、処理部分や、画面から指定されたURL先に、そのままジャンプしているだけです。言い換えると、コントローラー側では、次に起動するプログラムの情報はありません。
 このことは、いい場合もあります。たとえば、開発のはじめの時期において、どのような画面構成にするかどうかが決まっていない場合でも、部分的にでも決まっていれば、呼び出せることや、全体像について誰も知らなくても、このシステムなら、次の処理先さえ分かれば、問題なく処理できるからです。

 でも、逆に、コントローラーに、次に遷移する画面を、すべて登録しておいて、コントローラーさえ見れば、このシステムで、どのようなプログラムを使うのか、すべて把握したい場合もありえます。
 今回は、そのようなコントローラーで、すべての遷移プログラム情報を保持するケース(カオル姫-テンさん方式(集中)についてです。




 この場合、昨日の例では、nextURLに次に遷移するURLを書いていましたが、
 今回は、nextJobに、次にうつる仕事の指定(処理なのか、正常画面なのか、エラー画面なのか)を指定します。
 そして、コントロールを呼び出し、コントロールは、nextJobの値をみて、処理なり、各種画面なりに遷移するというものです。

以下、具体例で説明します。例の内容は、昨日のブログとおなじく、伝言板です。



■■ 具体例

● コントローラーのようす
 まずは、一番大きく変わる、コントローラーについて
<?
//==============================================//
//						//
//	コントローラー(nextJobで飛び先決定)	//
//						//
//==============================================//
	//	セッションをスタートさせる
	session_start();

	//	引数をセッションにいれる
	foreach($_POST as $key => $val)
	{
		$_SESSION[$key] = $val;
	}
	foreach($_GET as $key => $val)
	{
		$_SESSION[$key] = $val;
	}

	//	次のURL(VIEWまたはモデル)へ遷移

	if ( $_SESSION['debug_mode'] == "YES")
	{	//	デバッグモードのときには、デバッグ用画面
		$headwd = "Location:debug.php¥n¥n";
	}
	else
	{	//	それ以外のときは、次のURL画面
		switch($_SESSION['nextJob'])
		{
		case	"OK":
			$headwd = "Location:OK_shutyu.php¥n¥n";
			break;
		case	"SHORI":
			$headwd = "Location:shori_shutyu.php¥n¥n";
			break;
		default:
			$headwd = "Location:NG_shutyu.php¥n¥n";
			break;
		}
	}
	header($headwd);
?>

(上記の < > ¥ は実際には、半角のものを使ってください)
前のものと変わっているのは、次のURL指定、nextJobの値によって、遷移先を変えています。


●呼び出し側
 はじめに、フォームにユーザー名を入力し、コントローラーを呼び出すHTML画面は、こんな感じです。
<HTML>
<HEAD><TITLE>てすとだぴょん</TITLE></HEAD>
<BODY>
<Form action="ctl_shutyu.php "method="post">
    <input type="hidden" name="nextJob" value="SHORI">
    Name:  <input type="text" name="username"><br>
<input type="submit" name="submit" value="実行">
</form> 

(上記の < > ¥ は実際には、半角のものを使ってください)

前のnextURLのかわりに、nextJobで、次の画面を指定してます。
あと、actionの呼び先が変わってますが、これは、たまたま呼び先を変えたから、こうなっただけです。他には、基本的に変わってません。

●処理(モデル部分)について
 処理についても、同様で、違いはnextURLがnextJobになったこと、飛び先が変わったことだけです。
 こんなかんじ。
<?
//==============================================//
//						//
//	伝言設定処理部分			//
//						//
//==============================================//

  	//	セッション開始
	session_start();

	//	データセット
	//	本当は、DB検索とかをする
	$rec['simei'] = "社長";
	$rec['naiyo'] = "健康に注意して馬車馬のように働け";
	$data[1] = $rec;

	$rec['simei'] = "部長";
	$rec['naiyo'] = "オレの給料を上げるため、お前らは死ぬほど働け";
	$data[2] = $rec;

	$rec['simei'] = "係長";
	$rec['naiyo'] = "あのー、できないことを要求されても、できません";
	$data[3] = $rec;

	$_SESSION['dengon'] = $data;

	//	次のURLを設定
	if ( $_SESSION['username'] == "課長" )
	{
		$_SESSION['nextJob'] ="OK";
	}
	else
	{
		$_SESSION['nextJob'] ="NG";
	}

	//	コントローラーに戻す
	header("Location:ctl_shutyu.php¥n¥n");
?>

(上記の < > ¥ は実際には、半角のものを使ってください)

●画面(VIEW)について
 今回変わったところは、nextURLがnextJobにかわったことと、処理先です。
 よって、これらを使わない、表示だけの画面(正常画面OK.php)は、変更はありません。
 入出力を行うエラー画面のみ、nextJobの指定方法と処理先が変わります。
 こんなかんじ

<?
//==============================================//
//						//
//	NG画面(もう一度再入力)		//
//						//
//==============================================//
	session_start();
?>
<HTML>
<BODY>

<h1><font color="red">入力した名前は間違えています</font></h1>

<Form action="ctl_shutyu.php "method="post">
    <input type="hidden" name="nextJob" value="SHORI">
    Name:  <input type="text" name="username" value="<? print $_SESSION['username']?>"><br>

<input type="submit" name="submit" value="実行">
</BODY>
</HTML>

(上記の < > ¥ は実際には、半角のものを使ってください)




 ということで、これで、一通りの画面とプログラムの分離方法について、ご披露いたしましたが、

 じゃあ、これを使おうか?となると、実際は。。。

 というお話を、覚えていたら、気が向いたときにします。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHPで、MVCにわけ、処理、画面別々に、ユニットテストを行う例と、方法

2005-11-23 20:03:40 | PHP

 前のブログ PHP等でMVCにわけて、アジャイルっぽく開発できるようにするためのコーディング方略と例 で、カオル姫-テンさん方式(分散)、つまり、
 ・コントローラーをいれて
 ・画面部分と処理部分をわけ
 ・画面部分は、セッションの中身を表示するだけ
 ・処理部分は、画面表示内容をセッションに設定して、コントローラー呼び出し
の方法を示しました。

 で、今回は、その方法で、画面だけ、あるいは処理部分のPHPプログラムだけをテストする、ユニットテストの方法をしめします。




■■ 方略
 どうやって、ユニットテストをやるかということについて、画面(VIEW)と処理部分(モデル)とにわけて説明します。

●画面の場合
 ドライバ側で、セッションに、表示する値を設定して、
 headerで、画面のPHPを呼び出します。
  →セッションに設定した値が表示されるはずです。

●処理部分の場合
 ドライバ側で、セッションに、処理に必要な値を設定して、
 セッションのdebug_modeに"YES"を設定して、
 headerで、その処理PHPを呼び出します。
 →かならず、コントローラーにもどることになります。
  で、コントローラーでは、debug_modeがYESの場合は、nextURLの値にかかわらず
  debug.phpを呼び出しますので
 debug.phpで、セッションの中身を表示すれば、OKです。

ということで、ドライバとdebug.phpを作成し、ドライバから、値をセッションに設定、debug_modeをYESにして、画面なり、処理するPHPを呼び出せば、デバッグできそうです。




■■具体例

 では、今回は、処理プログラムshori.phpをテストしてみます。
 処理のテストの場合は、ドライバとdebug.phpを用意すればOKです。

●ドライバ側

 以下のようなドライバ側のPHPを作成します。
<?
//==============================================//
//						//
//	テストドライバ				//
//						//
//==============================================//

	//	セッション開始
	session_start();

	//	値設定
	$_SESSION['username']	=	"課長";
	$_SESSION['nextURL']	=	"shori.php";

			//	デバッグモードで
	$_SESSION['debug_mode']	=	"YES";

	//	機能呼び出し
	header("Location:shori.php¥n¥n");

?>

(上記の < > ¥ は実際には半角です)

 セッションをスタートし、データをセット、デバッグモードをYESにして、処理プログラムを呼び出します(コントローラーではありません。処理プログラムshori.phpを呼び出してくださいね)

● デバッグ表示用(debug.php)

 以下のようなデバッグ表示用のPHPを作成します。
<?

//////////////////////////////////////////////////////////
//	ここで使う関数					//
//////////////////////////////////////////////////////////

	//==============================================================//
	//	関数:print_dispdata					//
	//	内容:表示します					//
	//	引数	$data	表示するもの				//
	//		$mae	表示時、行の前の文字(スペース)	//
	//==============================================================//
	function print_dispdata($data,$mae)
	{
		foreach($data as $key => $val)
		{
			if ( is_array($val)	==	true)
			{
				print $key . "は、配列<BR>";
				print_dispdata($val,$mae . " ");
			}
			else
			{
				print $mae . $key . ":" . $val . "<BR>";
			}
		}
	} 
?>

<?
//////////////////////////////////////////////////////////
//	プログラム開始					//
//////////////////////////////////////////////////////////
	session_start();

?>

<html>
<head><title>テスト結果</title><head>
<body>

<h3>テスト結果</H3>
<? 
	print_dispdata($_SESSION,"");
?>

</body>
</HTML>

(上記の < > ¥ は実際には半角です)

 表になっているところは、配列なので、配列の場合は、キーと中身を再帰的に表示するようにしています。

 あとは、前のブログ で作成したファイル(コントローラーctl.phpとshori.phpが必要)を用意しておきます。

 そして、ドライバ用として作成したファイルを開いてください(http://127.0.0.1/ドライバ用ファイル.php のように、httpプロトコルのURLを入れて呼び出してね。C:¥program files¥なんとかかんとかみたいなかんじのファイル形式で呼び出さないでね!!ファイルをIEにドロップしても、ファイル形式になってしまうので、プログラムが見えるだけだよ!!)。

こんなかんじで、処理結果が見えます

テスト結果

username:課長 nextURL:OK.php debug_mode:YES dengonは、配列 1は、配列   simei:社長   naiyo:健康に注意して馬車馬のように働け 2は、配列   simei:部長   naiyo:オレの給料を上げるため、お前らは死ぬほど働け 3は、配列   simei:係長   naiyo:あのー、できないことを要求されても、できません





 で、実際には、ユニットテストだけでなく、ある程度処理をまとめて、結合してテストしたいわけです。その場合、画面表示までやるのであれば、デバッグモードをYESにしないで、テストすればいいし、いくつかの処理をさせたあとで、表示させたければ、コントローラー(ctl.php)の

if ( $_SESSION['debug_mode'] == "YES")

のところを、

if ( $_SESSION['nextURL'] == とめたいURL)

 のようなかんじで、nextURLに、とめたいURLの値がセットされていたら、debug.phpを表示するように書き換えればOKです。そこまでの処理結果がdebug.phpで表示されます。




 ということで、テスト方法についても書いたので、
 つぎは、コントローラーで集中管理する方法(カオル姫-テンさん方式(集中))です。
(覚えていて、気が向いたら)



  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHP等でMVCにわけて、アジャイルっぽく開発できるようにするためのコーディング方略と例

2005-11-23 13:37:03 | PHP

 PHPで、画面と処理部分に分けるお話で、ちゃんとコントローラーをいれることにより、ユニットテストもできるようにするためのコーディング規約、
 つまり、カオル姫-テンさん方式について、ここにご披露いたします。

 今回は、カオル姫-テンさん方式の分散のほう、つまり、コントローラーは、汎用的で何にでも使えるが、コントローラーをみても、次の画面については、なにもわからない(次の画面指定は、VIEWやモデルで指定する)について、具体例を示して、説明します。
 なお、今回は、テスト部分は、説明しません。ユニットテストの方法は、次回以降、気が向いたときにします。
 で、この方法は、ちょっとひねると、CGIでも、なんにでも使えるはずっす。




■■ 方法の概略
 この方法の概略は、こんなかんじ
・はじめのフォーム入力画面で、
  FormのAction先をコントローラーに指定します
  input type="hidden" name="nextURL"で、valueに、処理を行う(モデルとなる)
  URLを指定します。

・コントローラーは、
  セッションをスタートし、
  フォームの値等、$_POST,$_GETに入っている値をセッションに入れて
  セッションのnextURLで指定されたURLへ、遷移する
   →nextURLには、次の処理先や、遷移したい画面(VIEW)が入ってる

・処理プログラム(モデル部分)は
  セッションの値をもとに、DBアクセスなどをして、
  次の処理や表示する画面をきめて、セッションのnextURLに、URLをセット
  次の処理で使う値や、画面に表示する値をセッションに入れて
  headerのLocationにコントローラーのURLをセットし、
   コントローラーに戻る。
   →コントローラーに戻った後は上記のコントローラーの処理で
    nextURLに指定した画面または、次の処理へ遷移する

・画面では、セッションをスタートし
  動的部分に関しては、セッションの値をもとに、表示する
  なので、基本的に、foreachと、printくらいしかない。

という感じになります。




■■ 具体例
 では、以下に具体例をしめします。
 今回は、こんな伝言板を考えます。

 1.画面から、ユーザー名をいれます。
 2.ユーザー名が課長でなければエラー画面(再入力)
   課長なら、伝言をセットします
 3.エラー画面は、ユーザー名が再入力できて、2へ行きます
   正常画面は、伝言を表示します。

 では、以下、ソースを示します。




●はじめの、ユーザー名入力画面
ユーザー名入力画面は、こんなかんじ。
<HTML>
<HEAD><TITLE>てすとだぴょん</TITLE></HEAD>
<BODY>
<Form action="ctl.php "method="post">
    <input type="hidden" name="nextURL" value="shori.php">
    Name:  <input type="text" name="username"><br>
<input type="submit" name="submit" value="実行">
</form> 

(上記の< > は、実際には、半角です)

FORMのactionに、コントローラー(ctl.php)を指定し、
inputのhiddenで、nextURLに、処理プログラム(shori.php)を指定しています。

●コントローラー
 コントローラーは、今回のプログラムにかかわらず、どれも同じです。
<?
//==============================================//
//						//
//	コントローラー(どんなときでも共通)	//
//						//
//==============================================//
	//	セッションをスタートさせる
	session_start();

	//	引数をセッションにいれる
	foreach($_POST as $key => $val)
	{
		$_SESSION[$key] = $val;
	}
	foreach($_GET as $key => $val)
	{
		$_SESSION[$key] = $val;
	}

	//	次のURL(VIEWまたはモデル)へ遷移
	if ( $_SESSION['debug_mode'] == "YES")
	{	//	デバッグモードのときには、デバッグ用画面
		$headwd = "Location:debug.php¥n¥n";
	}
	else
	{	//	それ以外のときは、次のURL画面
		$headwd = "Location:" . $_SESSION['nextURL'] . "¥n¥n";
	}
	header($headwd);

?>

(上記の< > ¥ は、実際には、半角です)

 セッションを開始し、$_POST,$_GETの値(フォームの値)を、$_SESSIONにいれ、nextURLで指定されたURLに遷移します。なお、デバッグモードに関しては、次回以降で説明します。

●処理プログラム(モデル)
 モデル部分は、こんなかんじです
<?
//==============================================//
//						//
//	伝言設定処理部分			//
//						//
//==============================================//

  	//	セッション開始
	session_start();

	//	データセット
	//	本当は、DB検索とかをする
	$rec['simei'] = "社長";
	$rec['naiyo'] = "健康に注意して馬車馬のように働け";
	$data[1] = $rec;

	$rec['simei'] = "部長";
	$rec['naiyo'] = "オレの給料を上げるため、お前らは死ぬほど働け";
	$data[2] = $rec;

	$rec['simei'] = "係長";
	$rec['naiyo'] = "あのー、できないことを要求されても、できません";
	$data[3] = $rec;

	$_SESSION['dengon'] = $data;

	//	次のURLを設定
	if ( $_SESSION['username'] == "課長" )
	{
		$_SESSION['nextURL'] ="OK.php";
	}
	else
	{
		$_SESSION['nextURL'] ="NG.php";
	}

	//	コントローラーに戻す
	header("Location:ctl.php¥n¥n");
?>

(上記の< > ¥ は、実際には、半角です)
セッションをスタートし、表示する値などを取得、セッションに設定して(本当はDBからとってきたりするんですけど、ここでは、固定値を入れます)値によって、次の処理や画面を決定して、nextURLに設定し、コントローラーに遷移します。

●画面表示部分(VIEW)

まず、エラー(NG)画面は、こんなかんじです
<?
//==============================================//
//						//
//	NG画面(もう一度再入力)		//
//						//
//==============================================//
	session_start();
?>
<HTML>
<BODY>

<h1><font color="red">入力した名前は間違えています</font></h1>

<Form action="ctl.php "method="post">
    <input type="hidden" name="nextURL" value="shori.php">
    Name:  <input type="text" name="username" value="<? print $_SESSION['username']?>"><br>

<input type="submit" name="submit" value="実行">
</BODY>
</HTML>

(上記の< > ¥ は、実際には、半角です)

 画面表示なので、セッションをスタートさせ、printで値をセッションから取り出し、表示しています。同時にこの画面は(再)入力画面なので、はじめに取り上げた入力画面同様、FORMのactionをコントローラーにして、処理先(shori.php)を、input のtype=hidden name=nextURLで設定しています。

 正常(OK)画面は、こんなかんじです。
<?
//==============================================//
//						//
//	OK画面(伝言表示)			//
//						//
//==============================================//
	session_start();
?>

<HTML>
<BODY>

<? print $_SESSION['username']?>さんへ<p>

今日の伝言<p>
<table border=1>
<? foreach($_SESSION['dengon'] as $rec){ ?>
<tr><td><? print $rec['simei'] ?></td><td><? print $rec['naiyo'] ?></td></tr>
<? }?>
</table>
</BODY>
</HTML>

(上記の< > ¥ は、実際には、半角です)
 
 セッションをスタートし、セッションの内容をprintで表示しています。




 ということで、ここまででも、結構長くなってしまったので、プログラム規約のまとめや、テスト方法に関しては、記事を改めて書きます。

  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

画面とプログラムを分けても、コントローラーがないと、テスト&解析しにくい

2005-11-22 21:23:57 | PHP

 前のブログで、PHPで画面とプログラム部分を分けて書く方法(プログラム規約)を書きました。

で、今回は、その具体的例を示そうとおもったんだけど、

 それって、前に書いたブログ、PHPで、別のPHPや画面を呼び出す、あるいはエラー画面と正常画面を切り分ける方法 と、基本的に同じなので、(あとはbunki_cnt.phpで、セッションに値をいれて、その値を画面で表示すればいいだけ)その例は、今回は省略します。
 ホームページかなんかに、まとめたら、そのとき例を書くと思います。

 で、今回は、このやり方(画面とプログラムを分けるけど、コントローラーがない。カオル姫方式)の問題点として、テストしにくかったり、解析しにくいことを、上記ブログの例から示します。




 上記のブログで示した例について、まとめると、こんなかんじです

・ユーザー名を入れる画面を用意する(項目名:username)
・処理するプログラムのPHP(bunki_cnt.php)で処理を行い
   (例にはその部分はありませんが)画面に表示する値を取得、セッションに入れて
   その処理結果によって、headerのLocation指定で、次の画面を決める
     ここでは、usernameがgoodmanなら次の画面(OK.htm)
     そうでなかったら、エラー画面
・表示画面(例はhtmですけど、本来はPHP)では、そのセッションの中身を表示する。




■■ この方法の問題点。
 では、処理部分(bunki_cnt.php)のテストをしましょう。といったときなのですが、結果として、OK.htm,NG.htmのどちらが表示されるので、この両方とも、用意しないといけません。
 今回は処理が簡単ですし、画面も2つだからいいのですけど、これが、複数画面になってしまうと、全部の画面をあらかじめ用意して、で、その画面では、セッション内容を表示できるようにして。。。となったら、テスト負担が大きくなり、結局、全部できてから、流しで行うっていうことになってしまいます。




■■ この問題の改良法(なにもしないようでも、コントローラがいるわけ)
 で、それを防ぐには、どうしたらいいか、つまり、画面を用意しなくても、テストドライバだけで、モジュールテストするには、どうしたらよいか?ということなのですが、これは、
必ず、コントローラーに戻して、コントローラーが、次画面を表示するようにすれば、問題は解決します。

 つまり、上記の例をこのように修正します(太字の部分が修正箇所)
・ユーザー名を入れる画面を用意する(項目名:username)
・画面から、コントローラーを呼び出す
・コントローラーは、画面項目をセットし、処理するプログラムを呼び出す

・処理するプログラムのPHP(bunki_cnt.php)で処理を行い
   (例にはその部分はありませんが)画面に表示する値を取得、セッションに入れて
   その処理結果によって、セッションのnext_URLに表示したい画面のURLをセットする
     ここでは、usernameがgoodmanなら次の画面(OK.htm)
     そうでなかったら、エラー画面
   そして、コントローラーを呼び出す
・コントローラーは、next_URLの値をもとに、headerのLocationで表示画面を呼び出す

・表示画面(例はhtmですけど、本来はPHP)では、そのセッションの中身を表示する。

というかんじで、コントローラーにかならず戻るようにすると、この処理部分のユニットテストを行うには、

・ユニットテスト用コントローラーを作成する。
 そのコントローラーは、入力時のセッションの値をログなりどっかに出力
 出力時のセッションの値をログなりどっかに出力しておしまい
(画面表示はしない。次の画面は、セッションの値を出力しているので、そのnext_URLの値をみて、ただしくセットされているかどうか判断する)

・テストドライバとして、引数をセットして、そのユニットテスト用コントローラーを呼び出して、単体テストする。

・実際の時には、本番用コントローラーにきりかえる。そうすると、next_URLの値をもとに、表示画面へ遷移する。

みたいなかんじで行えます。




 で、この例にかぎらず、というか、PHPの話に限らず、コントローラーっていうのは、なーんにもしてないことも多いんですけど、必ずそこをとおる!というところがあると、便利だったりします。

 で、気が向いたら、このコントローラーを使った、まさにPHPでMVCを実現する方法について、書きます。で、このコントローラーつきのものを、カオル姫-テンさん方式とよびます。
 なぜ、テンがつくのかは、バレーづきの人にきいてください。
 このまえのJTのテレビCMと、
 「かならず、コントローラーにもどす」このコントローラーをセッターに言い換える。
 といえば、延々と、説明してくれる。。はずです。

P.S バレーとは、バレーボールのことで、踊るほうではない。女子バレー好きの人に聞いてね。

 

  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHP等で画面とプログラムを分離する(処理結果で画面分け:カオル姫方式)

2005-11-22 17:35:04 | PHP

 実際に、画面とプログラムを分離する際、プログラムの処理結果によって、画面を分けたい場合、

・コーディング規約だけで、特段のことを使わず
・さらに、アジャイルっぽく、テストファーストやモジュールテスト可能で
・もちろん、分業可能なようにするには?

どういう規約にすればいいかについて、書きます。

(なお、「カオル姫」で、このページに来ちゃった人、このページには、カオル姫のCM情報しかないです。>_<! ごめんなさい。CM情報は、このページで、1箇所だけ、リンクになっているところ)。

 この方法、3通りあります。
 1つは、コントローラーを使わないもの
 2つめは、コントローラーを使い、
   コントローラーが次に処理するプログラムや、画面を決める方式
 3つめは、コントローラーを使うものの、
   次に処理するプログラムや、画面はコントローラーが決めるのでなく、
   コントローラーを呼び出す側がきめるもの

 についてです。
 なぜ、3番が必要かは、3番について書くことがあったら、そのとき、覚えていて、気が向いたら書くことでしょう。

 なお、ここでは、以下、省略して
  1番の方法を、カオル姫方式
  2番の方法を、カオル姫-テンさん方式(集中)
  3番の方法を、カオル姫-テンさん方式(分散)と書きます。
 なんで、こんな名前にしたかは、あとで、書きます(このブログの中に書かれることでしょう)。

 今日は、カオル姫方式のご披露です。




 PHPで、プログラムと画面を分ける事は、意味があります。

 それは、デザイナー部分と、プログラマーの作成部分を分けるということもあるし、画面が来る前に、プログラム部分をテストしたり、プログラム部分ができてないとき、画面部分を先にテストできるからです。

 さらに、業務上の要請からもあります。

 業務において、こんなケースが考えられます。
  支払いが
   ・銀行振り込みのときは、何も処理しない
   ・カードのときは、与信チェック
     エラーのときは、エラー画面表示
  その後、なんかいろいろ処理して
  正常のときは、同じ「正常処理」画面をだしてね!

 といったように、エラー画面が出るか、正常画面が出るか分からない(与信チェックしないとわかんない)、かつ、場合によって、処理内容が違う。そして、1つ1つの処理は長い。でも、最終的には同じ画面を出すといったかんじ。

 こういう、処理結果によって画面が変わるとか、ある値によって、処理が違うといったときも、
   1画面1PHPプログラム、
   1処理1PHPプログラム
 にして、分離したいわけです(そーしないと、ものすごい量のプログラムになる)。

 で、どうするか。。。




そのとき、こういうコーディング規約にします。

■■ 画面側(VIEW)
・デザイン部分をあらかじめ作成しておきます。そして、動的に値が変わるところは、なにか、マークを入れておきます。
・はじめに、sessionをスタートさせます。
・セッションの中に、入っている値を表示します。
   項目名1つに、1つの値が入っているときはそのままprint、
   項目名が、複数レコードで、1レコードにいくつかの項目がある場合は、
   foreach(@_SESSION[項目名] as $rec) で1レコードぷん取り出すのを繰り返させ、
     その繰り返しの中で、 print $rec[カラム名] で値を表示する。
・デザイン時、動的に値が変わるところに、マークを入れてもらい、
 上記の書き換えを行う。

■■ 処理側(プログラム部分)
・Viewがクリックされた場合、処理用のPHPプログラムを呼び出す
・そのプログラムでは、画面表示するとき、動的に値が変わるところは、セッションの中に入る
・最後に、さらに処理が続く場合は、headerのロケーション指定で、次の処理を、
  VIEWで表示したい場合は、headerのロケーション指定で、VIEWのPHPを呼び出す

という形になります。




 つまり、イメージ的にいうと、

・プログラムの処理部分と、VIEW部分を、完全にPHPプログラムをわけてしまい、
・クリックしたときには、プログラムの処理部分を呼び出す。
・で、処理中に、表示したい値をセッションに入れて
・最後に適切な(画面表示したい)VIEWをheaderのLocationで呼び出す
・呼び出されたVIEWは、セッションの値を表示する

といったかんじ。




 この例を、先ほどの「業務において、こんなケースが考えられます」と挙げた例で書くと、

・画面入力後、「銀行振り込み・カード振り分け」PHPをForm のActionから呼び出す。

・銀行振り込み・カード振り分けPHPは、
   銀行振り込みのとき、「なんかいろいろ処理して」PHPを呼び出す
   カードのとき、カード処理PHPを呼び出す
 呼び出し方は、この前のブログに書いた、hederのLocationで

・カード処理PHPは、処理をして
   エラーだったら、表示に必要なものをセッションにセットして、
      エラー画面(VIEW)を呼び出す
   OKだったら、「なんかいろいろ処理して」PHPを呼び出す
 呼び出し方は、この前のブログに書いた、hederのLocationで

・「なんかいろいろ処理して」PHPは、いろいろ処理して、セッションに表示内容をセット
 最後に、「正常画面」PHP(VIEW)を呼び出す
 呼び出し方は、この前のブログに書いた、hederのLocationで

・呼び出された「正常画面」PHPや「エラー画面」PHPは、セッションから値を取得して
 それを表示する。

てなかんじになる。




 で、今CMで、これを見える化??したものがテレビのCMで、流れている。

 JTのCMで、バレーボールのやつ(ここ

 このCMで、バレーボールがセッションだと思ってください。

 このボールをカオル姫(菅山かおる選手、一番左上)が受け取って、次々に選手、さらに、工場や、運送のおにーさん、タバコ屋のおじさんがつないでいき、最後に、アタッカーがボールを打ちますよね。

 ここで、アタッカーは、境界、バウンダリになるので、Viewつーか、画面になります。
 その間の人は、ポールをつなぐ(セッションに値を入れる)という処理をしていますよね。
 このボールをつないでいる、それぞれの人が、PHPプログラム。

 つまり、セッションをつうじて、アタッカー(VIEWプログラム)へ、いろいろの人が処理(PHPプログラム)してる。

 で、JTの選手は、竹下さん(一番上4番目の写真)とカオル姫だけでなく、もっといろいろいるけど、ボールがきたのは、たまたま、この2人、つまり、セッションの中に入っている値によって、処理するPHPプログラムが選ばれる。

 で、カオル姫は、竹下さんは知ってるけど、まさか、タバコやのおじさんは知らない。

 つまり、PHPの処理プログラムは、状況によって、次に誰を呼び出すか(複数候補有)は知っていて、ボールによって=セッションの値によって、呼び出す先を決めて、呼び出す(headerのLocationで)てなかんじなわけです。




 ということで、この方式を、このCMからとって、カオル姫方式と、勝手にウィリアムのいたずらが命名しました(一番初めにボールを受けるのが、カオル姫なので)。

 で、次の話は、この具体例を示したり、カオル姫-テンさん方式についてご披露するのですが、それについては、気が向いたときに、またかきます。
 もう時間切れ!なのだ。



  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PHP等で画面とプログラムの分離&アジャイルっぽく開発(テストファースト、ユニットテスト)の例

2005-11-21 20:58:06 | PHP

 前のブログで、Webにおける画面とプログラムの分離方法の、問題がある方法についてかきましたけど、それで、具体的にはどうなるのか?という話と、これによって、アジャイルっぽくやると(テストファーストとかユニットテストとか)、どうなるかのお話です。

 なお、このあとに紹介予定のカオル姫方式でも、アジャイルっぽくできます。




 で、まず、具体例。

 ここでは、以下のサイトで、ボタンを押して、gamen1.php画面にいくとします。

<HTML>
<HEAD><TITLE>てすとだぴょん</TITLE></HEAD>
<BODY>
<Form action="gamen1.php "method="post">
    Name:  <input type="text" name="username"><br>
<input type="submit" name="submit" value="実行">
</form> 

(全角<>は、実際には半角です)

このファイルをtest.htmとします。

で、その場合、画面用PHPであるgamen1.phpと、同時に、gamen1_cnt.phpを作ります。

■■(1)gamen1.phpは、まずはじめに、こう書きます。
1.まず、HTMLファイルを作成します。
 HTMLエディタでもOK.デザイナーさんが作るのかなあ
 →で、ここで、プログラム的に文字が入るところに、$$$item1$$$とか、分かるマークを入れておいてもらうと、あとの作業が楽かもお。。

2.あたまに(HTMLタグの前でOK)、だまって、こうかきます。
<?php
	include("gamen1_cnt.php");
	gamen1_cnt_init();
?>

(全角<>は、実際には半角です)

3.ファイル名が、XXXX.HTMだったら、gamen1.phpになおしておきましょう。

ここまでで、gamen1.phpの内容は、こうなります
<?php
	include("gamen1_cnt.php");
	gamen1_cnt_init();
?>

<HTML>
<BODY>
表
<table border=1>
<tr><td>$$$list1['item1']$$$</td><td>$$$list1['item2']$$$</td></tr>
</table>
<Form action="gamen2.php "method="post">

    Name:  <input type="text" name="username" value=$$$name$$$><br>

<input type="submit" name="submit" value="実行">
</BODY>
</HTML>

(全角<>は、実際には半角です)
なお、$$$list1[item1]$$$とかいてあるのは、List1の中に、複数レコードが入っていて、そのレコードのitem1を表示しろという意味です。ここは、複数レコードのところなので、繰り返しになります。

■■(2)gamen1_cnt.phpは、まずはじめに、こう書きます。
1.関数gamen1_cnt_initを宣言し、中身空でかきます。
<?php
function gamen1_cnt_init()
{
}
?>

(全角<>は、実際には半角です)

■■(3)この時点で、test.htmでボタンを押しても、gamen1.phpのHTMLが表示されるだけで、なにもおこりません(ね、テストファーストっぽいでしょ ^^)

■■(4)ここで、文字がはいるところに、print文をいれます。
gamen1.phpで、処理結果の文字が入るところ($$$item1$$$とか、マークをいれておいてもらっているところ)に、print文で、セッションの値がはいるようにします。
1項目、1つの値が入るところは、
print $_SESSION['name']
のように(例の場合は項目名nameの値)表示されるように書きます。

1項目に、複数レコードのところ(繰り返し)のところは
foreach($_SESSION['list1'] as $rec)と、繰り返しの範囲のところを書いて、
レコードのある項目の値を入れるところは
print $rec['item1']
のように、書きます($recに1レコード分入っているから)
結果として、gamen1.phpは、こんなかんじです(これで画面側はOK)
<?php
	include("gamen1_cnt.php");
	gamen1_cnt_init();
?>

<HTML>
<BODY>
表
<table border=1>
<? foreach($_SESSION['list1'] as $rec){ ?>
<tr><td><? print $rec['item1'] ?></td><td><? print $rec['item2'] ?></td></tr>
<? }?>
</table>
<Form action="gamen2.php "method="post">

    Name:  <input type="text" name="username" value="<? print $_SESSION['name']?>"><br>

<input type="submit" name="submit" value="実行">
</BODY>
</HTML>

(全角<>は、実際には半角です)

■■(5)この時点で、表示できるかどうかみてみます。
 見ても、値ははいってこないはずです。まだかいてませんから。

■■(6)つぎに、ダミーの値をいれます。
gamen1_cnt.phpの関数gamen1_cnt_initで、セッションをスタートさせ、ダミーの値をいれておきます。これで、テストができるようにします。
 レコードの場合は、$rec[カラム名]=値のように、1レコード分セットして、そのレコードを
 $data[レコード番号]=$recというかんじで、レコードをセットし、最後に
 $_session[項目名]=$data
 の形で表全体をセットします。

こんなかんじです。
<?php

function gamen1_cnt_init()
{
	session_start();  	//	セッション開始

	$_SESSION['name'] = "aaa";

	$rec['item1'] = "1行目1項目目の値";
	$rec['item2'] = "1行目2項目目の値";
	$data[1] = $rec;

	$rec['item1'] = "2行目1項目目の値";
	$rec['item2'] = "2行目2項目目の値";
	$data[2] = $rec;

	$rec['item1'] = "3行目1項目目の値";
	$rec['item2'] = "3行目2項目目の値";
	$data[3] = $rec;

	$_SESSION['list1'] = $data;
}

?>

(全角<>は、実際には半角です)

■■(7)こうした状態で、test.htmからボタンをクリックすると、ダミーの値が表示されるはずです。

■■(8)あとは、コントロールの中gamen1_cnt_initの中を書けばいいことになります。




 逆に、gamen1_cnt_initの中だけ出来ている場合などは、セッションの値をprintすることにより、gamen1_cnt_initの中が、正しく出来ているかどうか、確認できます。

 なお、今回は、gamen1_cnt_initに渡す値がありませんでしたが、

■■ ※ test1.htm(呼び出し画面)からの値を渡したい場合
gamen1.phpの冒頭、gamen1_cnt_initを呼ぶ前に、session_startさせて、
foreach(@_POST as $key=>$val)
{
$_SESSION[$key]=$val;
}
(で、あってるかな?確認してないけど)みたいなかんじで、セッションに、画面の値を入れてしまってください。gamen1_cnt_initでは、そこから、値をとってきて、処理します。
 なので、test1.htmとgamen1_cnt_initで、同じセッションに値をいれて、重なってしまってまずい場合は、テキトーに命名規約をつくって、重ならないようにしてください。


 ということで、画面ができてなくても、こんなかんじで、ユニットテストできます

■■ ※画面をつかわずにユニットテストするには
gamen1_cntをインクルード
セッションをスタート
セッションに、呼び出し元でセットされるはずの値をセットする
gamen1_cnt_initを呼び出し
セッションの中身を全部表示

というPHPプログラムを作成する




っていうかんじで、画面とプログラム部分(コントロールとモデル部分)を分けて、画面だけを、ダミーの値を入れてテストしたり、プログラム部分だけを画面なしでテストしたりすることが可能になります。で、テストファーストっぽく徐々に、初めは何も怒らないところから作るので、
ね、アジャイルっぽいでしょ。

 今回はPHPでやりましたけど、CGIでも、JSPでも、まったく同じ方式でできるはずだと思います。

 でも、これだと、画面を複数切り替えられないので、つーか、もっと簡単に分離する方式を、気が向いたら、しめします(それがカオル姫方式。なぜカオル姫なのか(CMから取っている)は、その中で示される)


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Webにおける画面とプログラムの分離を単純に行い、わざと問題点をだしてみる。

2005-11-21 17:45:57 | PHP

 先ほどのブログにあった、Webプログラム(PHPなど)における画面とプログラムの分離を、規約によって行う方法について、ものすごーい単純な規約を使って、わざと問題点をだしてみます。

 この程度なら、たぶんテンプレートを使ったほうがよいと思われるでしょう。

 実際は、このやり方とは、違うやり方をします(それは、次回以降のブログで説明する)。

 ただし、このやり方を説明しておかないと
・あまりに唐突なやり方になってしまう。
・今回説明する方法でいいのでは?という意見が出る
ために、前もって説明しておいてしまいます。




 単純に、PHPとか(まあ、CGIでもJSPでもいいんだけど)で、画面と、プログラム部分を分離しようとすると、つまり、MVCモデルを実現しようとすると、こんなことでできます。

(1)画面部分は、
・コントロール部分のソースをインクルードする
・そこで、コントロールのモジュールを呼び出す
・(画面表示の値は、コントロール側でどこかにセットしておき)
  画面表示では、表示するだけにする。

(2)コントロール側では
・呼び出されるモジュールをつくり、そこで、モデルを呼び出す
・表示する値が求まったら、画面表示の値をどこかにセットする。




 今回は、画面表示の値を入れておくところを、セッションとしましょう
(セッション以外でもぜんぜんかまわないんだけど、次回以降の話のために、セッションに入れる)

そうすると、規約としては、

(1)画面表示側
・プログラム名はXXXX.PHP
・はじめに、コントロールのインクルードをして、次の行で、XXXX_cnt_init()を呼び出す。
・値を表示するためのプログラムしか、書いては、いかん。
 クリックされたら、ある処理を動かしたい場合、動かす処理を、XXXX_shoriYY(ひきすう)YYは数字という関数を呼び出すようにして、その関数は、コントロールファイルの中に書くようにする。

 値表示は、
  文字、数字のように、1項目に1つの値のときは、print $_SESSION['項目名']で
  表のように、1項目につき、複数行あり、その行が、複数のカラムを持つ場合は、
  foreach($_SESSION['項目名'] as $rec)で、1行分を$recの中にいれ
   各行につき、 print $rec['カラム名']で表示する
  リストのように、1項目につき、複数の値あるときは、表で、複数行、1カラムしかないものとして処理する。

(2)コントロール側は、
・プログラム名はXXXX_cnt.PHP
・XXXX_cnt_init()という関数を作成し、その関数の中で、セッションをスタートし、セッションの中に、表示させたい値を入れる。値の設定の仕方は、上記のとおり。
・もし、それ以外に、画面のほうで、関数を呼び出したいときには、ここにその関数を書く




ひえー、時間がなくなっちゃったんで、具体的例は、またこんど。

で、これの問題点。

いろいろあるけど、時間ないので、致命的なのを1個だけ。
エラー画面を表示したいときなどに別画面に遷移させにくい(させると、プログラム複雑になる)

この問題を解決した方法を、今度、書こうと思っています。

なずけて、カオル姫方式。

時間がないので、このへんで。



  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Webシステムのほうが、画面部分と、プログラム部分を分けたいはず。人件費の理由で。

2005-11-21 15:14:37 | PHP

 Javaだと、MVCとかで、画面のView部分と、プログラミング部分の(主に)Model部分を分けるという考えが浸透していると思う。
 PHPでも、HTMLテンプレートとか、Smartyとか、PEARのテンプレート機能を使うとかで、画面とプログラム部分を分離できるみたいですよね(こんなことしなくても、ちょっとしたコーディング規約を使うだけで、もっと柔軟に、分けることができると思う。それについて、今実験中)。

 で、ここで、いいたいのは、何で、画面とプログラム部分を分けるかという話。

 そうすると、MVCモデルがなんとかかんとか。。。っていう話になっちゃうけど、もっと、重大な話がある。

 デザイナーの単価と、プログラマーの単価が違うのだ。

 今日は、その話。

 で、その観点から考えると、できるだけ、簡単に画面と分離したい(つまり、デザイナーさんが、ちょっとしたマーカーをいれて、自動的とまではいかなくても、テンプレートにできるようなかんじ)けど、それについて、PHPだと、こういう規約を決めればいいじゃん!っていうのは、今、実験中なので、今度、実験がすんで、気が向いたら披露します。

 実は、「PHPだと」と書いたのは、はじめ、ウィリアムのいたずらは、この規約をJSP用に考えていた。しかし、JSPだけでなく、PHPでも、なんでも基本方針的には、応用できるじゃん!(そーいう点で、PHPを利用する立場とはちがう。この考え方さえ守れば、新しい言語がでてきても、応用できるという点で)つーものなんですけどね。でも、今日はその話じゃなくって、その前提の、なんで、こんな話をするのかということ。




 Web系において、デザイン部分と、プログラム部分を分けたいって言うのは、結構現実的な大きな理由として、デザイナーの単価と、プログラマーの単価の違いっていうのがあるんじゃないかな?って思うんですよ。

 デザイナーの単価は、「はっきり言って安い!」。

 1画面1万円くらいでも、やってくれるんじゃないかにゃー。
 (もっと、安いかな・・)

 そのうえ、この分野には、新規参入者が多い。
 ちょっとデザインのお勉強をして、起業しちゃう人なんかもいる。

 そのため、単価がどんどん安くなっている。




 一方、プログラマは、いくら、フリーには安い人がいるといっても、1日稼動して、数万円っていうのは、当たり前の世界なのよ。

 さらにだ、ちょっと大きくなると、マネージャーなんつーのも出てくる。
 マネージャーは、プログラムもホームページも作らないけど、しっかりお金を取っていくわけだ。

 で、じゃあ、実際にどれくらいになるか。。。というと、マネージャーが動くと、マネージャーは、たいてい正社員なので、年収400万円以上になっちゃうのよ。そーすると、月40万でしょ。
会社は上乗せするから(会社分の社会保険もはらうし、その他もろもろお金かかるし)結局月60万くらい。

 ところが、ECサイトなんかだと、中小企業の場合、2ヶ月で、100万くらいで作りたい!っていう場合もあるのよ。マネージャーさんにお金をだして、おわっちゃう(>_<!)

 マネージャーが2つも3つも掛け持ちすればいいじゃん!と考えるかもしれないけど、デザイン事務所のマネージャーならともかく、開発会社で、3つの案件を同時に掛け持つって、大変なのよ。
 マネージャーって、会議に出て、結構時間つぶれちゃうんで。

 なので、掛け持ちできる仕事が少なかったりする。

 プログラマーなら、もっと安いけど、デザイナーほどではない。

 とにかく、中小企業の感覚、100万でECサイト作って!とか言う場合、デザイナーにお金を払って、あと、データ入力をパンチャーにしてもらって、その他いろいろはらうと、この時点で、もう、お金たりないのよ。なので、プログラマーを動かしたくないわけ。

 それ以外のものでも、中小企業なんかが絡んできたり、小規模イベントの場合、プログラマーを動かすお金まで回らない。ましてやマネジャーつけて、大規模に開発することはできない。
(マネージャーつけるレベルになると、400万程度以上の案件になる。ソフトハウスが「部隊を動かして」請ける案件は、一般的にそれ以上のことが多い。それ以下のものは、プログラマだけでやったり、フリーにまわしたり、さらに零細ソフトハウスに紹介したり。。)




 ところが、デザイナーは安いのよ(それが社会的にいいことか悪いことかは別問題)。
 「アルバイトの」求人雑誌のなんかで、Webデザイナーの値段をみてね!

 なので、デザイン部分と、プログラム部分を分離し、プログラム部分をデザイナーがちょっと変形すればできる程度にしたい。。。と、いう感じだと思う。

 つまり、単価の立場から見て、デザイン部分(画面 Viewの部分)と、プログラム部分(モデル部分)を分けたいわけ。で、デザイン部分は、あるていど複雑/修正あってもかまわない(人件費安いから)けど、プログラム部分は、あんまり複雑にしないで、できれば、デザイナーさんがちょこちょこっといじって、プログラマ使わなくても終わり!にしたいわけ。

 つーので、フォームメールがウケたりするわけだ。あれなら、フォームメールCGI(共用サーバーでだいたい提供してくれる)を呼び出すだけだからねえ。。デザイナーでも対処可能。



  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする