PHPのフレームワークです。オートローディング、ルーティング、ORマッパ、フォームバリデータ、その他ユーティリティがセットになっています。
修订版 | 165 (tree) |
---|---|
时间 | 2022-04-08 11:47:25 |
作者 | tantancode |
notfoundやerrorのハンドリングを再定義
@@ -0,0 +1,100 @@ | ||
1 | + | |
2 | +●サンプル | |
3 | + | |
4 | + ・API "service/echo" をGET変数 foo=FOO で呼び出す。 | |
5 | + | |
6 | + var api = new Api("service/echo", {"foo":"FOO"}); | |
7 | + | |
8 | + var response = await api.transmit(); | |
9 | + console.log(response); | |
10 | + | |
11 | + ・API "service/echo" をGET変数 foo=FOO、POST変数 bar=BAR で呼び出す。 | |
12 | + | |
13 | + var api = new Api("service/echo", {"foo":"FOO"}, {"bar":"BAR"}); | |
14 | + | |
15 | + var response = await api.transmit(); | |
16 | + console.log(response); | |
17 | + | |
18 | + ・await を使わない場合は... | |
19 | + | |
20 | + var api = new Api("service/echo", {"foo":"FOO"}); | |
21 | + | |
22 | + // Promise をストレートに使うか... | |
23 | + api.transmit().then(function(response){ | |
24 | + console.log(response); | |
25 | + }); | |
26 | + | |
27 | + // コールバックスタイルも使える。 | |
28 | + api.transmit(function(response) { | |
29 | + console.log(response); | |
30 | + }); | |
31 | + | |
32 | +●共通仕様 | |
33 | + | |
34 | + ※ここに書かれている基礎的処理はすでに public/js/Api.js で実装されているので、普段は参照する必要はない。 | |
35 | + | |
36 | + ・アプリベースURL | |
37 | + | |
38 | + APIを呼び出すときは、この「アプリベースURL」に各APIの「パス」をつなげてURLを構築する。 | |
39 | + Environment["app_base"] で参照できる。 | |
40 | + | |
41 | + ・共通のGETパラメータ | |
42 | + | |
43 | + ver | |
44 | + クライアントが認識しているサーバ側バージョン。次のグローバル変数から取得できる。 | |
45 | + | |
46 | + var version = Environment["version_stamp"]; | |
47 | + | |
48 | + クライアントが動作中にサーバ側でこの値が更新されると、値がサーバ・クライアントの間で食い違うことになる。 | |
49 | + するとサーバはすべてのAPIでエラーコード "version" を返すようになる(後述)ので、クライアントはそれを認識して | |
50 | + ユーザに再読み込みを促す仕組みとなる。 | |
51 | + | |
52 | + ・共通のレスポンス | |
53 | + | |
54 | + error (struct) | |
55 | + | |
56 | + エラーが発生している場合にセットされる。エラーがない場合はセットされない。 | |
57 | + 以下のキーを持つ。 | |
58 | + | |
59 | + code (string) | |
60 | + 共通定義として、以下のような値がセットされる。これ以外の値が個別のAPIで定義されている場合もある。 | |
61 | + | |
62 | + exception | |
63 | + ユーザの操作を原因としないエラー。サーバ内でのエラーや、引数に渡した値が定義範囲外の場合など。 | |
64 | + ユーザへの案内: 問い合わせコードとして inquiry キーもセットされるのでその値を案内されたい。 | |
65 | + 案内後の遷移: トップページへ。 | |
66 | + maintenance | |
67 | + サーバメンテナンス中。 | |
68 | + ユーザへの案内: 「メンテナンス中」など。 | |
69 | + 案内後の遷移: 特に無い。トップページもメンテ状態なので、そのまま。 | |
70 | + banned | |
71 | + BANされている。 | |
72 | + ユーザへの案内: 「措置規定に該当したためアクセスが制限されている」など | |
73 | + 案内後の遷移: 特に無い。 | |
74 | + irregular | |
75 | + 以下のような、ユーザ起因だが、普通に操作していれば発生しないようなエラー。 | |
76 | + ・確認画面を長時間放置して、データが期限切れになった後に確定処理をしようとした | |
77 | + ・ブラウザの戻るや複数タブによるフォーム連投 | |
78 | + 専用のエラー処理を構えるのが面倒くさくなるくらいに稀なケースで使用される。 | |
79 | + ユーザへの案内: ユーザへの説明メッセージとして message キーもセットされるので、そのテキストをそのまま表示。 | |
80 | + 問い合わせコードとして inquiry キーもセットされるので、その値も案内されたい。 | |
81 | + 案内後の遷移: トップページへ。 | |
82 | + needlogin | |
83 | + ログインが必要。 | |
84 | + ユーザへの案内: 「ログインしてから再度操作して下さい」など。 | |
85 | + 案内後の遷移: ログインへ。 | |
86 | + version | |
87 | + クライアントが伝えたサーバ側バージョンと、現行のサーバ側バージョンが一致していない。 | |
88 | + リロード必須の更新がサーバ側で発生したことを意味している。 | |
89 | + ユーザへの案内: 「サーバ側にデータの更新があります」など。 | |
90 | + 案内後の遷移: トップページへ。 | |
91 | + | |
92 | + inquiry (string) | |
93 | + お問い合わせコード。ない場合はセットされない。 | |
94 | + | |
95 | + message (string) | |
96 | + 専用のエラー説明テキストがある場合にセットされる。 | |
97 | + | |
98 | + description (string) | |
99 | + デバック用。開発環境でのみセットされる。 | |
100 | + 例外メッセージやスタックトレースなど。 |
@@ -94,6 +94,25 @@ | ||
94 | 94 | return $url; |
95 | 95 | } |
96 | 96 | |
97 | + //---------------------------------------------------------------------------------------------------------- | |
98 | + /** | |
99 | + * 可能なら、現在アクセス中のユーザにおけるエラーカウントを一つ増やす。 | |
100 | + */ | |
101 | + public static function incrementErrorCount() { | |
102 | + | |
103 | + // ユーザIDが判明していて、管理者によるユーザ代行でないなら処理する | |
104 | + $session = Mojo::setting('process', 'mojo.session')::getSession(); | |
105 | + if($session['user_id'] && !$session['operator_code']) { | |
106 | + | |
107 | + // そのユーザの error_count を +1 する。 | |
108 | + $user = new UserInfo($session['user_id']); | |
109 | + if($user->load()) { | |
110 | + $user['error_count'] += 1; | |
111 | + $user->save(); | |
112 | + } | |
113 | + } | |
114 | + } | |
115 | + | |
97 | 116 | //--------------------------------------------------------------------------------------------------------- |
98 | 117 | /** |
99 | 118 | * デバック用。"<html><body>" と "</body></html>" で挟んだ上で、var_dump を行い、exitする。 |
@@ -171,58 +190,70 @@ | ||
171 | 190 | |
172 | 191 | //----------------------------------------------------------------------------------------------------- |
173 | 192 | /** |
174 | - * エラー処理をオーバーライド。 | |
193 | + * オーバーライド。 | |
194 | + * 引数に指定された例外を処理する。ここから例外をスローした場合はPHP標準の方法で処理される。 | |
175 | 195 | */ |
176 | 196 | protected static function processException($e) { |
177 | 197 | |
178 | - // リクエストされているサイトに、settings.php の mojo.error_action で設定されているアクションが存在する場合は、そのアクションでエラーを表示する。 | |
179 | - try { | |
198 | + $error = array(); | |
199 | + $error['exception'] = $e; | |
200 | + | |
201 | + // ログに記録して問い合わせコードと書き込み内容を得る。 | |
202 | + [ $error['inquiry'], $error['description'] ] = AppLog::exception($e); | |
203 | + | |
204 | + // ユーザに表示するメッセージを決定。IrregularAccess なら例外から取得する。 | |
205 | + $error['message'] = ($e instanceof IrregularAccess) ? $e->getMessage() : '申しわけありません。エラーが発生しました。'; | |
206 | + | |
207 | + // HTTPエラーコードを設定。 | |
208 | + if(!headers_sent()) | |
209 | + http_response_code(500); | |
210 | + | |
211 | + // 可能なら、ユーザのエラーカウント+1。 | |
212 | + AppMojo::incrementErrorCount(); | |
213 | + | |
214 | + // settings.php の mojo.error_direction で処理する。 | |
215 | + $direction = @self::setting('routing', 'mojo.error_direction'); | |
216 | + if($direction) { | |
180 | 217 | $site = self::setting('runtime', 'mojo.requested_site'); |
181 | - $action = self::setting('routing', 'mojo.error_action'); | |
182 | - if(self::searchAction($site, $action)) { | |
183 | - self::forward("{$site}/{$action}", ['error'=>$e]); | |
218 | + if( self::forward("$site/$direction", $error) ) | |
184 | 219 | return; |
185 | - } | |
186 | 220 | } |
187 | - // そこでも失敗した場合は、その失敗例外の方をデフォルトの方法で表示する。 | |
188 | - catch(Exception $miss) { | |
189 | - $e = $miss; | |
190 | - } | |
191 | 221 | |
192 | - // 以降、該当アクションがない場合のデフォルトエラー表示。 | |
222 | + // mojo.error_direction で処理されない場合は標準のエラー処理を行う。 | |
193 | 223 | |
194 | 224 | // 見やすいように text/plain にする。 |
195 | 225 | if(!headers_sent()) |
196 | 226 | header("Content-Type: text/plain; charset=UTF-8"); |
197 | 227 | |
198 | - // OperationalException では例外メッセージをそのままユーザメッセージとして使用する。 | |
199 | - if($e instanceof OperationalException) { | |
200 | - echo $e->getMessage(); | |
201 | - return; | |
202 | - } | |
228 | + // まずはメッセージを表示。 | |
229 | + echo $error['message'] . "\n"; | |
203 | 230 | |
204 | - // 以降、OperationalException 以外の処理。 | |
231 | + // 問い合わせコードがあるならそれも表示。 | |
232 | + if($error['inquiry']) | |
233 | + echo "\ncode: " . $error['inquiry'] . "\n"; | |
205 | 234 | |
206 | - // HTTPエラーコードを設定。 | |
207 | - if(!headers_sent()) | |
208 | - http_response_code(500); | |
235 | + // 本番環境以外では詳細も表示。 | |
236 | + if(static::setting('application', 'environment_type') != 'prod') | |
237 | + echo "\n" . $error['description']; | |
238 | + } | |
209 | 239 | |
210 | - // ログに記録する。 | |
211 | - $log = AppLog::exception($e); | |
240 | + //---------------------------------------------------------------------------------------------------------- | |
241 | + /** | |
242 | + * オーバーライド。 | |
243 | + * リクエストされたアクションが見付からない場合の処理を行う。 | |
244 | + */ | |
245 | + protected static function processNotfound($name) { | |
212 | 246 | |
213 | - // 本番環境なら簡易なメッセージとエラーログを引くためのコードを表示する。 | |
214 | - if(static::setting('application', 'environment_type') == 'prod') { | |
247 | + // routing設定で定められているnotfoundディレクションを、リクエストされているサイト内で探して処理させる。 | |
248 | + $notfound = static::setting('routing', 'mojo.notfound_direction'); | |
249 | + if($notfound) { | |
250 | + $site = static::setting('runtime', 'mojo.requested_site'); | |
251 | + if( static::forward("$site/$notfound") ) | |
252 | + return; | |
253 | + } | |
215 | 254 | |
216 | - echo "申しわけありません。エラーが発生しました。\n" | |
217 | - . "お問い合わせコード: {$log['code']}\n"; | |
218 | - | |
219 | - if($e instanceof IllegalTouchException) | |
220 | - echo "複数のタブでの操作や、ブラウザの戻る機能を利用した再送信は控えていただけると幸いです。\n"; | |
221 | - | |
222 | - // 本番環境でないなら詳細に表示。 | |
223 | - }else { | |
224 | - echo $log['text']; | |
225 | - } | |
255 | + // notfoundディレクションの設定がない、あるいは該当のアクションがない場合は基底の処理とする。 | |
256 | + parent::processNotfound($name); | |
226 | 257 | } |
227 | 258 | |
228 | 259 | //----------------------------------------------------------------------------------------------------- |
@@ -19,8 +19,8 @@ | ||
19 | 19 | * |
20 | 20 | * ・次のように展開すると... |
21 | 21 | * |
22 | - * $Localizer = new Localizer(); | |
23 | - * $r = $Localizer($s); | |
22 | + * $localizer = new Localizer(); | |
23 | + * $r = $localizer->processSymbolicText($s); | |
24 | 24 | * |
25 | 25 | * ・$r は次のような文字列になる。 |
26 | 26 | * |
@@ -35,9 +35,9 @@ | ||
35 | 35 | * |
36 | 36 | * 融合したシンボルを使わず、素直に関数を使って局所的に展開するほうが良いだろう。 |
37 | 37 | * |
38 | - * <div><?php echo $Localizer->expandSymbol('sample:これはフー') ?></div> | |
39 | - * <div><?php echo $Localizer->expandSymbol('sample:N個あるよ', ['num'=>5]) ?></div> | |
40 | - * <div><?php echo $Localizer->expandSymbol('sample:これはバー', ['keyword'=>'<span style="color:red">'']) ?></div> | |
38 | + * <div><?php echo $localizer->expandSymbol('sample:これはフー') ?></div> | |
39 | + * <div><?php echo $localizer->expandSymbol('sample:N個あるよ', ['num'=>5]) ?></div> | |
40 | + * <div><?php echo $localizer->expandSymbol('sample:これはバー', ['keyword'=>'<span style="color:red">'']) ?></div> | |
41 | 41 | * <div><?php echo $user_data ?></div> |
42 | 42 | * |
43 | 43 | * こうすれば、シンボル展開をする場所としない場所を制御できる。 |
@@ -352,19 +352,19 @@ | ||
352 | 352 | * /some/file/bar.txt |
353 | 353 | * |
354 | 354 | * 呼び出しと戻り値は次のようになる。 |
355 | - * $Localizer = new Localizer('xx'); | |
356 | - * $Localizer->getSpecificFile('/some/file/foo.txt'); // 戻り値 /some/file/foo.xx.txt | |
357 | - * $Localizer = new Localizer('yy'); | |
358 | - * $Localizer->getSpecificFile('/some/file/foo.txt'); // 戻り値 /some/file/foo.yy.txt | |
359 | - * $Localizer = new Localizer('zz'); | |
360 | - * $Localizer->getSpecificFile('/some/file/foo.txt'); // 戻り値 /some/file/foo.xx.txt フォールバックで xx が使われる。 | |
361 | - * $Localizer = new Localizer('xx'); | |
362 | - * $Localizer->getSpecificFile('/some/file/bar.txt'); // 戻り値 /some/file/bar.txt 派生版がないのでそのまま | |
363 | - * $Localizer->getSpecificFile('/some/file/baz.txt'); // 戻り値 /some/file/baz.txt 存在しない場合もそのまま | |
355 | + * $localizer = new Localizer('xx'); | |
356 | + * $localizer->getSpecificFile('/some/file/foo.txt'); // 戻り値 /some/file/foo.xx.txt | |
357 | + * $localizer = new Localizer('yy'); | |
358 | + * $localizer->getSpecificFile('/some/file/foo.txt'); // 戻り値 /some/file/foo.yy.txt | |
359 | + * $localizer = new Localizer('zz'); | |
360 | + * $localizer->getSpecificFile('/some/file/foo.txt'); // 戻り値 /some/file/foo.xx.txt フォールバックで xx が使われる。 | |
361 | + * $localizer = new Localizer('xx'); | |
362 | + * $localizer->getSpecificFile('/some/file/bar.txt'); // 戻り値 /some/file/bar.txt 派生版がないのでそのまま | |
363 | + * $localizer->getSpecificFile('/some/file/baz.txt'); // 戻り値 /some/file/baz.txt 存在しない場合もそのまま | |
364 | 364 | * |
365 | 365 | * 第二引数で基準ディレクトリを示して、第一引数は相対パスで指定したなら、戻り値もそれに従って変化する。 |
366 | - * $Localizer = new Localizer('xx'); | |
367 | - * $Localizer->getSpecificFile('file/foo.txt', '/some'); // 戻り値 file/foo.xx.txt | |
366 | + * $localizer = new Localizer('xx'); | |
367 | + * $localizer->getSpecificFile('file/foo.txt', '/some'); // 戻り値 file/foo.xx.txt | |
368 | 368 | * |
369 | 369 | * param 調べたいパス |
370 | 370 | * param 調べたいパスが相対である場合は、基準パス。 |
@@ -9,7 +9,7 @@ | ||
9 | 9 | /** |
10 | 10 | * 引数に指定されたURLパラメータを単一の文字列に変換する。 |
11 | 11 | * |
12 | - * param サイト・アクション名 | |
12 | + * param アクション名 | |
13 | 13 | * param GETパラメータ。Mojo::getUrl() と同様。 |
14 | 14 | * return パラメータを単一の文字列で表したもの。unserializeParams() で復元できる。 |
15 | 15 | */ |
@@ -30,7 +30,7 @@ | ||
30 | 30 | * serializeParams() で文字列化したURLパラメータを復元する。 |
31 | 31 | * |
32 | 32 | * param 単一の文字列化したパラメータ。serializeParams() の戻り値。 |
33 | - * return 復元したパラメータ。サイト・アクションは "@" のキーに含まれている。 | |
33 | + * return 復元したパラメータ。アクション名は "@" のキーに含まれている。 | |
34 | 34 | */ |
35 | 35 | public static function unserializeParams($serial) { |
36 | 36 |
@@ -112,12 +112,8 @@ | ||
112 | 112 | if( !preg_match('|^([\w\-\.]+/)?([\w\-\.]+)?(\?.*)?$|', $serial) ) |
113 | 113 | $serial = null; |
114 | 114 | |
115 | - // ないならデフォルトアクションへ。 | |
116 | - if(!$serial) | |
117 | - $serial = Mojo::setting('routing', 'mojo.default_action'); | |
118 | - | |
119 | 115 | // 復元。 |
120 | - return self::unserializeParams($serial); | |
116 | + return self::unserializeParams($serial ?? ''); | |
121 | 117 | } |
122 | 118 | |
123 | 119 | //----------------------------------------------------------------------------------------------------- |
@@ -1,93 +0,0 @@ | ||
1 | -<?php | |
2 | - | |
3 | -/** | |
4 | - * アクションファイルなし・ビューファイルのみでURLを有効化するためのトレイト。これを付けた NotfoundAction をサイトに置けば有効化できる。 | |
5 | - */ | |
6 | -trait ActionlessView { | |
7 | - | |
8 | - private $viewPath; | |
9 | - | |
10 | - //----------------------------------------------------------------------------------------------------- | |
11 | - /** | |
12 | - * コンストラクタをオーバーライド。 | |
13 | - */ | |
14 | - public function __construct($attributes) { | |
15 | - | |
16 | - // 先に呼ばないと、パラメータ path.site が埋まらない。 | |
17 | - parent::__construct($attributes); | |
18 | - | |
19 | - // ビューファイルがあるのかチェックして、見つけたらアクションパラメータの take.canonical を書き換える。 | |
20 | - $this->viewPath = $this->findView(); | |
21 | - } | |
22 | - | |
23 | - /** | |
24 | - * 引数に指定されたアクションパラメータに従ってビューを探す。 | |
25 | - * | |
26 | - * return ビューファイルのパス。見つからない場合は null。 | |
27 | - */ | |
28 | - private function findView() { | |
29 | - | |
30 | - // アクション名をグループ名とモーション名に分割。 | |
31 | - @[$group, $motion] = explode('.', $this->attributes['take.action']); | |
32 | - | |
33 | - // 分割できたなら... | |
34 | - if($motion) { | |
35 | - | |
36 | - // そのアクションの標準ビューファイルがあるならそれを使う。 | |
37 | - $view = $this->searchViewPath($group, $motion); | |
38 | - if($view) { | |
39 | - $this->attributes['take.canonical'] = sprintf('%s/%s', $this->attributes['take.site'], $this->attributes['take.action']); | |
40 | - return $view; | |
41 | - } | |
42 | - | |
43 | - // 分割できない、つまり "." がないなら... | |
44 | - }else { | |
45 | - | |
46 | - // xxxxx.index のビューを探す。 | |
47 | - $view = $this->searchViewPath($group, 'index'); | |
48 | - if($view) { | |
49 | - $this->attributes['take.canonical'] = sprintf('%s/%s.%s', $this->attributes['take.site'], $group, 'index'); | |
50 | - return $view; | |
51 | - } | |
52 | - | |
53 | - // default.xxxxx のビューを探す。 | |
54 | - $view = $this->searchViewPath('default', $group); | |
55 | - if($view) { | |
56 | - $this->attributes['take.canonical'] = sprintf('%s/%s.%s', $this->attributes['take.site'], 'default', $group); | |
57 | - return $view; | |
58 | - } | |
59 | - } | |
60 | - | |
61 | - // 見つからない場合は... | |
62 | - $this->attributes['take.canonical'] = sprintf('%s/%s', $this->attributes['take.site'], $this->attributes['take.action']); | |
63 | - return null; | |
64 | - } | |
65 | - | |
66 | - /** | |
67 | - * 引数で指定されたグループ名・アクション名でアクションのないビューを探す。 | |
68 | - * | |
69 | - * param グループ名 | |
70 | - * param モーション名 | |
71 | - * return ビューファイルのパス。見つからない場合はnull。 | |
72 | - */ | |
73 | - private function searchViewPath($group, $motion) { | |
74 | - | |
75 | - $view = sprintf('%s/%s/%sView.html', $this->attributes['path.site'], $group, ucfirst($motion)); | |
76 | - return leaf_exists($view) ? $view : null; | |
77 | - } | |
78 | - | |
79 | - //----------------------------------------------------------------------------------------------------- | |
80 | - protected function execute() { | |
81 | - | |
82 | - // リクエストされているサイト名とアクション名をビューで利用できるようにする。 | |
83 | - $this->renderer['site'] = $this->attributes['take.site']; | |
84 | - $this->renderer['action'] = $this->attributes['take.action']; | |
85 | - $this->renderer['name'] = $this->attributes['take.full']; | |
86 | - | |
87 | - // ビューファイルが見つかっているならそれを使うが、見つかっていないならステータスコードを404にして、このまま NotfoundView を使う。 | |
88 | - if($this->viewPath) | |
89 | - return $this->viewPath; | |
90 | - else | |
91 | - http_response_code(404); | |
92 | - } | |
93 | -} |
@@ -30,9 +30,8 @@ | ||
30 | 30 | $this->renderer['record'] = $this->record = $this->retrieveRecord(); |
31 | 31 | |
32 | 32 | // コンストラクタの引数が指定されているレコードであるにも関わらずロードできないのはIDフィクセイション。 |
33 | - // CrackingException にしても良いかもだが、ライフハック的にGET変数を指定する場合もあるだろうし、まあ普通に案内するのが筋だろう。 | |
34 | 33 | if($this->record->pkey() && $this->record->load() === false) |
35 | - throw new OperationalException('指定されたIDのデータは存在しません。'); | |
34 | + throw new IrregularAccess('指定されたIDのデータは存在しません。'); | |
36 | 35 | |
37 | 36 | // 規約によりコール。何らかの戻り値が示されているなら従う。 |
38 | 37 | $view = $this->prepareAction(); |
@@ -59,7 +58,7 @@ | ||
59 | 58 | /** |
60 | 59 | * このアクションで取り扱うレコードを返す。ここで返したレコードはビュー変数 record に格納される。 |
61 | 60 | * ただし、コンストラクタの引数を指定して作成したレコードインスタンスを返したときにそのレコードをロードできない場合、後続の処理で |
62 | - * IDフィクセイションと判断され、OperationalException で処理中断される。 | |
61 | + * IDフィクセイションと判断され、IrregularAccess 例外で処理中断される。 | |
63 | 62 | * |
64 | 63 | * return MojoRecordインスタンス。 |
65 | 64 | */ |
@@ -127,9 +127,8 @@ | ||
127 | 127 | */ |
128 | 128 | protected function outputFile($file) { |
129 | 129 | |
130 | - // アクションの getViewDirectories() が返すセカンダリディレクトリを取得。普通は、アクションが所属するサイトのディレクトリ。 | |
131 | - // これをテンプレート処理の基準位置として追加設定する。 | |
132 | - $dir = $this->action->getViewDirectories()[1]; | |
130 | + // アクションが所属するサイトのディレクトリを取得。これをテンプレート処理の基準位置とする。 | |
131 | + $dir = $this->action->attributes['path.site']; | |
133 | 132 | |
134 | 133 | // 親テンプレートがある場合は取得しておく。 |
135 | 134 | $parent = @$this->action->attributes['smarty.parent']; |
@@ -1,42 +0,0 @@ | ||
1 | -<?php | |
2 | - | |
3 | -/** | |
4 | - * ユーザの通常操作によってまれに発生しうる例外を表す。例えば次のようなもの。 | |
5 | - * ・確認画面を長時間放置して、データが期限切れになった後に確定処理しようとした | |
6 | - * ・取扱中のデータに他ユーザが同時期にアクセスしており、他ユーザの確定操作のほうが早かったため、データへのアクセス権を失った | |
7 | - * | |
8 | - * この例外によるエラーはログに記載されない。 | |
9 | - * ユーザにはエラーコードが表示されない代わり、この例外のコンストラクタにセットされたメッセージが表示される。 | |
10 | - * | |
11 | - * IllegalTouchException と似ているので注意。 | |
12 | - * IllegalTouchException | |
13 | - * ・ユーザがイレギュラーな操作(ブラウザバックとかフォーム送信の二度押しとか)を行うことで発生する | |
14 | - * ・ログされる | |
15 | - * ・専用のメッセージが表示される(カスタムできない)。 | |
16 | - * OperationalException | |
17 | - * ・通常の操作でもまれに発生する | |
18 | - * ・ログされない | |
19 | - * ・カスタムしたメッセージを表示できる。 | |
20 | - * | |
21 | - * ユーザに非常に簡易なエラーメッセージを表示するだけで事足りるような用途で用いる。複雑な案内が必要な場合は、個別のアクションでしっかり | |
22 | - * エラー処理したほうが良いだろう。 | |
23 | - */ | |
24 | -class OperationalException extends Exception { | |
25 | - | |
26 | - // エラー画面に表示する「戻る」リンクのリンク先パラメータ。 | |
27 | - public $link; | |
28 | - | |
29 | - //---------------------------------------------------------------------------------------------------------- | |
30 | - /** | |
31 | - * param ユーザに表示するエラーメッセージ。 | |
32 | - * param メッセージ表示画面の「戻る」リンクのURLパラメータ。省略した場合は現在のアクションにGETで再度アクセスすることになる。 | |
33 | - * 文字列を指定した場合は、戻り先アクション名が指定されたものと解釈する。 | |
34 | - * ApiBehaviorFilterフィルタを使っているアクションでは無視される。 | |
35 | - */ | |
36 | - public function __construct($message, $link = ['_here'=>true]) { | |
37 | - | |
38 | - parent::__construct($message); | |
39 | - | |
40 | - $this->link = is_array($link) ? $link : array('@'=>$link); | |
41 | - } | |
42 | -} |
@@ -1,30 +0,0 @@ | ||
1 | -<?php | |
2 | - | |
3 | -/** | |
4 | - * 通常のユーザ操作では考えられない、脆弱性を探るような操作を受けたときに発行する例外。ログにも記録されるし、エラーコードも表示される。 | |
5 | - * user_info.cracker_index が +1 されるので、確信があるときのみ発行される。複数のタブ・端末で同時アクセスしたりすると発生しうるものはこちらではなく | |
6 | - * IllegalTouchException が使われる。 | |
7 | - */ | |
8 | -class CrackingException extends Exception { | |
9 | - | |
10 | - /** | |
11 | - * 例外が作成されたときに、user_info.cracker_index を +1 する。 | |
12 | - */ | |
13 | - public function __construct($message = "", $code = 0, Exception $previous = null) { | |
14 | - | |
15 | - parent::__construct($message, $code, $previous); | |
16 | - | |
17 | - // ユーザIDが判明していて、管理者によるユーザ代行でないなら... | |
18 | - $session = Mojo::setting('process', 'mojo.session')::getSession(); | |
19 | - if($session['user_id'] && !$session['operator_code']) { | |
20 | - | |
21 | - // そのユーザの cracker_index を +1 する。 | |
22 | - $user = new UserInfo($session['user_id']); | |
23 | - if($user->load()) { | |
24 | - $user['cracker_index'] += 1; | |
25 | - $user->save(); | |
26 | - } | |
27 | - } | |
28 | - | |
29 | - } | |
30 | -} |
@@ -1,18 +0,0 @@ | ||
1 | -<?php | |
2 | - | |
3 | -/** | |
4 | - * 適切ではない順序でデータを操作しようとしたときに発生する例外。複数のタブ・端末で同時アクセスしたり、ブラウザバックしたりすると発生するもの。 | |
5 | - * ログにも記録されるし、エラーコードも表示されるが、表示されるエラーメッセージに複数タブによる操作などを戒める内容が追加される。 | |
6 | - * | |
7 | - * OperationalException と似ているので注意。 | |
8 | - * IllegalTouchException | |
9 | - * ・ユーザがイレギュラーな操作(ブラウザバックとかフォーム送信の二度押しとか)を行うことで発生する | |
10 | - * ・ログされる | |
11 | - * ・専用のメッセージが表示される(カスタムできない)。 | |
12 | - * OperationalException | |
13 | - * ・通常の操作でもまれに発生する | |
14 | - * ・ログされない | |
15 | - * ・カスタムしたメッセージを表示できる。 | |
16 | - */ | |
17 | -class IllegalTouchException extends Exception { | |
18 | -} |
@@ -42,7 +42,7 @@ | ||
42 | 42 | $shutter = $action->filterByClass('MaintenanceShutterFilter'); |
43 | 43 | if($shutter) { |
44 | 44 | $shutter->params[0] = function() use($action) { |
45 | - $action->renderer->params = array('error'=>'maintenance'); | |
45 | + $action->renderer->params = array('error'=>['code'=>'maintenance']); | |
46 | 46 | $action->renderer->render(); |
47 | 47 | }; |
48 | 48 | } |
@@ -49,7 +49,7 @@ | ||
49 | 49 | |
50 | 50 | // パラメータ post_only の処理。 |
51 | 51 | if($this->params['post_only'] && $_SERVER['REQUEST_METHOD'] != 'POST') { |
52 | - $this->handleException(new CrackingException('POSTメソッドでアクセスする必要があります。'), $action); | |
52 | + $this->handleException(new ErrorException('POSTメソッドでアクセスする必要があります。'), $action); | |
53 | 53 | return false; |
54 | 54 | } |
55 | 55 |
@@ -56,7 +56,7 @@ | ||
56 | 56 | // クライアントが示したバージョンが、サーバー側バージョンと合っていない場合はエラーにする。 |
57 | 57 | if($this->params['check_ver']) { |
58 | 58 | if( @$_GET['ver'] != AppMojo::getVersionStamp() ) { |
59 | - $action->renderer->params = array('error'=>'version'); | |
59 | + $action->renderer->params = array('error'=>['code'=>'version']); | |
60 | 60 | $action->renderer->render(); |
61 | 61 | return false; |
62 | 62 | } |
@@ -69,33 +69,31 @@ | ||
69 | 69 | */ |
70 | 70 | protected function handleException($e, $action) { |
71 | 71 | |
72 | - $response = array(); | |
72 | + $error = array(); | |
73 | 73 | |
74 | - // ログに記録する。ただしOperationalExceptionは記録しない。 | |
75 | - if( !($e instanceof OperationalException) ) | |
76 | - $log = AppLog::exception($e); | |
74 | + // 可能なら、ユーザのエラーカウント+1。 | |
75 | + AppMojo::incrementErrorCount(); | |
77 | 76 | |
78 | - // 例外の種別に応じて、エラーコードをセット。 | |
79 | - switch(true) { | |
80 | - case $e instanceof IllegalTouchException: | |
81 | - $response['error'] = 'illtouch'; | |
82 | - $response['inquiry_code'] = $log['code']; | |
83 | - break; | |
84 | - case $e instanceof OperationalException: | |
85 | - $response['error'] = 'operation'; | |
86 | - $response['error_message'] = $e->getMessage(); | |
87 | - break; | |
88 | - default: | |
89 | - $response['error'] = 'error'; | |
90 | - $response['inquiry_code'] = $log['code']; | |
91 | - } | |
77 | + // ログに記録して問い合わせコードと書き込み内容を得る。 | |
78 | + [ $error['inquiry'], $error['description'] ] = AppLog::exception($e); | |
92 | 79 | |
93 | - // 本番環境以外ではエラートレースもセットする。 | |
94 | - if(AppMojo::setting('application', 'environment_type') != 'prod') | |
95 | - $response['error_trace'] = Log::stringifyException($e); | |
80 | + // ユーザに表示するメッセージを決定。IrregularAccess なら例外から取得する。 | |
81 | + if($e instanceof IrregularAccess) | |
82 | + $error['message'] = $e->getMessage(); | |
96 | 83 | |
84 | + // 本番環境では詳細は伝えない。 | |
85 | + if(static::setting('application', 'environment_type') == 'prod') | |
86 | + unset($error['description']); | |
87 | + | |
88 | + // エラーコードの決定。 | |
89 | + $error['code'] = ($e instanceof IrregularAccess) ? 'irregular' : 'exception'; | |
90 | + | |
91 | + // HTTPエラーコードを設定。 | |
92 | + if(!headers_sent()) | |
93 | + http_response_code(500); | |
94 | + | |
97 | 95 | // 出力。 |
98 | - $action->renderer->params = $response; | |
96 | + $action->renderer->params = $error; | |
99 | 97 | $action->renderer->render(); |
100 | 98 | } |
101 | 99 | } |
@@ -4,7 +4,7 @@ | ||
4 | 4 | * このフィルタを適用するとBASIC認証が必要になる。 |
5 | 5 | * |
6 | 6 | * パラメータ) |
7 | - * passwd パスワードファイルのパス。APP_DIR からの相対パスで指定する。 | |
7 | + * passwd パスワードファイルのパス。先頭が "/" で始まっていない場合は APP_DIR からの相対パスとなる。 | |
8 | 8 | * 省略した場合はアクセス中のサイトディレクトリ直下の .htpasswd となる。 |
9 | 9 | * realm realm名。省略すると "realm" になる。 |
10 | 10 | * environments 対象環境を限定するときは指定する。配列で複数指定することも可能。 |
@@ -31,7 +31,7 @@ | ||
31 | 31 | |
32 | 32 | // passwd が省略されていた場合はアクションのサイトディレクトリ直下の .htpasswd とする。 |
33 | 33 | if( !isset($this->params['passwd']) ) |
34 | - $this->params['passwd'] = sprintf('%s/%s/.htpasswd', Mojo::setting('directories', 'mojo.sites'), $action->attributes['take.site']); | |
34 | + $this->params['passwd'] = sprintf('%s/.htpasswd', $action->attributes['path.site']); | |
35 | 35 | } |
36 | 36 | |
37 | 37 | //----------------------------------------------------------------------------------------------------- |
@@ -84,9 +84,12 @@ | ||
84 | 84 | if(!$userId) |
85 | 85 | return false; |
86 | 86 | |
87 | - // パスワードファイルを決定。 | |
88 | - $passwd = APP_DIR . '/' . $this->params['passwd']; | |
87 | + // パスワードファイルのパスを取得。 | |
88 | + $passwd = $this->params['passwd'] | |
89 | + if($passwd[0] != '/') | |
90 | + $passwd = APP_DIR . '/' . $passwd; | |
89 | 91 | |
92 | + // 読み込み。 | |
90 | 93 | $entries = file($passwd, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); |
91 | 94 | |
92 | 95 | // 1行ずつ照合していく。 |
@@ -52,7 +52,7 @@ | ||
52 | 52 | // パラメータ rules に従って MojoForm で処理する。検証でエラーになったら例外スロー。 |
53 | 53 | $form = new MojoForm($this->params['rules']); |
54 | 54 | if( !$form->validate($vars) ) |
55 | - throw new CrackingException(sprintf("%s変数の値がルールに適合しない。\nエラー:\n%s\n与えられた値:\n%s", $this->params['vars'], mini_dump($form->errors()), mini_dump($vars))); | |
55 | + throw new ErrorException(sprintf("%s変数の値がルールに適合しない。\nエラー:\n%s\n与えられた値:\n%s", $this->params['vars'], mini_dump($form->errors()), mini_dump($vars))); | |
56 | 56 | |
57 | 57 | // 検証が通ったなら、ルールによる入力補正を適用して終了。 |
58 | 58 | $vars = $form['value']; |
@@ -80,15 +80,19 @@ | ||
80 | 80 | * 引数に指定された例外をログファイルに記録する。 |
81 | 81 | * |
82 | 82 | * param ログに記録したい例外。 |
83 | - * param ログ名。 | |
84 | - * return 次のキーを持つ配列。 | |
85 | - * code 問い合わせコード。 | |
86 | - * text 書き込んだ文字列。 | |
83 | + * param ログ名。省略した場合は、IrregularAccess なら 'irregular'、それ以外では 'exception' が使われる。 | |
84 | + * return 次の2つの要素を持つ序数配列。 | |
85 | + * 0 問い合わせコード。 | |
86 | + * 1 書き込んだ文字列。 | |
87 | 87 | */ |
88 | - public static function exception($e, $name = 'exception') { | |
88 | + public static function exception($e, $name=null) { | |
89 | 89 | |
90 | 90 | $now = time(); |
91 | 91 | |
92 | + // ログ名が省略されている場合は、IrregularAccess なら 'irregular'、それ以外では 'exception'。 | |
93 | + if( is_null($name) ) | |
94 | + $name = ($e instanceof IrregularAccess) ? 'irregular' : 'exception'; | |
95 | + | |
92 | 96 | // 例外を説明する文字列を作成。 |
93 | 97 | $text = static::stringifyException($e); |
94 | 98 |
@@ -96,7 +100,7 @@ | ||
96 | 100 | (new static($name))->time($now)->write($text."\n"); |
97 | 101 | |
98 | 102 | // 問い合わせコードを生成して書き込み内容を返す。 |
99 | - return ['code'=>static::genErrorCode($now), 'text'=>$text]; | |
103 | + return [static::genErrorCode($now), $text]; | |
100 | 104 | } |
101 | 105 | |
102 | 106 | /** |
@@ -52,7 +52,7 @@ | ||
52 | 52 | $access = sprintf('%s:%s:%s?%s', |
53 | 53 | strtolower($_SERVER['REQUEST_SCHEME']), |
54 | 54 | strtolower($_SERVER['REQUEST_METHOD']), |
55 | - $action->attributes['take.canonical'], | |
55 | + $action->attributes['action.full'], | |
56 | 56 | self::makeLogString(Mojo::setting('runtime', 'real_get'), $masks) |
57 | 57 | ); |
58 | 58 |
@@ -7,9 +7,10 @@ | ||
7 | 7 | * boot → initialize → (initialize.php) |
8 | 8 | * parseRequestUri → processRoute → processRouteEntry |
9 | 9 | * parsePathInfo |
10 | - * forward → createAction → loadAction → searchAction → openAction → getActionPath | |
11 | - * processRedirect (MojoAction->run) (new MojoAction) | |
12 | - * processException (MojoAction->wake) | |
10 | + * forward → summonAction → searchAction → openAction → getActionPath | |
11 | + * processNotfound (MojoAction->run) (new MojoAction) | |
12 | + * processRedirect (MojoAction->wake) | |
13 | + * processException | |
13 | 14 | * |
14 | 15 | * getUrl → processUrl |
15 | 16 | * genUrl |
@@ -117,21 +118,22 @@ | ||
117 | 118 | // PATH_INFOの正規化、ルーティングの設定などを処理する。 |
118 | 119 | static::parseRequestUri(); |
119 | 120 | |
120 | - // PATH_INFO上のGETパラメータの正規化、リクエストされているサイト、グループ・アクションの取得を行う。 | |
121 | - list($site, $action) = static::parsePathInfo(); | |
121 | + // PATH_INFO上のGETパラメータの正規化、リクエストされているサイト、ディレクションの取得を行う。 | |
122 | + list($site, $direction) = static::parsePathInfo(); | |
122 | 123 | |
123 | 124 | // PATH_INFO上のGETパラメータの処理などが終わったこのタイミングで、これらの変数を取っておく。 |
124 | 125 | static::$settings['runtime']['real_get'] = $_GET; |
125 | 126 | static::$settings['runtime']['real_post'] = $_POST; |
126 | 127 | |
127 | - // リクエストされているサイト、グループ・アクションを setting() で取得できるようにする。 | |
128 | - $name = "{$site}/{$action}"; | |
128 | + // リクエストされているサイト、ディレクションを setting() で取得できるようにする。 | |
129 | + $name = "{$site}/{$direction}"; | |
129 | 130 | static::$settings['runtime']['mojo.requested_site'] = $site; |
130 | - static::$settings['runtime']['mojo.requested_action'] = $action; | |
131 | + static::$settings['runtime']['mojo.requested_direction'] = $direction; | |
131 | 132 | static::$settings['runtime']['mojo.requested_name'] = $name; |
132 | 133 | |
133 | - // そのアクションを処理する。 | |
134 | - static::forward($name); | |
134 | + // そのアクションを処理する。(該当のアクションがないなどで)処理できなかった場合は NotFound 処理。 | |
135 | + if( !static::forward($name) ) | |
136 | + static::processNotfound($name); | |
135 | 137 | } |
136 | 138 | // リダイレクトの処理。この中で例外が発生しても外のtryブロックでキャッチできるように二重になっている。 |
137 | 139 | catch(RedirectException $e) { |
@@ -141,11 +143,14 @@ | ||
141 | 143 | // ExitExceptionはスルー。 |
142 | 144 | catch(ExitException $e) { |
143 | 145 | } |
144 | - // スローされた例外はこちらで処理する。 | |
145 | - catch(Exception $e) { | |
146 | + // スローされた例外はこちらで処理する。processException() の内部でエラーになった場合はPHP標準の方法で処理される。 | |
147 | + catch(Throwable $e) { | |
146 | 148 | try { |
147 | 149 | static::processException($e); |
148 | 150 | } |
151 | + catch(RedirectException $e) { | |
152 | + static::processRedirect($e); | |
153 | + } | |
149 | 154 | catch(ExitException $e) { |
150 | 155 | } |
151 | 156 | } |
@@ -153,39 +158,43 @@ | ||
153 | 158 | |
154 | 159 | //----------------------------------------------------------------------------------------------------- |
155 | 160 | /** |
156 | - * 引数で指定されたアクションを起動する。 | |
161 | + * 引数で指定されたアクションを実行する。 | |
157 | 162 | * |
158 | - * param サイト・アクション名。サイト名とアクション名を "/" でつなげたもの。 | |
163 | + * param アクション名。サイト名とグループ・モーション名を "/" でつなげたもの。 | |
159 | 164 | * param アクションに渡したいパラメータがあればここに指定する。 |
165 | + * return 実行に成功したかどうか。 | |
160 | 166 | */ |
161 | 167 | public static function forward($name, $attributes = array()) { |
162 | 168 | |
163 | - [$site, $action] = explode('/', $name); | |
169 | + // アクションを起動。失敗したら false リターン。 | |
170 | + $action = static::summonAction($name, $attributes); | |
171 | + if( !$action ) | |
172 | + return false; | |
164 | 173 | |
165 | - // アクションをロード。 | |
166 | - $action = static::createAction($site, $action, $attributes); | |
167 | - if( !($action instanceof MojoAction) ) | |
168 | - throw new ErrorException(sprintf('%s クラスをMojoActionから派生させてください。', get_class($action))); | |
169 | - | |
170 | 174 | // アクションスタックに登録。 |
171 | 175 | array_push(static::$actionStack, $action); |
172 | 176 | |
173 | - // アクションを起動。 | |
177 | + // アクションを実行。 | |
174 | 178 | $action->run(); |
175 | 179 | |
176 | 180 | // アクションスタックから削除。 |
177 | 181 | array_pop(static::$actionStack); |
182 | + | |
183 | + return true; | |
178 | 184 | } |
179 | 185 | |
180 | 186 | //----------------------------------------------------------------------------------------------------- |
181 | 187 | /** |
182 | 188 | * 基本的に forward() と同じだが、出力をそのまま出力せずに戻り値として取得するところが異なる。 |
189 | + * アクションを実行できなかった場合は null が返る。 | |
183 | 190 | */ |
184 | 191 | public static function bring($name, $attributes = array()) { |
185 | 192 | |
186 | 193 | ob_start(); |
187 | - static::forward($name, $attributes); | |
188 | - return ob_get_clean(); | |
194 | + $result = static::forward($name, $attributes); | |
195 | + $ret = ob_get_clean(); | |
196 | + | |
197 | + return $result ? $ret : null; | |
189 | 198 | } |
190 | 199 | |
191 | 200 | //----------------------------------------------------------------------------------------------------- |
@@ -221,13 +230,13 @@ | ||
221 | 230 | /** |
222 | 231 | * 引数に指定されたアクションを指すURLを生成する。 |
223 | 232 | * |
224 | - * param アクション指定。"/controller/site/action" の形式で指定する。各区画は先頭から省略できる。 | |
233 | + * param アクション指定。"/controller/site/direction" の形式で指定する。各区画は先頭から省略できる。 | |
225 | 234 | * 例) |
226 | - * action 現在のフロントコントローラーとサイトで、action のURLとなる。 | |
227 | - * site/action 現在のフロントコントローラーで、site/action のURLとなる。 | |
228 | - * controller/site/action 現在のフロントコントローラーの場所で、controller.php/site/action のURLとなる。 | |
229 | - * /controller/site/action /controller.php/site/action のURLとなる。 | |
230 | - * 空文字を指定した場合は現在のサイト・アクションとなる。 | |
235 | + * direction 現在のフロントコントローラーとサイトで、direction のURLとなる。 | |
236 | + * site/direction 現在のフロントコントローラーで、site/direction のURLとなる。 | |
237 | + * controller/site/direction 現在のフロントコントローラーの場所で、controller.php/site/direction のURLとなる。 | |
238 | + * /controller/site/direction /controller.php/site/direction のURLとなる。 | |
239 | + * 空文字を指定した場合は現在のアクションとなる。 | |
231 | 240 | * param GETパラメータを表す連想配列。 |
232 | 241 | * 以下のキーは特殊な意味で扱われる。 |
233 | 242 | * _self trueにすると、現在のURLからパラメータが取得される。 |
@@ -253,7 +262,7 @@ | ||
253 | 262 | /** |
254 | 263 | * getUrl() で行うパラメータ正規化処理。 |
255 | 264 | * |
256 | - * param getUrl() に渡された第一引数。サイト名とアクション名を "/" でつなげた文字列を返す。 | |
265 | + * param getUrl() に渡された第一引数。アクションを指定する文字列。 | |
257 | 266 | * param getUrl() に渡された第二引数。GETパラメータを表す連想配列を返す。 |
258 | 267 | * return 使用するフロントコントローラーへのURL。 |
259 | 268 | */ |
@@ -290,17 +299,17 @@ | ||
290 | 299 | // 前方部分が省略されている場合は null を補う。これで要素数は 3 に固定される。 |
291 | 300 | $compartments = array_slice(array_merge(array(null, null, null), $compartments), -3); |
292 | 301 | |
293 | - // サイト名、アクション名が省略されている場合はそれぞれリクエストされている値を使う。 | |
302 | + // サイト名、ディレクション名が省略されている場合はそれぞれリクエストされている値を使う。 | |
294 | 303 | if( empty($compartments[1]) ) |
295 | 304 | $compartments[1] = static::setting('runtime', 'mojo.requested_site'); |
296 | 305 | if( empty($compartments[2]) ) |
297 | - $compartments[2] = static::setting('runtime', 'mojo.requested_action'); | |
306 | + $compartments[2] = static::setting('runtime', 'mojo.requested_direction'); | |
298 | 307 | |
299 | 308 | // サイト名がデフォルトサイトと一致するなら "-" とする。 |
300 | 309 | if($compartments[1] == static::setting('routing', 'mojo.default_site')) |
301 | 310 | $compartments[1] = '-'; |
302 | 311 | |
303 | - // サイト・アクション名を作成。 | |
312 | + // アクション名を作成。 | |
304 | 313 | $name = $compartments[1] . '/' . $compartments[2]; |
305 | 314 | |
306 | 315 | // 使用するフロントコントローラーへのURLを返す。この一文で、省略されている場合と指定されているの場合の双方に対応している。 |
@@ -312,7 +321,7 @@ | ||
312 | 321 | * 引数リストはgetUrl()と同じだが、_self などの特殊キーはすでに処理されており、引数の意味も固定されている。 |
313 | 322 | * |
314 | 323 | * param 使用するフロントコントローラーへのURL。 |
315 | - * param サイト・アクション名 | |
324 | + * param アクション名 | |
316 | 325 | * param GETパラメータ。ただし、"#" はURLフラグメントとして処理される。 |
317 | 326 | * param GETパラメータをクエリストリングではなくパスの一部としたい場合はtrueを指定する。 |
318 | 327 | * return 生成したURL |
@@ -372,10 +381,10 @@ | ||
372 | 381 | // 各パートを個別に取得。 |
373 | 382 | $components = explode('/', $apppath); |
374 | 383 | |
375 | - // アクション名がデフォルトと一致しているなら... | |
376 | - if( $components[3] == static::setting('routing', 'mojo.default_action') ) { | |
384 | + // ディレクション名がデフォルトと一致しているなら... | |
385 | + if( $components[3] == static::setting('routing', 'mojo.default_direction') ) { | |
377 | 386 | |
378 | - // アクション名は省略できる。 | |
387 | + // ディレクション名は省略できる。 | |
379 | 388 | array_pop($components); |
380 | 389 | |
381 | 390 | // さらにサイト名が "-" になっているなら... |
@@ -723,7 +732,7 @@ | ||
723 | 732 | |
724 | 733 | // ルーティング設定を取得。 |
725 | 734 | $routes = static::setting('routing'); |
726 | - unset($routes['mojo.default_site'], $routes['mojo.default_action'], $routes['mojo.notfound_action'], $routes['mojo.default_site.cli']); | |
735 | + unset($routes['mojo.default_site'], $routes['mojo.default_direction'], $routes['mojo.notfound_direction'], $routes['mojo.default_site.cli']); | |
727 | 736 | |
728 | 737 | // ルーティング設定を一つずつ見ていく。一致したルールを検出したらそこまでとする。 |
729 | 738 | foreach($routes as $route => $arrow) { |
@@ -787,10 +796,9 @@ | ||
787 | 796 | |
788 | 797 | //----------------------------------------------------------------------------------------------------- |
789 | 798 | /** |
790 | - * PATH_INFO に埋め込まれたGETパラメータの処理と、リクエストされているサイト、グループ・モーションの | |
791 | - * 抽出を行う。 | |
799 | + * PATH_INFO に埋め込まれたGETパラメータの処理と、リクエストされているサイト、ディレクションの抽出を行う。 | |
792 | 800 | * |
793 | - * return 第0要素にサイト、第1要素にアクション(グループ・モーション)の名前を格納した配列。 | |
801 | + * return 第0要素にサイト、第1要素にディレクションの名前を格納した配列。 | |
794 | 802 | */ |
795 | 803 | protected static function parsePathInfo() { |
796 | 804 |
@@ -800,8 +808,8 @@ | ||
800 | 808 | }); |
801 | 809 | $fields = array_values($fields); |
802 | 810 | |
803 | - // サイト部分とアクション部分を取得して除去する。 | |
804 | - [$site, $action, $fields] = static::pickoutActionFields($fields); | |
811 | + // サイト部分とディレクション部分を取得して除去する。 | |
812 | + [$site, $direction, $fields] = static::pickoutSummonFields($fields); | |
805 | 813 | |
806 | 814 | // サイトが省略されている場合は routing - mojo.default_site の値を使う。 |
807 | 815 | if(!$site || $site == '-') { |
@@ -817,9 +825,9 @@ | ||
817 | 825 | $site = static::setting('routing', 'mojo.default_site'); |
818 | 826 | } |
819 | 827 | |
820 | - // アクションが省略されている場合は routing - mojo.default_action の値を使う。 | |
821 | - if(!$action || $action == '-') | |
822 | - $action = static::setting('routing', 'mojo.default_action'); | |
828 | + // ディレクションが省略されている場合は routing - mojo.default_direction の値を使う。 | |
829 | + if(!$direction || $direction == '-') | |
830 | + $direction = static::setting('routing', 'mojo.default_direction'); | |
823 | 831 | |
824 | 832 | // URIパスに埋め込まれている変数を $_GET に設定する。 |
825 | 833 | foreach($fields as $field) { |
@@ -841,17 +849,17 @@ | ||
841 | 849 | // このとき、$_REQUEST にすでに存在するキーを上書きしないようにする。 |
842 | 850 | $_REQUEST += $_GET; |
843 | 851 | |
844 | - // サイト名とアクション名を返す。 | |
845 | - return [$site, $action]; | |
852 | + // サイト名とディレクション名を返す。 | |
853 | + return [$site, $direction]; | |
846 | 854 | } |
847 | 855 | |
848 | 856 | /** |
849 | - * 指定されたPATH_INFOフィールドの配列からサイト部分とアクション部分を取得、除去して返す。 | |
857 | + * 指定されたPATH_INFOフィールドの配列からサイト部分とディレクション部分を取得、除去して返す。 | |
850 | 858 | * |
851 | 859 | * param PATH_INFOを "/" で区切った配列 |
852 | - * return [サイト指定, アクション指定, 残りのフィールド] の3要素を含む配列。 | |
860 | + * return [サイト名, ディレクション名, 残りのフィールド] の3要素を含む配列。 | |
853 | 861 | */ |
854 | - protected static function pickoutActionFields($fields) { | |
862 | + protected static function pickoutSummonFields($fields) { | |
855 | 863 | |
856 | 864 | $pair = []; |
857 | 865 |
@@ -861,11 +869,11 @@ | ||
861 | 869 | // GET変数として指定されているフィールドはスキップ。 |
862 | 870 | if(strpos($field, '=') !== false) continue; |
863 | 871 | |
864 | - // サイト・アクション指定として取得する。このとき、特定の文字以外は除去する。 | |
872 | + // サイト・ディレクション名として取得する。このとき、特定の文字以外は除去する。 | |
865 | 873 | $pair[] = preg_replace('/[^\w\-\.]/', '', $field); |
866 | 874 | unset($fields[$i]); |
867 | 875 | |
868 | - // サイト・アクションの2つが取得できたらそこまで。 | |
876 | + // サイト・ディレクションの2つが取得できたらそこまで。 | |
869 | 877 | if(2 <= count($pair)) break; |
870 | 878 | } |
871 | 879 |
@@ -887,7 +895,7 @@ | ||
887 | 895 | |
888 | 896 | //----------------------------------------------------------------------------------------------------- |
889 | 897 | /** |
890 | - * 引数に指定された例外を処理する。 | |
898 | + * 引数に指定された例外を処理する。ここから例外をスローした場合はPHP標準の方法で処理される。 | |
891 | 899 | * |
892 | 900 | * param 発生した例外。 |
893 | 901 | */ |
@@ -899,92 +907,85 @@ | ||
899 | 907 | |
900 | 908 | //----------------------------------------------------------------------------------------------------- |
901 | 909 | /** |
902 | - * 引数で指定された名前のサイト・アクションをロードして、インスタンスを作成して返す。 | |
910 | + * リクエストされたアクションが見付からない場合の処理を行う。 | |
903 | 911 | * |
904 | - * param サイト名 | |
905 | - * param アクション名(グループ・モーション名) | |
906 | - * param アクションに渡すパラメータ | |
907 | - * return アクションインスタンス | |
912 | + * param リクエストされたアクション名。 | |
908 | 913 | */ |
909 | - protected static function createAction($site, $action, $attributes) { | |
914 | + protected static function processNotfound($name) { | |
910 | 915 | |
911 | - // アクションクラスをロードして、そのクラス名とファイルパスを取得する。得られなかったらエラー。 | |
912 | - $result = static::loadAction($site, $action); | |
913 | - if(!$result) { | |
914 | - http_response_code(404); | |
915 | - throw new ErrorException("アクションクラスが見付からない。(site:{$site}, action:{$action})"); | |
916 | - } | |
917 | - | |
918 | - // インスタンスの基本パラメータを作成。 | |
919 | - $params = array( | |
920 | - 'name.site'=>$result[2][0], 'name.group'=>$result[2][1], 'name.motion'=>$result[2][2], | |
921 | - 'take.site'=>$site, 'take.action'=>$action, | |
922 | - 'path.site'=>null, 'path.action'=>$result[1], | |
923 | - ); | |
924 | - | |
925 | - // インスタンスを作成。 | |
926 | - $action = new $result[0]($params + (array)$attributes); | |
927 | - $action->wake(); | |
928 | - return $action; | |
916 | + http_response_code(404); | |
917 | + echo "$name を処理するアクションクラスが見付からない。\n"; | |
929 | 918 | } |
930 | 919 | |
931 | 920 | //----------------------------------------------------------------------------------------------------- |
932 | 921 | /** |
933 | - * 引数で指定された名前のサイト・アクションのクラスをロードして、クラス名と定義されているファイルパスを返す。 | |
934 | - * notfound アクションなどのフォールバックも考慮される。 | |
922 | + * 引数で指定された名前のアクションのインスタンスを作成・起動して、返す。 | |
935 | 923 | * |
936 | - * param サイト名 | |
937 | - * param アクション名(グループ・モーション名) | |
938 | - * return 次の2要素を格納する序数配列。ロードできなかった場合は null。 | |
939 | - * 要素0 アクションクラス名 | |
940 | - * 要素1 アクションクラスが定義されているファイルのパス | |
941 | - * 要素2 ロードしたアクションの [サイト名, グループ名, モーション名] の配列 | |
924 | + * param アクション名。サイト名とディレクション名を "/" でつなげたもの。 | |
925 | + * param アクションに渡すパラメータ | |
926 | + * return アクションインスタンス。指定のアクションが見付からない、あるいは起動できないなら null。 | |
942 | 927 | */ |
943 | - protected static function loadAction($site, $action) { | |
928 | + protected static function summonAction($name, $attributes): ?MojoAction { | |
944 | 929 | |
945 | - // まずは通常通り探す。 | |
946 | - $result = static::searchAction($site, $action); | |
947 | - if($result) | |
948 | - return $result; | |
930 | + // サイト名とディレクション名を分離する。 | |
931 | + [$site, $direction] = explode('/', $name); | |
949 | 932 | |
950 | - // なかった場合は Notfound アクションを探す。 | |
951 | - $notfound = static::setting('routing', 'mojo.notfound_action'); | |
952 | - $result = static::searchAction($site, $notfound); | |
953 | - if($result) | |
954 | - return $result; | |
933 | + // 指定されたアクションを探してインスタンス化。 | |
934 | + $search = static::searchAction($site, $direction); | |
935 | + if($search) { | |
955 | 936 | |
956 | - // ロードできない場合は null を返す。 | |
957 | - return null; | |
937 | + // インスタンスの基本パラメータを作成。 | |
938 | + $params = array( | |
939 | + 'action.summon'=>$name, 'path.action'=>$search[1], | |
940 | + 'action.site'=>$search[2][0], 'action.group'=>$search[2][1], 'action.motion'=>$search[2][2], | |
941 | + ); | |
942 | + | |
943 | + $action = new $search[0]($params + $attributes); | |
944 | + | |
945 | + // 見付からない場合はアクションレス・ビューを探索するアクションを作成する。 | |
946 | + }else { | |
947 | + | |
948 | + // インスタンスの基本パラメータを作成。 | |
949 | + $params = array( | |
950 | + 'action.summon'=>$name, 'path.action'=>null, | |
951 | + 'action.site'=>$site, 'action.group'=>null, 'action.motion'=>null, | |
952 | + ); | |
953 | + | |
954 | + $action = new ActionlessViewAction($params + $attributes); | |
955 | + } | |
956 | + | |
957 | + // インスタンスを作成。 | |
958 | + return $action->wake() ? $action : null; | |
958 | 959 | } |
959 | 960 | |
960 | 961 | //----------------------------------------------------------------------------------------------------- |
961 | 962 | /** |
962 | - * 関数定義はloadActionと同じだが、notfound アクションなどのフォールバックは考慮されない。指定されたアクションに対する処理を行うのみ。 | |
963 | + * 引数で指定された名前のサイト・ディレクションのクラスをロードして、クラス名と定義されているファイルパスを返す。 | |
963 | 964 | * |
964 | 965 | * param サイト名 |
965 | - * param アクション名(グループ・モーション名) | |
966 | + * param ディレクション名(グループ・モーション名) | |
966 | 967 | * return 次の2要素を格納する序数配列。ロードできなかった場合は null。 |
967 | 968 | * 要素0 アクションクラス名 |
968 | 969 | * 要素1 アクションクラスが定義されているファイルのパス |
969 | 970 | * 要素2 見つけたアクションの [サイト名, グループ名, モーション名] の配列 |
970 | 971 | */ |
971 | - protected static function searchAction($site, $action) { | |
972 | + protected static function searchAction($site, $direction) { | |
972 | 973 | |
973 | - // アクション名を "." で分ける。 | |
974 | - @[$group, $action] = explode('.', $action); | |
974 | + // ディレクション名を "." で分ける。 | |
975 | + @[$group, $motion] = explode('.', $direction); | |
975 | 976 | |
976 | - // "." があるなら $group/$action か default/$group$action のどちらか。 | |
977 | - if($action) | |
978 | - return static::openAction($site, $group, $action) ?: static::openAction($site, 'default', ucfirst($group).ucfirst($action)); | |
977 | + // "." があるなら簡単なのだが、 | |
978 | + if($motion) | |
979 | + return static::openAction($site, $group, $motion); | |
979 | 980 | |
980 | 981 | // "." がない場合は、"xxxxx.index" を探して、それもない場合は "default.xxxxx" を探す。 |
981 | - return static::openAction($site, $group, 'index') ?: static::openAction($site, 'default', $group); | |
982 | + else | |
983 | + return static::openAction($site, $group, 'index') ?: static::openAction($site, 'default', $group); | |
982 | 984 | } |
983 | 985 | |
984 | 986 | //----------------------------------------------------------------------------------------------------- |
985 | 987 | /** |
986 | - * 引数で指定されたサイト名・グループ名・モーション名で、アクションクラスが記述されているファイルを探し、 | |
987 | - * アクションクラスの定義を読み込む。 | |
988 | + * 引数で指定されたサイト名・グループ名・モーション名で、アクションクラスが記述されているファイルを探し、アクションクラスの定義を読み込む。 | |
988 | 989 | * |
989 | 990 | * param サイト名 |
990 | 991 | * param グループ名 |
@@ -999,8 +1000,7 @@ | ||
999 | 1000 | // アクションファイル名を決定。先頭は大文字。 |
1000 | 1001 | $file = ucfirst($motion) . 'Action'; |
1001 | 1002 | |
1002 | - // サイト名・グループ名・アクションファイル名を指定して、アクションクラスが記述されているファイルを見つける。 | |
1003 | - // 見つからなかったらロードは出来ない。 | |
1003 | + // サイト名・グループ名・アクションファイル名から、そのファイルを見つける。見つからなかったらロードは出来ない。 | |
1004 | 1004 | $path = static::getActionPath($site, $group, $file); |
1005 | 1005 | if(!$path) |
1006 | 1006 | return null; |
@@ -1026,7 +1026,7 @@ | ||
1026 | 1026 | |
1027 | 1027 | //----------------------------------------------------------------------------------------------------- |
1028 | 1028 | /** |
1029 | - * 引数で指定されたサイト名・グループ名・アクションファイル名から、アクションクラスが記述されているファイルを探す。 | |
1029 | + * 引数で指定されたサイト名・グループ名・アクションファイル名から、該当のファイルを探す。 | |
1030 | 1030 | * |
1031 | 1031 | * param サイト名 |
1032 | 1032 | * param グループ名 |
@@ -5,69 +5,34 @@ | ||
5 | 5 | */ |
6 | 6 | class MojoAction { |
7 | 7 | |
8 | - // アクションに渡されたパラメータを表す連想配列。どんなキーがあるかは運用によって様々だが、次のキーは標準的に定義される。 | |
9 | - // name.site | |
10 | - // name.group | |
11 | - // name.motion | |
12 | - // このアクションのサイト名、グループ名、モーション名。リクエスト時に省略されていてもセットされる。 | |
13 | - // name.full | |
14 | - // 上記3つを "site/group.motion" の形でつなげたもの。 | |
15 | - // take.site | |
16 | - // take.action | |
17 | - // このアクションが処理しているサイト名とアクション名。 | |
18 | - // NotfoundAction などもあるので、この名前は自身のクラス名や所属サイト名とは必ずしも一致しない。 | |
19 | - // また、Mojo::forward() で転送されている場合もあるので、mojo.requested_site, mojo.requested_action とも必ずしも一致しない。 | |
20 | - // take.full | |
21 | - // 上記2つを "site/action" の形でつなげたもの。 | |
22 | - // take.canonical | |
23 | - // name.full と同様だが、アクションレスの NotfoundAction などでは代替したアクションのサイト名・アクション名がセットされる。 | |
24 | - // path.action | |
25 | - // このアクションが定義されているファイルのパス。イレギュラーな場所にあるなら null。 | |
26 | - // null の場合、ビューテンプレートなどの関連ファイルの探索パスが減る。 | |
27 | - // path.site | |
28 | - // このアクションが所属するサイトのディレクトリ。どのサイトにも所属しないなら null。 | |
29 | - // null の場合、ビューテンプレートなどの関連ファイルの探索パスが減る。 | |
30 | - // | |
31 | - // 例) | |
32 | - // "site1/motion1" がリクエストされ、"site1/default.motion1" が受けた場合、次のようになる。 | |
33 | - // | |
34 | - // mojo.requested_site site1 | |
35 | - // mojo.requested_action motion1 | |
36 | - // mojo.requested_name site1/motion1 | |
37 | - // name.site site1 | |
38 | - // name.group default | |
39 | - // name.motion motion1 | |
40 | - // name.full site1/default.motion1 | |
41 | - // take.site site1 | |
42 | - // take.action motion1 | |
43 | - // take.full site1/motion1 | |
44 | - // take.canonical site1/default.motion1 | |
45 | - // | |
46 | - // 例) | |
47 | - // "site1/group1.motion1" がリクエストされ、"site2/group2" へforward()されたところアクションがないため "site2/default.notfound" が受けて | |
48 | - // "site2/group2.index" に該当するビューを使用した場合、次のようになる。 | |
49 | - // | |
50 | - // mojo.requested_site site1 | |
51 | - // mojo.requested_action group1.motion1 | |
52 | - // mojo.requested_name site1/group1.motion1 | |
53 | - // name.site site2 | |
54 | - // name.group default | |
55 | - // name.motion notfound | |
56 | - // name.full site2/default.notfound | |
57 | - // take.site site2 | |
58 | - // take.action group2 | |
59 | - // take.full site2/group2 | |
60 | - // take.canonical site2/group2.index | |
61 | - // | |
62 | - // つまり、requested_* は常にリクエストされたアクションを、name.* は常に自分を、take.* はforward()に渡された命題を指している。 | |
63 | - // ※ mojo.requested_* はアクションの属性ではなく、Mojo::setting('runtime', ...) で取得するものなので注意。 | |
64 | - // | |
8 | + /** | |
9 | + * アクションに渡されたパラメータを表す連想配列。どんなキーがあるかは運用によって様々だが、次のキーは標準的に定義される。 | |
10 | + * action.site | |
11 | + * action.group | |
12 | + * action.motion | |
13 | + * このアクションのサイト名、グループ名、モーション名。リクエスト時に省略されていてもセットされる。 | |
14 | + * action.full | |
15 | + * 上記3つを "site/group.motion" の形でつなげたもの。 | |
16 | + * action.summon | |
17 | + * アクションが呼び出された時(Mojo::forward()がコールされた時)に指定されたアクション名。 | |
18 | + * 基本的に action.full と同じだが、"default" や "index" が省略されている可能性がある。 | |
19 | + * path.action | |
20 | + * このアクションが定義されているファイルのパス。イレギュラーな場所にあるなら null。 | |
21 | + * null の場合、ビューテンプレートなどの関連ファイルの探索パスが減る。 | |
22 | + * path.site | |
23 | + * このアクションが所属するサイトのディレクトリ。どのサイトにも所属しないなら null。 | |
24 | + * null の場合、ビューテンプレートなどの関連ファイルの探索パスが減る。 | |
25 | + */ | |
65 | 26 | public $attributes = array(); |
66 | 27 | |
67 | - // アクションの出力処理を担当するレンダラクラス。"default" の場合は settings.php の process - mojo.renderer の値が使われる。 | |
28 | + /** | |
29 | + * アクションの出力処理を担当するレンダラクラス。"default" の場合は settings.php の process - mojo.renderer の値が使われる。 | |
30 | + */ | |
68 | 31 | public $renderClass = 'default'; |
69 | 32 | |
70 | - // renderClass の設定をもとに作成されたレンダラインスタンス。 | |
33 | + /** | |
34 | + * renderClass の設定をもとに作成されたレンダラ・インスタンス。 | |
35 | + */ | |
71 | 36 | public $renderer; |
72 | 37 | |
73 | 38 | //----------------------------------------------------------------------------------------------------- |
@@ -76,29 +41,16 @@ | ||
76 | 41 | * |
77 | 42 | * param このアクションのパラメータ。attributes メンバ変数にセットされる。 |
78 | 43 | * どんなキーが必要かはアクション次第だが、メンバ変数 $attributes で説明しているキーは必ず必要になる。 |
79 | - * ただし path.site, name.full, take.full, take.canonical は推測するので不要。 | |
44 | + * ただし action.full, path.site は推測するので不要。 | |
80 | 45 | */ |
81 | 46 | public function __construct($attributes) { |
82 | 47 | |
83 | - // path.site が省略されている場合は path.action から推測してみる。 | |
84 | - if(!isset($attributes['path.site']) && isset($attributes['path.action'])) { | |
48 | + // 省略されている値を取得する。 | |
49 | + if( !isset($attributes['path.site']) ) | |
50 | + $attributes['path.site'] = Mojo::getDirectory('mojo.sites') . '/' . $attributes['action.site']; | |
51 | + if( !isset($attributes['action.full']) ) | |
52 | + $attributes['action.full'] = sprintf('%s/%s.%s', $attributes['action.site'], $attributes['action.group'], $attributes['action.motion']); | |
85 | 53 | |
86 | - $sites = Mojo::getDirectory('mojo.sites'); | |
87 | - | |
88 | - if(strpos($attributes['path.action'], $sites) === 0) { | |
89 | - $sites = preg_quote($sites, '#'); | |
90 | - $attributes['path.site'] = preg_replace("#^({$sites}/[^/]+)/.*#", '$1', $attributes['path.action']); | |
91 | - } | |
92 | - } | |
93 | - | |
94 | - // name.full, take.full, take.canonical は他の値から取得できる。 | |
95 | - if( !isset($attributes['name.full']) ) | |
96 | - $attributes['name.full'] = sprintf('%s/%s.%s', $attributes['name.site'], $attributes['name.group'], $attributes['name.motion']); | |
97 | - if( !isset($attributes['take.full']) ) | |
98 | - $attributes['take.full'] = sprintf('%s/%s', $attributes['take.site'], $attributes['take.action']); | |
99 | - if( !isset($attributes['take.canonical']) ) | |
100 | - $attributes['take.canonical'] = $attributes['name.full']; | |
101 | - | |
102 | 54 | // 渡されたパラメータを attributes メンバ変数で保持する。 |
103 | 55 | $this->attributes = array_replace($this->attributes, $attributes); |
104 | 56 | } |
@@ -155,10 +107,12 @@ | ||
155 | 107 | $result = array(); |
156 | 108 | |
157 | 109 | // プライマリ |
158 | - $result[] = dirname(@$this->attributes['path.action']); | |
110 | + if( isset($this->attributes['path.action']) ) | |
111 | + $result[] = dirname($this->attributes['path.action']); | |
159 | 112 | |
160 | 113 | // セカンダリ |
161 | - $result[] = @$this->attributes['path.site']; | |
114 | + if( isset($this->attributes['path.site']) ) | |
115 | + $result[] = $this->attributes['path.site']; | |
162 | 116 | |
163 | 117 | // ターシャリ |
164 | 118 | $result[] = Mojo::getDirectory('mojo.sites'); |
@@ -365,11 +319,13 @@ | ||
365 | 319 | |
366 | 320 | //----------------------------------------------------------------------------------------------------- |
367 | 321 | /** |
368 | - * アクションが作成された時、コンストラクタの最後に呼ばれる。 | |
369 | - * 末端のアクションクラスがその処理を記述するという位置づけなので、基本的に parent::wake() を呼ぶ必要はない。 | |
370 | - * なので、末端のアクション以外ではオーバーライドしないのが原則。 | |
322 | + * アクションが作成された時、コンストラクタの直後に呼ばれる。 | |
323 | + * | |
324 | + * return アクションの処理が可能かどうか。falseを返すと run() が呼ばれずこのアクションは処理不能として扱われる。 | |
371 | 325 | */ |
372 | 326 | public function wake() { |
327 | + | |
328 | + return true; | |
373 | 329 | } |
374 | 330 | |
375 | 331 | //----------------------------------------------------------------------------------------------------- |
@@ -404,3 +360,90 @@ | ||
404 | 360 | protected function finish($view) { |
405 | 361 | } |
406 | 362 | } |
363 | + | |
364 | +//========================================================================================================== | |
365 | +/** | |
366 | + * 比較的単純な画面表示のみなど、ビューのみ準備すれば事足りるようなアクションでアクションクラスを省略できるようにするアクション。 | |
367 | + * Mojo::forward() などで、指定のアクションが見付からない場合に使用される。 | |
368 | + */ | |
369 | +class ActionlessViewAction extends MojoAction { | |
370 | + | |
371 | + private $viewPath; | |
372 | + | |
373 | + //----------------------------------------------------------------------------------------------------- | |
374 | + /** | |
375 | + * オーバーライド。 | |
376 | + * アクションが作成された時、コンストラクタの直後に呼ばれる。 | |
377 | + */ | |
378 | + public function wake() { | |
379 | + | |
380 | + // ビューファイルがあるのかチェック。 | |
381 | + $this->viewPath = $this->findView(); | |
382 | + | |
383 | + // ビューが見付からない場合は処理できない。 | |
384 | + return (bool)$this->viewPath; | |
385 | + } | |
386 | + | |
387 | + /** | |
388 | + * アクションパラメータに従ってビューを探す。見つけたらアクションパラメータの action.group, action.motion, action.full を書き換える。 | |
389 | + * | |
390 | + * return ビューファイルのパス。見つからない場合は null。 | |
391 | + */ | |
392 | + private function findView() { | |
393 | + | |
394 | + // forward() で指定されたアクション名からグループ名とモーション名を取得。 | |
395 | + [$_, $direction] = explode('/', $this->attributes['action.summon']); | |
396 | + @[$group, $motion] = explode('.', $direction); | |
397 | + | |
398 | + // モーション名まで指定されている場合。 | |
399 | + if($motion) { | |
400 | + | |
401 | + // そのアクションの標準ビューファイルがあるならそれを使う。 | |
402 | + $view = $this->searchViewPath($group, $motion); | |
403 | + | |
404 | + // モーション名まで指定されていない場合。 | |
405 | + }else { | |
406 | + | |
407 | + // xxxxx.index のビューを探す。 | |
408 | + $motion = 'index'; | |
409 | + $view = $this->searchViewPath($group, $motion); | |
410 | + | |
411 | + // 見付からないなら default.xxxxx のビューを探す。 | |
412 | + if( !$view ) { | |
413 | + $motion = $group; | |
414 | + $group = 'default'; | |
415 | + $view = $this->searchViewPath($group, $motion); | |
416 | + } | |
417 | + } | |
418 | + | |
419 | + // 見つかったなら、アクションパラメータもそれに合わせて修正しておく。 | |
420 | + if($view) { | |
421 | + $this->attributes['action.group'] = $group; | |
422 | + $this->attributes['action.motion'] = $motion; | |
423 | + $this->attributes['action.full'] = sprintf('%s/%s.%s', $this->attributes['action.site'], $group, $motion); | |
424 | + } | |
425 | + | |
426 | + return $view; | |
427 | + } | |
428 | + | |
429 | + /** | |
430 | + * 引数で指定されたグループ名・アクション名でアクションのないビューを探す。 | |
431 | + * | |
432 | + * param グループ名 | |
433 | + * param モーション名 | |
434 | + * return ビューファイルのパス。見つからない場合はnull。 | |
435 | + */ | |
436 | + private function searchViewPath($group, $motion) { | |
437 | + | |
438 | + $view = sprintf('%s/%s/%sView.html', $this->attributes['path.site'], $group, ucfirst($motion)); | |
439 | + return leaf_exists($view) ? $view : null; | |
440 | + } | |
441 | + | |
442 | + //----------------------------------------------------------------------------------------------------- | |
443 | + protected function execute() { | |
444 | + | |
445 | + $this->renderer['actionpars'] = $this->attributes; | |
446 | + | |
447 | + return $this->viewPath; | |
448 | + } | |
449 | +} |
@@ -3,6 +3,9 @@ | ||
3 | 3 | /** |
4 | 4 | * アクションの出力処理を担当するクラス(レンダラ)。 |
5 | 5 | * 普通、一つのレンダラインスタンスは一つのアクションインスタンスに紐づく。一つのインスタンスで複数のアクションを処理したりすることはない。 |
6 | + * | |
7 | + * 主なメソッドフローは次の通り。 | |
8 | + * render → output | |
6 | 9 | */ |
7 | 10 | class MojoRenderer implements ArrayAccess { |
8 | 11 |
@@ -124,6 +127,10 @@ | ||
124 | 127 | //========================================================================================================= |
125 | 128 | /** |
126 | 129 | * ビューとしてテンプレートファイルを伴うレンダラ実装。 |
130 | + * | |
131 | + * 主なメソッドフローは次の通り。 | |
132 | + * render → output → getViewFile | |
133 | + * outputFile | |
127 | 134 | */ |
128 | 135 | class TemplateRenderer extends MojoRenderer { |
129 | 136 |
@@ -144,8 +151,11 @@ | ||
144 | 151 | |
145 | 152 | // ビューファイルを取得。見付からない場合はエラー。 |
146 | 153 | $file = $this->getViewFile($view); |
147 | - if(!$file) | |
148 | - throw new ErrorException(sprintf('ビューファイルが見付からない。(site:%s, action:%s, view:%s)");', $this->action->attributes['name.site'], get_class($this->action), $view)); | |
154 | + if(!$file) { | |
155 | + throw new ErrorException(sprintf( | |
156 | + 'ビューファイル "%s" が見付からない。action:%s(%s)");', $view, get_class($this->action), $this->action->attributes['action.summon'] | |
157 | + )); | |
158 | + } | |
149 | 159 | |
150 | 160 | // ビューを出力。 |
151 | 161 | $this->outputFile($file); |
@@ -189,13 +199,11 @@ | ||
189 | 199 | // アクションからテンプレート検索ディレクトリを取得、一つずつ見ていく。 |
190 | 200 | $dirs = $this->action->getViewDirectories(); |
191 | 201 | foreach($dirs as $dir) { |
192 | - if($dir) { | |
193 | 202 | |
194 | - // テンプレートファイルを見つけたらリターン。 | |
195 | - $path = $dir . '/' . $view; | |
196 | - if( file_exists($path) && is_file($path) ) | |
197 | - return $path; | |
198 | - } | |
203 | + // テンプレートファイルを見つけたらリターン。 | |
204 | + $path = $dir . '/' . $view; | |
205 | + if( file_exists($path) && is_file($path) ) | |
206 | + return $path; | |
199 | 207 | } |
200 | 208 | |
201 | 209 | // ここまで来ると分からない。 |
@@ -222,8 +230,12 @@ | ||
222 | 230 | //========================================================================================================= |
223 | 231 | /** |
224 | 232 | * レンダリングエンジンとしてPHPをそのまま使う実装。 |
225 | - * TemplateRenderer もそうなっているが、こちらはレイアウトファイルを指定できるなど、すこしだけリッチに | |
226 | - * なっている。 | |
233 | + * TemplateRenderer もそうなっているが、こちらはレイアウトファイルを指定できるなど、すこしだけリッチになっている。 | |
234 | + * | |
235 | + * 主なメソッドフローは次の通り。 | |
236 | + * render → output → getViewFile | |
237 | + * getLayoutFile | |
238 | + * outputFile | |
227 | 239 | */ |
228 | 240 | class PhpRenderer extends TemplateRenderer { |
229 | 241 |
@@ -250,8 +262,11 @@ | ||
250 | 262 | |
251 | 263 | // レイアウトファイルを取得。見付からない場合はエラー。 |
252 | 264 | $file = $this->getLayoutFile(); |
253 | - if(!$file) | |
254 | - throw new ErrorException(sprintf('レイアウトファイルが見付からない。(site:%s, action:%s, layout:%s)");', $this->action->attributes['name.site'], get_class($this->action), $this->layout)); | |
265 | + if(!$file) { | |
266 | + throw new ErrorException(sprintf( | |
267 | + 'レイアウトファイルが "%s" が見付からない。action:%s(%s)");', $this->layout, get_class($this->action), $this->action->attributes['action.summon'] | |
268 | + )); | |
269 | + } | |
255 | 270 | |
256 | 271 | // レイアウトを出力。 |
257 | 272 | $this->outputFile($file); |
@@ -272,17 +287,14 @@ | ||
272 | 287 | // レイアウトファイルの名前を取得。 |
273 | 288 | $name = $this->layout . '.' . $this->templateExt; |
274 | 289 | |
275 | - // アクションからテンプレート検索ディレクトリを取得、セカンダリから一つずつ見ていく。 | |
290 | + // アクションからテンプレート検索ディレクトリを取得、一つずつ見ていく。 | |
276 | 291 | $dirs = $this->action->getViewDirectories(); |
277 | - array_shift($dirs); | |
278 | 292 | foreach($dirs as $dir) { |
279 | - if($dir) { | |
280 | 293 | |
281 | - // レイアウトファイルを見つけたらリターン。 | |
282 | - $path = $dir . '/' . $name; | |
283 | - if( file_exists($path) && is_file($path) ) | |
284 | - return $path; | |
285 | - } | |
294 | + // レイアウトファイルを見つけたらリターン。 | |
295 | + $path = $dir . '/' . $name; | |
296 | + if( file_exists($path) && is_file($path) ) | |
297 | + return $path; | |
286 | 298 | } |
287 | 299 | |
288 | 300 | // ここまで来ると分からない。 |
@@ -294,8 +306,8 @@ | ||
294 | 306 | //========================================================================================================= |
295 | 307 | /** |
296 | 308 | * 出力を行わないレンダラ。 |
297 | - * 一定数のアクションの共通処理として出力を行いたくない場合に使う。個別のアクションで出力したくないだけなら | |
298 | - * これを使わずとも execute() で "none" を返せばよい。 | |
309 | + * 一定数のアクションの共通処理として出力を行いたくない場合に使う。個別のアクションで出力したくないだけならこれを使わずとも | |
310 | + * execute() で "none" を返せばよい。 | |
299 | 311 | */ |
300 | 312 | class NullRenderer extends MojoRenderer { |
301 | 313 |
@@ -1,5 +1,5 @@ | ||
1 | 1 | |
2 | -●URLとサイト、グループ、モーション | |
2 | +●URLとアクション | |
3 | 3 | |
4 | 4 | ○ルーティング |
5 | 5 |
@@ -13,20 +13,12 @@ | ||
13 | 13 | |
14 | 14 | クラス名は BazAction でも良いのだが、あまり凡庸な名前だと他と被ることになるかも。 |
15 | 15 | |
16 | - ○GETパラメータ | |
16 | + ○用語 | |
17 | 17 | |
18 | - $_GETで参照できるクエリパラメータを付けたい場合は、普通に次のように出来る。 | |
18 | + |-- アクション名 --| | |
19 | + http://sample.com/index.php/[サイト名]/[グループ名].[モーション名] | |
20 | + |-- ディレクション名 --| | |
19 | 21 | |
20 | - http://sample.com/index.php/site/group.action?key1=val1&key2=val2&key3=val3&key4=val4 | |
21 | - | |
22 | - 次のようにもできる。 | |
23 | - | |
24 | - http://sample.com/index.php/site/group.action/key1=val1/key2=val2?key3=val3&key4=val4 | |
25 | - | |
26 | - "=" が含まれているフィールドはGET変数の指定と解釈するので、次のようにもできる。 | |
27 | - | |
28 | - http://sample.com/index.php/key1=val1/site/group.action/key2=val2?key3=val3&key4=val4 | |
29 | - | |
30 | 22 | ○省略 |
31 | 23 | |
32 | 24 | グループ名 default なら省略できる。 |
@@ -52,7 +44,7 @@ | ||
52 | 44 | |
53 | 45 | ○デフォルト |
54 | 46 | |
55 | - 次のようにアクション部分を省略し、設定ファイルの routing - mojo.default_action の値を使うことが出来る。 | |
47 | + 次のようにディレクション部分を省略し、設定ファイルの routing - mojo.default_direction の値を使うことが出来る。 | |
56 | 48 | |
57 | 49 | http://sample.com/index.php/user |
58 | 50 |
@@ -65,18 +57,20 @@ | ||
65 | 57 | |
66 | 58 | /-/foo.bar |
67 | 59 | |
68 | - ○グループが存在しない場合 | |
60 | + ○GETパラメータ | |
69 | 61 | |
70 | - 基本的に | |
62 | + $_GETで参照できるクエリパラメータを付けたい場合は、普通に次のように出来る。 | |
71 | 63 | |
72 | - sites/サイト/グループ/モーションAction.php | |
64 | + http://sample.com/index.php/site/group.motion?key1=val1&key2=val2&key3=val3&key4=val4 | |
73 | 65 | |
74 | - となるが、見つからない場合は | |
66 | + 次のようにもできる。 | |
75 | 67 | |
76 | - sites/サイト/default/グループモーションAction.php | |
68 | + http://sample.com/index.php/site/group.motion/key1=val1/key2=val2?key3=val3&key4=val4 | |
77 | 69 | |
78 | - も探索される。 | |
70 | + "=" が含まれているフィールドはGET変数の指定と解釈するので、次のようにもできる。 | |
79 | 71 | |
72 | + http://sample.com/index.php/key1=val1/site/group.motion/key2=val2?key3=val3&key4=val4 | |
73 | + | |
80 | 74 | ●フィルタ |
81 | 75 | |
82 | 76 | 各アクションに事前処理と事後処理を行う「フィルタ」を設定できる。 |
@@ -119,7 +113,7 @@ | ||
119 | 113 | ●コマンドラインでの実行 |
120 | 114 | |
121 | 115 | php コマンドに与えるスクリプトパスとしてフロントコントローラーを与える。普通はルートにある mojo.php が良いだろう。 |
122 | - サイトとアクションは第一引数として与える。example/test を実行したいなら次のようにする。 | |
116 | + アクション名は第一引数として与える。example/test を実行したいなら次のようにする。 | |
123 | 117 | |
124 | 118 | php /foo/bar/mojo.php example/test |
125 | 119 |
@@ -159,7 +153,6 @@ | ||
159 | 153 | BasicAuthenticationFilter.php アクションにBASIC認証をかけるためのフィルタ。 |
160 | 154 | LogSlowFilter.php 実行に時間がかかるアクションをログするためのフィルタ。 |
161 | 155 | mojo/ フレームワーク拡張 |
162 | - ActionlessView.php Notfoundアクションなどにアクションのないビューを取り扱う能力を付与するためのトレイト。 | |
163 | 156 | SmartyRenderer.php Smartyを使ったレンダラ。 |
164 | 157 | mojo/ フレームワークコア。 |
165 | 158 | resources/ ブラウザから直接参照される必要がないアセットの配置場所。 |
@@ -582,7 +582,7 @@ | ||
582 | 582 | return ($value == $check) ? null : $value; |
583 | 583 | } |
584 | 584 | |
585 | -// 引数が正の数または負の数であるかに関わらずく、ただ小数点とそれ以降にある数字を切り捨てた値を返す。javascript の Math.trunc() に相当。 | |
585 | +// 引数が正の数か負の数かに関わらず、ただ小数点とそれ以降にある数字を切り捨てた値を返す。javascript の Math.trunc() に相当。 | |
586 | 586 | function trunc($x) { |
587 | 587 | return $x < 0 ? ceil($x) : floor($x); |
588 | 588 | } |
@@ -673,7 +673,7 @@ | ||
673 | 673 | function string_cast($v) { |
674 | 674 | |
675 | 675 | if(is_array($v)) { |
676 | - return sprintf('array(%s)', implode(',', array_each($v, function($v, $k){ | |
676 | + return sprintf('array(%s)', implode(', ', array_each($v, function($v, $k){ | |
677 | 677 | return "$k=>" . (is_array($v) ? 'array' : (string)$v); |
678 | 678 | }))); |
679 | 679 | } |
@@ -727,9 +727,9 @@ | ||
727 | 727 | } |
728 | 728 | |
729 | 729 | // コマンドの出力が逐次出力される標準関数 system() を、コマンドの出力全体を戻り値とするように改造したもの。 |
730 | -// コマンド出力をモニタしながら実行するバッチなどで便利なことがある。 | |
730 | +// コマンド出力をそのままモニタ出力して、しかしプログラムでも処理するバッチなどで便利なことがある。 | |
731 | 731 | // コマンドの末尾に "| tee" を付けて動作するので、末尾でシェル操作をしているようなコマンドではうまく動かないかも。 |
732 | -function system_exec($command, &$retval=null) { | |
732 | +function exec_tee($command, &$retval=null) { | |
733 | 733 | |
734 | 734 | // 出力を得るための一時ファイルを作成。 |
735 | 735 | $tmpfile = tempnam(sys_get_temp_dir(), 'php-'); |
@@ -20,7 +20,7 @@ | ||
20 | 20 | 'mojo.mojo' => 'mojo', // Mojoのクラスファイルがあるディレクトリ。 |
21 | 21 | 'mojo.resources' => 'resources', // リソース類を格納するディレクトリ。 |
22 | 22 | 'mojo.libs' => 'lib', // "libs" ディレクトリ。サブディレクトリを含め、このディレクトリより下のファイルはオートロードの対象になる。 |
23 | - 'mojo.sites' => 'sites', // サイト・アクションファイルを格納しているディレクトリ。 | |
23 | + 'mojo.sites' => 'sites', // 各サイトを直接格納している親ディレクトリ。 | |
24 | 24 | 'mojo.var' => 'var', // サーバ処理で生成されるファイルの格納ディレクトリ。 |
25 | 25 | 'smarty.cache' => 'var/smarty.cache', |
26 | 26 | 'smarty.compile' => 'var/smarty.compile', |
@@ -32,12 +32,12 @@ | ||
32 | 32 | |
33 | 33 | // ルーティングに関する設定。 |
34 | 34 | 'routing' => array( |
35 | - 'mojo.default_site' => 'public', // URLでサイトが省略された場合のデフォルト。 | |
36 | - 'mojo.default_site.cli' => 'command', // コマンドラインで実行された場合のデフォルトサイト。 | |
37 | - 'mojo.default_action' => 'index', // URLでアクションが省略された場合のデフォルト。 | |
38 | - 'mojo.default_front' => 'index.php', // 省略可能なフロントコントローラー。URL生成時に参照される。 | |
39 | - 'mojo.notfound_action' => 'notfound', // 該当のアクションが見つからない場合のアクション。 | |
40 | - 'mojo.error_action' => 'sorry.error', // エラーが発生した場合のエラー処理アクション。AppMojo クラスで探索されている。 | |
35 | + 'mojo.default_site' => 'public', // URLでサイトが省略された場合のデフォルト。 | |
36 | + 'mojo.default_site.cli' => 'command', // コマンドラインで実行された場合のデフォルトサイト。 | |
37 | + 'mojo.default_direction' => 'index', // URLでディレクションが省略された場合のデフォルト。 | |
38 | + 'mojo.default_front' => 'index.php', // 省略可能なフロントコントローラー。URL生成時に参照される。 | |
39 | + 'mojo.notfound_direction' => 'sorry.notfound', // 該当のアクションが見つからない場合のディレクション。 | |
40 | + 'mojo.error_direction' => 'sorry.error', // エラーが発生した場合のエラー処理アクション。AppMojo クラスで探索されている。 | |
41 | 41 | |
42 | 42 | // ここの設定で、リクエストされているパスを先頭一致で検査するURLリライトのような挙動を設定できる。 |
43 | 43 | // |
@@ -127,7 +127,7 @@ | ||
127 | 127 | // これらは実行時に設定される。ここには説明のためにキーのみが記述されている。 |
128 | 128 | 'runtime' => array( |
129 | 129 | 'mojo.requested_site' => '', // リクエストされているサイト名。 |
130 | - 'mojo.requested_action' => '', // リクエストされているグループ・モーション名。 | |
130 | + 'mojo.requested_direction' => '', // リクエストされているディレクティブ名(グループ.モーション)。 | |
131 | 131 | 'mojo.requested_name' => '', // 上記二つを "/" で連結したもの。 |
132 | 132 | 'mojo.front_dir' => '', // REQUEST_URI から PATH_INFO を除き、さらに実行ファイル部分を除いたもの。 |
133 | 133 | // たとえば、/some/path/index.php/abc/def であれば /some/path |
@@ -20,9 +20,6 @@ | ||
20 | 20 | // hrefを生成。 |
21 | 21 | $href = AppMojo::getUrl($params['action'], ['id'=>$params['id'], '_backto'=>true]); |
22 | 22 | |
23 | - // リンク文字列に「(id)」を付ける。 | |
24 | - $content .= sprintf('(%s)', htmlspecialchars($params['id'])); | |
25 | - | |
26 | 23 | // <a>で囲んで出力。HtmlUtil::tag() を使ってないのは二重エンコードを避けるため。 |
27 | 24 | return sprintf('<a href="%s">%s</a>', htmlspecialchars($href), $content); |
28 | 25 | } |
@@ -4,18 +4,17 @@ | ||
4 | 4 | * 指定されたアクションの出力を取得してテンプレートに挿入する。 |
5 | 5 | * |
6 | 6 | * パラメータ) |
7 | - * action 指定のサイト・アクション名。サイト名とアクション名を "/" でつなげたものだが、 | |
8 | - * "partial" サイトならばサイト部分は省略できる。 | |
7 | + * action 指定のアクション名。サイト名とディレクション名を "/" でつなげたものだが、"partial" サイトならばサイト部分は省略できる。 | |
9 | 8 | * その他 指定のアクションの attributes として渡される。 |
10 | 9 | */ |
11 | 10 | function smarty_function_partial($params, $template) { |
12 | 11 | |
13 | - // パラメータから "action" キーを取り出して、サイト名とアクション名に分ける。 | |
14 | - @[$site, $action] = explode('/', ArrayUtil::eject($params, 'action')); | |
12 | + // パラメータから "action" キーを取り出して、サイト名とディレクション名に分ける。 | |
13 | + @[$site, $direction] = explode('/', ArrayUtil::eject($params, 'action')); | |
15 | 14 | |
16 | 15 | // "/" がないのはサイト名の省略。 |
17 | - if( is_null($action) ) { | |
18 | - $action = $site; | |
16 | + if( is_null($direction) ) { | |
17 | + $direction = $site; | |
19 | 18 | $site = ''; |
20 | 19 | } |
21 | 20 |
@@ -27,5 +26,6 @@ | ||
27 | 26 | $params['smarty.parent'] = $template; |
28 | 27 | |
29 | 28 | // 指定のアクションを実行。 |
30 | - Mojo::forward("$site/$action", $params); | |
29 | + if( !Mojo::forward("$site/$direction", $params) ) | |
30 | + trigger_error("アクション $site/$direction を実行できません。", E_USER_WARNING); | |
31 | 31 | } |
@@ -4,7 +4,7 @@ | ||
4 | 4 | * パラメータで指定されたアクションへのURLを返す。 |
5 | 5 | * |
6 | 6 | * 以下のパラメータは特別に処理する。 |
7 | - * action サイト・アクション名。"site/action" の形式で指定する。現在のサイトと同一ならサイト名は省略できる。 | |
7 | + * action アクション名。"site/direction" の形式で指定する。現在のサイトと同一ならサイト名は省略できる。 | |
8 | 8 | * params パラメータを配列で指定したい場合はこのキーで指定する。 |
9 | 9 | * encode 出力のエンコード方法。"html" か "json"。省略時は "html" |
10 | 10 | * absolute 絶対URLにしたい場合は true を指定する。 |
@@ -6,7 +6,7 @@ | ||
6 | 6 | function smarty_modifier_uncapsule($value) { |
7 | 7 | |
8 | 8 | if( is_array($value) ) |
9 | - return sprintf('array(%s)', implode(', ', $value)); | |
9 | + return string_cast($value); | |
10 | 10 | else |
11 | 11 | return $value; |
12 | 12 | } |
@@ -20,7 +20,7 @@ | ||
20 | 20 | // APIでないなら... |
21 | 21 | if( !$this->filterByClass('ApiBehaviorFilter') ) { |
22 | 22 | |
23 | - // 次の変数を全アクションで使えるようにする。 | |
23 | + // 次のビュー変数を全アクションで使えるようにする。 | |
24 | 24 | $this->renderer['application'] = AppMojo::setting('application'); |
25 | 25 | |
26 | 26 | // backtoパラメータを解析してヘッダ部分のメニューバック階層を得る。 |
@@ -27,7 +27,7 @@ | ||
27 | 27 | |
28 | 28 | 404 Not Found.<br /> |
29 | 29 | site: {[$site]}<br /> |
30 | - action: {[$action]}<br /> | |
30 | + direction: {[$direction]}<br /> | |
31 | 31 | |
32 | 32 | </body> |
33 | 33 |
@@ -10,7 +10,7 @@ | ||
10 | 10 | |
11 | 11 | // 入力検証 |
12 | 12 | if( $error = MojoForm::execute($_POST['table'], ['type'=>'word']) ) |
13 | - throw new CrackingException('フォームに入力された変数tableの値が不正(%s)', $error); | |
13 | + throw new ErrorException('フォームに入力された変数tableの値が不正(%s)', $error); | |
14 | 14 | |
15 | 15 | // 投入対象が指定されていないならすぐビューへ。 |
16 | 16 | if( !$_POST['table'] ) return; |
@@ -11,7 +11,7 @@ | ||
11 | 11 | // このバッチの実行期限。ワンショットなバッチなどで設定する。少しでも間違い実行を防ぐため。 |
12 | 12 | protected $batchExpiration = null; // 設定するなら '2021-03-09 15:21:23' など。 |
13 | 13 | |
14 | - // 出力先ログ名。nullの場合はアクション名から生成される。 | |
14 | + // 出力先ログ名。nullの場合はアクションクラス名から生成される。 | |
15 | 15 | protected $logname = null; |
16 | 16 | |
17 | 17 | // バッチの出力先となる Log インスタンス。ready() でセットされる。 |
@@ -26,8 +26,8 @@ | ||
26 | 26 | // APIコール時の現在バージョンとしても使う。 |
27 | 27 | Runtime["requested_site"] = {[AppMojo::setting('runtime', 'mojo.requested_site')|json nofilter]}; |
28 | 28 | // リクエストされているサイト名。サービス名じゃないよ。 |
29 | - Runtime["requested_action"] = {[AppMojo::setting('runtime', 'mojo.requested_action')|json nofilter]}; | |
30 | - // リクエストされているグループ・アクション名。 | |
29 | + Runtime["requested_direction"] = {[AppMojo::setting('runtime', 'mojo.requested_direction')|json nofilter]}; | |
30 | + // リクエストされているディレクション名。 | |
31 | 31 | </script> |
32 | 32 | |
33 | 33 | {[block name="site-head"]}{[/block]} |
@@ -12,7 +12,7 @@ | ||
12 | 12 | public function run() { |
13 | 13 | |
14 | 14 | if(AppMojo::setting('runtime', 'mojo.requested_site') == 'partial') |
15 | - throw new CrackingException('partialサイトを直接実行しようとした'); | |
15 | + throw new ErrorException('partialサイトを直接実行しようとした'); | |
16 | 16 | |
17 | 17 | return parent::run(); |
18 | 18 | } |
@@ -14,7 +14,8 @@ | ||
14 | 14 | $attributes = $this->attributes; |
15 | 15 | $attributes['resultset'] = array( ArrayUtil::eject($attributes, 'record') ); |
16 | 16 | |
17 | - AppMojo::forward('partial/resultset', $attributes); | |
17 | + AppMojo::forward('partial/resultset', $attributes) | |
18 | + | |
18 | 19 | return 'none'; |
19 | 20 | } |
20 | 21 | } |
@@ -0,0 +1,14 @@ | ||
1 | +{[extends file='layout.html']} | |
2 | +{[$title="ERROR!"]} | |
3 | + | |
4 | +{[block name="content"]} | |
5 | + | |
6 | + <p> | |
7 | + <pre>{[$action->attributes['message']]}</pre> | |
8 | + {[if $action->attributes['inquiry']]} | |
9 | + <pre>問い合わせコード: {[$action->attributes['inquiry']]}</pre> | |
10 | + {[/if]} | |
11 | + <pre>{[$action->attributes['description']]}</pre> | |
12 | + </p> | |
13 | + | |
14 | +{[/block]} |
@@ -0,0 +1,10 @@ | ||
1 | +{[extends file='layout.html']} | |
2 | +{[$title="NOT FOUND"]} | |
3 | + | |
4 | +{[block name="content"]} | |
5 | + | |
6 | + <p> | |
7 | + アクション {[Mojo::setting('runtime', 'mojo.requested_name')]} が見つかりません。 | |
8 | + </p> | |
9 | + | |
10 | +{[/block]} |
@@ -61,8 +61,8 @@ | ||
61 | 61 | |
62 | 62 | $ret = AppLog::exception(new Exception('this is test'), 'test'); |
63 | 63 | $this->checkRegexp('AppLog::exception() による書き込みが正常に機能している。', file_get_contents($testfile), '/^\d{2}:\d{2}:\d{2} .+?\(\d+\) Exception\(0\): this is test/'); |
64 | - $this->checkRegexp('AppLog::exception() の戻り値 code が正常に返されている。', $ret['code'], '/-\d{10}$/'); | |
65 | - $this->checkRegexp('AppLog::exception() の戻り値 text が正常に返されている。', $ret['text'], '#^/.+?Exception\(0\): this is test#'); | |
64 | + $this->checkRegexp('AppLog::exception() の戻り値 code が正常に返されている。', $ret[0], '/-\d{10}$/'); | |
65 | + $this->checkRegexp('AppLog::exception() の戻り値 text が正常に返されている。', $ret[1], '#^/.+?Exception\(0\): this is test#'); | |
66 | 66 | unlink($testfile); |
67 | 67 | |
68 | 68 | AppLog::lineAccess('test'); |