開発環境


MLの過去ログ読んでたら
http://hp.vector.co.jp/authors/VA025040/ctags/
これに気付いた。
っていうかサーバ移し替えてから忘れてた。


Debian付属のetagsじゃPHP使えないんだもの。
まだソースコードもファイル数も少なかったからc++とかJavaとかの設定で対応していた。
ちょっと思い出したので入れてみる。


普通に make install したらデフォルトの/usr/bin/ctags ではなくて /usr/local/bin/ctags にインストールされたのでこっちが優先される。



そして検索したらなんともタイムリーな記事が。
http://tsuttayo.sytes.net/php/emacs/

このサイト、ブックマークしてあるよ・・・。やっぱりブックマークしてるだけじゃ見ないみたいだ。

  • EUC-JP, SJISでファイル編集でき、日本語が通る。
  • PHP構文、HTMLのカラー表示ができる。
  • 1つのファイルで複数のエリアを同時に参照・編集できる。
  • 瞬時に関数やクラス定義へジャンプできる。
  • 安定しており、軽いこと。
  • 関数、クラス、メソッド、プロパティが一覧表示可能。

最後の一覧表示はまだ出来ていませんが、それ以外はemacsですべて可能だとわかりましたので、emacsを使い始めました。

私はアウトラインモードで一覧表示を対応している。
もしかしてあまり使ってる人居ないのかな?
っていうことで私が使ってるのをそのまま載せてみる。


http://d.hatena.ne.jp/katase_n/19700201
完成度低いけど無いよりマシでしょってことで。。
誰かもっとちゃんとやってる人居ないかなー。

連想配列のキーに使える文字

$a = array('あ' => 1,
           'い' => 2,
           "\n" => 3,
           '$a' => 4);

var_dump($a);

$key = 'あ';
var_dump($a[$key]);


期待通りの動作。
柔軟過ぎるだろう・・。


単に . とか - とか > とかが使えるか知りたかっただけなんだけどね。
演算子なんだからやらない方がいいような・・・とは思うけどclass->methodとかclass.methodっていうキーにした方が分かりやすいもの。。

自分用のあれ 暫定メモ

自動設定

index.php?action=ModuleName を想定

  • 設定ファイル
    • ModuleName.ini
    • 無ければモジュール名がそのままアクションクラス名となる
  • アクションクラス
    • ModuleName.class.php
    • 無ければアクションクラス名がそのままテンプレートファイル名となる
  • テンプレート
    • ModuleName.html
    • 必須

クラス変数

アクションやフィルタやコンポーネント(特に違いはないただのクラス)のメンバ変数は自動的に値が設定される。

  • 設定ファイルの[properties]セクション
  • 変数名が_[A-Z]で始まる場合はコンポーネント
    • 生成されていなければ生成

アクションクラスとフィルタクラスは更に、リクエスト変数がアンダースコアから始まらない変数に設定される。



同じ名前の変数は値が上書きされる。


フィルタからアクションへ値を使い回したい場合は、リクエストクラスに値を入れると自動的に設定される。
またはコンポーネントなどを通じて明示的に取得する。



フレームワークから呼び出されるクラスを作る時に変数名について唯一の注意点は、自動的に書き換えたくない変数は_[a-z](アンダースコアの後に小文字で始まる)という名前を使用する。


メソッド名についても、自動的に実行しない場合はアンダースコアから始める。


モジュール設定iniファイル

;; index.php?action=ModuleName
[module]
;; ModuleName->execute()が実行される
module = ModuleName

[filters]
;; ActionFilter->actionFilter()が実行される
action1 = ActionFilter
;; ActionFilter->PreFilter()が実行される
action2 = ActionFilter.PreFilter

view1 = ViewFilter
view2 = ActionFilter.postFilter

[properties]
_userId = 1

[methods]
init =
getConnection = dbname, username

[results]
;; index.php?action=ErrorViewと同じ意味
error = ErrorView
transfer = OtherModule

[DIContainer]
DB = DB.dicon.ini
;; index.php?action=OtherModule
[module]
;; ModuleName->OtherModule()が実行される
class = ModuleName

[filters]
;; ModuleNameの設定ファイルにあるフィルタが実行された後、
;; ModuleName->OtherModule_actionFilter()が実行される
;; 特に命名規則は無いので自分で考える
action1 = ModuleName.OtherModule_actionFilter

[results]
;; index.php?action=ModuleNameと同じ意味
;; 値の引き継ぎはRequestクラスやコンテナで
success = ModuleName
;; ModuleNameの設定ファイルで設定したerrorを上書き
error = OtherErrorView


設定は上層フィルタから順に上書きされる。


[module]セクションの値とURLの引数が違う場合はその値をモジュールとして処理を行う。キーは module と class があり、moduleは他からの転送を受け付ける。他から呼び出されたクラスは実行関数が呼び出し元のモジュール名となる。





