kazpgmの日記

『プログラム自動作成@自動生成』作成の日記

TOOL更新_お助けTOOLをEthnaに移植する方法を調査する。

1.お助けTOOLをEthnaに移植する方法を調査する。ToDoリストの(http://d.hatena.ne.jp/kazpgm/20090403/1238773943)暫定99.の調査
  今後わかったことはここに書く。
  仕様はhttp://ethna.jp/ethna.html (Ethna)から抜粋した。UTF-8で作成使用したいから「Ethna 2.5.0 preview1以降」を使う予定。「Ethna 2.5.0 」が固まるまで触らないほうがいいかも。

・認証 
  Ethna

roleの概念を付加した認証の仕組みも簡単に作れます。
ユーザ名と、パスワードでログインして、各ユーザのグループ権限ごとに行う処理を変えるとか。
認証情報を管理するクラスを作っておいて、それをauthenticateの中で呼び出してやるだけです。
と書かれている。実際どうやるかは未調査。

  お助けTOOL:

自分でログイン用テーブルを読んでチェックOK、NGを判定している。
phpロジック、htmlは自動作成。

・DB
  Ethna

   ・DBコネクト

・etc/[appid]-ini.phpにdsn定義を行う。
  $config = array(
      'debug' => false,
      'dsn'   => 'mysql://user:pass@unix+localhost/dbname',
  );

   ・複数件read

$db =& $this->backend->getDB();
return $db->db->getAll( "SELECT xxx from xxxxxx WHERE xxx = ? AND xxxx = ?" , array($xxx, $xxxx), DB_FETCHMODE_ASSOC );

$sql = "SELECT id FROM test";
$result =& $db->query($sql);
$i = 0;
while ($data[$i] = $result->fetchRow()) {
  $i++;
}

$db =& $this->backend->getDB();
$sql  = "SELECT ・・・ ";
$result = $db->query($sql);
if (Ethna::isError($result)) {
  print_r($result);
} else {
  if ($result->numRows() > 0) {
    for ($i = 0; $i < $result->numRows(); $i++) {
      $row =& $result->fetchRow(DB_FETCHMODE_ASSOC);

   ・1件read

$db =& $this->backend->getDB();
return $db->db->getRow( "SELECT xxx from xxxxxx WHERE xxx = ? AND xxxx = ?" , array($xxx, $xxxx), DB_FETCHMODE_ASSOC );

$db =& $this->backend->getDB();
$sth =& $db->db->prepare("SELECT xxxx FROM xxxxxxx WHERE xxxx = ?  ");
$result =& $db->db->execute($sth, array($xxx));
if (Ethna::isError($result)) {
  print_r($result);
  $return_value = -1;
} else {
  if ($result->numRows() > 0) {
    $row =& $result->fetchRow(DB_FETCHMODE_ASSOC);
    $return_value = $row['xxxx'];
  }
}

$db =& $this->backend->getDB();
return $db->db->getOne('SELECT xxxx FROM members WHERE xxxx = ? LIMIT 1', array($xxxx), DB_FETCHMOD_ASSOC );

   ・追加

$res =& $db->query(
  'INSERT INTO xxxxxx SELECT * FROM xxxxxx'
);

/* INSERT */
$xxxxxxx =& new Xxxxxx($this->backend); // EthnaO/RマッピングクラスであるEthna_AppObjectクラス
$xxxxxxx->xxxxxxxx();
$xxxxxxx->set('xxxx', $db->db->nextId('dxxxxxxxxxxxxx'));
$now = date('Y-m-d H:i:s');
$xxxxxxx->set('ins_ts', $now);
$xxxxxxx->set('upd_ts', $now);
$xxxxxxx->add();

/* REPLACE */
$xxxxxxx =& new Xxxxxx($this->backend); // EthnaO/RマッピングクラスであるEthna_AppObjectクラス
$xxxxxxx->set('xxxx', '1'); 
$xxxxxxx->set('ins_ts', $now); // 登録日時
$result =& $xxxxxxx->replace(); // 更新がないとき追加
if (Ethna::isError($result)) {
  $valid = false;

   ・更新

$db =& $this->backend->getDB();
$db->db->query('UPDATE xxxxxxxxx SET xxx = ? WHERE xxxx = ?', array($xxx,$xxxx));

/* UPDATE */
$xxxxxxx =& new Xxxxxx($this->backend, 'xxxx', 
     $this->af->get('xxxx')); // EthnaO/RマッピングクラスであるEthna_AppObjectクラス
$xxxxxxx->set('xxxx', $this->af->get('xxxx'));
// Array → Timestamp
$xxxxxxx->set('upd_ts', date('Y-m-d H:i:s'));
$xxxxxxx->update();

   ・削除

$db =& $this->backend->getDB();
$db->begin();
$db->db->setFetchMode(DB_FETCHMODE_ASSOC);
$db->query('DELETE FROM xxxxxxx WHERE xxxx = ' . $db->db->quote($XXXX));

    
  お助けTOOL:

PEAR DB(DB.php)を使用している。

   ・DBコネクト

$db =& dbCheck(DB::connect(DSN));
$db->setFetchMode(DB_FETCHMODE_ASSOC);

   ・複数件read

$result = $db->getAll($sql);

   ・1件read

$o = dbCheck($db->getRow($sql));

   ・追加

$columns = array(
  'xxxxx'      => 'yyyyy',
);
dbInsert($db, 'TABLE', $columns);

   ・更新

$data = array(
 'xxxxx'      => 'yyyyy',
);
dbUpdate($db, 'TABLE', $columns, array('KEY = '. $db->quoteSmart( 'xxxxx')));

   ・削除

dbDelete($db, 'TABLE', array('KEY = '. $db->quoteSmart( 'xxxxx') ));

・セッションデータ、リクエストデータ処理
  Ethna

・ActionClassはメンバ変数にセッションオブジェクトを保持している
 例)
  function perform()
  {
      var_dump($this->session->get('hoge'));
  }
・フォーム値にはget()/set()メソッドでアクセスします 
・アプリケーション設定値(フォーム値以外で、ビューに表示させたいダイナミックな値)は
 setApp()メソッドでアクションフォームに格納します 
・アプリケーション設定値(HTMLエスケープさせたくない値)はsetAppNE()メソッドで
 アクションフォームに格納します 
・フォーム値はテンプレートで{$form.フォーム名}としてアクセスします。
 値は常にHTMLエスケープされます。 
・アプリケーション設定値(setApp()で格納されたもの)はテンプレートで
 {$app.変数名}としてアクセスします。値は常にHTMLエスケープされます。 
・アプリケーション設定値(setAppNE()で格納されたもの)はテンプレートで
 {$app_ne.変数名}としてアクセスします。この値はHTMLエスケープされません(基本的には使用しません)。
・なお、アクションフォームはアクションクラスと対になって必ず生成され、
 アクションクラスのprepare()あるいはperform()メソッド、また、ビューオブジェクトのpreforward()では必ず
 $this->action_form // 面倒なら$this->afでも可でアクセスできることが保証されています。
 アクションクラスに対応するアクションフォームが未定義の場合は、
 フォーム値定義の無いデフォルトのアクションフォームが生成されます。

  お助けTOOL:

session_start();
$_SESSION['zzz']のまま使っている。
unset($_SESSION['zzz']);

$_REQUEST['xxxx']のまま使っている。

・入力チェック
  Ethna

・アクションフォームには以下のvalidateチェックを行っている。
		27         /*
		28         'sample' => array(
		29             'name'          => 'サンプル',      // 表示名
		30             'required'      => true,            // 必須オプション(true/false)
		31             'min'           => null,            // 最小値
		32             'max'           => null,            // 最大値
		33             'regexp'        => null,            // 文字種指定(正規表現)
		34             'custom'        => null,            // メソッドによるチェック
		35             'filter'        => null,            // 入力値変換フィルタオプション
		36             'form_type'     => FORM_TYPE_TEXT   // フォーム型
		37             'type'          => VAR_TYPE_INT,    // 入力値型
		38         ),
		39         */

・validateチェック中のフィルタの利用方法
・フォーム値のfilter属性に、フィルタ名をカンマで区切って列挙する 
 フィルタメソッドをアクションフォームクラスに"_filter_[フィルタ名]"という名前で定義する 
 例)
  'filter' => 'numeric_zentohan,alphabet_zentohan,ltrim,rtrim,ntrim',
  'filter' => FILTER_HW,
・カスタムメソッド
 ・フォーム値の'custom'属性にメソッド名を記述する 
  例)'custom'    => 'checkSample',
 ・指定したメソッド名のメソッドをアクションフォームクラスに定義する
  例)
   function checkSample($name)
   {
       if (strtotime($this->form_vars[$name]) > time()) {
           $this->ae->add($name, "{form}には未来の時間を入力してください", E_FORM_INVALIDVALUE);
       }
   }
 ・すでに定義されてるカスタムメソッド
  checkVendorChar: 機種依存文字 
  checkBoolean: bool値 
  checkMailaddress: メールアドレス 
  checkURL: URL
  例えばメールアドレスのチェックを行うには
  'custom' => 'checkMailaddress',

  お助けTOOL:

「AppCheckUtil」クラス(http://d.hatena.ne.jp/kazpgm/20090520/1242839505)使用

・メール
  Ethna

・メールを送信する
 ・project_dirの/template/jaにmailフォルダを作成、そこにSmartyテンプレートをおく
 ・ActionClassとかで送信 (Ethna_MailSender は継承させて使うこと。)
   $ethna_mail =& new Sample_MailSender($this->backend);
   $ethna_mail->send('send_to_mail@example.com',
       'contact',
       array('username'=>$resign_user));
      <=arg1:送信元、arg2:テンプレート名($def配列中の)、arg3:項目値の配列

  お助けTOOL:

mb_send_mail使用して自作している。

・VIEW(HTML)
  Ethna

・ビューはSmartyを使用している。
・テンプレート中のフォーム値は自動的にSmarty変数になっている。
 例){$form.*}でフォーム値を示している。 サニタイズ済みである。
・エラーメッセージは配列として{$errors}というSmarty変数に割り当てられている。
・特定のフォーム名に対応するエラーメッセージを表示させるには、
 Ethnaフレームワークの提供するSmarty関数"message"を利用。
 例){message name="password"}

  お助けTOOL:

