2

OK、今は MVC の概念の基本です。同様の質問があることは知っていますが、これについてはまだ明確な答えが見つかりませんでした。MVC について読んでいると、矛盾する例がいくつか見つかったので、どちらの概念が優れているかを知りたいと思いました。

コントローラーを使用してモデルからデータをロードし、そのデータをビューに渡すか、ビューにモデルからデータをロードさせ、コントローラーを使用して適切なビューを選択する必要があります。

私にとってより自然な(正しい)方法は、コントローラーがモデルをロードすることですが、2つの異なるビューを持つ同じコンテンツが必要な場合は、次のようになります。

  1. ビューには簡単な記事のテキストが表示されます
  2. ビューには同じ記事のテキストが表示されますが、記事の著者情報を含むボックスも表示されます。

私を混乱させているのは、ID 33 の記事を表示する単一の要求があることです。最初のケースではすべてが明確ですが、2 番目のビューは、(著者に関する) 追加データを表示する別のテンプレートを使用してレンダリングされます。モデルからデータを要求するビュー (作成者について) またはロジック全体をコントローラーで実行する必要がありますか?

ビューがレンダリングする必要があるテンプレートに基づいて、コントローラーがモデルから適切なデータを要求する必要があるため、混乱します。

私が理にかなっていることを願っています:)

4

2 に答える 2

2

簡単な答え: モデルをコントローラーとビューに渡します。

長い答え: MVC では、コントローラーは「モデルからデータをロードし、そのデータをビューに渡す」ことはしません。ビューはモデルと直接関係があり、そこからデータを要求します。参照: CodeIgniterおよびhttp://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controllerで MVC がどのように機能するか:出力表現を生成します。」

そのため、疎結合を有効にするには、モデル ビューとコントローラーを完全に独立して開始し、それらを相互に渡します。

これにより、MVC 支持者が主張する懸念事項を厳密に分離することができ、何もハードコーディングされていないため、任意のコンポーネントを他のコンポーネントと再利用できます。

何かのようなもの:

$model = new Model;
$controller = new Controller($model);
$view = new View($model, $controller);
echo $view->output();

コントローラーはビューを選択するべきではなく、モデルを選択するべきでもありません。この責任をコントローラーに置くことで、コントローラーは他のビューやモデルで再利用できなくなります。

編集:ビューがそのコントローラーについて知る必要がある理由についてのトレスコのコメントに答えるためにこれを更新しました。

コントローラーをビューにハードコーディングするのを避けるために、ビューにはコントローラーが必要です。これは、ビューが現在のコンテキストでペアになっているコントローラーを認識し、それにポストバックできるようにするためです。

イベント (ユーザー アクション) はビューで発生し、コントローラーで処理する必要があります。

それには 3 つの方法があります。

1) view:controller の関係をハードコーディングします。Web では、これは<a href="/some/hardcoded/route";を使用して実現されます。または<a href="' . $this->router->create('someController, 'action') . '>'これにより、望ましくない他のコントローラーでビューを使用する可能性がなくなります。

2) コントローラをビューに渡し、イベントが発生するコントローラをビューに知らせます。Web では、このアプローチを使用すると、コントローラーのアクションをルートに変換するルーターもビューに必要になります。例えば<a href="' . $this->router->getRoute($this->controller, 'action') . '>'

3) ビューをコントローラーに渡し、コントローラーにビューに対するアクションを設定させます: (コントローラー コード) $this->view->setEvent('buttonClick', $this->router->getRoute($this, 'action'))... (ビュー コード)<a href="' . $this->getEvent('buttonClick') . '>'

これらの、

1) 柔軟性に大きく影響するため、最も望ましくない。ビューは、非常に特定のコントローラーでのみアクションを呼び出すことができます。

2) 開発者の作業量は最小ですが、各コントローラーには特定のインターフェイスが必要です。

