
CakePHP2のshellでModelはすんなり呼べるのにコントローラとコンポーネントを呼び出すのがいまいち意味不明なのでまとめ。
定期的にメールを送信するという非常に鬱陶しいジョブを作ってみる。
cakeを覚える気はないのでなるべくコピペで行きたいこの頃。
環境
- CakePHP 2.7.6
- PHP 5.6.18
shellでコンポーネントを使う
いちいちインスタンス化しないといけないようだ。
そしてComponentCollectionが大事らしい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php //コンポーネント App::uses('ComponentCollection', 'Controller'); App::uses('HogehogeComponent', 'Controller/Component'); class HogeShell extends AppShell { public function main() { $collection = new ComponentCollection(); //使いたいコンポーネント //インスタンス化の際にComponentCollectionを渡さないといけないらしい $hogehoge = new HogehogeComponent($collection); $hogehoge->foo(); } } |
shellでコントローラを使う
いちいち(ry
コンポーネントよりは呼び出しやすい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php //コントローラ App::uses('AppController', 'Controller'); App::uses('HogehogeController', 'Controller'); class HogeShell extends AppShell { public function main() { $hogehoge = new HogehogeController(); $hogehoge->foo(); //アクセスレベル次第では Hogehoge::foo(); } } |
定期的にメールを送信してみる
shellのお作法が分かったところでいざ実践。
- ReminderShell.php
- メールを送信させるジョブ
- RemindController.php
- shellに叩かれるコントローラ
- MailComponent.php
- 実際にメールを送信している処理
app/Console/Command/ReminderShell.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<?php /** * メール用のShell */ //コントローラ App::uses('RemindController', 'Controller'); //コンポーネント App::uses('ComponentCollection', 'Controller'); App::uses('MailComponent', 'Controller/Component'); class ReminderShell extends AppShell { function startup() { //cronのログに「Welcome to CakePHP 〜」はいらないので消すために上書き } /** * メインジョブ */ public function main() { //催促対象を取得 $list = $this->get_target(); if(empty($list)) { $this->out('empty.'.PHP_EOL, true); exit(); } //コントローラ $Remind = new RemindController(); //出力用 $out = ''; foreach ($list as $val) { $result = $Remind->mail_send($val['User']['id']); $out .= date('Y-m-d H:i:s').' '; $out .= ($result) ? '[done] ' : '[fail] '; $out .= 'User.id => '.$val['User']['id'].PHP_EOL; } $this->out($out, true); } /** * メール送信対象を取得する */ public function get_target() { //コンポーネント $collection = new ComponentCollection(); //インスタンス化の際にComponentCollectionを渡さないといけない $mail = new MailComponent($collection); //対象のデータを取得 return $mail->get_target(); } } |
app/Controller/RemindController.php
コンポーネントの呼び方に注意。
↓これだとShellから叩いた時に使えない。
1 |
public $components = ['Mail']; |
なのでメソッドの中でロードする。
1 |
$this->Mail = $this->Components->load('Mail'); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?php class RemindController extends AppController { //Model public $uses = ['User']; //コンポーネントの呼び出しはこれだとShellから叩いた時に使えない //public $components = ['Mail']; /** * 受け取ったUser.idでDBを検索してメールを送りつける */ public function mail_send($_id = '') { $user = $this->User->find('first', [ 'conditions' => [ 'User.id' => $_id, ] ]); if(empty($user)) return false; $header = [ 'to' => $user['User']['email'], 'from' => ['admin@hogehoge.com' => 'システム管理者'], 'subject' => '題名', ]; $body = ['body' => 'aaaaaaaa']; //コンポーネント呼び出し $this->Mail = $this->Components->load('Mail'); //送信 return $this->Mail->reminder($header, $body); } } |
app/Controller/Component/MailComponent.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
<?php App::uses('Component', 'Controller', 'Configure'); App::uses('CakeEmail', 'Network/Email'); /** * メール関連のコンポーネント * * @access public */ class MailComponent extends Component { /** * デフォルトヘッダーセット */ protected $_header = [ 'to' => '', 'from' => ['admin@hogehoge.com' => 'システム管理者'], 'subject' => 'だいめいです', ]; /** * デフォルトmail body */ protected $_body = [ 'body' => 'ないようです', ]; /** * メール送信 * * @param array $header * @param array $body * @return bool */ public function reminder($header = [], $body = []) { //初期値をマージ $header = array_merge($this->_header, $header); $body = array_merge($this->_body, $body); try { $email = new CakeEmail('smtp'); $email->template('hogehoge') ->viewVars(['body' => $body['body']) ->from($header['from']) ->to($header['to']) ->subject($header['subject']) ->send(); } catch(Exception $e) { return false; } return true; } /** * メールを送信する対象を取得 * $user_idの指定がなければすべて取得 * * @param string|int $member_id * @return array */ public function get_target($member_id = '') { //Model $User = ClassRegistry::init('User'); $query = []; //送信する条件などなど return $User->find('all', $query); } } |
shellを実行する
ググるとコレまた実行の仕方が何通りもある。
まじしおいやん(シレン2)なんだけど。
1 2 3 |
$ /path/to/cake/app/Console/cake reminder 2016-03-17 14:45:02 [done] User.id => 1000 |
これをcronに書いて終了。
5分おきに送りつけてやる。
1 2 3 4 |
$ crontab -e # m h dom mon dow command */5 * * * * /path/to/cake/app/Console/cake reminder >> ~/cron.log |
cron再起動。
1 2 3 |
$ sudo service cron restart [....] Restarting periodic command scheduler: cron[....] Stopping periodic comma[ ok heduler: cron. [ ok ] Starting periodic command scheduler: cron. |
しおかんべん。