web-dev-qa-db-ja.com

PHPのMVCビューについて

私はMVCでビューの概念を把握するのに問題があるように見えます、私が読んだことによると、それらはアプリケーションのプレゼンテーションを管理するレイヤーですが、私が読んでいた多くの資料はこれに関して異なっているようです PHP Master.com からのこの問題。

ビューは、いくつかのHTMLコードを返す関数を持つクラスです。残りのHTMLはどこにありますか?このViewコードにアクセスする独立した.htmlページに配置する必要がありますか?

この記事では、 php-html.net から、ビューは.php拡張子を持つ単純なHTMLファイルですが、どのようにしてそのデータにアクセスしますか? require()または最初のチュートリアルのインスタンス化のようなものは見当たりません。

31
Eduardo Naveda

注:MVCおよびMVCにヒントを得たパターンは高度な構造です。それらは、通常のオブジェクト指向( [〜#〜] solid [〜#〜] およびその他のガイドラインに従う)コードが管理不能になり始めるコードベースで使用されることを意図しています。このパターンを導入すると、追加の制約が課せられ、非常に複雑なアプリケーションを含めることができます。 MVCはnot「hello world」アプリ向けです。


最初から始めましょう...

MVCおよびMVCにインスパイアされたデザインパターンの背後にあるコアアイデアは、 Separation of Concerns です。この分離は2つあります。

  • モデルレイヤーはUIレイヤーとは別です:
  • ビューはコントローラーから分離されています

enter image description here

モデルレイヤー(「クラス」または「オブジェクト」ではない)には、それぞれがビジネスロジックの異なる側面として処理する構造の複数のグループが含まれます。主な部分は次のとおりです。

  • ドメインオブジェクト :検証、ビジネスルール
  • ストレージの抽象化:ドメインオブジェクトからのデータの永続性とキャッシュ
  • サービス:アプリケーションロジック

また、 リポジトリ作業単位 などが混在している場合があります。

UIレイヤーは、主にビューとコントローラーで構成されます。ただし、どちらもサービスを利用してモデルレイヤーと対話します。サービスは、コントローラーがモデル層の状態を変更し、ビューがその新しい状態に基づいて情報を収集する方法を提供します。

Webのコンテキストでは、ビューとコントローラーは疎なペアを形成します。これは、Webアプリケーションが示す要求と応答の性質のためです。

コントローラーcanは現在のビューの状態を直接変更しますが、これらの変更はモデルを介して行われるのが一般的です。ビューを直接変更する1つの理由は、たとえば、XMLの代わりにJSONで応答する必要がある場合です。

また、出力形式ごとに異なるビューを簡単にインスタンス化し、ポリモーフィズムを利用できると主張することもできます。


ビューではないものは何ですか?

ビューは単に美化されたテンプレートファイルであるという誤解が広まっています。この間違いは、RubyOnRailsプロトタイピングフレームワークのリリース後に非常に一般的になりました。

ビューはテンプレートではありません。これらをそのまま使用すると、MVCおよびMVCにヒントを得たパターンの背後にある中核的な原則を破ることになります。

テンプレートがビューであるふりをすると、アーキテクチャに多大な影響を及ぼします。ビューにはプレゼンテーションロジックを配置する場所がないため、コントローラーまたはモデルレイヤーのいずれかでプレゼンテーションロジックをプッシュします。通常の選択は「コントローラー」です。ほとんどの人は、プレゼンテーションロジックがモデルレイヤーに場所がないことを理解しているためです。

基本的に、これはビューとコントローラーの合併を引き起こします。


ビューは何をしていますか?

ビューの責任は、プレゼンテーションロジックを処理することです。 Webのコンテキストでは、ビューの目標は、ユーザーへの応答を生成することです(これは、人間ではなくブラウザです)

技術的には、クライアントサイドビューを作成し、そのユーザーWebソケットでモデルレイヤーを監視することは可能ですが、実際には実装することは事実上不可能です。特にPHP環境ではありません。

この応答ビューを作成するには、モデルレイヤーから情報を取得し、収集したデータに基づいて、データをテンプレートに配信してレンダリングするか、場合によってはHTTPロケーションヘッダーを送信して応答を組み立てます。

Post/Redirect/Get を使用する場合、リダイレクト部分はビューによって実行され、多くの人が行う傾向があるコントローラーではありません。


非常に主観的なビット

最近、次のアプローチを使用してMVCと対話することを好みました。

  // the factory for services was injected in constructors
  $controller->{ $method.$command }($request);
  $response = $view->{ $command }();
  $response->send();

$methodは現在のREQUEST_METHODで、RESTに似たAPIを偽装して調整されており、$commandは、人々が通常「アクション」と呼ぶものです。コントローラーには、GETおよびPOST(他の)要求用の個別のルーチンがあります。これは、すべての「アクション」に同じifが含まれないようにするのに役立ちます。

そして、ビューで、クライアントに送信される応答を準備する同様の名前のメソッドを呼び出します。

警告:このセットアップには [〜#〜] srp [〜#〜] 違反が含まれていると思われます。あなた自身のものとしてそれを採用することは悪い考えかもしれません。


DRYはどうですか?

既にお気づきかもしれませんが、ビューをインスタンスとして持つことにはわずかな問題があります。最終的には、コードの一部が繰り返されることになります。例:メニューまたはページネーション。

ページネーションを見てみましょう。ページネーションにはロジックが含まれていますが、このロジックはモデルレイヤーに関連していません。モデルには「ページ」の概念はありません。代わりに、このビットのロジックはUIレイヤーにあります。しかし、各ビューにページネーションが含まれているか継承されている場合、SRP(および実際には他のいくつかの原則)に対する明らかな違反となります。

この問題を回避するために、ビューに プレゼンテーションオブジェクト を導入できます(そして、そうすべきです)。

注:ファウラーはそれらを「プレゼンテーションモデル」と呼んでいますが、その名前は「モデルとは何か」という混乱をさらに強めていると思います。したがって、代わりに「プレゼンテーションオブジェクト」と呼ぶことをお勧めします。

プレゼンテーションオブジェクトは、繰り返されるロジックを処理します。これにより、ビューがかなり多く"lighter"になり、一部の局面では、モデル層からサービスの構造をミラーリングし始めます。

プレゼンテーションオブジェクトと テンプレート の相互作用は、ドメインオブジェクトと データマッパー の相互作用に似ています。


このすべてが常に必要ですか?

いいえ。この特定のアプローチは、コードに重点を置いており、UIレイヤーは非常に複雑であり、入力処理とプレゼンテーションを分離する必要があります正気に。

.. emm ..のように、アプリケーションが非常にシンプルなUIを持っている場合、RESTより大きな統合プロジェクト用のAPIを作成しています。そのようなpragmaticオプションは、すべてのコントローラーとビューのペアを単一のクラスにマージするだけです。

また、この制約の少ないアプローチを使用すると、古いコードのチャンク全体を移動できるため、レガシーコードベースをリファクタリングする際の良いステップにもなります。このような古いコードを分離し、すべてが機能することを確認したら(レガシーコードにはテストがないため、「レガシー」になります)、ビジネスロジックの分離に集中しながら、さらに分割を開始できます。 UIから。


P.S。私自身は、ビューを処理する最善の方法を見つけるのにまだ苦労しています。この投稿は答えではなく、私の現在の理解のスナップショットのようなものです。

73
tereško

2番目のチュートリアルは、Code Igniterフレームワークの動作方法であり、私が慣れている方法です。フレームワークをまったく使用しない場合でもそれに従います。

実際、開発者はMVCに似た原則を実践する必要があります。そうしないと、MVCに最も近い指向フレームワークを使用してラザニアやスパゲッティを作ることができます。

「PHPファイルをビューテンプレートとして」アプローチを使用する場合、理想的には最小PHPステートメント、基本的に繰り返し構造(foreach ($array as $item))のみ、基本条件(if ($boolean))およびecho-まるでテンプレート言語であるかのように、それ以上ではありません。

そのため、ビューテンプレートファイル内の<?php ?>タグは、単にプレースホルダーであり、他には何もないはずです。

ビューテンプレートファイルでは、データベースクエリ、モデルへのアクセス、計算などを実行しないでください。基本的に、プレースホルダーを含むHTMLファイルとして扱う必要があります。 (CSSとJavaScriptが関連付けられています。アプリケーションがJavaScriptに依存している場合、事態はさらに複雑になる可能性があります/ AJAX a ...)

これらの簡単な原則に従って、プレゼンテーションをビジネスロジックから効果的に分離します。とてもシンプルに聞こえますが、私はそれに従わないCode Igniterコードを扱うことにうんざりしています。モデル/データベース呼び出しを偽装するために「ヘルパー関数」を使用する人もいます-そしてそれは良い習慣だと思います! :-)

これらのPHPテンプレートファイルを表示する]の内部にはrequireが表示されません。これらは代わりに「ビュー構築」メソッドから必要とされるためです。

もちろん、コントローラーとモデル関数の内部からechoprintを使用しないでください。これも非常に簡単ですが、スパゲッティコードがCIコントローラーメソッド内からHTMLをエコーアウトするのを見るのも疲れています。

実際には、コントローラーはモデルメソッドを呼び出し、ビューに必要なすべてのデータを構築し、最後のステップとして、ビューを呼び出して(つまり、それを構築して出力し)、以前に取得したデータを渡します。

理にかなっていますか?あなたの質問に答えたかどうかはわかりません。少なくとも、これらは私の「2セント」です。

11
J. Bruni

異なるフレームワークは、異なるロジックを使用して変数を割り当て、そのコンテンツを表示および取得します。以下は、ob_start()関数を使用した簡単な例です。

<?php
     $title = 'Hello...';
     ob_start();
     file_get_contents('view.phtml');
     $viewContents = ob_get_clean();
     echo $viewContents;

?>

//view.phtml
<b>Hello the title is <?php echo $title; ?></b>

これがあなたの質問に答えることを願っています...

1
Jay Bhatt

あなたは、出力形式に依存しないビューを構築するために必要なすべてをビュークラスのメソッドに渡すことになっています。ほとんどの開発者は、何らかのテンプレートエンジンを使用してページの大部分を構築し、リクエスト固有の情報を本文に入力します。これを行うには、さまざまな方法があります。また、フォームや入力などの一般的な要素のヘルパーメソッドを定義する抽象ビュークラスがあると便利です。

このレイヤーは抽象化されているため、デザインまたは出力形式を何らかの方法で変更する場合でも、アプリケーションのロジックを変更する必要はありません。

編集: MVCセットで表される各モジュールには、出力をブラウザに送信するメソッドのコレクションを持つ独自のビューがあります。あなたが行くことができる多くの方法がありますが、ここに一つの例があります:

class testModule_view extends viewAbstract {
    public function showTestData($title, $subtitle, $data) {
        $XHTML = '<h1>' . $title . '</h1>'
            . '<h2>' . $subtitle . '</h2>'
            . parent::data2table($data);

        parent::outputToBrowser(DEFAULT_TEMPLATE, $XHTML);
    }
}

これは、簡単なビューメソッドがどのように見えるかを知るための簡単な例です。

1
km6zla
<?php

クラスビュー{

protected $data;

protected $path;

protected static function getDefaultViewPath() {
    $router = App::getRouter();

    if(!$router){
        return false;
    }

    $controller_path = $router->getController();
    $method_path = ($router->getMethodPrefix() !== "" ? $router->getMethodPrefix() . '_' : '') . $router->getAction();

    return ROOT . "/views/" . $controller_path . "/" . $method_path . ".phtml";
}

public function __construct($data = array(), $path = null) {

    if(!$path){
        //default
       $path = $this->getDefaultViewPath();
    }

    if(!file_exists($path)){
        throw new Exception("Error view file!");
    }

    $this->data = $data;
    $this->path = $path;
}


public function render(){
    $data = $this->data;

    ob_start();
    include ($this->path);
    $content = ob_get_clean();

    return $content;
}

}

0
David

ブラウザがページを呼び出すと、このページ用のコントローラーがロードされます。コントローラーはアプリのライフサイクルを管理します。彼はデータを取得するためだけに使用されるモデルからデータを取得します(おそらくデータベースから)。ビューはHTMLのみであり、コントローラーはビューをエコーし​​、必要な場合はいくつかのパラメーターを渡します。

0
hice3000

このコードを確認してください:

include_once(ROOT.'/'.'config/config.php');

function __autoload($class_name){
    $lib_path = ROOT . '/' . 'lib/class.'.$class_name . '.php';
    $controller_path = ROOT . '/' . 'controllers/'.str_replace("controller", "", strtolower($class_name)) . '.controller.php';
    $model_path = ROOT . '/' . 'models/'.strtolower($class_name) . '.php';

if(file_exists($lib_path)){
    require_once ($lib_path);
} else if (file_exists($controller_path)){
    require_once ($controller_path);
} else if(file_exists($model_path)){
    require_once ($model_path);
} else {
    throw new Exception("File {$class_name} cannot be found!");
}

}
0
David