MVCでは、モデルからの基本的なデータ取得をビューで実行できますか?


10

「細いコントローラー、ファットモデル」の概念と、出力用のデータが必要な場合にビューがモデルを直接呼び出すことができるという一般的な受け入れを考えると、コントローラーではなくビュー内のリクエストの「取得と表示」部分の処理を検討する必要がありますか?例(コードをかなり一般的なものにしようとする):

コントローラ

<?php

class Invoice extends Base_Controller {

    /**
     * Get all the invoices for this month
     */

    public function current_month() {

        // as there's no user input let's keep the controller very skinny,
        // DON'T get data from the Model here, just load the view

        $this->load->view('invoice/current_month');

    }

}

見る

<?php

// directly retrieve current month invoices here

$invoices = $this->invoice_model->get_current_month();

// get some other display-only data, e.g. a list of users for a separate list somewhere on the page

$users = $this->user_model->get_users();

?>

<h1>This month's invoices</h1>

<ul>
<?php foreach ($invoices as $invoice) { ?>

<li><?php echo $invoice['ref']; ?></li>

<?php } ?>
</ul>

私にとって、これは、要求が本質的に単なるビューである場合、少なくともある程度は理にかなっています。コントローラーがデータを取得できるのに、コントローラーがデータを収集してビューに渡す必要があるのはなぜですか?これにより、コントローラーは純粋に「アプリケーションレベル」の処理(たとえば、GET / POSTリクエストの処理、アクセス権とアクセス許可の管理など)のために開いたままになり、モデルの再利用可能性やその他すべての優れた機能を維持します。

この例を拡張してユーザーが結果をフィルターできるようにした場合、コントローラーはフォームからのPOSTを処理し、フィルターをビューに渡すだけで、今度はフィルターを使用してデータを再度要求します。

これはMVCアプリケーションを開発する有効な方法ですか?それとも、コントローラーが果たすべき役割の重要な部分を見落としているか?

回答:


17

はい、技術的には可能です。いいえ、それを行うべきではありません。そして、はい、コントローラーの用途が少し不足しています。

コントローラは、ビューをモデルから切り離すためにあります。ビューをほとんど使い捨てのコードと見なす必要があるため、分離は有益です。UIテクノロジーが変化するにつれて、新しいビューの生成に必要なやり直しを最小限に抑える必要があります。コントローラーは、その分離を可能にし、UIテクノロジーを介して存続するコードの場所を提供します。

モデルを追加または変更する必要がある場合も、逆に機能します。上流の変更はすべてコントローラー内に含まれ、ビューはそのままになります。

もう1つのリスクは、ビューがは非常にシンプルである一方で、そのライフ全体を通じてビューがシンプルなままであるという保証が少なくなることです。(非常にシンプルな)ビューから直接モデルを呼び出すことにより、ドアを少し開いて、非常に単純なビューをそれほど単純ではないものにする必要がある場合に、後で追加の悪い習慣が入り込むのを許可します。将来の開発者は、コードをリファクタリングしてコントローラーと対話するのではなく、それほど単純ではないビューからより多くのモデル呼び出しを行うように誘惑されるでしょう。


1
すばらしい回答、ありがとうございます。「先読み」シナリオを少し拡張します。リクエストされたものとは別のページに共通の情報がある場合(たとえば、ユーザーが特定の製品を表示している場合、「最新の特別オファー」の一般的なリストが横に表示されます)どのように/どこで呼び出しを行うoffers_model->get_latest()必要がありますか?これをコントローラーのすべてのメソッドに追加する(私が以前に愚かに試みたように)は、やり過ぎのようであり、明らかに乾燥していないようです。
アダムウェストブルック2013年

2
@AdamWestbrook MVVMを見てください。そのViewModel部分は、この特定の問題に対処できます。あなたは追加することができますoffers_model->get_latest()ProductViewModel、基本クラスまたは類似した何か。
ザカリーイェーツ2013年

1
よろしくお願いいたします。MVVMについては、もう一度お礼を申し上げます。
アダムウェストブルック2013年

非常に良い答えですが、この星に挑戦し続けます。個人的には私もMVVMの大ファンです:)
Benjamin Gruenbaum 2013年

@BenjaminGruenbaum PHPでMVVMを使用していますか?もしそうなら、それのために特定のフレームワークを使用していますか?
Adam Westbrook 2013

6

「細いコントローラー、ファットモデル」の概念と、出力にデータが必要な場合にビューがモデルを直接呼び出すことができるという一般的な受け入れを考えると

いいえ、これは正しくありません。ビューはモデルを直接呼び出すことはできません。何らかの理由でプログラマがそれらのオブジェクトをビューに公開していない限り、ビューはモデルオブジェクトにアクセスできません。

