この記事を三行にまとめると
シェルでコンポーネントを使いたいシェルとえるをかけている……わけではない
ロードローラーの運転には資格が必要
シェルを使って何やらデータを操作したいときってありますよね。cronを設定して自動で何か処理したいときとか、おもたーい処理をバックグラウンドでやりたいときとか。
CakePHPでシェルを使う場合、基本的にはコントローラーでやるようなことをそのまま書けば動くんだけど、ちょーっとだけ違うことをしなきゃいけない部分もある。知っとかないと困ることもある。
例えば、シェルの中でコンポーネントを使う場合。コントローラーと同じような書き方では動かない。じゃーどうすれば良いのか。私、気になります!
ってことで、調べました。
appフォルダの中に「Console」ってフォルダがあって、その中にさらに「Command」というフォルダがあります。シェル用のファイルはその中に作る。
こんな風に。
シェルファイルの名前のつけ方は、基本的に「○○Shell.php」となる。先頭は大文字じゃないといけないのかな……?
ファイルの中身はこんな感じです。ざっくりと。
使いたいモデルがある場合は、コントローラーのときと同じように「$uses」で読み込むことができる。
で、この「sampleFunc」ってやつを使う場合は、以下のように書いてcronで自動的に実行したり、execとかshell_exec、systemを使ってPHPから実行したりすればオッケーっす。
「/usr/bin/php」というのは、えー……こういうの何て言うんだっけね……よく分かんないですが、とにかくコマンドライン上でPHPを実行するときのコマンドです。サーバーの設定によってこのパスは変わるので、人によっては「/usr/local/bin/php」とかかもしれない。分からないって人は、whichコマンドを使って調べれば分かります。
それから「Cakeフォルダまでのパス」と「appフォルダまでのパス」は、まさにそのまま、サーバー上でCakeのコアライブラリが入ってるフォルダと、appフォルダのパスを書けば良いです。cronに書く場合は自分でパスを書く必要がありますけど、もしCakePHPの中でexecとか使って実行する場合は、「CAKE」「APP」という定数がそれぞれすでに用意されているので、それを書けば大丈夫です。
こうですね。クォーテーションの中に書いちゃダメよ。
ちなみに、cronの方に書いてある「0 0 * * *」は、毎日0時0分に実行するという意味です。「分 時 日 月 曜日」という風にスペースとかタブで区切って書きます。曜日は、日曜から土曜までを0から6の数字で書く。0は日曜、6が土曜。
いくつか適当な例を挙げてみまっしょい。
もうちょいいろんな書き方がありますが、今回はここは別に本題じゃないんで、省略で。
でもダメでした。
例えばこんな風にAuthコンポーネントを使いたい。コントローラーならこれで動く。でもシェルはそうもいかない。もしかしたらクラスを読み込むために「App::uses()」を使えば良いのかと思って、こんなことも試してみたけど、やっぱりダメでした。
エラーの内容とかちゃんと確認したわけじゃないけど、動かないのは間違いない。「ふん、この程度で動かせると思うとは、なめられたもんだな。俺はコントローラーのようには甘くないぜ? この俺を動かしたきゃロードローラーでも持って来るんだな」と言わんばかりに動かん。
まあ、ぶっちゃけそんなことを言われたところで、別に僕らは今、承太郎の上にロードローラーを落としたいわけでもないので、ロードローラーを持って来るのはDIOに任せるとして、僕たちはコンポーネントを使うために必要なものを持って来ることにしましょう。
どうやら「ComponentCollection」ってやつを読み込んでやる必要があるようで、それを使って自分でインスタンスを生成すれば、コントローラーのときと同じようにAuthコンポーネントなり他のコンポーネントが使えるようになります。
いつものことながら、分かってしまえばどーってことないささいなことなんですけど、まあ、たいていのことは分かってしまえばそんなもんですよね。世の中、分からないから難しいわけで。
ロードローラーだって、運転したことないからやり方が分かんないだけで、運転の仕方を覚えてさえしまえば、乗りこなせるようになるもんね。まあ、仮に運転を覚えても、大型免許と締固め用機械運転者とかいう資格がないと、運転できないみたいだけど。
CakePHPでシェルを使う場合、基本的にはコントローラーでやるようなことをそのまま書けば動くんだけど、ちょーっとだけ違うことをしなきゃいけない部分もある。知っとかないと困ることもある。
例えば、シェルの中でコンポーネントを使う場合。コントローラーと同じような書き方では動かない。じゃーどうすれば良いのか。私、気になります!
ってことで、調べました。
シェルの使い方
一応、さらっとおさらいしときましょう。さらっとと言いつつ、長くなりそうな予感がビンビンですけど……まるで朝起きたばかりのちn(自主規制)appフォルダの中に「Console」ってフォルダがあって、その中にさらに「Command」というフォルダがあります。シェル用のファイルはその中に作る。
こんな風に。
/app
└ /Console
└ /Command
└ SampleShell.php
シェルファイルの名前のつけ方は、基本的に「○○Shell.php」となる。先頭は大文字じゃないといけないのかな……?
ファイルの中身はこんな感じです。ざっくりと。
App::uses('Shell', 'Console');
class SampleShell extends Shell {
public $uses = array('Model');
public sampleFunc() {
}
}
使いたいモデルがある場合は、コントローラーのときと同じように「$uses」で読み込むことができる。
で、この「sampleFunc」ってやつを使う場合は、以下のように書いてcronで自動的に実行したり、execとかshell_exec、systemを使ってPHPから実行したりすればオッケーっす。
//cronで毎日深夜0時に実行する場合
0 0 * * * /usr/bin/php /Cakeフォルダまでのパス/Console/cake.php SampleShell sampleFunc -app /appフォルダまでのパス/
//PHPから実行する場合(shell_execやsystemも同様)
exec('/usr/bin/php /Cakeフォルダまでのパス/Console/cake.php SampleShell sampleFunc -app /appフォルダまでのパス/');
「/usr/bin/php」というのは、えー……こういうの何て言うんだっけね……よく分かんないですが、とにかくコマンドライン上でPHPを実行するときのコマンドです。サーバーの設定によってこのパスは変わるので、人によっては「/usr/local/bin/php」とかかもしれない。分からないって人は、whichコマンドを使って調べれば分かります。
//コマンド
# which php
//実行結果
/usr/bin/php
それから「Cakeフォルダまでのパス」と「appフォルダまでのパス」は、まさにそのまま、サーバー上でCakeのコアライブラリが入ってるフォルダと、appフォルダのパスを書けば良いです。cronに書く場合は自分でパスを書く必要がありますけど、もしCakePHPの中でexecとか使って実行する場合は、「CAKE」「APP」という定数がそれぞれすでに用意されているので、それを書けば大丈夫です。
exec('/usr/bin/php '.CAKE.'Console/cake.php SampleShell sampleFunc -app '.APP);
こうですね。クォーテーションの中に書いちゃダメよ。
ちなみに、cronの方に書いてある「0 0 * * *」は、毎日0時0分に実行するという意味です。「分 時 日 月 曜日」という風にスペースとかタブで区切って書きます。曜日は、日曜から土曜までを0から6の数字で書く。0は日曜、6が土曜。
いくつか適当な例を挙げてみまっしょい。
//1時間に1回実行
0 * * * * /usr/bin/php
//7月10日の18時に実行
0 18 10 7 * /usr/bin/php
//毎週金曜日の4時に実行
0 4 * * 5 /usr/bin/php
//毎月1日の0時に実行
0 0 1 * * /usr/bin/php
もうちょいいろんな書き方がありますが、今回はここは別に本題じゃないんで、省略で。
コンポーネントの読み込み方
モデルを使う場合はコントローラーと同じように$usesを書けば良いって言うくらいだから、同じ要領でコンポーネントも使えそうとか思うじゃん? 思うよね? 俺は思いました。でもダメでした。
App::uses('Shell', 'Console');
class SampleShell extends Shell {
public $uses = array('Model');
public $components = array('Auth');
public sampleFunc() {
//Authコンポーネント
$pass = $this->Auth->password('test');
}
}
例えばこんな風にAuthコンポーネントを使いたい。コントローラーならこれで動く。でもシェルはそうもいかない。もしかしたらクラスを読み込むために「App::uses()」を使えば良いのかと思って、こんなことも試してみたけど、やっぱりダメでした。
App::uses('Shell', 'Console');
//以下の一行を追加してみた
App::uses('AuthComponent', 'Controller/Component');
class SampleShell extends Shell {
public $uses = array('Model');
public $components = array('Auth');
public sampleFunc() {
//Authコンポーネント
$pass = $this->Auth->password('test');
}
}
エラーの内容とかちゃんと確認したわけじゃないけど、動かないのは間違いない。「ふん、この程度で動かせると思うとは、なめられたもんだな。俺はコントローラーのようには甘くないぜ? この俺を動かしたきゃロードローラーでも持って来るんだな」と言わんばかりに動かん。
まあ、ぶっちゃけそんなことを言われたところで、別に僕らは今、承太郎の上にロードローラーを落としたいわけでもないので、ロードローラーを持って来るのはDIOに任せるとして、僕たちはコンポーネントを使うために必要なものを持って来ることにしましょう。
App::uses('Shell', 'Console');
//以下の二行を追加
App::uses('ComponentCollection', 'Controller');
App::uses('AuthComponent', 'Controller/Component');
class SampleShell extends Shell {
public $uses = array('Model');
public sampleFunc() {
//以下の二行を追加
$collection = new ComponentCollection();
$this->Auth = new AuthComponent($collection);
//Authコンポーネント
$pass = $this->Auth->password('test');
}
}
どうやら「ComponentCollection」ってやつを読み込んでやる必要があるようで、それを使って自分でインスタンスを生成すれば、コントローラーのときと同じようにAuthコンポーネントなり他のコンポーネントが使えるようになります。
いつものことながら、分かってしまえばどーってことないささいなことなんですけど、まあ、たいていのことは分かってしまえばそんなもんですよね。世の中、分からないから難しいわけで。
ロードローラーだって、運転したことないからやり方が分かんないだけで、運転の仕方を覚えてさえしまえば、乗りこなせるようになるもんね。まあ、仮に運転を覚えても、大型免許と締固め用機械運転者とかいう資格がないと、運転できないみたいだけど。