Лучше установить переменную в представлении или контроллер в Zend Framework?

Мой вопрос требует небольшой настройки, поэтому, пожалуйста, потерпите меня:

Я перешел на использование View Helpers для получения данных из модели, а не разбрасывал их по всем контроллерам (отзыв Эрика Клеммонса). Это намного более многоразово и гибко там. Я просто люблю это!

Обычно я делаю шаблон в index.phtml, а затем, когда мне нужно получить что-то из модели, помещаю этот фрагмент в detail.phtml, чтобы логика была как можно дальше.

Тем не менее, я начинаю видеть необходимость в переменных, которые используются повторно. Например, название категории. Теперь вы не хотите использовать помощник вида, чтобы снова и снова получать имя кота от модели. Хотя вы можете его кешировать, очевидно, это слишком много хлопот.

Поэтому я начал использовать пару строк php в detail.phtml для установки переменных. И это больше не пахнет правильно. Представления не должны иметь слишком много логики.

Так что же вы все говорите? Если VAR используется повторно, поместите его в контроллер? Или не возражаете против пары переменных, установленных в представлении?

РЕДАКТИРОВАТЬ: Алан Сторм попросил привести пример помощи:

detail.phtml:

<ul id="productList">

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

</ul>

(готовлюсь к атаке анти-шортгеров)

ДРУГОЕ РЕДАКТИРОВАНИЕ: Я вижу, что не может быть 2 правильных ответов. Ну что ж...

7 ответов

Решение

Я не уверен, о какой именно технике ты говоришь. Далее предполагается, что вы создаете методы в помощниках вида, которые возвращают информацию, заключая вызовы в методы вашей модели "получить данные". Это отдаляет вас от шаблона пассивного просмотра, используемого многими другими PHP MVC Frameworks. Представления идут непосредственно к моделям для их данных. Вы полагаете, что несколько обращений к помощнику вида приведут к тому, что модель получит данные дважды. Это потенциальная проблема производительности, которую, кажется, легко избежать.

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

Если это точно описывает вашу проблему, подход "если мне нужно использовать его дважды, установите переменную представления в контроллере, в противном случае просто используйте помощник вида", вероятно, неправильный подход. Это в большей степени мое личное предпочтение, но какой бы подход вы ни выбрали для получения данных из моделей в вашем представлении, вам следует придерживаться во всем приложении.

Проблема, которую вы пытаетесь решить, заключается в том, что "выборка данных непосредственно из моделей имеет высокую производительность". Это проблема, которую должна решить реализация модели. Это не то, что должно быть исправлено из-за неопрятного стиля кодирования:)

Лучшее решение, как вы уже упоминали, это кэширование. Кэширование не должно быть "слишком хлопотным", если вы умны в этом.

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];
}

Если кэширование не подходит для того, как вы используете модели, я бы предложил добавить в вашу модель метод получения нужных вам данных и использовать extract для определения переменных в области просмотра.

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>

Это все еще немного неуклюже, но вы получаете последовательность в ваших файлах представления (единственная строка вверху), которые будут пахнуть меньше. Тем не менее, кэширование - это "правильный подход", способ сделать это. Избежать этого - обменять один запах на другой. Один из способов подумать о том, когда вы определяете переменную представления (либо непосредственно в представлении, либо устанавливая ее в контроллере), вы уже используете кэширование, просто случайным образом.

Ни контроллер, ни представление не предназначены для хранения состояния приложения. Вот для чего модель.

Имейте в виду, что "Модель" в MVC не является таблицей базы данных! Модель - это место, где вы реализуете бизнес-логику для приложения, и хранение ее в базе данных является внутренней деталью реализации модели. Но в вашем приложении могут быть Модели, которые не имеют ничего общего с базой данных.

Мне не очень нравится эта идея переменных: она добавляет больше кода либо в представление, либо в контроллер, и это не очень приятно.

