2

私の質問には少し設定が必要ですので、ご容赦ください。

私はモデルからデータを取得するためにビュー ヘルパーを使用するようになりました ( Eric Clemmonsへのハット チップ)。そこでは、はるかに再利用可能で柔軟です。私はそれが大好きです!

私が通常行うことは、テンプレートを index.phtml にレイアウトし、モデルから何かを取得する必要がある場合は、そのスニペットを detail.phtml に配置することです。これにより、ロジックは可能な限り邪魔になりません。

しかし、再利用される変数の必要性が見えてきました。たとえば、カテゴリ名。ビュー ヘルパーを使用してモデルから猫の名前を何度も取得する必要はありません。キャッシュすることはできますが、明らかに面倒です。

そこで、変数を設定するために、detail.phtml で数行の php を使用し始めました。そして、それはもう適切ににおいがしません。ビューには、ロジックが多すぎてはなりません。

それで、あなたは何を言いますか?変数が再利用される場合は、コントローラーに入れますか? または、ビューに設定されたいくつかの変数を気にしませんか?

EDIT : Alan Storm が viewhelpers の例を求めました:

詳細.phtml:

<ul id="productList">

<? foreach($this->getProductById($id) as $product) : ?>
    <li><?= $this->escape($product['name']) ?></li>
<? endforeach; ?>

</ul>

(アンチショートタガーの攻撃に備えて)

別の編集:2つの正しい答えはあり得ないことがわかりました。しかたがない...

4

7 に答える 7

5

Controller も View も、アプリケーションの状態を保存するためのものではありません。それがモデルの目的です。

MVC の「モデル」はデータベース テーブルではないことに注意してください。モデルは、アプリケーションのビジネス ロジックを実装する場所であり、それをデータベースに格納することは、モデルの内部実装の詳細です。ただし、データベースとは関係のないモデルをアプリに含めることはできます。

于 2009-08-12T22:14:07.393 に答える
2

簡単な答え:私見、はい、コントローラーに入れます。

理由:

1) ビューに変数を渡すコントローラーは、より典型的な MVC です。

2) 保守性: 3 か月後に再びビューにアクセスしたときに、変数を探すために隣接するビュー/テンプレートを探し回る必要はありません。ここで、スパゲッティ コードに戻り、特定の変数がどこから発生したかを推測する必要があります。

于 2009-08-12T22:15:37.517 に答える
2

私はこの変数の考え方があまり好きではありません: ビューまたはコントローラーのいずれかにコードを追加し、気分が良くありません。

一方、私はこのキャッシュのアイデアが好きです...複雑すぎる/やり過ぎだと思うならイベント。

途中で道を見つけてみませんか?file/APC/memcache のようなキャッシュを使用せず、スクリプトの実行のためにデータをメモリに保持しますか?
そのために静的変数を使用できます。クラス内、またはメソッド内で直接(「クラスのメソッド間でそのキャッシュを共有することは理にかなっていますか?」に応じて)

この考え方を説明するために、コードの一部を簡単に示します。このクラスを検討してください:

class A {
    public function test($param) {
        static $cache = array();
        if (isset($cache[$param])) {
            var_dump("cache hit : $param = {$cache[$param]}");
            return $cache[$param];
        } else {
            // Fetch from DB (here, simulated ^^ )
            $cache[$param] = mt_rand(0, 9999);
            var_dump("cache miss : $param = $cache[$param]");
            return $cache[$param];
        }
    }
}

このtestメソッドは、DB からフェッチされたデータを格納するために静的変数 (クラスのインスタンスによって共有される、その変数のインスタンスが 1 つだけ存在します) を使用します。

これをそのように呼び出す場合:

$a = new A();
$b = new A();

$a->test(10);   // miss
$a->test(15);   // miss
$b->test(10);   // hit
$b->test(25);   // miss
$a->test(25);   // hit

あなたはこれを得るでしょう:

string 'cache miss : 10 = 3745' (length=22)
string 'cache miss : 15 = 7800' (length=22)
string 'cache hit : 10 = 3745' (length=21)
string 'cache miss : 25 = 8623' (length=22)
string 'cache hit : 25 = 8623' (length=21)

メソッドが新しいパラメーターで呼び出されるたびに、それはミスであり、DB に移動します。しかし、パラメータがすでに一度使用されているときに呼び出されると、データはメモリ内にあり、DBには移動しません;-)

それは役に立ちませんか?あなたの場合、Aクラスはビューヘルパーであると推測しています;-)そしてmt_rand、DBクエリになります^^

補足として:これは大きすぎるオブジェクトに対して行うべきではありません.RAMを使用するためです...そしてそれらの多くはありません...


編集: Zend Framework を使用しているので、その静的変数の代わりに使用することに興味があるかもしれませんZend_Memory: RAM の使用量などを処理します (たとえば、必要に応じて「キャッシュ」からデータを削除できます)。正しく覚えてください。

また:はい、あなたはまだメソッドを何度も呼び出しています...しかし、クエリを実行するよりはましです...そして、この方法では、ビューもコントローラーもあらゆる種類の「キャッシュ」を気にする必要はありません:それは彼らのものではありません仕事。

また、私はこのテクニックを何年も問題なく使用しています(この方法で小さなオブジェクトのみを保存し、あまり多くない限り)。これを使っているのは私だけではありません。たとえば、Drupal もこれを使用します。

于 2009-08-12T22:16:06.033 に答える
2

