Akelosを使う

新しいプロジェクトで一瞬CakePHPを使おうとしたけど、なんか気持ち悪いのでやめることにした。
ということでどのフレームワーク使おうかという提案をしなきゃいけないのでいろいろ調べてたらAkelosが良い感じに気持ちがよさそうなので使ってみる。日本語の情報は今のところ希少。

  • RoRのコピーを目指してるらしい
  • PHP4でも5でも動くよ
  • PEARとか使ってないよ
  • まだベータだけど全然使える

という感じなので、早速スクリーンキャストを見て自分なりにまとめてみる。
ちなみに実際にプログラムをさわらずに書いてるので間違いがあるかもしれない。


Akelosのダウンロードは公式から。svn でもいいし tarball 落としてきて展開しても良いし。
とにかく公開ディレクトリではない適当なところに入れておく。

1.プロジェクトの準備

$ /[PathToAkelos]/akelos ~/Project/Blog
$ cd ~/Projects/Blog
$ ln -s ~/Projects/Blog/public /[PathToDocumentRoot]
$ open http://localhost/

これでAkelosのプロジェクトセットアップ画面が出ればおk。

2.初期設定

ウィザード形式でセットアップを行う。
※でもその前に ~/Project/Blog 配下を chmod -R 777 しておかないとエラーがでるんじゃないか?
 もしくは chgrp -R www-data して chmod -R g+w でもいいかもしない。

 11/16追記: chmod -R 777 じゃダメだ。どうやら chgrp -R www-data と chmod -R g+w が正解。

データベースの選択

利用可能なDBが表示されるのでMySQLを選択

開発用、製品用、テスト用のDBを作成

コンソール等で開発用、製品用、テスト用のDBを作成しておく
スクリーンキャストではそれぞれ「blog_dev, blog, blog_tests」にしてる。

DB接続設定

作成したDBへの接続設定を行う。まぁ見たまんま。

言語設定

Akelosは国際化にも対応できるっぽい。とりあえず日本語しかないなら「ja」だけ入力しておけばいい。
複数言語を切り替えるなら「ja,en,ch」みたいな感じで入力

完了

これで完了。というかこれだけならconfig直接いじってもいいんじゃないかと。

3.コントローラの作成

./script/generate controller コントローラ名

上記コマンドでコントローラを生成できる。このコマンドで作られるファイルは

  • app/controllers/コントローラ名_controller.php
  • app/helpers/コントローラ名_helper.php
  • test/functional/controllers/コントローラ名_controller.php
  • test/fixtures/app/controllers/コントローラ名_controller.php
  • test/fixtures/app/helpers/コントローラ名_helper.php

の5つ。スクリーンキャストではBlogコントローラを作成。

$ ./script/generate controller Blog

この状態で http://localhost/blog にアクセスすると「indexアクションがありませんよ」というエラーが出るので
app/controllers/blog_controller.php に indexアクションを追加

<?php

// 略

  function index()
  {
    $this->renderText('Hello World!');
  }

http://localhost/blog にアクセスし「Hello World」を確認。renderText(文字列)は文字列をViewに渡して終了。

今度はView用にファイルを作って表示させてみる。

indexアクションから $this->renderText('Hello World!'); を削除し
app/views/blog/index.tpl を作成する。

app/views/blog/index.tpl
<h1>Hellow World!</h1>

http://localhost/blog にアクセスし確認する。

ということで

  • Controllerは app/contollers/コントローラ名_controller.php
  • Actionはコントローラクラスの function アクション名(){}
  • Viewテンプレートは app/views/コントローラ名/アクション名.tpl

という命名規則になってるみたい。

4.モデルの作成

./script/generate model モデル名

上記コマンドでモデルを生成できる。このコマンドで作られるファイルは

  • app/models/モデル名.php
  • app/installers/モデル名_installer.php
  • test/unit/モデル名_test.php
  • test/fixtures/モデル名(複数形).yml

の3つ。スクリーンキャストではPostモデルを作成。

./script/generate model Post

app/installers/post_installer.phpを編集
<?php

//略

  function up_1()
  {
    $this->createTable('posts', "
      id,
      title
    ");
  }
  function down_1()
  {
    $this->dropTable('posts');
  }

このようにインストーラファイルに記述することで、migrateコマンドでテーブルのインストールができる

$ ./script/migrate Post install

postsテーブルにidとtitleカラムが作成される。
ちなみにidは自動的にプライマリキーに設定してくれて、titleはちゃんとVARCHARになる。ありふれたカラム名なら賢くやってくれるみたいだ。
※ちゃんと指定したいなら

$this->createTable('posts', "
      id,
      title VARCHAR
    ");

みたいに書けば良いのか?

5.足場の作成

./script/generate scaffold モデル名 コントローラ名 --force

上記コマンドで指定したモデルをCRUDするためのアクションをコントローラに自動生成してくれる。
多分内容は思い切り上書きされるので、開発中期にやってしまわないように。

./script/generate scaffold Post Blog --force

http://localhost/blog にアクセスし確認すると、単純なCRUD用のアプリケーションができている。
これを元に開発を進めていくと良いよって事だろう。


ここで、データベースにカラムを追加してみる。

app/installers/post_installer.phpに追加
<?php

// 略

  function up_2()
  {
    $this->addColumn('posts', 'body text');
  }

installerはバージョンの管理(app/installer/versions 配下)されているので、前述の function up_1(){} に追加してもダメ。正しくは function up_2(){} に処理を追加する事。


postモデルのmigrateを実行

$ ./script/migrate post install

再度足場の作成を実行

$ ./script/generate scaffold Post Blog --force

http://localhost/blog にアクセスしいろいろやってみる。ちゃんと本文(body)の編集ができるようになっている。

さらにapp/installers/post_installer.phpに追加

<?php

// 略

  function up_3()
  {
    $this->addColumn('posts', 'posted_at');
  }
$ ./script/migrate post install
$ ./script/generate scaffold Post Blog --force

今度はposted_atカラムを追加した。モデル名(複数形)_at カラムは自動的にdatetime型になり、insertした際にタイムスタンプが自動登録されるマジックカラム。

他にもモデル名に依存しない感じで created_at, updated_at とかがあるのだろう。多分。

http://localhost/blog にアクセスし日時カラムの追加されたのを確認

app/controllers/blog_controller.phpを開き、足場作成後の状態を確認してみる。いろいろアクションが追加されているはず。

6.バリデーション

app/models/post.phpを開き以下を追加

<?php

// 略

  function validate()
  {
    $this->validatesPresenceOf('title');
  }

このようにすることでtitleカラムのチェックを行えるっぽい。
http://localhost/blog/add よりtitle空欄での追加時にエラーが表示されることを確認
※他にどんなvalidateメソッドがあるのかあとで調べる。

7.SintagsによるViewの編集

SintagsはViewテンプレートで使用されるテンプレート言語。ちなみにネイティブなphpでも構わない。基本的には {〜} で記述されるらしい。

$ ./script/generate scaffold Post Blog --force --sintags

↑これは意味不明。--sintagsを付けたらどうなるのか?付けないとsintags自体が使えないの?後で確認。

Sintags {〜} を使ってViewの編集

{post.body}: $Post->body
{post.posted_at}: $Post->posted_at

↓これらはsintagsじゃないけど一応出てきたのでおさらい

<%= link_to リンクタイトル, :controller => コントローラ名, :action => アクション名, :id => xx, ... %>

<%= link_to_edit post %>: これはblog_helperに自動的に追加されたヘルパーでeditアクションへのリンクを作る

<%= textilize post.body %>: textilizeで構文整形する

<%= render :partial => 'post' %>: パーシャル「_post.tpl」を読み込む

<%= render :partial => 'post', :collection => posts %> パーシャル「_post.tpl」にpostsからpostを渡して表示

_post.php
  <h2>{post.title}</h2>
  <p>{post.body}</p>
  {post.posted_at}

8.モデルの追加

Commentモデルを追加してみる。

$ ./script/generate model Comment
app/models/comment.phpにアソシエーション設定

var $belongs_to = 'post';

app/models/post.phpに1対多のアソシエーション設定

var $has_many = 'comments';

app/installers/comment_installer.php
<?php

// 略

  function up_1()
  {
    $this->createTable('comments', "
      id,
      body,
      post_id
    ");
    
    Ak::import('post,comment');
    $Post = new Post(1);
    $Post->comment->create(array('body' => 'HOGE'));
    $Post->save();
  }
  
  function down_1()
  {
    $this->dropTable('comments');
  }

コメントモデルをinstallしてみる

$ ./script/migrate comment install

app/views/blog/show.tplにcommentのviewを追加

  {loop post.comments}
    {comment.body}
  {end}
  
  <%= form_tag :action => 'comment', :id => post.id %>
  <%= text_area 'comment', 'body' %>
  <%= submit_tag 'Comment!' %>
  </form>

app/contollers/blog_controller.phpにcommentアクションを追加

<?php

// 略

  function comment()
  {
    $Post = $this->Post->find($this->params['id']);
    $Post->comment->create($this->params['comment']);
    $Post->save();
    
    $this->flash['notice'] = $this->t('Your comment was successfly');
    
    $this->redirectTo(array('action' => 'show', 'id' => $Post->id));
  }

http://localhost/blog で動作確認。ちゃんとcommentモデルが呼び出せてる。

ここではなんかいろいろやってる。Sintagsで {loop 〜}〜{end} が出てきた。foreachの事だろうけど、複数形から単数形の自動処理が気持ちよさそう。
$this->t('〜')ってなんだ?多言語対応用?あとflash['notice']もよく分からない。これはViewにflash変数をassignしてるだけか?

9.国際化対応

まとめると

  • View内で _{〜} として書かれた内容は多言語表示可能
  • app/locales/blog/en.php とか ja.php とかに連想配列で辞書を書くといいよ
  • 言語の切替は http://url/[ここにenとかjaとか]/〜 で簡単にできるよ

って事だろう。ここは

10.ログ

app/configs/config.php に以下を追加することで動作ログをとれる

  define ('AK_LOG_EVENTS', true);


tail -f log/development.log とかすればリアルタイムにログ見ながら開発できて幸せになれるらしい。

11.ユニットテスト

test/unit/app/models/post.php とか comment.phpとかに書く
./script/test unit でテストの実行。
例えば以下のような感じになる。

test/unit/app/models/post.php
<?php
()

    function test_Post()
    {
      $Post = new Post(array('title' => 'testtest', 'body' => 'hoge, fuga'));
      $Post->comment->create(array('body' => 'Hello!'));
      $Post->save();
      $Post->reload();
      
      $this->assertEqual(1, $Post->comment->count());
    }


上記実行は Passed: 1 Failure: 0

$this->assertEqual(2, $Post->comment->count()) にすると Passed: 0 Failure: 1 になるよってこと。

12.コンソール

コンソールからもモデルを利用できるのでデバッグに便利

$ ./script/console

>> $Post = new Post(1);

>>> $Post->title = 'TEST from console';

>>> $Post->save();

全部期待通りに動くよ。



だいたいスクリーンキャストはこんな感じか。まだ実際にさわってないので分からないけどRails使いたいけどPHPしか環境無い場合とか、CakePHPが気持ち悪く感じた時はかなり使えそうな予感がしている。でも多分scaffoldはつかわないだろうなー。