2012年12月28日金曜日

今年読んだ技術本:2冊だけかい・・・

コードの複雑さを上げずに「世界の複雑さ」と戦うために読んでおきたい良書5選【2012年のインプットlog-和田卓人】を読んで、

今年、2012年に読んだ本は?
と調べてみた。

Amazonの購入履歴をみれば、すぐわかる・・・

いい時代だ・・・

クリック、クリック・・・

たったの2冊 orz


少なすぎだ。


ちなみに去年(2011年)は8冊。
それなりに読んでいる。

だいたい読んだはずだけど、あまり内容を覚えてないなぁ。
それも問題だが。

ということで、来年は、もう少し本を読もう。
体系的に、効率的に、自分の実力を強化するには本を読むのが一番いいと思う。


ちなみに、今年購入した本は次の二冊。
(アフィリエイトリンク付き)

達人に学ぶDB設計 徹底指南書 初級者で終わりたくないあなたへ


今すぐ必要ないけれど、少しずつ読んでおこうと思った本。




NOSQLの基礎知識 (ビッグデータを活かすデータベース技術)


ざっくりと、最近の話題について行こうと思った本。
深く理解できたとは思えないが、言葉に慣れた気がする。




で、感想は?


さて、ここでの問題は、ほとんど感想をかけないことだ。

本を読んでも、身になってなければ意味がない。
ノウハウ的な本なら、必要なときにパラパラめくればいいのだろうが。

来年は、本を読んだらブログに内容を書く。
という目標を立てよう。

この目標のために本を読まなくなった、てな事になりませんように。

2012年12月23日日曜日

PHP: 2012年のオレオレ=自作フレームワーク

2012年は2つも、フレームワークを自作してしまった。
俗にいう「オレオレ」である。
来年の抱負を考えるに当たり、一度まとめてみる。

AmidaMVC


恥ずかしながら、まともにMVCフレームワークを使ったことがなかった。ルーティングやらコントローラーぐらいのコードは読んではいるけど、理解しているとは言いがたい。じゃ、一度作ってみるかと…

最初は1ヶ月ぐらい開発して雰囲気がつかめたら終了と思っていたが、意外と面白く、書き直しも含めて数ヶ月近く作ってた気がする。

これを開発しながらPHPStormの使い方を覚えた。
またBEAR.Sundayなどのブログを読みふけっていた。

特徴はChain of Responsibility(CoR)というデザインパターンをフロントディスパッチャーとして使ってること。Request、Routerなどもモジュールの一つと捉えて、モジュールを次々と呼び出す。CoRは極めて柔軟性が高くて、使うモジュールを途中で差し替えたりできる。

もう一つの特徴は、マークダウンのファイルを、そのまま読み込んで、ヘッダー・フッターを付け加えたりできる。

さらに、テンプレートも裏に入っているので、githubからcloneして、中身をマークダウンで書けば、綺麗なサイトができる。エディターまでつけてしまって、もうフレームワークというよりCMSな感じになった。

そしてファットなフロントエンドが出来上がった。
ちょっと太りすぎで、今ひとつな感じになってしまった。

WScore


今、開発中のフレームワーク。
というかデータマッパー。

Doctrine2にフォーム生成をくっつけた感じ。

なので厳密にはフレームワークとは言えないかも。

目標は、

・今まで使っていたライブラリとの互換性を(ほんの少し)残す、
・「Cenaデータ転送エージェント」に対応する、
・できるだけ簡単かつ少ないコードで、
・最近学んだ「正しい」オブジェクト指向で開発する、
などで、個人的な内容が多いかな。

オレオレだから仕方がない。

開発して一ヶ月で意外と早く動き出した。その後、DCIに目移りして一ヶ月ほど寄り道したりしたけど、ただ、動くのと使いやすいのは違っていて… ある程度、動き出してからの修正に時間がかかってる。テスト書いていてよかった、と身を持って経験できた。

今は、多対多のリレーション絡みが少し抽象化が弱くて、Cenaに対応させるのに苦労しそうな感じです。とは言えサンプル・デモでは、Cenaをスキップさせることで動いてしまいましたが。

あとは1+N問題の対応とか、本格的に使うには
もう少し時間が必要そう。

2012年12月22日土曜日

PHP:2012年はPHPStormとBEAR.Sundayの年

