知りたいこと
以下の具体例において、php で throw
すべきか否か・・ご意見いただけませんでしょうか
具体例
例えば「ライブラリに保存」とかの際に、「端末Aからすでに保存済みだが、端末BのHTML上ではまだ未保存であり、ゆえに保存処理はPOSTされうる」というケースがあるかと思います。
これは「不正なPOST」の一種かもしれませんけれど、「電話番号のフォームに住所が入力されたなどの不正なPOST」とは明らかにその性質が異なりますよね。
ちょっとだけ不正(JavaScript の検証を突破したわけではない不正さ、データベースに入ったらダメな値というほどではない不正さ)とでもいいましょうか。
ではこのようなちょっとだけ不正な値のPOSTに対して throw
すべきか否か、というのを知りたいです。
現状の実装
現状では下記 throwIfExistsLibraryTag()
メソッドで既存なら例外という処理を挟んでみたのですが、わざわざ throw
すべきなのかな、と疑問に思いました。(尚、このメソッドは「ちょっとだけ不正」を意味する専用の class nonThreatIllegalException extends \Exception
を throw
します。)
php
1final class LibraryTagController extends Controller 2{ 3 // ライブラリにタグを追加 4 final public function createLibraryTagAction(): void 5 { 6 $request = json_decode(file_get_contents('php://input'), true); 7 8 $this->validator->setRules([ 9 'tagId' => [ 10 'function' => fn ($v) => $this->validator->isId($v), 11 ], 12 ]); 13 14 $validatedRequest = $this->validator->validate($request)->getValidatedData(); 15 16 $libraryTagRowMapper = new LibraryTagRowMapper(); 17 18 $libraryTagRow = LibraryTagRow::newUsingArray([ 19 'libraryId' => (new LibraryRowMapper)->getUsersLibraryId($this->currentUser->getId()), 20 'tagId' => $validatedRequest['tagId'] 21 ]); 22 23 // 既存確認 24 $libraryTagRowMapper->throwIfExistsLibraryTag($libraryTagRow); 25 26 // `library_tags` テーブルに INSERT 27 $libraryTagRow = $libraryTagRowMapper->insert($libraryTagRow); 28 29 parent::render([ 30 'status' => 'succeeded' 31 ]); 32 } 33}
改善案?
そしてもしわざわざ throw
などしない方がいいとなると、
上記 throwIfExistsLibraryTag()
, insert()
のコンビ (既存なら throw
する) でなく
下記 selectOrInsert()
, wasInserted()
のコンビ (既存なら 'exists'
を返す) で良いですか?
php
1final class LibraryTagController extends Controller 2{ 3 // ライブラリにタグを追加 4 final public function createLibraryTagAction(): void 5 { 6 $request = json_decode(file_get_contents('php://input'), true); 7 8 $this->validator->setRules([ 9 'tagId' => [ 10 'function' => fn ($v) => $this->validator->isId($v), 11 ], 12 ]); 13 14 $validatedRequest = $this->validator->validate($request)->getValidatedData(); 15 16 $libraryTagRowMapper = new LibraryTagRowMapper(); 17 18 $libraryTagRow = LibraryTagRow::newUsingArray([ 19 'libraryId' => (new LibraryRowMapper)->getUsersLibraryId($this->currentUser->getId()), 20 'tagId' => $validatedRequest['tagId'] 21 ]); 22 23 // `library_tags` テーブルに 既存でなければ INSERT 24 $libraryTagRow = $libraryTagRowMapper->selectOrInsert($libraryTagRow, ['libraryId', 'tagId']); 25 26 parent::render([ 27 'status' => $libraryTagRowMapper->wasInserted() ? 'succeeded' : 'exists', 28 ]); 29 } 30}
求めるご意見
throw
すべき。だって▲▲だから。throw
しない。だって■■だから。
のように、ご経験をふまえての理由も教えて頂けると幸いです。
よろしくお願い致します。
補足
HTTPステータスコードに 409 Conflict
なるものがあると知りました。もしかしてこれがぴったりでしょうか?
だとすると当質問へのベストな回答は、以下のように「ConflictException
という例外クラスを作った上でthrow
すべき」という内容になりますでしょうか?
php
1class HttpException extends \Exception 2{ 3 protected int $statusCode; 4 5 public function __construct(string $message, int $statusCode = 500) 6 { 7 parent::__construct($message); 8 $this->statusCode = $statusCode; 9 } 10 11 public function getStatusCode(): int 12 { 13 return $this->statusCode; 14 } 15} 16 17class ConflictException extends HttpException 18{ 19 public function __construct(string $message = 'Conflict detected') 20 { 21 parent::__construct($message, 409); 22 } 23}
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2025/01/01 05:42