2011-06-27 12 views
2

私はPHPベースのModel-View-Controller構造化Webサイトで作業しています。私は、モデルがビジネスロジックを処理し、HTML(または何でも)をユーザに提示し、コントローラがこれを容易にすることを理解する。私が立ち往生している場所は形である。 コントローラーにどのくらいの処理を加え、モデルをどのくらい入れますか?MVC Webサイトでフォーム提出を検証して処理する場所

ユーザーの最初の&の姓を更新しようとしているとします。私がしたいのは、AJAXを使って私のコントローラの1つにフォームを送信することです。私は、データを(もう一度)サーバ側で検証し、有効な場合はデータベースに保存してから、JSON応答を成功またはエラーとしてビューに返します。

コントローラに自分のユーザーモデルのインスタンスを作成するか、モデルの静的メソッドにコントローラをリレーするだけでよいですか?

オプション#1:モデルのProcess POST

<form action="/user/edit-user-form-submit/" method="post"> 
    <input type="text" name="firstname"> 
    <input type="text" name="lastname"> 
    <button type="submit">Save</button> 
</form> 

<?php 
    class user 
    { 
     public function __construct($id){} // load user from database 
     public function set_firstname(){} // validate and set first name 
     public function set_lastname(){} // validate and set last name 
     public function save_to_database(){} // save object fields to database 

     public static function save_data_from_post() 
     { 
      // Load the user 
      $user = new user($_POST['id']); 

      // Was the record found in the db? 
      if($user->exists) 
      { 
       // Try to set these fields 
       if(
        $user->set_firstname($_POST['firstname']) 
        and 
        $user->set_lastname($_POST['lastname']) 
       ) 
       { 
        // No errors, save to the dabase 
        $user->save_to_database(); 

        // Return success to view 
        echo json_encode(array('success' => true)); 
       } 
       else 
       { 
        // Error, data not valid! 
        echo json_encode(array('success' => false)); 
       } 
      } 
      else 
      { 
       // Error, user not found! 
       echo json_encode(array('success' => false)); 
      } 
     } 
    } 

    class user_controller extends controller 
    { 
     public function edit_user_form() 
     { 
      $view = new view('edit_user_form.php'); 
     } 
     public function edit_user_form_submit() 
     { 
      user::save_data_from_post(); 
     } 
    } 
?> 

オプション#1:モデルのProcess POST

<form action="/user/edit-user-form-submit/" method="post"> 
    <input type="text" name="firstname"> 
    <input type="text" name="lastname"> 
    <button type="submit">Save</button> 
</form> 

<?php 
    class user 
    { 
     public function __construct($id){} // load user from database 
     public function set_firstname(){} // validate and set first name 
     public function set_lastname(){} // validate and set last name 
     public function save_to_database(){} // save object fields to database 
    } 

    class user_controller extends controller 
    { 
     public function edit_user_form() 
     { 
      $view = new view('edit_user_form.php'); 
     } 
     public function edit_user_form_submit() 
     { 
      // Load the user 
      $user = new user($_POST['id']); 

      // Was the record found in the db? 
      if($user->exists) 
      { 
       // Try to set these fields 
       if(
        $user->set_firstname($_POST['firstname']) 
        and 
        $user->set_lastname($_POST['lastname']) 
       ) 
       { 
        // No errors, save to the dabase 
        $user->save_to_database(); 

        // Return success to view 
        echo json_encode(array('success' => true)); 
       } 
       else 
       { 
        // Error, data not valid! 
        echo json_encode(array('success' => false)); 
       } 
      } 
      else 
      { 
       // Error, user not found! 
       echo json_encode(array('success' => false)); 
      } 
     } 
    } 
?> 

2ここでは、これは仕事ができるかの2つの例であります例はまったく同じことをします、私はそれを実現します。しかし、これを行う正しい方法と間違った方法がありますか?私はスキニーコントローラと脂肪モデルについて多くのことを読んできましたが、オプション#1はどこから来ましたか。どのようにこれを扱っていますか?ありがとう、そして長い質問のために申し訳ありません!

答えて

4

すぐに言えば、ではなくのいずれかの方法を使用することができます。少し変更する必要があります。

これを考慮してください:モデルは実際にポスト、ゲット、その他のものについて「認識」していません。彼らは、あなたのビジネスに関係する事柄を、あなたの場合にはユーザーとして知る必要があります。

アプローチ#1を使用することができますが、ではなく、モデルから直接ポスト変数にアクセスする必要があります。代わりに、関数をパラメータの配列にして、ユーザーを作成するために使用します。

このようにすれば、シェルスクリプトなどでコードを簡単に再利用することができます。$_POSTなどはありません。

コントローラで2番目のアプローチはより冗長ですが、これもできることです。しかし、おそらくスタイルのより良いアプローチは、 "サービスクラス"を使用することです。このサービスにはメソッドがあります。たとえば、 "createUserFromArray"と言うと、配列を受け取り、ユーザーを返します。再度、このメソッドをパラメータとして$_POSTに渡します。変更した#1の関数に渡す方法と似ています。