コントローラーではなくビュー内でリクエストの「取得および表示」部分を処理することを検討する必要がありますか?

これは基本的にコントローラーを消去し、それらを持っているという意味を打ち負かします。

コントローラーがデータを取得できるのに、コントローラーがデータを収集してビューに渡す必要があるのはなぜですか?

コントローラはデータを収集しません。モデルはデータの収集を行います。コントローラ、このデータをビューに渡すかどうかを決定します。ビューはデータの表示を行います。

この例を拡張してユーザーが結果をフィルターできるようにした場合、コントローラーはフォームからのPOSTを処理し、フィルターをビューに渡すだけで、今度はフィルターを使用してデータを再度要求します。

番号。

コントローラーは、POSTされたデータが有効かどうかを確認し、このデータをオプションとしてモデルに渡します。モデルはデータソースにクエリを実行してデータを返し、コントローラーはそれをビューに渡します。

これはMVCアプリケーションを開発する有効な方法ですか?それとも、コントローラーが果たすべき役割の重要な部分を見落としているか?

コントローラは、ブラウザからのリクエストに対するハンドラとして動作します。ディスパッチャがリクエストをコントローラのアクションに送信し、コントローラのアクションがリクエストをモデルに送信します。モデルにはすべてのビジネスロジックが含まれ(これは重要な部分です)、データをコントローラーに返します。その後、コントローラーはデータを簡略化および調整できるため、ビューでの表示がより簡単になります。

ビューの目的は、HTMLの表示とDataSourceの間の構造と依存関係を分離することです。これは難しいかもしれませんが。ビューは、モデルから直接取得したデータを常に表示するとは限りません。多くの場合、コントローラーは関連する追加データを追加します。

MVCにはたくさんのチュートリアルがあると思います。それらのいくつかを読むことをお勧めします。


Mathewに感謝します。明確にするために、これまで私は常に、ビューとモデルをコントローラーで切り離し、読んで示唆してきました。ただし、「細い」コントローラーを維持することについて読み始めたので、これらのコントローラーから何を移動する必要があるか、または移動できるかを考えていただけなのですが、この質問に至るまでの思考プロセスは、1つまたは2つのステップにすぎました。
アダムウェストブルック

多くのコントローラーで使用されるモデルを取得するとき。それらが脂肪である必要性は非常に明確になります。ビューに多くのPHPが含まれ始めると、コントローラーが薄くなることがわかります。コントローラーが非常に太っているとき。他のコントローラーを同じように動作させる(たとえば、APIサービスを追加する)ことは困難です。
Reactgular 2013年

3

最近Pythonを学習しているときに同じ問題に遭遇したので、あなたの質問は非常に興味深いものでした。

与えられた答えは説得力のある議論をしますが、私は、ビューがコントローラーを経由せずにモデルの状態を取得するという偶然に出くわした別の意見を付け加えようと思いました。

MVC

ビューとコントローラーの両方がモデルに依存することに注意することが重要です。ただし、モデルはビューにもコントローラーにも依存しません。これは、分離の主な利点の1つです。この分離により、視覚的な表現とは無関係にモデルを構築およびテストできます。ビューとコントローラーの分離は、多くのリッチクライアントアプリケーションでは二次的なものであり、実際、多くのユーザーインターフェイスフレームワークはロールを1つのオブジェクトとして実装しています。一方、Webアプリケーションでは、ビュー(ブラウザー)とコントローラー(HTTP要求を処理するサーバー側コンポーネント)の分離は非常に明確に定義されています。

Model-View-Controllerは、ユーザーインターフェイスロジックをビジネスロジックから分離するための基本的な設計パターンです。残念ながら、パターンの人気により、多くの誤った説明が生じています。特に、「コントローラ」という用語は、さまざまな状況でさまざまなことを意味するために使用されてきました。幸いなことに、ビューとコントローラーの分離が非常にはっきりしているため、Webアプリケーションの出現により、あいまいさの一部が解決されました。

Smalltalk-80でのアプリケーションプログラミング:Model-View-Controller(MVC)[Burbeck92]の使い方で、Steve BurbeckはMVCの2つのバリエーション、パッシブモデルとアクティブモデルについて説明しています。

パッシブモデルは、1つのコントローラーがモデルを排他的に操作するときに使用されます。コントローラーはモデルを変更し、モデルが変更され、更新する必要があることをビューに通知します(図2を参照)。このシナリオのモデルは、ビューとコントローラーから完全に独立しています。つまり、モデルがその状態の変化を報告する手段はありません。HTTPプロトコルはこの例です。ブラウザからサーバーから非同期更新を取得する簡単な方法はありません。ブラウザーはビューを表示してユーザー入力に応答しますが、サーバー上のデータの変更を検出しません。ユーザーが明示的に更新を要求した場合のみ、サーバーは変更について問い合わせを受けます。

