直近思案しているのはLaravel5.5案件なのですが。
まぁ割と「あちこちのPHP MVCフレームワークで言える(ような気がする)」ので、あちこちに疑問を投げかける的な想定で。
端的には「データの入力やvalidateの処理、Modelに書きますか? Controllerに書きますか?」的な内容です。
さて。いわゆるMVCの「Model」ですが。
本来的には
・アプリケーションデータ、ビジネスルール、ロジック:システムの本体
をつかさどる、とされています。
言い方を変えると「どのModelを使うかの制御(Controller)、表示や出力(View)」以外全部、をつかさどる、と言い伝えられています。
ただまぁ、どこのRoRが元凶とかActive Record以下検閲削除とかは言いませんが、半歩間違えると、Modelって
・ORマッパーのことでしょ?
的なお話になることも、少なからずあるように思われます。
いや別に「Model === ORM」だ、ってんならそれはそれでよいのですが。
その場合はまぁ「Controllerがfatになるのは避けられないよねぇ」とか思うわけです。
いやもちろん「一旦処理を外に書き出して"Controllerというファイル名のファイルの中身は細くする"」ってことも可能ですが、それって本当に「not Fat Controllerなの?」とか思うわけです。
「書き出したクラス」って、所属はController? Model?
「ControllerでもModelでもないそれ以外」だとしたら、それは本当にMVC? とかとか。
あぁ念のため「おいちゃん的には、トップハム・ハット卿 *1 を否定している」わけではありません。
いやまぁ肯定もとくにせんのですが。
その辺はぶっちゃけると「どっちでもいいんじゃないかなぁ一貫性があれば」。
正直、ある程度の規模のシステムを組めば
・太った子が出てくるか
・やたら大量の子だくさんになるか
のどちらかはどちらにしても不可避なので。ゆえに「ある程度納得できる理由と芯の通った哲学」があればよいのではないかなぁ、と思うのですます。
んで。「どっちでもよい」ので、一旦、仮定として「例えば、トップハム・ハット卿を避ける方向」で考えた場合。
Modelですが。「ビジネスロジック全部まるっと」はちぃと難しそうな気がせんでもないのですが、「あるデータの塊に対する責務全般」くらいは、お願いしてもよいのではないかなぁ? とか、おいちゃん個人としては思うのでございます。
ほら「Tell, Don't Ask」とか言うじゃないですかまぁ一般的なModelのコードもそんな感じだとは思うのですが。とはいえ、もうちょっと「いろいろ、Modelに持ち込んでもよいのかなぁ」とか、なんとか。
で、ちょいとちょうど良い感じがあったので、さっそくの実例。
ちと書いてもらったコードがあったので、微妙に細部を変えながら、転記。
public function postTweet(Request $request) { $userId = auth()->id(); if (null === $userId) { return redirect('/'); } // ここはもうちょっと「$request->validate」つかうのが本当なんだろうと思う $tweetPost = $request->input('tweet'); if (144 < strlen($tweetPost)) { return redirect('/'); } $tweetModel = new Tweet(); $tweetModel->user_id = $userId; $tweetModel->tweet = $tweetPost; $tweetModel->save(); Session::flash('message', 'tweet した'); return redirect('/'); }
うんたぶん、LaravelでなくほかのPHP MVC系フレームワークであっても、大体こんな感じだろうなぁと思うですサンプルコード見ている限り。
別の場所をグぐってみても。
http://libro.tuyano.com/index3?id=7896003&page=3
public function postNew(Request $request) { $name = $request->input('name'); $mail = $request->input('mail'); $age = $request->input('age'); $data = array( 'name' => $name, 'mail' => $mail, 'age' => $age ); MyTable::create($data); return redirect()->action('HeloController@getIndex'); }
https://qiita.com/yagi21/items/eea131ef0d3bc20be59a
public function res(Request $request){ //フォームから受け取る $フォームのname = $request->input('フォームのname'); . . . //DB保存 }
などなど。
公式も
https://readouble.com/laravel/5.5/ja/eloquent.html
class FlightController extends Controller { /** * 新しいflightインスタンスの生成 * * @param Request $request * @return Response */ public function store(Request $request) { // リクエストのバリデート処理… $flight = new Flight; $flight->name = $request->name; $flight->save(); } }
なので、Laravel公式的にも「処理はControllerに書く」のほうに倒れてるんだろうなぁ、とは思うです。
さて上述に共通するのは「Controllerにデータ取得とvalidateの処理が書いてある」あたり。
んで、おいちゃんが気になっているのが
・入力データの取得
・validate
の処理を「Controllerでやっている」あたり。
その辺「どうなんだろう??」と思うですだす。
で、一案っつか二案なんだが。
上述の処理を「model側に移す」のって、みんなの印象値的にどうなんだろう? という、質問ですます。
1つは「全部まとめて1メソッド」、もう1つは「入力、validate、保存の3メソッド」の提案。
まぁModel内部的にはどちらにしても切り分けるんだろうけど。
1つまとめの場合は身もふたもなくて
public function postTweet(Request $request) { $tweetModel = new Tweet(); $r = $tweetModel->insert用に入力してvalidateして保存(); if (true === $r) { Session::flash('message', 'tweet した'); } return redirect('/'); }
3つの場合は
public function postTweet(Request $request) { $tweetModel = new Tweet(); $r = $tweetModel->insert用の入力(); if (false === $r) { return redirect('/'); } $r = $tweetModel->insert用のvalidate(); if (false === $r) { return redirect('/'); } $r = $tweetModel->insert保存(); if (true === $r) { Session::flash('message', 'tweet した'); } return redirect('/'); }
なんかifがうざったいから、例外投げるほうが楽かもしんまい。
public function postTweet(Request $request) { try { $tweetModel = new Tweet(); $tweetModel->insert用の入力(); $tweetModel->insert用のvalidate(); $tweetModel->insert保存(); } catch(Throwable $e) { return redirect('/'); } Session::flash('message', 'tweet した'); return redirect('/'); }
こんな感じ。
細かい話をすると「insertとupdate」って、似てるけど処理が違うので。データ取り込みもvalidateも保存する時も、微妙に入り口を分けていたい感じではある。
ので、全体的に「insert用の」ってつけてるの感じ。
Modelのほうはまぁだいたいイメージがつくと思うので適宜オミット。
ちな、これの実装を愚直にやると「formのnameアトリビュート値が固定」になるんだけど。「いやまぁ固定でもいいじゃない」ってのと「可変にしたきゃ、デフォルト引数とかうまく使ってよ」とか、まぁ解決策はいくつか。
面倒なんで書かないけど、質問がきたら書くかも。
あと、細かいところでエラー処理。
まぁ例外投げる時は「例外のメッセージの中に、それこそjson文字列とかででも細かい情報突き返せばよくね?」とかアバウトにアバウトに。いやまぁModelインスタンスん中にエラー情報入れてgetってもいいだろうし。
戻り値でreturnであれば、別途「error_detail」とかってメソッド使って詳細吐き出せばよいと思うですます。
ってなわけで、これやると「Controllerでやることが減る」変わりに「Modelでやることが増える」んだよねぇ当たり前だよ動かしただけだもん。
ただ、Modelって「実のところ、なんなの?」って考えた時に。
もしModelが「ある程度のビジネス処理をつかさどるところ」なのであれば、一つの提案としては上述のようなコード「も」想定できるかなぁ、とか思うわけですます。
一方で「LaravelのController(の1メソッド)って、必ずしも"外部から呼ばれる"前提とは限らない」と思われるので(web.phpとかにルーティング書かなければ呼ばれないし)。
例えば「このControllerのこのメソッドは"このデータの塊を、入力受け取ってvalidateして保存する"用のメソッドなんだ!!」ってなるのであれば、それはそれで「そーゆー方向性と指針なんだなぁ」とも思うのです。「それって、ビジネスロジックって言わね?」とかって疑問もありますが、別にそれはそれで一貫性があれば。「Controllerにビジネスロジックを書いたら死ぬ」ってわけでもないだろうし。
いやまぁ結果的に「Controllerに書く内容が増えて、太りやすくなるよなぁ」とは思うのですが「それはそれでいいじゃん」であれば、それはそれでよいんじゃないかなぁ、とも思いますです。はい。
ってなわけで。
上述みたいなコードで「データに紐づく責務」をModel側に移すのって、世間的にはどーゆー反応なのかしらん? ってのが、おいちゃんの疑問。いや上述のような感じのコードって、見る見ないでいうと「ほとんど見かけない」ので。
「個人的見解と感想と好みと雑感と偏見」ざぶざぶでよいので、コメントなどいただけると、おいちゃんが喜んだりすると思われますので、ぜひ ノ