あなたが話している正確なテクニックはわかりません。以下は、モデルの「データ取得」メソッドへの呼び出しをラップすることによって情報を返すビュー ヘルパーのメソッドを作成していることを前提としています。これにより、他の多くの PHP MVC フレームワークで採用されているパッシブ ビューパターンから解放されます。ビューは、データのモデルに直接行きます。あなたの懸念は、ビューヘルパーへの複数の呼び出しにより、モデルがデータを2回フェッチすることです。これは、簡単に回避できると思われる潜在的なパフォーマンスの問題です。

//example of how I'm assuming you're using view helpers
echo $this->viewHelperName->modelName->getDataIWant('key');

それがあなたの問題を正確に説明している場合、「2回使用する必要がある場合は、コントローラーにビュー変数を設定し、それ以外の場合はビューヘルパーを使用する」というアプローチはおそらく間違っています。これは私の個人的な好みですが、モデルからビューにデータを取得するためにどのアプローチを選択したとしても、アプリケーション全体でこれに固執する必要があります。

ここで解決しようとしている問題は、「モデルから直接データをフェッチするとパフォーマンス コストが高くなる」ことです。これは、モデルの実装で修正する必要がある問題です。ぎこちないコーディングスタイルで修正すべきものではありません:)

すでに述べたように、最善の解決策はキャッシュです。キャッシングは、頭が良ければ「面倒」である必要はありません。

public function getDataIWant($key, $clear_cache=false)
{
    if(!array_key_exists($key, $this->_cache) || $clear_cache)
    {
        $this->_cache[$key] = parent::getDataIWant[$key];
    }

    return $this->_cache[$key];
}

モデルを使用している方法でキャッシングが実行できない場合は、必要なデータを取得するためのメソッドをモデルに追加し、抽出を使用してビュー スコープで変数を定義することをお勧めします。

class MyModel
{
    ...
    function getDataForFooView
    {
        return Array(
            'company_name'=>$this->getCompanyName
        );
    }
    ...
}

...
//top of the view file
<?php extract($this->viewHelper->modelName->getDataForFooView()) ?>
<h1><?php echo $company_name; ?></h1>

これはまだちょっとぎこちないですが、ビュー ファイル (上部の 1 行) に一貫性があり、臭いが少なくなります。そうは言っても、キャッシングはこれを行うための「正しい™」方法です。それを避けることは、ある匂いを別の匂いと交換するだけです. ビュー変数を (ビューで直接、またはコントローラーで設定して) 定義するときに考えられる 1 つの方法は、すでにキャッシングを無計画に使用しているということです。

于 2009-08-12T23:19:47.387 に答える
1

私はほとんどすべての変数の割り当てをコントローラーで行います。なんで?すべてのアクションで利用できる複数のビューがあります。ContextSwitchを使用して、ATOM、RSS、そしてプレーンHTMLのページのフィードを提供しています。多くの方法で、これをAPI(jsonまたはxml)およびoEmbed処理に拡張できます。ビューが異なればモデルとは異なるデータが必要になるため、モデルオブジェクトのリストで割り当てていますが、割り当てたものにアクセスしているだけです。

良い点は、コントローラーを1回記述してから、データを表示したい方法でビュースクリプトを記述できることです。ビューベースのロジックを増やすために、あちこちでいくつかのビューヘルパーを使用しています。

これは、より複雑なビューヘルパーを使用して行うことができると思います(そして、リクエストでメモ化/キャッシュしたいデータに何らかのレジストリを使用します)が、必要以上に深く隠しているように見えますが、それはおそらく意見の問題。

于 2009-08-13T14:29:45.940 に答える
1

そこで、変数を設定するために、detail.phtml で数行の php を使用し始めました。そして、それはもう適切ににおいがしません。ビューには、ロジックが多すぎてはなりません。

ビューには、好きなだけ表示ロジックを含めることができます。ビジネス ロジックは、重いモデルを好むか軽いモデルを好むかに応じて、モデルおよび/またはコントローラーに含める必要があります。

私自身の仕事では、ビュー ヘルパーを使用してナビゲーションや広告などをレンダリングする場合を除き、すべての変数をコントローラーに割り当てる傾向があります。ビュー ヘルパーは、実際にはサイトの多くの部分で再利用するもののためのものです。

コントローラーの変数をビューに割り当て、レコードセットがある場合、そのレコードセットをループして連想配列にプッシュする傾向があります。実際のレコードセットをビューに渡す代わりに、この配列を渡します。

この理由は、次のことができるようにするためです。

  1. ビューではなくコントローラーで表示する値を操作します (電話: 1234567890 は 123-456-7890 になります)
  2. コントローラーで結合またはその他のフェッチを行う
  3. 些細な表示ロジックをビューから除外します (つまり、偶数行と奇数行に css クラスを設定するなど)

コントローラーの例:

$count = 0;
$list = array();
$result = mysql_query("select * from items limit 10");
while($item = mysql_fetch_object($result))
{
   if($count % 2 ==0){ $css_class = 'even'; } else { $css_class = 'odd'; }
   $count++;
   $item->css_class = $css_class;

   if($item->first_name && $item->last_name)
   {
      $item->name = $item->first_name.' '.$item->last_name;
   }
   else
   {
      $item->name = $item->username;
   }

   $list[] = $item;
}
$this->view->list = $list;

例のビュー:

<?foreach($this->list as $item):?>
<tr class="<?=$item->css_class?>">
    <td><?=$this->escape($item->name)?></td>
</tr>
<?endforeach;?>
于 2009-08-18T13:05:11.157 に答える