直近思案しているのは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側に移すのって、世間的にはどーゆー反応なのかしらん? ってのが、おいちゃんの疑問。いや上述のような感じのコードって、見る見ないでいうと「ほとんど見かけない」ので。
「個人的見解と感想と好みと雑感と偏見」ざぶざぶでよいので、コメントなどいただけると、おいちゃんが喜んだりすると思われますので、ぜひ ノ