コントローラだけが入力を直接処理する必要があります。これは、コントローラがリクエストを処理し、ポストについて知ることができるからです。

tl; drあなたのモデルでは、直接$_POSTのような超球体を使用しないでください。

+0

入力いただきありがとうございます。モデル内のグローバルにアクセスしないことを知っておくとよいでしょう...それは理にかなっています。サービスクラスに関する面白い考え。サービスクラスの機能を1つのメソッド(つまり、配列から新しいユーザーを作成する)に限定するか、update_user_from_arrayのような他の関数を追加するのは意味がありますか?また、これらの関数の両方に対して、配列内の特定の数の値を強制的に渡すか、関数に渡されたものを単純に処理させますか?(firstnameとlastname、別の時刻のユーザー名とパスワード) – Jonathan

+0

一般に、サービスには、通常、特定のタイプのモデルに関連する任意の数のメソッドが含まれます。たとえば、ユーザーモデルとやり取りするさまざまな方法を含むユーザーサービスを作成できます。私は、メソッドの配列は任意の数の値を含むことができると思うが、実際に必要な値を確認し、必要な値がmissngの場合は、例外をスローする必要があります。この概念は、より多くの情報を検索する場合は、「サービス層」と呼ばれます。 –

+0

サービスレイヤー、これは決して考えられませんでした!しかし、複数のドメインモデルを扱うときに通常使用されるサービス層ではありませんか?私はそのアイデアが気に入っていますが、それは典型的な小さなウェブアプリでは過度のものでしょうか? – Jonathan

0

私の視点から見ると、仕事でやっているところでは、モデルは渡されるデータの検証とフィルタリングを処理しますが、コントローラを使用してモデル内のデータをプッシュします。

上記のコメントに記載されているモデルは、$ _POSTまたは$ _GETについてはコントローラが処理しなければならないユーザー入力であることを知る必要はありません。一方、モデルは、プロジェクトの異なるコード部分でデータの検証を何度も何度も繰り返したくないため、モデルに渡されたデータの検証をすべて処理する必要があります。

+0

私は抽象的な 'Cleaner'、' Sanitizer'、 'Validator'クラス(三つ組)を作成しました。 'filter_input_array()'と$ _FILESを利用して、様々な入力ソースに対して具体的な 'Sanitizer'クラスが存在します。具体的な 'Cleaner'クラスは、フォーム/状況固有のクラスであり、' Sanitizer'オブジェクトをプロパティとして持っています。 'Cleaners'は' Sanitizers'を使用して入力を消去し、 'Cleaners'は配列を具体的な' Validator'に渡します。そのようなインスタンスの三つ組はどこに住んでいますか?なぜなら、これは実際に入力に関するものであり、入力が使用される理由ではないからです。何か案は? –

+0

ところで、ServerCleaner、ServerSanitizer、およびServerValidatorがあります。この目的は、$ _SERVERの重要な値を検証することです。これはリクエスト自体を処理するため、ルータがその処理を行う前にこのトライアドが発生する必要がありますか? –

0

MVCデザインパターンの大きな理由は、それが分離の懸念を維持する良い方法だということです。ビューはモデルを知らないで、その逆もあります。コントローラーは、モデルとビューの間を仲介する一種の交通警察官としてのみ存在します。したがって、コントローラはビ​​ューからデータを取得し、ビューがどのように実装されているかを(HTMLフォームを介して)知らなくてもモデルがデータを理解し、モデルに渡すことができるように最小限の処理を行い、データを保持することができます。

これにより、複数のコントローラ間でアイテムを保存するコードを複製せずに、アイテムをHTMLフォーム以外の方法で作成/保存/永続化する必要がある場合に、モデルを再利用できます。

更新:私は妥当性検査について言及しなかった。コントローラはデータを保持するのと同じ行に沿って、必要なデータの正確なフォーマットを知っているModelであるため、コントローラはデータを取得して検証のためにModelに渡す必要があります。モデルが無効な場合、モデルが無効な場合にモデルが例外をスローすることで、検証と永続性を組み合わせることができます。コントローラは必要に応じてキャッチして対処できます(JSONエラー応答のレンダリングなど)。

+0

時間を割いていただき、ありがとうございます。私はモデルとビューの関係は私が苦労していることを認めなければならないが。ビュー内のモデルにアクセスするのは容易ではありません。コントローラがこの情報をどのようにリレーすることが役立つかは実際にはわかりません。多分あなたは精巧にすることができますか? – Jonathan

+1

@Jonathan:そうですね、特に小さなプロジェクトの場合、非常に多くのレイヤーのコードを抽象化することを正当化するのは難しいでしょう。オブジェクト指向設計は、プロジェクトの初期段階で複雑さを増します。しかし、後で拡張する必要がある場合、重複した機能を避けるためにコード全体をリファクタリングする必要はありません。後でWeb APIを追加するとどうなりますか?最終的にデータストレージシステムを変更する必要がある場合はどうなりますか?コードベースの変更は、すべてがすでに管理可能な拡張可能なチャンクに収まっていれば、はるかに包括的ではなくなり、時間が大幅に節約されます。 – curtisdf

関連する問題