htmlを<?php ?>を使用して作成。

・Control
  Ethna

Ethnaでは基本的に、クライアントから送信されアクションフォームに格納されたフォーム値が
 GET/POST(REQUEST_METHOD)のどちらに由来するかを区別しません。

・submitした際のアクションを「action_XXXX_do」="dummy"をhiddenでわたす。
 これを受け取って「アクションスクリプト,ビュースクリプト,テンプレート」名
 が決まる。

・アクション定義(省略した場合の値)
 Ethnaでは、Mojaviのように命名規則に従ってファイル名とクラス名を作成することで、
 アクション定義、ビュー定義を省略することができます。
  ・省略しない場合のアクション定義、ビュー定義: 
   Controllerにアクション定義、ビュー定義を追加します。
   具体的には、app/Sample_Controller.phpを編集します。

   ・「var $action = array」(action定義)は省略する予定。
   ・「var $forward = array」(forward定義)は記述する予定。
     (「'forward_path'」を定義したいから。)

 ・アクション名が"some_action_name"だとすると、アクション定義省略時にインクルードされる
  アクションスクリプトはSome/Action/Name.phpとなります("_" -> "/"+先頭1文字を大文字)。
   <=このphpの中に以下の2クラスを作る。
  ・また、アクションクラス名は
   {$アプリケーションID}_Action_SomeActionName
  ・そしてアクションフォーム名は
   {$アプリケーションID}_Form_SomeActionName

 ・遷移名が"some_action_name"だとすると、ビュー定義省略時にインクルードされる
  ビュースクリプト,テンプレートはそれぞれ
  ・view/Some/Action/Name.php
  ・template/ja/some/action/name.tplとなります("_" -> "/"+先頭1文字を大文字)。
 ・また、ビュークラス名は
  {$アプリケーションID}_View_SomeActionName


  お助けTOOL:

