FuelphpのPHP Quick Profilerを特定のControllerだけ止める方法
FuelphpにはPHP Quick Profiler(pqp)が付属しています。
すごく便利なのですが、JSONを扱う開発など特定のControllerに対して一時的に停止したいこともあるかと思います。
かなり無理矢理ですがやってみました。
まずクラスの作成
class Stopprofiler extends Profiler { public static function stop_profiling() { static::$profiler = null; } }
その後、該当のコントローラで、
Stopprofiler::stop_profiling();
を呼び出せば無事PQPがなくなっているかと。
仕組みは見たまんまです。
Profilerクラスの静的変数$profilerがprotectedなので、継承して書き換えただけです。
オブジェクト指向的には非常に問題のある方法ですが(;´Д`)
なにか他にいい方法があれば教えて下さい。
\Fuel::$profiling = false;
はてブ経由で指摘がありました。これでいいみたいです。
FuelPHPでGearmanを動かしてみた
Gearmanとは?
Gearmanはジョブキューサーバの一つです。
時間のかかる処理等をバックグラウンドで処理する時や、分散処理を行いたい時に使うとではないかと。
他の使い方はわかりませんが、これだけでも十分利用価値があります。
使ってみる
インストール方法は他のサイトみて下さい。
以前にビルドしたものの、どうやったか覚えてないので(;´Д`)
参考:
TheSchwartzの代わりにGearman+libdrizzleでジョブキューサーバ作る - 個人事業主のつぶやき
ジョブキューサーバ Gearmand を PHP から使ってみた | tech.kayac.com - KAYAC engineers' blog
とりあえず自分はgearmandにlibdrizzleを組み合わせてMySQLにキューを保存しています。
Net_Gearmanの導入
http://pear.php.net/package/Net_Gearman/からではなく、
https://github.com/lenn0x/net_gearmanからダウンロードして下さい。
E_STRICTエラーが発生するので…
fuel/app/vendor/net_gearmanへ解凍。
Tasksを作成。Clientも追加
fuel/app/tasks/gearman.php
<?php namespace Fuel\Tasks; set_include_path(get_include_path() . PATH_SEPARATOR . APPPATH . 'vendor/net_gearman'); require_once 'Net/Gearman/Client.php'; class Gearman { public function run() { \Daemon\Daemon::forge()->setCallback('\\Gearman_Worker::worker')->run(); } public function workertest() { $client = new \Net_Gearman_Client('localhost:4730'); $client->test(array('name'=>'world')); } }
なお、前回のDaemonパッケージを利用しています。
Workerを作成
fuel/app/classes/gearman/worker.php
<?php set_include_path(get_include_path() . PATH_SEPARATOR . APPPATH . 'vendor/net_gearman'); define('NET_GEARMAN_JOB_PATH', APPPATH . 'classes/gearman/job'); define('NET_GEARMAN_JOB_CLASS_PREFIX', 'Gearman_Job_'); require_once 'Net/Gearman/Worker.php'; class Gearman_Worker { public static function worker() { $servers = array('localhost:4730'); try { $worker = new Net_Gearman_Worker($servers); $worker->addAbility('test'); $worker->beginWork(); } catch (Net_Gearman_Exception $e) { new FuelException($e->getMessage()); } } }
Jobを作成
fuel/app/classes/gearman/job/test.php
<?php class Gearman_Job_test extends Net_Gearman_Job_Common { public function run($arg) { Log::error("Hello, " . $arg['name'] . "!"); } }
動かしてみる
$ php oil refine gearman $ ps aux | grep php harul 1939 0.0 0.1 136040 7532 ? S 13:33 0:00 php oil refine gearman harul 1940 0.0 0.2 136040 8056 ? S 13:33 0:00 php oil refine gearman harul 2967 0.0 0.0 15360 912 pts/0 S+ 13:33 0:00 grep --colour=auto php
動いているようだ
clientを動かしてみる
$ php oil refine gearman:workertest
ログを確認してみる
Error - 2012-08-12 13:51:35 --> Hello, world!
無事動いた
めでたしめでたし
FuelPHPのデーモンパッケージ
Webアプリを作っている時に、バックグラウンドで処理をしたい事があるかと思います。
今回、Gearmanのworkerを動かそうと思ったのですが、
Unix系OSのPHPでは
php oil refine ほげほげ &
としても、うまく動きません。
そこで、デーモンを動かすようにバックグラウンドで処理を行うパッケージを作ってみました。
正直に言うと<fuelphpのバックグラウンドプロセスパッケージ>のパクリです。ただ、あちらはUnix系では動かないので…
設置
次の位置においてください
FuelPHP Daemon package/fuel/packages/daemon
なお、このパッケージを動かすためには、PHPのpcntlとposixが有効になっている必要があります。
config.phpを編集
daemonをAPPPATH/config/config.php の always_load の部分に追加します
return array( 'always_load' => array( 'packages' => array( 'daemon', // 追加 ), ) );
使用例
<?php namespace Fuel\Tasks; class Daemontest { public function run() { \Daemon\Daemon::forge()->setCallback('\\Fuel\\Tasks\\Daemontest::callback')->run(); } public static function callback() { while(TRUE){ //ここにいろいろな処理を書く sleep(1); } } }
注意点とか
Windowsでは動きません
動作のしくみ
run()が呼ばれたときには下図プロセス1しかありません。
まずプロセス1からfork()して子プロセス2の生成
そのプロセス2をsetsid()にて新しいセッションに移す。
その後、プロセス1は終了し、またプロセス2はfork()を行ってプロセス3を生成。
セッションリーダとなるプロセスが残っていると、端末に紐付することができてしまうので、
プロセス2は終了。
最後に、プロセス3にてfork()を行い、子プロセス4にてcallbackの呼び出しを行っています。
この状態で、プロセス3にSIGTERMが呼ばれた場合には、
プロセス4にSIGINTを送っています。
書いてもいまいちわかりにくいですね。申し訳ない。
次はGearmanのパッケージを作ります。
FuelPHP TreeOrm Packageをより使えるようにした
前回に作成した、FuelPHPでもTree Behaviorをより使えるように改良しました。
準備
設置
次の位置においてください
FuelPHP TreeOrm Package
/fuel/packages/treeorm
指定のフィールドの確認
使用するテーブルに以下のフィールドが必要です
`id` int unsigned NOT NULL auto_increment, `parent_id` int unsigned default '0', `lft` int(10) default '0', `rght` int(10) default '0', PRIMARY KEY (`id`)
config.phpを編集
treeormとormをAPPPATH/config/config.php の always_load の部分に追加します
return array( 'always_load' => array( 'packages' => array( 'orm', // 追加 'treeorm', // 追加 ), ) );
モデル毎の設定
該当のモデルにovserversの追加
use Orm\Model; class Model_Testtree extends Model { protected static $_properties = array( 'lft', 'rght', 'parent_id', ); protected static $_observers = array( 'TreeOrm\\Observer_Tree' => array( 'events' => array('before_save','before_delete'), 'property' => array( 'left' => 'lft', 'right' => 'rght', 'parent_id' => 'parent_id', 'id' => 'id') ), ); }
これで、とりあえず使えます
ここまでは前回とほぼ一緒
もし、propertyがなかった場合、上記の値がデフォルトとなります。
基本的な使い方
ノードの追加・編集・削除
モデルのsaveメソッドを呼び出したときに自動でlft,rghtに値がセットされます。
モデルのdeleteメソッドを呼び出したときには、子ノードも含め全て削除されます。
ただし、必ずparent_idを指定して下さい。(ルートノードのparent_idには0もしくはNULLを指定)
なお、ルートノードは1つだけ作成できます
メソッドの呼び出し方法
controller等から
TreeOrm\Tree::forge('モデル名')->メソッド名();
または、
$data = モデル::find($id); TreeOrm\Tree::forge($data)->メソッド名();
メソッド一覧
change( $id1 = null, $id2 = null)
ノードの入れ替え
$id1 対象ノード1のキー
$id2 対象ノード2のキー
返り値 成功したかどうか
childCount( $id = null, $direct = false)
子ノード数の取得をします
$id キー・falseを指定した場合ルートノード、nullを指定した場合インスタンスのノードを示します
$direct 直下の子のみを対象とするか。直下の子のみならばTRUE、子要素全て取得ならばFALSE
元のノードが存在していれば子ノード数、存在していなければfalseを返す
children( $id = null, $direct = false, $orderColumn = null, $orderDirection = null, $limit = null)
子ノードの取得をします
$id キー・falseを指定した場合ルートノード、nullを指定した場合インスタンスのノードを示します
$direct 直下の子のみを対象とするか。直下の子のみならばTRUE、子要素全て取得ならばFALSE
$orderColumn ソートカラム名
$orderDirection ソート順の指定、'DESC' または 'ASC'。デフォルトは'ASC'。
$limit 取得最大数
元のノードが存在していれば子ノードの配列、存在していなければfalseを返します
getParentNode( $id = null)
親ノードの取得をします
$id キー・nullを指定した場合インスタンスのノードを示します
親ノードが存在していれば親ノードの配列、存在していなければfalseを返します
getPath( $id = null)
パスの取得をします
$id キー・nullを指定した場合インスタンスのノードを示します
ノードが存在していればルートから順番に配列として、存在していなければfalseを返します
moveDown( $id = null, $number = 1)
ノードの階層を変えずに位置を下げる
$id キー・nullを指定した場合インスタンスのノードを示します
$number 移動回数、TRUEを指定した場合、端まで移動
moveUp( $id = null, $number = 1)
ノードの階層を変えずに位置を上げる
$id キー・nullを指定した場合インスタンスのノードを示します
$number 移動回数、TRUEを指定した場合、端まで移動
reorder( $id = null, $field = null, $order = 'ASC')
ノードの再配置を行います。lft、rghtが未設定の場合はparent_idに基づき自動的に設定します。
初期データを登録するときなどに使用して下さい。
$id キー・falseを指定した場合ルートノード、nullを指定した場合インスタンスのノードを示します
$orderColumn ソートカラム名
$orderDirection ソート順の指定、'DESC' または 'ASC'。デフォルトは'ASC'。
reset()
ノードの添字振りなおしを行います。
ノードの削除などで添え字が連続しなくなったときに使用して下さい。
注意事項
モデル名でメソッドの呼び出しを行った場合、現在位置は一番最初に見つかったノード(通常はidが一番若いノード、ほぼルートノード)となります
今後の予定・改良点など
まずテストケースを作らなければならない…
しかしながら、どうすればいいか検討がつきません…
FuelPHPでもTree Behavior
CakePHPにはTree BehaviorとTree Helperといった便利なものがあります。
詳しくは、
CakePHPの「OrderedBehavior」と「TreeBehavior」はマジで使うべき
とかを参照してもらうとして、
簡単にツリー構造を使いたい!といった要求から
こんなものを作ってしまいました。
しかしながら、未だ要素の追加、削除、親IDの変更しか作っていませんが…
使い方
設置
次の位置においてください
/fuel/packages/treeorm
config.phpを編集
treeormとormをAPPPATH/config/config.php の always_load の部分に追加します
return array( 'always_load' => array( 'packages' => array( 'orm', // 追加 'treeorm', // 追加 ), ) );
該当のモデルにovserversやフィールド等の追加
use Orm\Model; class Model_Testtree extends Model { protected static $_properties = array( 'lft', 'rght', 'parent_id', ); protected static $_observers = array( 'TreeOrm\\Observer_Tree' => array( 'events' => array('before_save','before_delete'), ), ); }
こいつを使うには必要なフィールドがあります。
`id` int unsigned NOT NULL auto_increment, `parent_id` int unsigned default '0', `lft` int(10) default '0', `rght` int(10) default '0', PRIMARY KEY (`id`)
これで、とりあえず使えるようになるはず
ソースを見ていただければわかるのだが、非常に汚いし、機能も全然ないのでそのうち綺麗に作り込む予定
FuelPHP Plupload Packageを作った
巨大ファイルや複数ファイルのアップロードにPluploadが非常に使えるのでFuelPHPのパッケージを作ってみた。
必要なもの
設置方法
次の位置においてください
/fuel/packages/plupload
jsフォルダを/public/assets/plupload
へ
jQueryとjQuery UIについては、適当にCDNなりローカルからの読み込み等を行って下さい
実装例
/fuel/app/classes/controller/plupload.php
<?php class Controller_Plupload extends Controller { function action_index() { return View::forge('plupload'); } static function upload_callback($filename) { // アップロード終了時処理 // $filenameに保存されたファイル名を返す } function action_upload() { Plupload::upload('Controller_Plupload::upload_callback'); } }
/fuel/app/views/plupload.php
<!DOCTYPE HTML> <html lang="ja-JP"> <head> <meta charset="UTF-8"> <title>Plupload</title> ここにjQueryとjQuery UIの読み込み処理を挿入 <?php echo Plupload::insert_header(); ?> </head> <body> <form method="post" action="examples_dump.php"> <div id="uploader" style="height: 330px; width: 500px;"> <p>You browser doesn't have Flash, Silverlight, Gears, BrowserPlus or HTML5 support.</p> </form> </body> </html>
/fuel/app/config/plupload.php(/fuel/packages/plupload/config/plupload.phpからコピーして編集でもよい)
<?php return array( 'url' => \Uri::create('plupload/upload'), 'ui' => 'jqueryui', );
参考にした所
jQueryUI読み込みのフォールバック処理
前回のjQueryのフォールバックを行ったので、今度はjQuery UIのフォールバックでも
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/themes/smoothness/jquery-ui.css" type="text/css" /> <script type="text/javascript"> $.each(document.styleSheets, function(i,sheet){ if(sheet.href){ if(sheet.href.split(':')[1]=='//ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/themes/smoothness/jquery-ui.css') { var tID1 = setInterval(function(){ if(sheet.rules || sheet.cssRules){ clearInterval(tID1); var rules = sheet.rules ? sheet.rules : sheet.cssRules; if (rules.length == 0) { $('<link type="text/css" rel="stylesheet" href="/css/smoothness/jquery-ui-1.8.21.custom.css" />').appendTo('head'); } } },10); } } }) </script> <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/i18n/jquery-ui-i18n.min.js"></script> <script>window.jQuery.ui || document.write('<script src="/js/jquery-ui-1.8.21.custom.min.js"><\/script>')</script>
rulesかcssRulesがセットされるまでsetIntervalでループさせ、セットされたら長さのチェック、長さ0ならローカルのCSSを読み込むと行った流れ。