DIContainer設定iniファイル

[main]
component = DB
class     = MyDB
path      = MyDB.class.php

[properties]
dbname = mydb

[methods]
conn =


[DIContainer]
Other = OtherComponent.dicon.ini

[main]セクションにそれぞれコンポーネント名、クラス名、クラスファイルパスを記述する。


その他のセクションはモジュール設定と同じ





取り敢えず進捗状況をまとめてみたらこんな感じになった。


・・・・・。



guessworkの動作とMapleのソースで勉強しながら作ったから当然の結果だよね・・・。




やりたかったのはフィルタもアクションもごちゃ混ぜにしたかったってこと。
あとは設定ファイル無しで連鎖的なコンポーネントのメンバ変数代入。


取り敢えず今のところコンポーネントを5コほど使ってるけど、設定ファイルはDB用の文字列が書いてあるコンポーネント用の設定ファイル1つのみ。

うーんすっきり。



逆にアクションの方は設定ファイルの方が多くなった。
設定ファイルレスも出来るけど、どちらかというとアクションクラスレス?いや、ただ他のアクションの関数呼んでるだけなんだけど・・。




あぁ、上の方でDIContainerとか書いてあるけど、単にメンバ変数を設定したかっただけでDIContainerを意識して作ったわけじゃないからこの名前はまずいよなぁ。

プチ感動がおさまる前に

作りたいものは

  • トップ画面
    • ログイン済ユーザと非ログインユーザで表示が異なる
  • ユーザ情報画面
    • ログイン済ユーザ専用


で、作る。
HTMLは


Top.html

<html>
<body>

<p>%message%</p>

<!-- define:IS_LOGINED -->
<p>ようこそ%name%さん</p>
<p><a href="?action=UserData">ユーザ情報</a></p>
<p><a href="?action=Logout">ログアウト</a></p>

<!-- else -->

<form action="./">
<input type="hidden" name="action" value="Login">
<input type="text" name="id">
<input type="password" name="password">
<input type="submit">
</form>
<!-- endif -->

</body>
</html>

UserData.html

<html>
<body>
<p>id : %id%</p>
<p>name : %name%</p>
<p>phone : %phone%</p>
</body>
</html>

LoginRequiredError.html

<html>
<body>
<p>会員専用のページです</p>
</body>
</html>


取り敢えずこれだけテンプレートのHTMLを用意する。



そしてここからがPHP
何もないところから(と言ってもコンポーネントや共通で使うライブラリはある)作る。



まずはトップページの処理。

class Top
{
    var $message;

    function execute(){
    }
}


やることは無いが初期化用の変数だけ設定しておく。
これでトップページが表示可能。


次にログイン処理を作る。

Login.class.php

class Login{
    var $_UserUtils;
    var $_Request;
    var $id;
    var $password;

    function execute(){
        if ($_UserUtils->checkLogin($this->id, $this->password)){
            $this->_Request->add('message', 'ログイン成功');
            return 'success';
        }else{
            $this->_Request->add('message', 'ログイン失敗');
            return 'error';
        }
    }
}

Login.ini

[module]
module = Login

[results]
success = Top
error   = Top


これでログイン処理の完了。
しかしこのままだとログインが成功してもしなくても、ログインフォームが表示されてしまう。



そこで表示の切り替えフィルタを作る。


GlobalFilter.php

class GlobalFilter
{
    var $_UserUtils;
    var $_View;

    var $name;

    function actionFilter(){
        if ($_UserUtils->isLogined()){
            $this->_View->add('IS_LOGINED', true);
            $this->name = $this->_LoginUtils->getName();
        }
    }
}


これでユーザがログイン済かどうかでの切り替え処理が完了。
フィルタで設定した変数も表示に反映される。


そして会員専用ページの作成。


UserData.class.php

class UserData
{
    var $_UserUtils;
    var $id;
    var $name;
    var $phone;

    function execute(){
        $this->id    = $_UserUtils->getId();
        $this->name  = $_UserUtils->getName();
        $this->phone = $_UserUtils->getPhone();
    }

    function checkLoginedUser(){
        if(!$_UserUtils->isLogined()){
            return 'login_required_error';
        }
    }
}

フィルタも同じクラスに作成。規模が大きければ分けたらいいし、それは自由。
このフィルタを使うための設定は

UserData.ini

[module]
module = UserData

[filters]
action1 = UserData.checkLoginedUser

[results]
login_required_error = LoginRequiredError

これでログイン済ユーザ専用ページの完成。




いつも書きながら頭の中の考えが変わるんだけど・・・これ、楽になってるんかな。

そしてこのまま規模が大きくなっても破綻しないんかな。



取り敢えず今後のために現時点ではこんな動き考えててここまで出来ましたよーってことで。