URL/XXXX/YYYY.phpはxxxxフォルダYYYY.php

・エラーハンドリング
  Ethna

・エラーハンドリングの機能を用意している。(フレームワークとして)
  if (Ethna::isError($obj)) { // Ethna::isError() でエラーかどうか判定

・エラーレベルを考慮したログが出せる。(フレームワークとして)
 ・etc/[アプリケーションID]-ini.php の $config グローバル変数に 'log' というキーで設定を記述
  共通のログ設定については log_option, log_filter_do, log_filter_ignoreにて設定可能
  補足:データベースに問い合わせた全てのSQL文を出力することもできる。
  例)
   $config = array(
       // debug
       'debug'	=> true,
       // log
       'log_facility'  => 'echo',
       'log_level' => 'warning',
       'log_option' => 'pid,function,pos',
       'log_alert_level' => 'alert',
       'log_alert_mailaddress' => 'xxx@XXX.XX.XX,xxx@XXX.XX.XX',
       'log_filter_do' => '',
       'log_filter_ignore' => 'Undefined index.*%%.*tpl',

  お助けTOOL:

DBエラーのみログ出力するようにしてある。その他のエラーはphp.iniのとおり。

・ファイルへのアクセス
  Ethna

・'type'属性にVAR_TYPE_FILEを指定
・PHPの$_FILES変数と同様にアクセスが可能。
 例)var_dump($this->af->get('sample_file'));
   array(5) {
     ["name"]=>
     string(10) "sample.gif"
     ["type"]=>
     string(9) "image/gif"
     ["tmp_name"]=>
     string(14) "/tmp/php3PxT99"
     ["error"]=>
     int(0)
     ["size"]=>
     int(220)
   }
