質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

PHP 処理の分け方

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 2,022

Z-TALBO

score 493

はじめに

今回は、プログラムのコード等に関する質問ではありません。
当然、今回の質問に対して状況や考え方など正解という正解もなく、また不正解ということもないのは理解しております。
例題に関しても、それならそもそももっと細かくわけるなどあると思いますが、アドバイスやいろんな情報を共有できればと思います。

指摘というよりは、こういう考え方などのご意見を求めています。

処理の分け方等に関して

処理を分ける、、、最近、classなんかもなんとなくこうやれば動くというのはできるようにはなってきましたが、はっきり言って、それぞれの役割や、この処理はこっちなどがまだまだ理解不足であると認めざるを得ません。

MVCをフルスクラッチで書いておりますが、、、初心者にありがちかどうかはわかりませんが、、、
indexがあり値を送信してからの処理などをcontrollerで処理しまくって、DBに関わることだけをmodelに流すということをしていました。

それはそれで動くのは当然な部分もありますし、変な話処理はこっち、DBに関するものはこっちという分け方は、初心者からするとわかりやすい感じもしました。

しかし、もう少しネットの解説なりなんなりを見ていくと、やはりこの認識ではちょっと違う部分の方が多い、、、ということはわかってきつつも、、、
では、実際にこういう処理をする際の流れの中で、この処理はこっち、この処理はこっち、、、
そもそもそれはフロントサイドですればいいということが、分けきれず、逆にいろんなところにメソッドを振ってしまい、あれ、、、これはあっちか、、、あっこっちかという状況になってしまいました。

そこで、例として、ある処理の流れを元に書くならこっちというアドバイスをいただければと思い、質問いたしました。

例:値をDBにInsertする処理

<form action="" method="POST">
    <input type="text" name="name[first]">
    <input type="text" name="name[family]">
    <input type="submit" name="submit" value="送信">
</form>


上記のとおり、簡単に姓と名を入力後送信を押すといろいろチェックしたりして、登録するという流れを考えていこうと思います。

今回のファイル構成をざっとですが、、、
[index.php] // 実際に画面に表示されている
[controller.php]
[model.php]
[db.class.php]
他にfunctionやらもあるでしょうが、そのあたりは省略いたします。
db.class.phpには汎用的に使えるclassがあるとします。

さて、私がまず処理を箇条書きで出すとしたら
1.POST送信があったか?
2.name['first'], name['family']に値がセットされているか?
3.2でセットされていなければエラーを出して次の処理にはいかない
4.2でセットされていれば、その文字の正規表現チェック(数字など混ざってないか?)
5.2の値を元にDBにデータがあるかチェック
6.DBにデータがあったら登録せずに、エラーを出す
7.DBにデータがなければ送信された日付を配列に追加する
8.DBにfirst, family, dateを登録する

このように抜き出しました。
実際はもっと細かく、、、があるかもしれませんが、大まかに書き出しました。