年末なので自分のPHP生活を振り返ってみます。
2012年はPHPStormというIDEを使い始めたこと、そしてBEAR.Sundayに出会えたことが大きかった。

これにより開発スタイルやOOPに関する理解が深まりました。
というか、今まで一人で=独学で開発してました。
それによる限界を感じてたのですが、少し超えることができたとおもいます。

PHPStorm

もうすでに一度書いていますが、2012年1月からPHPStormをPHP開発のIDE(統合開発環境)に使い始めました。もっと早くから使っておけばよかったと後悔しています。

Eclipse、netbeansと使ってましたが、今ひとつ馴染めず。
とにかく重くて遅くて。
ちょっと修正するのにも一苦労。
その割には、デバッガーを設定しても一ヶ月もすると動かなくなるし。

それに比べると・・・

さて、PHPStormを使い始めて、やっと分かったことがあります。

・PHPDocsは便利。
・Interfaceは便利。

使うと開発が楽になるから、PHPDocsとinterfaceを使うようになりました。

難しい理屈で考えるより、よいIDEを使って開発すれば
返り値のタイプがあると自動補完で便利だな、
複数のクラスを返す場合でもInterface使えば使えるな…
いや、開発が楽です。

BEAR.Sunday

どこで、出会ったのか記憶にないのですが・・・
おそらくDependency Injectionを調べている時に見つけたのだと思います。

単にDIだけでなく、
オブジェクト指向で大事なのことは何か?
を考えるようになりました。

全てはリソース(Because Everything is A Resource)の言葉通り、リソース思考を極めた革新的なフレームワークですが、一つ一つの要素技術を見ても、そして開発理念も、とても勉強になります。

もう有名になった「PHP: Dis Is It」とか、読んでるだけで元気になってきます。そんな人が作っているフレームワークですから、人を元気にするフレームワークです。

2012年12月13日木曜日

BEAR.Sunday 0.Go.Go インストールログ

BEAR.Sundayの最新パッケージがリリースされたので、インストールしてみました。バージョンは0.GO.GO(0.55)だそうです。

まずはgithubのレポジトリへGo!
そして書いてあるとおりに作業する!

git clone git://github.com/koriym/BEAR.Package.git cd BEAR.Package composer intallphp scripts/check_env.php

すると、NGの印が・・・

まずはデータベースから。
check_env.phpの中を覗くと、DBはmysqlで、環境変数からDB接続に使うユーザー名とパスワードを取得していました。では早速設定して。。。

export BEAR_DB_ID='admin'export BEAR_DB_PASSWORD='*****'

もう一度走らせるとOKに変わりました。

もう一つのNG、apc.enable_cliは無視して先に進むことに。。。

Built-In Web Server

を走らせてみます。
これも書いてあるとおりの作業でした。

chmod -R 777 apps/Sandbox/datacd apps/Sandbox/public/php -S localhost:8088 web.php

ブラウザーで http://localhost:8088 アクセスすると、見慣れたBEAR.Sundayのトップ画面が表示されました。あっけないぐらい簡単に動きました。

で、さり気なくクリックした「Web IDE≫」で腰を抜かすなど。


ブラウザーだけでソースコードが見れて、しかも修正もできそうだ。

とはいえ、デバッガーで追いかけたいので、ローカルのPHPで動かそう。
とか思っていたらPHPのビルトインサーバーでもデバッガーが動いた。xdebugからの出力をポートで受けるので関係なかったのか…

コードリーディング

さて、一時間ほど追いかけたが、ひとまずここまで。
理解したとは到底言えない状態だけれども、
大きくくくれば、
1)ゴニョゴニョとセットアップ、
2)ページリソースを取得、
3)HTMLに展開、
となっている事を確認した。
当たり前すぎて泣けてくる。

リソースのコード自体はBEAR.ResourceにあるResource.phpで、ほとんどDSLのようにマジックメソードを使って、あちこちの機能を呼んでいる。もっともクラスとしては比較的に小さくて分かりやすいと思う。

リソースの本体はSandbox以下にあるResourceフォルダーに入っている。ココらへんで、半年近く前に追いかけた内容を、ようやく思い出してきた。

最初にPageリソースが呼ばれ、その中からAppリソースが呼ばれる。

次に調べたいのは、
・DIコンテナがどこで設定されているか?モジュールかな?
・リソースとコンストラクション、
・$appって何だろう?
あたりから始めよう。