・ファイルに関してもフォーム値の自動検証を利用して、
 必須チェック、ファイルの最大、最小サイズ等のチェックが可能

  お助けTOOL:

$_FILES['sample_file']を使用。

・配列へのアクセス
  Ethna

・例)
 ・フォーム値
   'sample_array' => array(
       'type'  => array(VAR_TYPE_STRING),
   ),
 ・テンプレートも通常のPHPでのフォーム配列と同様
   <form method="post">
    <input type="checkbox" name="sample_array[]" value="1">
    <input type="checkbox" name="sample_array[]" value="2">
    <input type="checkbox" name="sample_array[]" value="3">
    <input type="checkbox" name="sample_array[]" value="4">
    <input type="submit">
   </form>
 ・フォーム値にアクセス
   perform()
   {
       var_dump($this->af->get('sample_array'));
   }
   array(2) {
     [0]=>
     string(1) "3"
     [1]=>
     string(1) "4"
   }

  お助けTOOL:

・例)
 <input type="checkbox" name="sample_array[]"  value="1" id="check_ssample_array[]1"  />
 <label for="check_sample_array[]1">Super管理者</label>
 <input type="checkbox" name="sample_array[]"  value="2" id="check_sample_array[]2"  />
 <label for="check_sample_array[]2">管理者</label>

 if (!empty($_REQUEST['sample_array']) && is_array($_REQUEST['sample_array'])) {
   $tempArray = dbQuotes($db, $_REQUEST['sample_array']);
   AppSrchUtil::setSqlStrSub1($conditions);
   $conditions .= " it.item13 in (". join(', ', $tempArray) . ')'; // 完全一致
 }

・2重POSTのチェック
  Ethna

  登録画面の前のページ(確認画面等)にユニークIDを仕込む 
  {uniqid}
  登録処理の Action でチェックする。
   if (Ethna_Util::isDuplicatePost()) {

  お助けTOOL:

現在2重POSTのチェックなし


2009/05/27 20:00 - 02:45
2009/05/28 10:00 - 00:30

■サイト:http://kazpgm.ddo.jp/