次に、私が今の理解度で上記の処理を振り分けるなら、、、
1 = indexでif($_SERVERとかif(filter_inputとかで判定する
2 = controllerに値を飛ばして、さらにmodelに値を渡し、modelでセットされているかチェックする。
3 = modelからの返りがエラーであれば、controllerで$errorを出してindexで表示
4 = modelでそのまま正規表現のチェックを行い、エラーなら3同様
5 = modelからdbにアクセスしチェックを行う(SELECT)
6 = trueだったら既に登録済みなので、3同様
7 = modelで日付をセットさせる
8 = modelからDBにInsertさせる

とりあえず、こう考えてみました。

ということは、indexでcontrollerのインスタンスでInsert()みたいなメソッドで処理が始まり、controllerではmodelのインスタンスを作りmodelでいろいろ処理をしている感じ?になるのかな?という感じです。

まぁ、この例程度の処理であれば、こういう処理をわけるほうがあっちこっちになるかもしれませんが、アドバイス等よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

色々な意見があり、MVCパターンやら MVVCとか派閥に近いような思想が色々出てます。
なので個人的な意見だと思ってください。

ビジネスロジックという単語もよく出ますが、ビジネスロジックという単語の定義もおそらく思想によって多種多様なので、個人的には使わないようにしています。

ロジックはControllerに書くかモデルに書くか

ControllerとModelの間にPresenter層を設けます。

ひとつのURLが1つのテーブルのみのCRUDを担当するなんてほぼ皆無で必ず複数のテーブルを処理します。
しかしORMなどはテーブル単位に処理されることが多く、そのURLの処理に特化してトランザクションを管理するレイヤーが必要です。

URL特化のロジックであれば直接ControllerとActionメソッドに書いちゃえば良いじゃんと思われますが、Presenterに書くのはHTTPから切り離した処理を書くようにしています。

つまり、Controllerの処理としてはHTTPとデータロジックの受け渡しです。

 HTTPの処理とは

・CookieのデータGET,SET
・SessionのデータGET,SET
・ヘッダーのパラメータのGET,SET
・QueryStringのGET,URL生成
・レスポンスの生成(リダイレクトも含む

などなどです。

つまりControllerを見ただけでHTTPの流れのアウトラインが分かるようにします。
・パラメータ異常->エラーページリダイレクト
・パラメータ異常->入力画面に戻す
・POSTからGETへのリダイレクト
・データ保存して結果出力

などなど。
これらを必ずControllerに書く必要は無く、Utilityクラスを作成してそちらに任せてもいいでしょう。
UtiltiyクラスはPresenter層に影響を与えてはいけません。

Presenter

Presenterに書くのはHTTPを完全に切り離した入出力です。

入力パラメータは1つのオブジェクトにしておくとメンテナンスが楽です。
出力オブジェクトも1つのオブジェクトにしましょう。それがViewModelになります。

こうすることでPOSTだろうがGETだろうがCookieだろうがSessionだろうが方針を変えてもPresenter層に影響はなく、Presenter層の単体テストが容易になります。

Model

Modelにはテーブル単体の良く使うQuery実行をメソッド化してまとめておきます。

slect文でjoinが必要な場合は良く使うものであれば左になる(基準になる)テーブルのModelに書きますが
大抵はその処理固有のものになるので直接Presnterに記述するのもありです。

Presenterのメリットとしてはたとえば会員登録のPresenterのメソッドであればそのメソッドからWebで実行したのと同じロジックでテストデータを大量投入したり、テスト用に使いまわすことができるようになります。

またフロントサイトの他CMSを裏で持っている場合、CMSから実行したりなども可能になります。

その他の意見

Presenter自体をWebApiとして切り出してしまえばWebAPI経由で操作できるじゃんという意見もあると思います。それはその通りです。

考え方は個人個人だと思うので、ひとつの意見としてお納めください。

自分自身もこの考えに固執するつもりはなく、メンバーとの意見を取り入れてある程度みんなが納得できる仕組みで実装するのがいいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/17 10:53

    回答ありがとうございます。
    まだまだ知識不足で、ViewModelやPresenter自体が聞き慣れず、検索して見てみました。
    これを一つ挟むことによるメリットなど、試してみて少し考えてみたいと思います。

    キャンセル

+2

送信されたパラメータが妥当かどうかを評価する(Validation)部分は、
再利用する可能性が高いため、
その機能だけで独立したクラスにしてもいいかもしれないくらいです。
よくある入力項目(例えば電話番号とか日付とか時刻とか)って、
正規表現一発で済むかもしれませんが、
同じような検査をあちこちに書かずに一箇所にまとめて再利用した方が良いですよね。

アクションメソッドの中にDB処理以外を全部長々を書き連ねてしまって、
今後はそういう風に処理を改めていきたいなと。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/17 10:50

    回答ありがとうございます。
    確かに再利用ということを考えるとまた違った見方というかできますね。
    このページからの値をチェックというより、値のチェックということを考えると、確かに一つそれだけの機能をまとめると良いなと思いました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる