Лучше установить переменную в представлении или контроллер в 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 для установки переменных. И это больше не пахнет правильно. Представления не должны иметь слишком много логики.
Представления могут содержать столько логики отображения, сколько вам нужно. Бизнес-логика должна быть в модели и / или контроллере, в зависимости от того, предпочитаете ли вы тяжелые или легкие модели.
В своей собственной работе я склонен назначать все переменные в контроллере, если только я не использую помощник вида для отображения навигации, рекламы и т. Д. Помощники вида действительно предназначены для вещей, которые вы будете повторно использовать во многих частях сайта.
При назначении переменных в контроллере представлению, и у меня есть набор записей, я стремлюсь циклически проходить по этому набору записей и помещать их в ассоциативный массив. Вместо того, чтобы передавать фактический набор записей в представление, я передаю ему этот массив.
Причина в том, что я могу:
- Манипулировать значениями для отображения в контроллере, а не в представлении (телефон: 1234567890 становится 123-456-7890)
- Делать какие-либо соединения или другие выборки в контроллере
- Держите тривиальную логику отображения вне поля зрения (т.е. устанавливайте класс 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. Теперь я присваиваю в своем списке объектов модели, так как разные представления требуют разных данных от моих моделей, но я просто получаю доступ к тому, что я назначил.
Приятно то, что я могу написать контроллер один раз, а затем написать сценарий представления так, как я хочу представить данные. Я использую несколько помощников вида здесь и там для большей логики на основе вида.
Теперь, я думаю, вы могли бы сделать это с помощью более сложных помощников вида (и использовать какой-то реестр для данных, которые вы хотите запоминать / кэшировать в запросе), но кажется, что вы прячете вещи глубже, чем вам нужно, но это может быть вопрос мнения.