3) これは最も技術的な柔軟性を提供しますが、開発者にはより多くの作業が必要であり、コントローラーはそのビューについて多くのことを知る必要があります。API を超えて、ビューで使用できるイベントを知る必要があります。ビューが更新され、新しいアクションがある場合、それを考慮して各コントローラーを更新する必要があります。これは 2) にも当てはまりますが、2 はインターフェイスを使用して簡単に処理できるため、2 を使用するすべてのクラスを追跡する方がはるかに簡単です。

私の意見では、2 と 3 はどちらも優れたアプローチですが、2 の方がはるかに堅牢なシステムを可能にし、最も再利用できるため優れています。欠点は、コントローラーが特定のインターフェイスを実装する必要があることです。3 では、コントローラは任意のインターフェイスを持つことができますが、そのビューについてかなり多くのことを知っている必要があります。

CakePHP やその他の一般的なフレームワークは、この例では関係をハードコーディングする傾向があります (例: http://book.cakephp.org/2.0/en/views.html ) echo $this->Html->link('edit', array( 'action' => 'edit', $post['Post']['id'])); ?>。リンクは "Edit" コントローラーにしか移動できません。これは再利用に深刻な影響を与えます。

于 2013-02-04T17:15:18.560 に答える
-1

私の提案は、データ ソースとビューを結合するためのロジックは、完全にコントローラー内で実行する必要があるということです。ビューを特定のデータ ソースにバインドしないでください。

たとえば、Smarty 構文 (または類似の構文) を名前付きプレースホルダーと共に使用するビューがある場合、任意のデータ ソース、テキスト、モデルなどを使用して、テンプレートにレンダリングする情報を提供できます。ビューがモデルに関連付けられている場合は、他のモデルへの影響を認識してモデルとビューを変更する必要があります。

このような密結合は、誤って何かを壊す可能性が少ない疎結合よりも、誤って何かを見落とすことにより、より多くの問題につながります。

例:

class Page_Controller extends Controller {

  // __construct/__destruct/__callStatic/__call/etc, whatever you need in your implementation

  // -------------------------------------------------------
  // Adjust to suit your situation for passing data
  // This controller doesn't care where objSource comes from
  // -------------------------------------------------------
  private function pageSpecificImplementation($objSource = null){

    // using a factory class - but assume a view is created in whatever way works for you
    // the key thing here is that the view could be anything that can be returned as a string - but use whatever works for you
    $tplMain = make::view( 'template-url-or-path' )->assign(array(
       'placeholder1' => $objSource->value1,
       'placeholder2' => $objSource->value2
    ));

    $tplSub = make::view( 'template-url-or-path' )->assign( $objSource );

    $tplMain->assign('sub',$tplSub->render())->render();

    // $tpl is some form of html? csv?, who knows - not relevant at THIS stage

    // okay - now I know what I want to do!
    // decide what to do with it here - output headers for html
    // save to a file
    // output and cache the output, whatever works for you here
    // output to pdf?
    // send as an email?
    output::html( $tplMain, $cacheable, $cachetime... );
    // output::email( $tplMain, $extra_params );
    // output::pdf( $tplMain, $extra_params );
  }

}

ここでは、ビューを出力に密結合せずに使用しています。コントローラーは、実行時に適用されているビジネス ルールに基づいて出力を変更できますが、データ ソースはビューに関連付けられておらず、出力はビューに関連付けられていません。

同様の原則に従う方法で分離する「いくつかの」実装をお勧めします。YMMV は、何をしているのか、どのように実装したいかによって異なりますが、MVC では各要素を分離しておくようにしてください。

一部の実装では、「何の」ビューに言及せずに、ビュー内のものを「置換」するためのロジックが表示されます。これは Smarty で一般的に行われます。その後、コントローラのフローによってビューを決定できます。データは、複数のモデルまたはその他のソースから取得できます。これは、適切なビューに影響する場合と影響しない場合があります。

したがって、ビューからデータのロードを確実に分離する必要があります。決定が行われる場所であるコントローラーに保管してください。追加のビジネス ロジックが含まれていない密結合テーマ ビューを含むテーマ モデルなど、特定のユース ケースを念頭に置いている場合を除き、ビューはモデルに接続しないでください (可能性は低いですが可能ですか?)。

于 2013-02-04T17:03:33.763 に答える