アジャイル,Trac,オープンソースなどの話。認定スクラムマスター。Twitterは@ryuzee
久々のどうでもよい話。
別にKVSなんて今に始まった話でもないんだけど、ちと仕事で使うかもしれないので試してみた。
以下の特徴をもつ所謂NoSQLデータベースの1つ。(特徴の日本語訳はこのへん)
MongoDBはこの辺からダウンロード
Mac用もWindows用もその他のOS用もビルドされたモジュールが用意されている。
試験環境はWindows XP SP3(32bit)なので、それに該当するものをダウンロード
ダウンロードしたファイルは単なるzipファイルなので、解凍して適当な場所に配置する。
以上で準備完了。
起動するには、binディレクトリに移動して、コマンドプロンプトで
とすれば良い。
これだとMongoDBを開始・停止するのが面倒なのでWindowsのサービスに登録する。こんなかんじでコマンド打つとサービスとしてインストールされる。
なお、--dbpathの指定をしないとうまくインストールできないようなので注意
(Linuxの人は/etc/rc.d/init.d/あたりに起動スクリプト用意すればよし)
ちゃんとPHP用の拡張が用意されている。
Linux系の環境なら
として、php.iniに
を追加すればOK。
Windowsの場合は、peclコマンドでソース持ってきたところでコンパイルできないので、バイナリを導入する。
詳細はPHPのマニュアルに書いてある。
テスト環境はPHP5.2.8なので、こちらのTSモジュールをダウンロード・解凍して、php_mongo.dllを[XAMPPのインストールフォルダ]/php/extにコピーする。
(XAMPPの場合は、Thread Safe版のモジュールでないと、php5.dllが無いぞ~、というエラーでPHPが起動しないはず)
その上で、php.iniに以下を追記(XAMPPの場合、apache/bin/php.iniとphp/php.iniの2つの設定ファイルが利用される。前者はapache経由の場合、後者はCLIの場合)
その後(一応)XAMPPのapacheを再起動しておく。
このチュートリアルが良くまとまっている(英語)ので、それを見ればおおよそ分かる。
コンストラクタの引数に、下記のように接続先のMongoDBの情報を設定できる。
もしこのtestdbが存在しなければ自動で作られる。
コレクション(テーブルみたいなもん)も存在しない場合は自動で作成される。
連想配列にセットして、insertすればOK。第二引数はoption配列で、safeをtrueに指定すると追加に成功したかどうかの戻り値を応答する。
テーブルのデータを全件取得する。
ID指定で検索できる。
開始位置や件数を指定できる。
IDを指定して、$setの配列に更新フィールドをセットすることでデータの更新を行う。
IDをキーにしてデータを削除する。safeオプションの意味は追加時と同じ。
CakePHPでMongoDBに接続するには以下を参照。
http://d.hatena.ne.jp/cakephper/20100122/1264140610
もうタイトルのまんまですが、データの更新時に自動でデータの差分を取得して履歴テーブルに突っ込むbehaviorを作りました。
自分で作っているアプリケーションで、データ更新時の変更履歴を表示させたいと思ったのだが、対象テーブルが沢山あっていちいち似たような実装をあちこちに作るのは気が狂いそうなので汎用化しちゃえ、というのが作った動機
AutoLoggerBehavior
http://github.com/ryuzee/auto_logger_behavior から入手可能
ライセンスはMITライセンス
1. 入手したauto_logger.phpをapp/models/behaviors/に配置
2. 履歴テーブルの作成
3. 履歴テーブル用のモデルを作成。上記のテーブルの場合はapp/models/以下にchange_log.phpという名でChangeLogモデルを作成
4. 履歴を取得したいモデルを開き、以下を追加。savetoには履歴を保存したいモデル名を指定する。省略時はChangeLogモデルとみなす。
5. 以上で完了。あとは対象モデルの新規作成、編集、削除時に自動で指定のテーブルに履歴が保存されます。
自分が使うために作ったので、あんまり細かくテストしていないです。ご利用は自己責任で。
別にUNIONに限らず、生のSQLを投げて取得したデータは、何でも同じようにページングできる。
・ページングのために利用する新しいモデルを作成する
・そのモデルでは$usetable=falseに設定し、既存のテーブルとは関連付けしない。
・そのモデルにおいて、paginate関数とpaginateCount関数をoverrideする。
・コントローラー側では、既存のpaginateと同じ利用の仕方をする。但し引数として設定しても無視する項目がある。
下記のサンプルコードはPHPMyScrumでのタスクとストーリーの横断検索機能の実装。
app/models/search.php
function setKeyword($value)
{
$this->keyword = "%" . $value . "%";
$this->bind_param = array(
ITEMTYPE_STORY,
$this->keyword,
$this->keyword,
ITEMTYPE_TASK,
$this->keyword,
$this->keyword,
);
}
/** * Overridden paginate method */
function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array())
{
if($page == 0){ $page = 1; }
$recursive = -1;
$sql = $this->base_sql . ' LIMIT '.(($page-1)*$limit) . ',' . $limit;
return $this->query($sql, $this->bind_param);
}
/** * Overridden paginateCount method */
function paginateCount($conditions = null, $recursive = 0, $extra = array())
{
$this->recursive = $recursive;
$results = $this->query($this->base_sql, $this->bind_param);
return count($results);
}
}
app/controllers/search_controller.php
function index()
{
$result = array();
if(isset($this->passedArgs['Search.query']))
{
$keyword = $this->passedArgs['Search.query'];
$this->Search->setKeyword($keyword);
}
$this->paginate = array(
'limit' => 20,
);
$result = $this->paginate();
$this->set('result', $result);
}
function search()
{
$url['action'] = 'index';
foreach ($this->data as $k=>$v){
foreach ($v as $kk=>$vv){
$url[$k.'.'.$kk]=$vv;
}
}
$this->redirect($url, null, true);
}
}
Webserviceコンポーネントを使うと、既存のコントローラーにほとんど手を入れることなく、簡単に応答をXMLやjsonに切り替えることが出来る。
Webserviceコンポーネントは、Jose Diaz-Gonzalez氏が作成し、MITライセンスで公開されている。
からgit cloneで入手する。
※日本語対応やいくつかの問題を筆者がforkして修正した。
入手したファイルのうち
controller/components/webservice.phpを自身のアプリケーションのcontroller/components/にコピーする。
views/webservice.phpを自身のアプリケーションのviewsにコピーする
app/config/route.phpを開き、末尾に以下を追加する
XMLやjson形式で応答したいコントローラーにおいて
を追加する。
以上で作業は完了。
XMLやjson形式で応答したい場合は以下のようにリクエストを行う。
/controller名/action名.xml
/controller名/action名.json
現在のコンポーネントだと、有効にしたコントローラーの全アクションでXMLとjsonの応答が有効になるけど、このあたりは簡単にカスタマイズできるだろう。
CakePHP標準だとRailsのような差分情報を含めたスキーマの管理ができず、不特定多数に配布するアプリケーションでの更新が困難だったり、開発現場でも人によってスキーマが異なってしまったり、といった問題が起こりやすかった。
このような問題を解決するのがCakePHP Migrations Pluginだ。
CakePHP Migrations Pluginは、CakeDCがMITライセンスで配布するオープンソースのCakePHPのプラグインで、これを利用するとRailsのMigrationと同じことが出来る!
詳細については
http://cakedc.com/downloads/view/cakephp_migrations_plugin
入手は最新版をgithubから。
http://github.com/CakeDC/Migrations
なお、動作検証はCakePHP1.3で行った。
でスキーマを生成する。
という順番で作業する
差分ファイルは以下のような形式で出力される(一部抜粋)。
Migrationファイルは最新のschema.phpをもとに差分情報を生成しているので、schema.phpが古い状態で複数のMigrationファイルを作成した場合、同時に適用すると同じ変更を複数回実行しようとしてエラーになる。
この場合は作成されたmigrationファイルのうちconflictするものを自分で削除し、map.phpを編集する必要がある。
なお、このmigration機能を利用するためには、modelが作成されていることが(ほぼ)前提となる。
また、僕の環境だと、debugモードが0だとモデルがキャッシュされており、schemaファイルやmigrationファイルに変更が反映されなかったので、debugモードは0以外にして作業を行うことが必要そうだ。
マイグレーションを実行するとき
とする。
問題ないようであれば以下のように出力される。
[002] 002
> Adding field display_name to users.
> Changing field email from users.
All migrations have completed.
なお、詳細なマニュアルは
http://cakedc.com/eng/downloads/view/cakephp_migrations_plugin
を参照のこと。
ハマったのでメモ。
となって、スキーマの生成で落ちてしまう。
modelディレクトリ以下のクラスにおいて、
でないモデルは全てテーブルが存在することを期待してしまっているのが原因。
なので、app_model.phpはappディレクトリの直下に置くようにする。
常識らしいが、無知というのは怖い。
かなり今更な自分用メモ。プラグインで解決できる。
QdsmtpはオープンソースSMTP用ライブラリで、こちらから入手できる。
僕はCakePHPでQdmailとQdsmtpの組み合わせでメールを送信することが多いんだけど、今回真面目にエラー処理をする必要があったので調べてみた。
で、以下が僕の実装なんだけど、たぶんQdmailでの定石だと思うのでメモしておく。
大事なのは上2行。errorDisplayをfalseにしないと、Qdmailでのエラーが、レスポンスで表示されてしまう。
またQdmailではQdsmtp側のエラーは抑止してくれないので、2行目の項目を入れないと、Qdmail側のエラーは抑止できても、SMTPサーバへの接続エラーみたいなPHPレベルでのエラーが画面に出力されてしまうことになる。
errorDisplayをfalseに設定しない場合、ListenしていないSMTPサーバにつなげようとすると、以下のようなエラーが画面に出る。
一方で、errorDisplayをfalseにしつつ、$this->Qdmail->smtpObject()->error_display = false;の設定をしていない場合は以下のように画面表示される。
両方設定していた場合は、接続先SMTPサーバが存在しなかったり、応答してくれない場合も、画面上にエラー文字列は出ない。
こういうところを適当にしておくと、環境情報が何かのきっかけで表に出てしまったりしてよろしくないので注意する必要がある。
2010/04/08にタイトル変更しました。すまんです。実は1.2.6を使っていたつもりで、1.3RCを使っていたというオチでした。
ちなみに以下の話は1.2系から1.3系に移行する場合はそのまま適用できます。
最近オープンソースのScrum支援ツールを作っていて、CakePHPを使っているのだが、最新の1.3RCで細かい挙動がかなり変わっていて、ちょっとハマったのでメモ。
は以下のようになる。
これに伴って、メール送信ライブラリのqdmailに手を入れる必要がある。qdmail.phpの3823行目付近
は以下のように変える必要がある。
ちなみに、沢山の箇所にrenderElementがあるような場合はapp_view.phpにrenderElementを定義すれば良いんじゃないかな?
画像リンクを作るときに、昔の定石では以下のようにしていた。(第5引数がリンク対象をエスケープするかどうか、だった)
でも、1.2.6では以下のようにする。
他にも気づいたら書く。
cakephpではSchema機能を使ってテーブルを作成することが出来る。
で、ついでにマスター系データもまとめて登録する方法が【CakePHP】お手軽便利なCakeSchemaに載っている。
ただ載っている方法には若干問題がある。
ということで僕なりにアレンジしたのが以下の方法。
schema.phpのafterメソッド
$model_names = array();
$prop = get_class_vars(get_class($this));
foreach($prop as $key => $value)
{
$s = Inflector::classify($key);
if (!($s == "Name" || $s == "File" || $s == "Path" || $s == "Log" || $s == "Connection" || $s == "Table"))
{
$model_names[] = $s;
}
}
if(!empty($event['create'])){
if(!isset($this->InitialValues)){
require_once($this->path.DS.'initial_values.php');
$this->InitialValues = new InitialValues();
}
$modelname = Inflector::classify($event['create']);
if($modelname == $model_names[count($model_names)-1])
{
foreach($model_names as $target_modelname)
{
$this->InitialValues->set($target_modelname);
}
}
}
}
肝は、全部のデータを最後のテーブルの作成完了後に作る、というだけ。
NameとかFileとか除外しているところはin_arrayで除外した方がいいけど、まぁいいか。
日記 PHP オープンソース インストールマニアックス IIS Trac MySQL Perl Linux Agile・生産性向上 wordpress フリーソフト 自宅サーバ 書評 ブックマーク phpMyFaq TraM Plugin 早起き Delphi apache CakePHP Firefox Ruby eclipse セキュリティ プラグイン アジャイル mojavi Subversion Ajax/Web2.0 SQLServer Zope サーバ フレームワーク phpBB 仮想化 PostgreSQL OpenVZ scuttle CMS 文字化け 自宅 翻訳・日本語化 ApacheDS LDAP Excel 生産性向上 CodeIgniter XAMPP hacks taskfreak 修正 言語ファイル Ajax SBM ダウンロード HTML::FillInForm mod_security 情報共有