С другой стороны, мне нравится эта идея кеша... Событие, если вы думаете, что это слишком сложно / излишне.

Почему бы не найти путь в середине? Не использовать какой-нибудь кеш, такой как 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 Метод использует статическую переменную (будет один и только один экземпляр этой переменной, совместно используемый любыми экземплярами класса) для хранения данных, извлеченных из БД.

Если вы называете это так:

$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)

Каждый раз, когда метод вызывается с новым параметром, это промах, и вы идете в БД. Но когда он вызывается, когда параметр уже используется один раз, данные находятся в памяти - и вы не переходите в БД;-)

Разве это не поможет? Я предполагаю, в вашем случае, A класс является помощником вида, кстати;-) И mt_rand будет запрос к БД ^^

Как примечание: это не должно быть сделано для слишком больших объектов, так как он будет использовать немного оперативной памяти... и не будет много таких...


Изменить: так как вы используете Zend Framework, вы можете быть заинтересованы в использовании Zend_Memory вместо этой статической переменной: она имеет дело с такими вещами, как объем занятой памяти (например, она может удалять данные из "кэша", если необходимо), если я правильно помню.

Кроме того: да, вы все еще вызываете метод много раз... Но это лучше, чем выполнять запрос... и, таким образом, ни View, ни Controller не должны заботиться о каком-либо "кэше": это не их работа.

А также: я использую эту технику в течение многих лет без каких-либо проблем (до тех пор, пока я храню только небольшие объекты, а не слишком много); И я не единственный, кто использует это; Например, Drupal тоже это использует.

Краткий ответ: ИМХО, да положи его в контроллер.

Причины:

1) Контроллер, передающий переменные в представления, является более типичным MVC.

2) Ремонтопригодность. Когда я снова посещаю представление через 3 месяца, мне не нужно просматривать соседние представления / шаблоны в поисках переменных. Теперь вы вернулись к спагетти-коду, и вам нужно угадать, откуда взялась конкретная переменная.

Я использую это в моих контроллерах: $ this-> view->someVariable = 1;

.... в представлении

view->someVariable

Поэтому я начал использовать пару строк php в detail.phtml для установки переменных. И это больше не пахнет правильно. Представления не должны иметь слишком много логики.

Представления могут содержать столько логики отображения, сколько вам нужно. Бизнес-логика должна быть в модели и / или контроллере, в зависимости от того, предпочитаете ли вы тяжелые или легкие модели.

В своей собственной работе я склонен назначать все переменные в контроллере, если только я не использую помощник вида для отображения навигации, рекламы и т. Д. Помощники вида действительно предназначены для вещей, которые вы будете повторно использовать во многих частях сайта.

При назначении переменных в контроллере представлению, и у меня есть набор записей, я стремлюсь циклически проходить по этому набору записей и помещать их в ассоциативный массив. Вместо того, чтобы передавать фактический набор записей в представление, я передаю ему этот массив.

Причина в том, что я могу:

  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;?>

Я делаю почти все переменные в контроллере. Зачем? У меня есть несколько просмотров для каждого действия. Я использую ContextSwitch для подачи каналов для страниц в ATOM, RSS, а затем в обычном HTML. Во многих отношениях я мог бы распространить это на API (json или xml) и обработку oEmbed. Теперь я присваиваю в своем списке объектов модели, так как разные представления требуют разных данных от моих моделей, но я просто получаю доступ к тому, что я назначил.

Приятно то, что я могу написать контроллер один раз, а затем написать сценарий представления так, как я хочу представить данные. Я использую несколько помощников вида здесь и там для большей логики на основе вида.

Теперь, я думаю, вы могли бы сделать это с помощью более сложных помощников вида (и использовать какой-то реестр для данных, которые вы хотите запоминать / кэшировать в запросе), но кажется, что вы прячете вещи глубже, чем вам нужно, но это может быть вопрос мнения.

Другие вопросы по тегам