2009年2月3日火曜日

Django for PHP

Pluf
出ました。
いや、出てました。
すばらしい。

テンプレートエンジン以外はPure PHPと言うところがウリの一つです。

まずURL設定。

$ctl = array();
$base = Pluf::f('idf_base');

$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/$#',
'base' => $base,
'priority' => 4,
'model' => 'IDF_Views_Review',
'method' => 'index');

$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/(\d+)/$#',
'base' => $base,
'priority' => 4,
'model' => 'IDF_Views_Review',
'method' => 'view');

$ctl[] = array('regex' => '#^/p/([\-\w]+)/review/create/$#',
'base' => $base,
'priority' => 4,
'model' => 'IDF_Views_Review',
'method' => 'create');
return $ctl;

うん、まあこんな感じだろうね。
重複も多いし、modelとmethodで分かれているから、少し長い。
あと、分割も標準の方法が見つからないのでもう一工夫ほしいところ。


viewは見慣れたコード。
名前付き引数がないので$match[1]になることと、
名前空間がないので、名前が長くなることがおしい。

public function updateItem($request, $match)
{
$item = Pluf_Shortcuts_GetObjectOr404('Todo_Item', $match[1]);
$new_data = $item->getData();
if ($request->method == 'POST') {
$form = Pluf_Shortcuts_GetFormForModel($item, $request->POST);
if ($form->isValid()) {
$item = $form->save();
$url = Pluf_HTTP_URL_urlForView('Todo_Views::viewList',
array($item->list));
return new Pluf_HTTP_Response_Redirect($url);
}
} else {
$form = Pluf_Shortcuts_GetFormForModel($item, $item->getData());
}
return Pluf_Shortcuts_RenderToResponse('todo/item/update.html',
array('page_title' => 'Update a Todo Item',
'item' => $item,
'form' => $form));
}



テンプレート

{extends 'todo/base.html'}

{block body}
<h2>{$list.name}</h2>

{if $items}
<ol>
{foreach $items as $item}
<li><a href="{url 'Todo_Views::viewItem', array($item.id)}">{$item.item}</a></li>
{/foreach}
</ol>
{/if}

<p><a href="{url 'Todo_Views::addItem', array($list.id)}">Create a new item</a> | <a href="{url 'Todo_Views::updateList', array($list.id)}">Update the list</a></p>
{/block}

すばらしい。
文句のつけようがありません。
まあ、テンプレートエンジンだから当然か。
ところどころPHPの流儀を守っているところがさすがです。

しっかりテストクライアントが付いているところが粋です。

$client->post('/login/', array('login' => 'toto',
'password' => 'secret'));
$client->get('/privatepage/');
$reponse = $client->get($url, array('optional_get_param' => 'toto'));
$this->assertEqual(200, $response->status_code);
// print $response->content;
// print_r($response->template);


モデル

class Todo_Item extends Pluf_Model
{
public $_model = __CLASS__;
// ここに定義を書く
function init()
{
// テーブル名。設定ファイルでprefix設定可能
$this->_a['table'] = 'todo_items';

// クラス名を書く。PHPって自分のクラス名を取れなかったっけ?
$this->_a['model'] = 'Todo_Item';

// フィールド定義
$this->_a['cols'] = array(
// 残念ながらID定義は必要
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
),
'item' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
'size' => 250,
'verbose' => __('todo item'),
),
'completed' =>
array(
'type' => 'Pluf_DB_Field_Boolean',
'default' => false,
'verbose' => __('completed'),
),
'list' =>
array(
// おまちかね。関連設定。verboseがrelated_nameになる。
'type' => 'Pluf_DB_Field_Foreignkey',
'blank' => false,
'model' => 'Todo_List',
'verbose' => __('in list'),
'help_text' => __('To easily manage your todo items,'.
'you are invited to organize your todo items in lists.'),
),
);
}

get_ + lower case name of the related model + _list
で関連リストが取れます。
でもどうでしょうね。
定義も単純だし、Selectも弱いので、こればっかりは様子見か。


FormはDjangoに忠実。
すばらしいです。
これは使いやすい。
ちゃんとFormForModelがあるので安心。
このFormと他ORMのアダプタをいくつか書いたほうがいいんじゃないのかな。
clean_nameなどのValidationも健在。


middlewareもあるし、
Dispatcherも「おっ!」と思うほどシンプル。
さらになんと、CodeIgniterよりも速い!
残念ながら、Djangoとディレクトリ構成が違うため、
規模が大きくなると散らかってしまうかも。
このあたりはLoaderを書き直してほしい。


面白いことに、このソースが配布されている
http://projects.ceondo.com/自体がPlufで書かれています。
git,svn,hgに対応したSourceBrowser,CodeReviewerにIssueTracker。
非常によいサンプルになり、なおかつ、読みやすいことがわかるのでとてもよい。
http://projects.ceondo.com/p/indefero/
この規模がこれだけ読みやすいなら個人的な用途は十分まかなえそうです。
PHPのソースで読みやすいと感じたのは久しぶりです。

これが広まれば、きっとPHPからDjangoへ流れる人が増えるはず。
PHP派もDjango派も目いっぱい布教しましょう。
オススメです。

0 件のコメント: