IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Open source  >

PHP のフレームワーク: 第 5 回 外部タスクを統合する

フレームワークが作成したタスクのスケジューリングは、その方法さえ理解できれば容易で安全です

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

サンプルコード

原文はこちら

原文はこちら


レベル: 中級

Duane O'Brien (d@duaneobrien.com), PHP developer, Freelance

2008年 2月 19日

ほんの数年前、PHP に対する一般的な批判の中に、PHP が MVC スタイルのアーキテクチャーをサポートしていないというものがありました。現在では、開発者は数多くの PHP フレームワークの中から好きなものを選択することができます。この「PHP のフレームワーク」シリーズは、広く使われている 3 つの PHP フレームワークである、Zend、symfony、そして CakePHP を取り上げます。そして、この 3 つの各フレームワークを使ってサンプル・アプリケーションを作成し、また拡張しながら、各フレームワークの類似点と相違点を検証します。今回の記事では、外部タスクを統合し、スケジューラー cron を使って呼び出すことのできる単純なタスクを作成します。

このシリーズについて

このシリーズは、フレームワークを使いたいと思いながら、現在利用可能なフレームワークの詳細を検討する機会がなかった PHP 開発者のためのものです。このシリーズでは、この 3 つのフレームワークが選ばれた理由と各フレームワークのインストール方法を検証します。また、この 3 つの各フレームワークでテスト・アプリケーションを拡張して適切に扱えるようにします。そう聞くと膨大な作業に思えるかもしれませんが、心配はありません。必要な情報は理解しやすいブロックに分かれています。

第 1 回では、まずこのシリーズ全体の概要を示し、検証対象となるフレームワークを紹介するとともに、そのインストール方法を説明しています。さらに、これから作成する最初のテスト・アプリケーションについても説明しています。

第 2 回では、3 つの各フレームワークを使ってサンプル・アプリケーションを作成するための手順を、それぞれの類似点と相違点に焦点を当てながら説明しています。

第 3 回では、まずテスト・アプリケーションを拡張し、次にフレームワークのルールから外れた場合の処理を扱います。どのフレームワークも、それらのフレームワークが本来目的とする作業を実行する場合は適切に動作します。しかしどのプロジェクトでも、そのフレームワークでは想定されていない作業をしなければならない場合が必ずあります。第 3 回では、そうした例を説明しています。

第 4 回では Ajax のサポートに主な焦点を当て、ネイティブ・コードとサードパーティーのライブラリーを使って Ajax を利用する方法を検証します。具体的には、各フレームワークがどう振る舞い、よく使われる特定のライブラリーをどう扱うかを検証します。

第 5 回では、フレームワークの外部での作業について説明します。1 つのタスク (毎晩更新されるスクリプト) を考え、このタスクを完了するためのプロセスを各フレームワークについて検証します。




上に戻る


この記事について

アプリケーションとデータベースとのインターフェースを行う際、何らかの自動タスクを設定しなければならないことは珍しくありません。通常、こうしたタスクは、テーブルのプルーニングやアカウントの失効処理など、基本的なデータベース管理のためのものです。プログラミングの歴史では、こうしたタスクは Perl で作成することが一般的でした。確かに Perl は優れた言語ですが、PHP では得られないメリットをもたらしてくれるのでない限り、自動タスクとアプリケーションを 1 つの言語で作成した方が得策です。その方がサポートは容易であり、コードを共有することができ、また 2 つの言語の間を行ったり来たりしている間に構文で混乱することがなくなります。

そうした考えから、これまでの記事で Blahg を作成するのに利用したフレームワークを使って一般的な自動タスクを実行できたら非常に素晴らしいことです。フレームワークを使えば、既に確立されている一般的な構造を使ったり、作成済みのメソッドを使ったりすることができ、またモデルを使うことで得られるデータベースに依存しないタスクを維持することができ、特定のデータベースとインターフェースを取るためのコードを作成する必要がありません。フレームワークを使おうとするのであれば、すべてに対してフレームワークを使った方が得策なのです。

この記事では、30 日を超えた古い投稿をすべてプルーニングする、Blahg 用の自動タスクを作成する方法を調べます。このタスクはコマンドラインから呼び出すことができるため、cron のようなスケジューラーを使ってタスクを自動化することができます。ここでは、このアプリケーションを各フレームワークで作成し、Zend、symfony、そして CakePHP での自動タスクの処理がどう異なるのかを理解します。

この記事を読む前提として、このシリーズの第 1 回から第 4 回までを読み終えている必要があります。これらの記事では、各フレームワークに関してインストール方法や前提条件、最初のアプリケーションの作成と拡張、そして Ajax について説明しています。まだこれらの記事を読んでいない人は、今すぐ読んでください。

注意: それぞれの記事には、その記事で作成され、説明されているすべてのコードを含んだ ZIP ファイルが含まれています。これらのファイルは、その記事全体をとおしてコード・アーカイブと呼ばれます。




上に戻る


近道を避けます

フレームワークの構造を考えると、cron から呼び出せる自動タスクを作成するための近道があります。つまりそのタスクを既存の (あるいは新しい) コントローラーの中のアクションにし、そのアクションを wget を使って呼び出すのです。この方法が動作しないということはありません。タスクを実行する方法として安直で、そして何よりもセキュアではない方法でも構わないのであれば、おそらく wget を使う方法で十分でしょう。

しかし、この「セキュアではない」という言葉を聞いたら、気を付ける必要があります。この wget を使う方法で自動タスクを作成すると、外部の人がそのタスクを利用できることになります。たとえこのアクションに対してどんな方法でもリンクさせず、Mxyzptlk という名前のコントローラーを使い、あるいはこのアクションを実行するために 40 文字の固有のストリングを渡さなければならないようにしたとしても、それでもやはり外部からアクションを実行できてしまいます。難解にすることによるセキュリティーは、とてもセキュリティーとは言えません。自動タスクはデータベース操作を中心とするものが多いため、データベースに関するアクションをランダムに実行されるのは望ましくありません。

そのため、タスクを自動化するための近道があるにしても、理想的にはもっとセキュアな手法を探す必要があります。これから示す例はどれも、各フレームワークでタスクを自動化するための 1 つの方法を示しています。方法は必ず複数あります。この記事を読み終えたら、皆さん独自の方法を試す、あるいはさらに調査する必要があるでしょう。そして他の人達が行った方法を調べてみてください。

また、ぜひ先に進む前にテーブルをバックアップしておいてください。操作の中で一部のレコードを削除します。そのため、後でテストを行えるようにテーブルをデフォルトの状態に戻すことができると便利です。

前置きはこのくらいにして、実際の説明に入りましょう。




上に戻る


Zend Framework での外部タスク

Zend Framework では何から何まで選択できることから、このフレームワークを使って自動タスクを作成する場合には、何を使い、何を使わないかを少し柔軟に判断することができます。Web リクエストを扱う既存のフロント・コントローラーを使って Web アプリケーションにアクセスするわけではないため、スクリプトの実行を管理するための追加のコントローラーを作成する必要があります。このコントローラーは、モデルに対してオートローダーを登録し、ベース・アダプターを定義する、という点ではフロント・コントローラーと似ています。しかし重要な違いは PHP のインストールや構成にあるかもしれません。

Web サーバーから PHP を呼び出す場合と比較すると、コマンドラインの PHP は通常、異なる SAPI (Server Application Programming Interface) を使って実行されます。PHP のインストールと構成の方法にもよりますが、異なる SAPI を使うということはインクルード・パスが異なるということを意味しているかもしれません。そのため、include_path ini の設定には Zend Framework のファイルをインストールした /column/include ディレクトリーを含める必要があります。

注意: OS によって include_path の定義方法が異なることを忘れないでください。以下の例は Linux® の場合です。

これから作成する、スクリプト・コントローラーとスクリプト関係の追加ファイルを保存するために使用する、/column/protected/zend/scripts という新しいディレクトリーを作成します。今回は 1 つのタスクを作成するだけなので、まず新しい scripts ディレクトリーの中にファイル prune.php を作成することから始めます。このファイルの前半にはスクリプト・コントローラー用の基本的なコードが含まれています。


リスト 1. スクリプト・コントローラー用のコード
                
<?php

ini_set('include_path', ini_get('include_path') . ':/column/include');

require_once("Zend/Loader.php");
Zend_Loader::registerAutoload();

$params = array(
        'host'          => 'localhost',
        'username'      => 'frameworks',
        'password'      => 'fwpw',
        'dbname'        => 'zend'
);

$db = Zend_Db::factory('PDO_MYSQL', $params);

Zend_Db_Table::setDefaultAdapter($db);

このファイルの残り部分には、実行対象となる単純なタスクが含まれています。投稿モデルをインクルードしてインスタンス化し、where 節を作成して標準的な delete クエリーを実行します。


リスト 2. 実行対象のタスク
                
require_once("/column/protected/zend/models/Posts.php");

$posts = new Posts();

$where = $posts->getAdapter()->quoteInto('modified  < ?', 
    date('Y-m-d H:i:s', strtotime('-30 days')));

$posts->delete($where);

?>

これができあがると、このスクリプトをコマンドラインから実行することができます (php /column/protected/zend/scripts/prune.php)。

このスクリプトをコマンドラインから呼び出せると、このスクリプトをスケジューリングしたりバッチ処理したり、あるいは cron を使って実行したりすることができます。このスクリプトを午前 0 時に実行するための crontab のエントリーは、00 00 * * * php /column/protected/zend/scripts/prune.php のようなものになります。

スクリプト・コントローラーが作成できると、Zend Framework を使ってスクリプトを実行するための大量のオプションを利用できるようになります。また、スクリプト・コントローラーでもアプリケーションの他の部分と共通のモデルを使用することができ、必要な場合には複合スクリプト・オブジェクトを作成できるなど、さまざまなことができます。

これで、Zend で cron ジョブを行うための方法はよく理解できました。次は同じことを symfony で行う方法を調べてみましょう。




上に戻る


symfony での外部タスク

Zend Framework でコマンドライン・スクリプトを実行したい場合には、フロント・コントローラーの代わりに使用できるスクリプト・コントローラーを作成しました。symfony の場合も、ほとんど同じです。

まず symfony の Blahg スクリプトを保存しておくディレクトリー (/column/protected/sf_column/apps/blahg/scripts/) を作成し、さらに新たなスクリプト・コントローラーとなる、prune.php というファイルを作成します。このファイルの前半は (皆さんが作成した) symfony のフロント・コントローラーとほとんど同じです。必要な定数を定義し、config ファイルを要求します。今回違うところは、symfony のインスタンスを取得するための方法にあります。フロント・コントローラーの中では、コントローラーを探してリクエストをディスパッチするように symfony に指示しましたが、スクリプト・コントローラーの場合は、そうはしません。


リスト 3. 必要な定数を定義し、そして config ファイルを要求する
                
<?php

define('SF_ROOT_DIR',    '/column/protected/sf_column');
define('SF_APP',         'blahg');
define('SF_ENVIRONMENT', 'prod');
define('SF_DEBUG',       false);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR
.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');

sfContext::getInstance();

次に、投稿モデルに渡して delete を実行するための基本的な Criteria を作成します。


リスト 4. 基本的な Criteria を作成する
                
$c = new Criteria();

$c->add(PostPeer::MODIFIED, date("Y-m-d H:i:s", 
          strtotime("-45 days")), Criteria::LESS_THAN);
$posts = PostPeer::doDelete($c);

このファイルを保存すれば、すべて終わりです。これで、Zend Framework の場合とほとんど同じように、このスクリプトをコマンドラインで実行することができます (php /column/protected/sf_column/apps/blahg/scripts/prune.php)。

このタスクをスケジューラーから呼び出す方法も、Zend Framework の場合とほとんど同じです (もちろん、Zend スクリプトではなく symfony スクリプトを指定します)。cron は、00 00 * * * php /column/protected/sf_column/apps/blahg/scripts/prune.php のようになります。

最後に、同じタスクを CakePHP で行う方法を調べてみましょう。




上に戻る


CakePHP での外部タスク

Cake コンソールは CakePHP V1.2 の新しい機能であり、Cake フレームワークにコマンドライン・インターフェースを提供します。独自のコマンドライン・タスクを作成するためには、いわゆるシェルを作成します。シェルは、これまでに作成したコントローラーとほとんど同じようなものです。

まず、/column/protected/cakephp/app/vendors/shells ディレクトリーでファイル prune.php を作成することから始めます。これは prune という新しいシェルであり、30 日を超えた古い投稿をすべて削除するために使われます。シェル・クラスを継承する新しいクラス、PruneShells を定義します。これから投稿を削除するので、シェルは (変数 $uses を使って指定される) 投稿モデルを使う必要があります。デフォルトの動作としては、シェルを実行するように Cake に指示しているのに、具体的なアクションを表すパラメーターを渡さない場合、Cake は main というメソッドを探し、もしそのメソッドが見つかるとそれを実行します。この時点で、空のシェルはリスト 5 のようなものです。


リスト 5. 新しい PruneShells クラスを定義する
                
<?php

class PruneShell extends Shell {
    var $uses = array('Post');

    function main() {
    }
}
?>

これで、あとは 30 日を超える古い投稿をすべて削除するコードを main メソッドに追加するだけです。


リスト 6. 30 日を超える古い投稿を削除する
                
$conditions = array (
    "Post.modified" => "< " . date("Y-m-d H:i:s", strtotime("-30 days"))
);
$this->Post->deleteAll($conditions);

このスクリプトをコマンドラインから実行するためには、prune シェルを実行するように Cake に指示します。すべてのコードは main メソッドの中にあるので、このスクリプトはデフォルトで実行されます。また、どれが app ディレクトリーなのかも Cake に伝える必要があります。これは app ディレクトリーからコマンドを実行している場合には必要ありませんが、app ディレクトリーの正しい場所を伝えない限り cron ジョブは正しいディレクトリーから実行されません (/column/protected/cakephp/cake/console/cake prune -app /column/protected/cakephp/app/)。

このシェルを実行する cron ジョブを午前 0 時に実行するようにスケジューリングするためには、00 00 * * * /column/protected/cakephp/cake/console/cake prune -app /column/protected/cakephp/app/ のようにします。

注意: PATH に /column/protected/cakephp/cake/console ディレクトリーを追加した場合には完全なパスを指定する必要はないので、コンソールでの作業がずっと楽になります。バッチ・ジョブあるいは cron ジョブの中で完全なパスを指定することで、そのジョブを実行するユーザーにかかわらず、ジョブを確実かつ適切に実行することができます。

これでコマンドラインからスクリプトを呼び出せるようになったので、このスクリプトをバッチ処理したり、cron で実行したり、あるいはスケジューリングしたりすることができます。




上に戻る


まとめ

アプリケーション用に自動タスクを作成することには明らかなメリットがあります。自動タスクを作成する際には、好みのフレームワークを利用することができます。フレームワークを使ってタスクを作成することで、一貫した手法をコード全体に適用することができ、また既に用意されている既存の構造を利用することができます。

プルーニング用のスクリプトをテストしている際に気付いたかもしれませんが、プルーニングされた投稿が削除される際、その投稿に関連付けられているコメントや評価が残らなかったかもしれません。これまでフレームワークに関して既に学んだことを元にプルーニング用の各スクリプトを変更し、関連するコメントや評価がプルーニングを行う中で削除されるようにしてください。そして、関連するテーブルを操作するために各フレームワークに用意された特定の方法を使ってみてください。





上に戻る


ダウンロード

内容ファイル名サイズダウンロード形式
Part 5 sample codeos-php-fwk5-column_part5.zip32KBHTTP
ダウンロード形式について


参考文献

学ぶために

製品や技術を入手するために
  • 皆さんの次期オープン・ソース開発プロジェクトを IBM trial software を使って革新してください。ダウンロード、あるいは DVD で入手することができます。

  • IBM 製品の評価版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。


議論するために


著者について

Duane O'Brien はゲーム Oregon Trail がテキストのみで構成されていた頃から、万能な技術者として活躍しています。彼の好きな食べ物は寿司です。彼はまだ月に行ったことがありません。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


12345
不充分・不完全である大変素晴らしい
 


この記事を共有する

はてなブックマーク はてなブックマーク livedoorクリップ livedoorクリップ del.icio.us del.icio.us Buzzurl(バザール) Buzzurl(バザール) Choix! Choix!
Saafブックマーク Saafブックマーク FC2ブックマーク FC2ブックマーク MM/memo MM/memo ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
CZブックマーク CZブックマーク newsing newsing




上に戻る


    日本IBMについて プライバシー お問い合わせ