やっと眠くなってきたので、おやすみなさい。

2012年12月6日木曜日

PHPで「かっこういい」HTMLタグ生成クラス

2012年PHPアドベントカレンダー6日目です。

ちょっと前に、HTMLフォーム要素を動的に出力する必要が出てきて、調べても使いやすそうなクラスが見つからなかったので自分で作ったものです。

思った以上に「格好良い」ものができたので、広報してみることにしました。

ソースコード:https://github.com/asaokamei/Tags

コンストラクション


$tags = new Tags();

依存性ゼロです。簡単に使えます。

簡単なサンプル


早速、簡単な使い方の例を見てみます。
echo $tags->a( 'link' )->href( 'tags.php' );
// <a href="tags.php">link</a>

なにか、いい感じですよね!?
タグをネストしてみます。

$ul = $tags->ul(
  $tags->li( 'list #1' ),
  $tags->li( $tags->img()->src( 'img.gif' ) ),
  'just a text'
);
echo $ul;
/*
<ul>
  <li>list #1</li>
  <li><img src="img.gif" /></li>
  just a text
</ul>
*/

htmlタグと同じように使えます。

なおimgの場合はタグで囲まないようになってます。

基本的な使い方



使い方は、
最初にHTMLタグ名のメソード名にして、
後はアトリビュート名をチェーンしてゆきます。

$tags->tag( '中身' ) -> attr1( val1 ) -> attr2( val2 );
// <tag attr1="val1" attr2="val2">中身</tag>

基本、タグ一個につき、オブジェクト一つ作ります。

imgやinputなどのタグは、終端タグを出力しないようになっています。

少し複雑なサンプル


最初にTagsオブジェクトを作っておいて、後から中身を追加することもできます。複雑になりがちなoptgroupのあるSelect文を作ってみます。

$lang = array(
//  array( value, option name, optgroup ), ...
    array( 'zhi',  'chinese',   'asia'   ),
    array( 'jpn',  'japanese',  'asia'   ),
    array( 'kor',  'korean',    'asia'   ),
    array( 'eng',  'english'             ),
    array( 'fra',  'french',    'europe' ),
    array( 'ger',  'german',    'europe' ),
    array( 'spa',  'spanish',   'europe' ),
);
$select = $tags->select()->name( 'language' );
$groups = array();
foreach( $lang as $item ) // ループ languages.
{
    $option = $tags->option( $item[1] )->value( $item[0] );
    if( isset( $item[2] ) ) // has an optgroup.
    {
        if( !isset( $groups[ $item[2] ] ) ) { // 新規 optgroup.
            $groups[ $item[2] ] = $tags->optgroup()->label( $item[2] );
            $select->contain_( $groups[ $item[2] ] );
        }
        $groups[ $item[2] ]->contain_( $option );
    }
    else {
        $select->contain_( $option );
    }
}
echo $select;
/*
<select name="language">
  <optgroup label="asia">
    <option value="zhi">chinese</option>
    <option value="jpn">japanese</option>
    <option value="kor">korean</option>
  </optgroup>
  <option value="eng">english</option>
  <optgroup label="europe">
    <option value="fra">french</option>
    <option value="ger">german</option>
    <option value="spa">spanish</option>
  </optgroup>
</select>
 */

中身を追加する際は、contain_メソードを使います。

タグがオブジェクトのままなので、後から好きなだけ中身を追加できます。
昔書いたoptgroupのコードに比べて、短くすっきりできました。

オブジェクトなので


後から中身を強制的に変更することもできます。


$input = $tags->input()->type( 'check' )->name( 'checkMe' )->value( 'Yeap' );
echo $input;
$input->walk( function( $tags ) {
    if( isset( $tags->attributes['name'] ) ) $tags->attributes['name'].='[]';
} );
echo $input . "\n";
/*
<input type="check" name="radioMe" value="Yeap" />
<input type="check" name="radioMe[]" value="Yeap" />
 */

walkというメソードは、変数内のTagsオブジェクトをすべて走査して、クロージャーを適用します。これが理由で、多くのプロパティはpublicだったりします。

例は、nameアトリビュートに「[]」を追加して、配列に変えています。

コードについて少し解説


中身はどうなっているのか?
PHPのマジックメソードを使っています。

