Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
66.67% |
90 / 135 |
|
58.33% |
28 / 48 |
CRAP | |
0.00% |
0 / 1 |
LogicBase | |
66.67% |
90 / 135 |
|
58.33% |
28 / 48 |
257.70 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getRequest | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
getFile | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getRequestContent | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getRequestJson | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setHttpStatus | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getHttpStatus | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCookie | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setCookie | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
12 | |||
removeCookie | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
peekTemporary | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
popTemporary | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
pushTemporary | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
removeTemporary | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
existsSession | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSession | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
requireSession | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setSession | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
removeSession | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
cancelSession | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
restartSession | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
shutdownSession | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addResponseHeader | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
registerParameterKeys | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
4.03 | |||
setValue | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
3.14 | |||
hasError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
clearErrors | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
removeError | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
addCommonError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addError | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
3.14 | |||
validation | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
validateImpl | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
executeImpl | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
startup | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
cleanup | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
validate | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
run | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
3 | |||
getResponseHeaders | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getViewData | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
setTextContent | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setJsonContent | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setContent | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setFileContent | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
setDownloadContent | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getContent | |
60.00% |
3 / 5 |
|
0.00% |
0 / 1 |
3.58 | |||
tryGetResult | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
equalsResult | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
receiveErrorMessage | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
receiveErrorKind | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace PeServer\Core\Mvc; |
6 | |
7 | use DateInterval; |
8 | use DateTimeImmutable; |
9 | use PeServer\Core\Binary; |
10 | use PeServer\Core\Collection\Arr; |
11 | use PeServer\Core\Environment; |
12 | use PeServer\Core\Http\HttpRequest; |
13 | use PeServer\Core\Http\HttpStatus; |
14 | use PeServer\Core\I18n; |
15 | use PeServer\Core\IO\File; |
16 | use PeServer\Core\IO\IOUtility; |
17 | use PeServer\Core\Log\ILogger; |
18 | use PeServer\Core\Mime; |
19 | use PeServer\Core\Mvc\DataContent; |
20 | use PeServer\Core\Mvc\IValidationReceiver; |
21 | use PeServer\Core\Mvc\LogicCallMode; |
22 | use PeServer\Core\Mvc\LogicParameter; |
23 | use PeServer\Core\Mvc\Template\TemplateParameter; |
24 | use PeServer\Core\Mvc\UploadedFile; |
25 | use PeServer\Core\Mvc\Validator; |
26 | use PeServer\Core\Store\CookieOptions; |
27 | use PeServer\Core\Store\CookieStore; |
28 | use PeServer\Core\Store\SessionStore; |
29 | use PeServer\Core\Store\SpecialStore; |
30 | use PeServer\Core\Store\Stores; |
31 | use PeServer\Core\Store\Template\TemporaryStore; |
32 | use PeServer\Core\Text; |
33 | use PeServer\Core\Throws\ArgumentException; |
34 | use PeServer\Core\Throws\InvalidOperationException; |
35 | use PeServer\Core\Throws\KeyNotFoundException; |
36 | use PeServer\Core\Utc; |
37 | |
38 | /** |
39 | * コントローラから呼び出されるロジック基底処理。 |
40 | */ |
41 | abstract class LogicBase implements IValidationReceiver |
42 | { |
43 | #region define |
44 | |
45 | protected const SESSION_ALL_CLEAR = Text::EMPTY; |
46 | |
47 | #endregion |
48 | |
49 | #region variable |
50 | |
51 | /** |
52 | * ロジック開始日時。 |
53 | */ |
54 | protected readonly DateTimeImmutable $beginTimestamp; |
55 | |
56 | /** |
57 | * ロガー。 |
58 | */ |
59 | protected readonly ILogger $logger; |
60 | |
61 | /** |
62 | * リクエストデータ。 |
63 | */ |
64 | private readonly HttpRequest $request; |
65 | |
66 | /** |
67 | * HTTPステータスコード。 |
68 | */ |
69 | private HttpStatus $httpResponseStatus; |
70 | /** |
71 | * 検証エラー。 |
72 | * |
73 | * @var array<string,string[]> |
74 | */ |
75 | private array $errors = []; |
76 | /** |
77 | * 応答データ。 |
78 | * |
79 | * @var array<non-empty-string,mixed> |
80 | */ |
81 | private array $values = []; |
82 | |
83 | /** |
84 | * 要素設定がなされている場合に応答データのキーをこの項目に固定。 |
85 | * |
86 | * @var non-empty-string[] |
87 | */ |
88 | private array $keys = []; |
89 | |
90 | /** |
91 | * コントローラ内結果データ。 |
92 | * |
93 | * @var array<string,mixed> |
94 | */ |
95 | protected array $result = []; |
96 | |
97 | /** |
98 | * 検証処理。 |
99 | */ |
100 | protected Validator $validator; |
101 | |
102 | /** |
103 | * 応答データ。 |
104 | */ |
105 | private ?DataContent $content = null; |
106 | |
107 | /** |
108 | */ |
109 | protected readonly Stores $stores; |
110 | |
111 | protected readonly Environment $environment; |
112 | |
113 | /** |
114 | * 応答ヘッダ。 |
115 | * |
116 | * @var array<non-empty-string,string[]> |
117 | */ |
118 | private array $responseHeaders = []; |
119 | |
120 | #endregion |
121 | |
122 | /** |
123 | * 生成。 |
124 | * |
125 | * @param LogicParameter $parameter ロジック用パラメータ。 |
126 | */ |
127 | protected function __construct(LogicParameter $parameter) |
128 | { |
129 | $this->beginTimestamp = Utc::create(); |
130 | $this->httpResponseStatus = HttpStatus::OK; |
131 | $this->request = $parameter->request; |
132 | $this->stores = $parameter->stores; |
133 | $this->environment = $parameter->environment; |
134 | $this->logger = $parameter->logger; |
135 | |
136 | $this->validator = new Validator($this); |
137 | } |
138 | |
139 | #region function |
140 | |
141 | /** |
142 | * 要求データの取得。 |
143 | * |
144 | * @param string $key 要求キー。 |
145 | * @param string $fallbackValue 要求キーに存在しない場合の戻り値。 |
146 | * @param bool $trim 取得データをトリムするか。 |
147 | * @return string 要求データ。 |
148 | */ |
149 | protected function getRequest(string $key, string $fallbackValue = Text::EMPTY, bool $trim = true): string |
150 | { |
151 | if (!$this->request->exists($key)->exists) { |
152 | return $fallbackValue; |
153 | } |
154 | |
155 | $value = $this->request->getValue($key); |
156 | |
157 | if ($trim) { |
158 | return Text::trim($value); |
159 | } |
160 | |
161 | return $value; |
162 | } |
163 | |
164 | protected function getFile(string $key): UploadedFile |
165 | { |
166 | if (!$this->request->exists($key, true)->exists) { |
167 | throw new KeyNotFoundException('$key: ' . $key); |
168 | } |
169 | |
170 | $file = $this->request->getFile($key); |
171 | return $file; |
172 | } |
173 | |
174 | /** |
175 | * 要求本文の生データを取得。 |
176 | * |
177 | * @return Binary |
178 | */ |
179 | protected function getRequestContent(): Binary |
180 | { |
181 | return $this->request->specialStore->getRequestContent(); |
182 | } |
183 | |
184 | /** |
185 | * 要求本文から JSON を取得。 |
186 | * |
187 | * @return array<mixed> |
188 | */ |
189 | protected function getRequestJson(): array |
190 | { |
191 | return $this->request->specialStore->getRequestJson(); |
192 | } |
193 | |
194 | /** |
195 | * HTTP応答ステータスコードの設定。 |
196 | * |
197 | * @param HttpStatus $httpStatus HTTPステータスコード。 |
198 | * @return void |
199 | */ |
200 | protected function setHttpStatus(HttpStatus $httpStatus): void |
201 | { |
202 | $this->httpResponseStatus = $httpStatus; |
203 | } |
204 | |
205 | /** |
206 | * HTTP応答ステータスコードの取得。 |
207 | * |
208 | * @return HttpStatus |
209 | */ |
210 | public function getHttpStatus(): HttpStatus |
211 | { |
212 | return $this->httpResponseStatus; |
213 | } |
214 | |
215 | /** |
216 | * Cookie を取得。 |
217 | * |
218 | * @param string $key キー。 |
219 | * @param string $fallbackValue 取得失敗時の値。 |
220 | * @return string |
221 | */ |
222 | protected function getCookie(string $key, string $fallbackValue = Text::EMPTY): string |
223 | { |
224 | return $this->stores->cookie->getOr($key, $fallbackValue); |
225 | } |
226 | |
227 | /** |
228 | * Cookie を設定。 |
229 | * |
230 | * @param string $key キー。 |
231 | * @param string $value 設定値。 |
232 | * @param CookieOptions|array{path:?string,span:?DateInterval,secure:?bool,httpOnly:?bool,sameSite:?string}|null $options オプション。 |
233 | * @return void |
234 | */ |
235 | protected function setCookie(string $key, string $value, CookieOptions|array|null $options = null): void |
236 | { |
237 | /** @var CookieOptions|null */ |
238 | $cookieOptions = null; |
239 | |
240 | if ($options !== null) { |
241 | if ($options instanceof CookieOptions) { |
242 | $cookieOptions = $options; |
243 | } else { |
244 | /** @var string */ |
245 | $path = $options['path'] ?? $this->stores->cookie->options->path; |
246 | /** @var \DateInterval|null */ |
247 | $span = $options['span'] ?? $this->stores->cookie->options->span; |
248 | /** @var bool */ |
249 | $secure = $options['secure'] ?? $this->stores->cookie->options->secure; |
250 | /** @var bool */ |
251 | $httpOnly = $options['httpOnly'] ?? $this->stores->cookie->options->httpOnly; |
252 | /** |
253 | * @var string |
254 | * @phpstan-var CookieSameSiteAlias |
255 | */ |
256 | $sameSite = $options['sameSite'] ?? $this->stores->cookie->options->sameSite; |
257 | |
258 | $cookieOptions = new CookieOptions( |
259 | $path, |
260 | $span, |
261 | $secure, |
262 | $httpOnly, |
263 | $sameSite |
264 | ); |
265 | } |
266 | } |
267 | |
268 | $this->stores->cookie->set($key, $value, $cookieOptions); |
269 | } |
270 | |
271 | /** |
272 | * Cookie を削除。 |
273 | * |
274 | * @param string $key キー。 |
275 | * @return void |
276 | */ |
277 | protected function removeCookie(string $key): void |
278 | { |
279 | $this->stores->cookie->remove($key); |
280 | } |
281 | |
282 | protected function peekTemporary(string $key, mixed $fallbackValue = null): mixed |
283 | { |
284 | $value = $this->stores->temporary->peek($key); |
285 | if ($value === null) { |
286 | return $fallbackValue; |
287 | } |
288 | |
289 | return $value; |
290 | } |
291 | |
292 | protected function popTemporary(string $key, mixed $fallbackValue = null): mixed |
293 | { |
294 | $value = $this->stores->temporary->pop($key); |
295 | if ($value === null) { |
296 | return $fallbackValue; |
297 | } |
298 | |
299 | return $value; |
300 | } |
301 | |
302 | protected function pushTemporary(string $key, mixed $value): void |
303 | { |
304 | $this->stores->temporary->push($key, $value); |
305 | } |
306 | protected function removeTemporary(string $key): void |
307 | { |
308 | $this->stores->temporary->remove($key); |
309 | } |
310 | |
311 | protected function existsSession(string $key): bool |
312 | { |
313 | return $this->stores->session->tryGet($key, $unused); |
314 | } |
315 | |
316 | protected function getSession(string $key, mixed $fallbackValue = null): mixed |
317 | { |
318 | return $this->stores->session->getOr($key, $fallbackValue); |
319 | } |
320 | |
321 | protected function requireSession(string $key): mixed |
322 | { |
323 | if ($this->stores->session->tryGet($key, $result)) { |
324 | return $result; |
325 | } |
326 | |
327 | throw new KeyNotFoundException($key); |
328 | } |
329 | |
330 | |
331 | protected function setSession(string $key, mixed $value): void |
332 | { |
333 | $this->stores->session->set($key, $value); |
334 | } |
335 | protected function removeSession(string $key): void |
336 | { |
337 | $this->stores->session->remove($key); |
338 | } |
339 | protected function cancelSession(): void |
340 | { |
341 | $this->stores->session->setApplyState(SessionStore::APPLY_CANCEL); |
342 | } |
343 | protected function restartSession(): void |
344 | { |
345 | $this->stores->session->setApplyState(SessionStore::APPLY_RESTART); |
346 | } |
347 | protected function shutdownSession(): void |
348 | { |
349 | $this->stores->session->setApplyState(SessionStore::APPLY_SHUTDOWN); |
350 | } |
351 | |
352 | /** |
353 | * 応答HTTPヘッダ追加。 |
354 | * |
355 | * @param non-empty-string $name |
356 | * @param string $value |
357 | * @return void |
358 | */ |
359 | public function addResponseHeader(string $name, string $value): void |
360 | { |
361 | if (isset($this->responseHeaders[$name])) { |
362 | $this->responseHeaders[$name][] = $value; |
363 | } else { |
364 | $this->responseHeaders[$name] = [$value]; |
365 | } |
366 | } |
367 | |
368 | /** |
369 | * パラメータキーの設定。 |
370 | * |
371 | * @param non-empty-string[] $keys |
372 | * @param bool $overwrite キー項目を要求データで上書きするか |
373 | * @param bool $initialize キー情報を初期化するか |
374 | * @return void |
375 | */ |
376 | protected function registerParameterKeys(array $keys, bool $overwrite, bool $initialize = true): void |
377 | { |
378 | if ($initialize) { |
379 | $this->keys = $keys; |
380 | } else { |
381 | $this->keys += $keys; |
382 | } |
383 | |
384 | foreach ($this->keys as $key) { |
385 | if ($overwrite) { |
386 | $value = $this->getRequest($key, Text::EMPTY); |
387 | $this->values[$key] = $value; |
388 | } else { |
389 | $this->values[$key] = Text::EMPTY; |
390 | } |
391 | } |
392 | } |
393 | |
394 | /** |
395 | * 応答データとして設定。 |
396 | * |
397 | * @param non-empty-string $key |
398 | * @param mixed $value |
399 | * @return void |
400 | * @throws ArgumentException 入力データとして未登録の場合に投げられる。 |
401 | */ |
402 | protected function setValue(string $key, $value): void |
403 | { |
404 | if (Arr::getCount($this->keys)) { |
405 | if (array_search($key, $this->keys) === false) { |
406 | throw new ArgumentException("未登録 key -> $key"); |
407 | } |
408 | } |
409 | |
410 | $this->values[$key] = $value; |
411 | } |
412 | |
413 | /** |
414 | * 検証エラーが存在するか。 |
415 | * |
416 | * @return boolean |
417 | */ |
418 | protected function hasError(): bool |
419 | { |
420 | return 0 < count($this->errors); |
421 | } |
422 | |
423 | protected function clearErrors(): void |
424 | { |
425 | $this->errors = []; |
426 | } |
427 | |
428 | protected function removeError(string $key): void |
429 | { |
430 | if (isset($this->errors[$key])) { |
431 | unset($this->errors[$key]); |
432 | } |
433 | } |
434 | |
435 | protected function addCommonError(string $message): void |
436 | { |
437 | $this->addError(Validator::COMMON, $message); |
438 | } |
439 | |
440 | protected function addError(string $key, string $message): void |
441 | { |
442 | if (isset($this->errors[$key])) { |
443 | if (array_search($message, $this->errors[$key]) === false) { |
444 | $this->errors[$key][] = $message; |
445 | } |
446 | } else { |
447 | $this->errors[$key] = [$message]; |
448 | } |
449 | } |
450 | |
451 | /** |
452 | * キーに対する一括検証処理。 |
453 | * |
454 | * @param string $key |
455 | * @param callable(string,string):void $callback |
456 | * @param array{default?:string,trim?:bool}|null $options オプション |
457 | * * default: 取得失敗時の値。 |
458 | * * trim: 値をトリムするか。 |
459 | * @return void |
460 | */ |
461 | protected function validation(string $key, callable $callback, ?array $options = null): void |
462 | { |
463 | /** @var string */ |
464 | $default = $options['default'] ?? Text::EMPTY; |
465 | /** @var bool */ |
466 | $trim = $options['trim'] ?? true; |
467 | |
468 | $value = $this->getRequest($key, $default, $trim); |
469 | $callback($key, $value); |
470 | } |
471 | |
472 | /** |
473 | * 検証ロジック実装。 |
474 | * |
475 | * @param LogicCallMode $callMode 呼び出し。 |
476 | * @return void |
477 | */ |
478 | abstract protected function validateImpl(LogicCallMode $callMode): void; |
479 | |
480 | /** |
481 | * 実行ロジック実装。 |
482 | * |
483 | * @param LogicCallMode $callMode 呼び出し。 |
484 | * @return void |
485 | */ |
486 | abstract protected function executeImpl(LogicCallMode $callMode): void; |
487 | |
488 | protected function startup(LogicCallMode $callMode): void |
489 | { |
490 | //NOP |
491 | } |
492 | |
493 | protected function cleanup(LogicCallMode $callMode): void |
494 | { |
495 | //NOP |
496 | } |
497 | |
498 | /** |
499 | * 検証ロジック実装。 |
500 | * |
501 | * @param LogicCallMode $callMode 呼び出し。 |
502 | * @return void |
503 | */ |
504 | private function validate(LogicCallMode $callMode): void |
505 | { |
506 | $this->validateImpl($callMode); |
507 | } |
508 | |
509 | /** |
510 | * 実行ロジック。 |
511 | * |
512 | * @param LogicCallMode $callMode 呼び出し。 |
513 | * @return void |
514 | */ |
515 | private function execute(LogicCallMode $callMode): void |
516 | { |
517 | $this->executeImpl($callMode); |
518 | } |
519 | |
520 | /** |
521 | * ロジック処理。 |
522 | * |
523 | * @param LogicCallMode $callMode 呼び出し。 |
524 | * @return boolean |
525 | */ |
526 | public function run(LogicCallMode $callMode): bool |
527 | { |
528 | try { |
529 | $this->startup($callMode); |
530 | |
531 | $this->validate($callMode); |
532 | if ($this->hasError()) { |
533 | return false; |
534 | } |
535 | |
536 | $this->execute($callMode); |
537 | |
538 | if ($this->hasError()) { |
539 | return false; |
540 | } |
541 | |
542 | return true; |
543 | } finally { |
544 | $this->cleanup($callMode); |
545 | } |
546 | } |
547 | |
548 | /** |
549 | * 応答ヘッダの取得。 |
550 | * |
551 | * @return array<non-empty-string,string[]> |
552 | */ |
553 | public function getResponseHeaders(): array |
554 | { |
555 | return $this->responseHeaders; |
556 | } |
557 | |
558 | /** |
559 | * View表示用データの取得。 |
560 | * |
561 | * @return TemplateParameter |
562 | */ |
563 | public function getViewData(): TemplateParameter |
564 | { |
565 | return new TemplateParameter( |
566 | $this->httpResponseStatus, |
567 | $this->values, |
568 | $this->errors |
569 | ); |
570 | } |
571 | |
572 | final protected function setTextContent(string $data): void |
573 | { |
574 | $this->setContent(Mime::TEXT, $data); |
575 | } |
576 | |
577 | /** |
578 | * JSON応答データ設定。 |
579 | * |
580 | * @param array<mixed> $data |
581 | * @return void |
582 | */ |
583 | final protected function setJsonContent(array $data): void |
584 | { |
585 | $this->setContent(Mime::JSON, $data); |
586 | } |
587 | |
588 | /** |
589 | * 応答データ設定。 |
590 | * |
591 | * @param non-empty-string $mime |
592 | * @phpstan-param non-empty-string|\PeServer\Core\Mime::* $mime |
593 | * @param string|array<mixed>|Binary $data |
594 | * @return void |
595 | */ |
596 | protected function setContent(string $mime, $data): void |
597 | { |
598 | $this->content = new DataContent(HttpStatus::None, $mime, $data); |
599 | } |
600 | |
601 | /** |
602 | * ファイルを応答として設定。 |
603 | * |
604 | * @param string|null $mime |
605 | * @phpstan-param Mime::*|null $mime |
606 | * @param string $path |
607 | */ |
608 | protected function setFileContent(?string $mime, string $path): void |
609 | { |
610 | if (Text::isNullOrWhiteSpace($mime)) { |
611 | $mime = Mime::fromFileName($path); |
612 | } |
613 | |
614 | $content = File::readContent($path); |
615 | |
616 | $this->content = new DataContent(HttpStatus::None, $mime, $content->raw); |
617 | } |
618 | |
619 | /** |
620 | * ダウンロードデータ応答。 |
621 | * |
622 | * @param non-empty-string $mime |
623 | * @phpstan-param non-empty-string|\PeServer\Core\Mime::* $mime |
624 | * @param string $fileName |
625 | * @param Binary $data |
626 | * @return void |
627 | */ |
628 | final protected function setDownloadContent(string $mime, string $fileName, Binary $data): void |
629 | { |
630 | $this->content = new DownloadDataContent($mime, $fileName, $data); |
631 | } |
632 | |
633 | /** |
634 | * 応答データ取得。 |
635 | * |
636 | * @return DataContent |
637 | * @throws InvalidOperationException 応答データ未設定 |
638 | */ |
639 | public function getContent(): DataContent |
640 | { |
641 | if ($this->content === null) { |
642 | throw new InvalidOperationException(); |
643 | } |
644 | |
645 | if ($this->content instanceof DownloadDataContent) { |
646 | return $this->content; |
647 | } |
648 | |
649 | return new DataContent($this->httpResponseStatus, $this->content->mime, $this->content->data); |
650 | } |
651 | |
652 | /** |
653 | * ロジック結果に指定キー項目が存在するか。 |
654 | * |
655 | * @template TValue |
656 | * @param string $key |
657 | * @param mixed $result |
658 | * @phpstan-param TValue $result |
659 | * @return boolean |
660 | */ |
661 | public function tryGetResult(string $key, &$result): bool |
662 | { |
663 | return Arr::tryGet($this->result, $key, $result); |
664 | } |
665 | |
666 | /** |
667 | * ロジック結果の指定キー項目が指定値に一致するか。 |
668 | * |
669 | * @template TValue |
670 | * @param string $key |
671 | * @param mixed $value |
672 | * @phpstan-param TValue $value |
673 | * @return boolean |
674 | */ |
675 | public function equalsResult(string $key, $value): bool |
676 | { |
677 | if ($this->tryGetResult($key, $result)) { |
678 | return $result === $value; |
679 | } |
680 | |
681 | return false; |
682 | } |
683 | |
684 | #endregion |
685 | |
686 | #region IValidationReceiver |
687 | |
688 | public function receiveErrorMessage(string $key, string $message): void |
689 | { |
690 | $this->addError($key, $message); |
691 | } |
692 | |
693 | public function receiveErrorKind(string $key, int $kind, array $parameters): void |
694 | { |
695 | $map = [ |
696 | Validator::KIND_EMPTY => I18n::ERROR_EMPTY, |
697 | Validator::KIND_WHITE_SPACE => I18n::ERROR_WHITE_SPACE, |
698 | Validator::KIND_LENGTH => I18n::ERROR_LENGTH, |
699 | Validator::KIND_RANGE => I18n::ERROR_RANGE, |
700 | Validator::KIND_MATCH => I18n::ERROR_MATCH, |
701 | Validator::KIND_EMAIL => I18n::ERROR_EMAIL, |
702 | Validator::KIND_WEBSITE => I18n::ERROR_WEBSITE, |
703 | ]; |
704 | |
705 | $this->receiveErrorMessage($key, I18n::message($map[$kind], $parameters)); |
706 | } |
707 | |
708 | #endregion |
709 | } |