MVC-パッシブモデル

私はどちらの意見が「正しい」と言う立場にありません。正直に言うと、ここの回答とリンクされた記事を読んだ後、少し混乱します。

記事の全文はこちら


右、そして混乱を追加する他の事柄はクライアントサーバーです、そしてそれはオリジナルのSmallTalk MVCが実際に説明しませんでした。クライアントサーバー(javascriptなど)には、クライアントにプレゼンテーション指向のモデル、ビュー、コントローラーがあり、サーバーにはドメイン指向のビューとコントローラーがありますが、サーバーは混乱を招くプレゼンテーション指向の処理も行います。また、ドメインビューに永続性を持たせたい場合があります。つまり、ビューパラメータが独自のモデルを形成しますが、必ずしもドメインモデルの一部ではありません。
Erik Eidt 2013

リンクをありがとう、私はこれを考えることに怒っていないことを知っていました!これは、モデルがどのように/どこにアクセスするかに関係なく、モデルに何も依存していない限り、アイデアを少し遠ざける前に私が本質的に行っていたものです。次の開発にどのようなアプローチをとるかはまだ決めていませんが、これは間違いなく役立ちます。
アダムウェストブルック

1

考慮すべきもう一つは、あなたが自動的にロードしているように見えるということですuser_modelし、invoice_modelそれらにアクセスするためのビューを許可します。これが確実に機能するためには、おそらくすべてのモデルをオートロードます($this->load->model()ビューで見た目が間違っているだけなので、そうではありません...)

これを行うと、決して使用されない可能性のあるものをロードすることにより、スタックを不必要に膨らませます。複数のモデルを使用する理由の1つは、関連するロジックをカプセル化して、特定のタスクに必要なものだけをロードできるようにすることです。

これはCodeIgniterのように見えます。私は多くのCI開発を行ったので、実際に必要以上に自動ロードしたくないという個人的な経験から共有できます。$this->output->enable_profiler(TRUE);コントローラーのコンストラクターを追加して、オートロード(のようなヘルパーを含むdatabase)をいじってみてください。ロード時間と実行時間、特にメモリ割り当てに大幅な変化が見られるでしょう。


1
わかりやすくするために、特定の構文の一部を削除しましたが、これはCIに基づいています。私はほとんどすべての時間とDRYの理由でほとんどすべてを「オートロード」する習慣に慣れていますがload->model、ほとんどのコントローラーとメソッドで同じことをたくさん持っているのは少し気違いに思われました。適切なオートロード機能を使用しないことは、CIの下位互換性について私が最も嫌うことの1つですが、それは他の完全な議論です...
Adam Westbrook

0

簡単に言えば、コードサンプルの形式は一見すると直感的です。これは「心にやさしい」方法だと思われるでしょう。


問題#1

あなたModelViewオブジェクト緊密に結合されます。

でメソッドを追加または削除するModel必要がある場合は、Viewそれに応じて変更する必要があります。

基本的に、MVCはコマンドオブザーバーのパターンから派生しています。がフックできるインターフェース(API)を介して操作される独立した「モデル」(つまり、委譲)が必要です。Controller

多くの場合、これはにインスタンスを挿入して、のプロパティとして格納すること Modelを意味しViewます。次に、作業領域として(つまりコマンド)のメソッドを使用して、「モデルがアプリケーションの状態の更新を完了した後」から)にデータを渡しますControllerControllerController View Model

データ(配列、反復可能オブジェクトなど)を渡すと、とインスタンス間の結合緩くModelなりViewます。インスタンスをに挿入する場合は、上記の問題#1を参照してください。ModelView

覚えておいて、Views表現状態転送方法論(REST)以下、HTML、JSON、テキスト、XML、HTTPヘッダ、YAML、またはほとんど何でもかまいません

このように、との関係を管理する方法を理解する鍵Modelとは、Viewsそれが何であるかについての関係、確認することです一対多を(潜在的に)!これはまさに、Observerパターンが達成するために設計されたものです。

ほとんどの設定では一度に1つのビューしか考慮されませんが、MVCアーキテクチャパターンが一度に複数のビューを更新するのを妨げるものはありません。従来のCRUD Webアプリケーションを使用すると、人々は1対1で考えるようになりますが、これはObserverパターンがどのように機能するかを示す最小の例です(1対多が他方です)。

あなたが1だった場合はこのように、Modelと複数のViews潜在的な頭痛のすべての更新のViews'あなたが何かを変更したため、実装コードをModel'sAPI /方法は、今となっ急性

インスタンスでViewsなくに データを渡しますModels

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.