public function __call( $name, $args )
{
    // attribute or tag if not set.
    if( is_null( $this->tagName ) ) { // set it as a tag name
        return new static( $name, $args );
    }
    else {
        $this->setAttribute_( $name, $args );
    }
    return $this;
}

と言っても、それほど変なことはしてなくて、

  1. 自分自身にtagNameが設定されていなければ、新しくオブジェクトを作ってタグ名を設定して、返しています。
  2. tagNameが設定されていれば、アトリビュートとして追加して、自分自身を返しています。


なかなか気に入ったものが出来ず、試行錯誤しましたが、一番最初のメソード名をタグ名と考えることに気がついたことで使いやすくなりました。欲しいHTMLと同じ順番でコードをかけるので、迷わず使えます。

文字列への変換する部分です。

public function __toString()
{
    return $this->toString_();
}

オブジェクトが文字列に変換する際には、__toStringメソードが呼ばれるので、そこでHTMLタグとして文字列を返しています。

この先のコードは・・・
出力をキレイにしようとすると、コードが汚くなる不思議。

参考サイト


php-XML_Builder
php-class-html-generator

使っている技法は「メソードチェーン」と呼ばれるものですが、DSL(ドメイン・スペシフィック・ランゲージ)を作っているという考えかたもあるようです。

それで検索して見つけたのが、このプレゼンテーション
使い方は、まだ簡単になりそうですね。

2012年12月2日日曜日

ウェブでのInteractionとContextの実装例

前回前々回に書きなぐったDCIの続きです。
あのあと試行錯誤しながらコードを書いているうちに、自分なりに納得できるところまで来ました。ということで、もう1ヶ月以上コーディングしてるんですね。なお、今回は実際に動かしました。

参考コード: https://gist.github.com/4185350
実際に動かすには、他のオブジェクトが必要です。

interactで登録フォーム



インターアクションを使った登録フォームのコードです
動きも今までと同じ、ただしメソードも含めて
  1. get form : フォームを表示。
  2. post form : フォームからの登録を読み込む。
  3. get confirm : トークンをつけて確認画面を表示。
  4. post save : トークンを確認したらデータを保存して、完了画面を表示。
という処理を行います。

ここにあるContextというのは、処理のまとまり、なわけですが…

コンテキストってなんでしょう?
日本語だと文脈なのですが。

このコードでは、
  • データ(エンティティ)に操作して何らかの処理を行う、
  • アクションがコンテキストに対応しているかどうかを判断する、
というルーチンをコンテキストと呼んでます。

今の実装だと、contextXXXからの返り値がfalse以外の場合はコンテキストに対応するので、ビューを表示します。

一方、返り値がfalseの場合は(なんか処理は行ったかもしれないけれど)コンテキスト外なので次の処理に進みます。

contextFormAndLoad


例として、contextFormAndLoadの処理を簡単に説明すると、
  • 必ず一回はフォームを表示する(trueを返す)。
  • アクションが$formと一致する(trueを返す)。
  • アクションが$formと一致しメソードがポストの場合は$_POSTからデータを読み込んでエンティティに書き込む(コンテキストと関係なく必ず処理されます)。
  • 必ずデータはバリデートする。
  • バリデーションで問題があった場合(trueを返す)。
返り値がtrueの場合、コンテキストに対応するということで登録フォームを表示します。複雑ですね。

そのコードです
複雑怪奇ですね。

最初に納得したとか書きましたが…
自分でしか理解できないコードな気がします。

また、このブログを書きながら、コードを見なおしてみて、切り分け方が今ひとつだなと感じてるし… また後で、書きなおす予定。

Interactionクラス


さて、今回のコードの基本がInteractionクラス。セッションに自分自身の状態を保持・読み出します。エンティティも最初に一度作り、あとはセッションから読みだします。

フォームを一度だけ表示する、データを二重に保存しない、という機能を実現するためにpinPoint/checkPinという簡単なメソードを使うことで実現しました。$this->checkPin( 'save' );とすれば、一度だけsaveの状態を実行できます。

なお、ピンだけだとCSRF対策としては弱いと思うので、
別にトークンを使ってます。

ココらへんをInteractionクラス側に隠したことで、処理フローを制御しているのが$actionのみ(に見える)ため、前回よりコードが(少しは)見通しが良くなったと思ってます。

大事なのは、汎用性が高く、使いやすくて、バグのない、コンテキストをたくさん用意できるか?という事になりそうです。