Так как include выполняется в контексте класса, то внутри шаблона будет доступен $this. Следовательно реализуйте __get и используйте $this->{имя переменной} в шаблонах. Использование просто переменных очень плохо, так как в случае неопределения какой-либо переменной, она будет взята из глобальной области видимости. Я даже не говорю про notice, если эта переменная вообще нигде неопределена
>> Тут немного не понял основной мысли. Имеется ввиду передача данных в шаблон и их последующая выгрузка в переменные?
Да. Есть __set — этот метод модифицирует внутреннее состояние класса, а метод show по логике не должен модифицировать внутреннее состояние класса, так как его назначение на основании предопределенного внутреннего состояния выдать какой-то результат. Вы же создали путаницу, добавив в метод show изменение внутреннего состояния класса. Это не смертельно, но это очень нелогично и вносит путаницу. Лучше создать метод assign, который будет заносить данные из массива.
На самом деле ужасно. Не забывайте, что та статья — 2007 года. Для 2007 года там высказываются вполне современные идеи. Но сейчас на дворе уже 2011 год и ТАК писать — право, стыдно. По пунктам:
>> Вместо PDO написал некий класс, названный мной как Active Records
Это напоминает мне «принципиально новую ОС с нескучными обоями». Мало того, что PDO написан и оттестирован десятками разработчиков, так он еще и в разы быстрее, так как это native расширение. Итог: сэкономили на спичках.
>> Переписан немного класс Template, добавлена возможность делать вложенные шаблоны
Убейте меня, не нашел там вложенных шаблонов.
>> extract($this->vars);
Это сразу премия Дарвина в ИТ. Попробуйте ради интереса выполнить что-то типа $this->template->show('main_template', array('_get' => 'OLOLO'));
Template::__set определена, __get — нет. Зачем передавать еще один массив в функцию show? Почему вместо этого не сделать метод assign? Зато вызывается __set при передаче массива — лишний код и лишние вызовы.
Существование переменных и индексов автора вообще не интересует. Пробуем: $this->template->show('main_template', null);
Полная чехарда с ошибками и исключениями. Не найден каталог? Это исключение. Не найден файл? А это уже просто ошибка. Где логика? А в Loader::library, если нет файла — просто false возвращаем…
Везде обычный include. Таким образом $router->delegate()->delegate(); гарантированно вызывает падение.
Передача параметров по ссылке в метод класса!!! И это в 5-м PHP!!!
>> $class = 'Controller_'. $controller;
$controller = new $class();
Отлично! А если файл есть, а класса в нем нет? Где проверки на существование класса?
Зачем в контроллере loader и template сделаны публичными?
function __set($varname, $value) {
$this->$varname = $value;
return true;
}
Метод неплох, но есть несколько замечаний:
1. Инициализация кэша не должна выполняться внутри данного класса. У ZF для этого есть bootstrap и конфиг. Лучше сделать статические методы getCache и setCache, которые бы запускались из bootstrap.
2. Было бы неплохо указать, что этот класс работает только в PHP 5.3
Сайт сделан отвратно. Ежесекундные запросы на update.php для получения статуса — это бред. Почему нельзя было для этого использовать Socket.io — непонятно.
Ну и безапелляционный flash — тоже не радует. Могли бы в духе стартапа сделать поддержку html5 audio.
[conspiracymode=«On»]
Это гугл спровоцировал утечку, чтобы потом показать, что: «Пользователям Google Chrome ничего не угрожает так как он проверяет валидность сертификатов онлайн.»
Огнелису еще обновляться нужно, а пользователи Хрома уже вне опасности.
[conspiracymode=«Off»]
Если же говорить о конкретно вашем случае, с использованием только Table Gateway, то я бы делал так:
Пусть нам изначально ставят задачу вывести список юзеров. Нет ничего проще.
class Users extends Zend_Db_Table_Abstract
{
protected $_primary = 'id';
public function getAll()
{
return $this->fetchAll();
}
}
Казалось бы, ну что за идиотизм делать такую функцию, кому она нужна, если можно напрямую вызвать fetchAll???
Но тут начальство ставит нам задачу: выводить список юзеров + количество комментариев каждого юзера.
Все, что нам нужно, слегка модифицировать наш метод:
class User extends Zend_Db_Table_Row_Abstract
{
protected $_commentsCount = 0;
public function init()
{
parent::init();
if (array_key_exists('commentsCount', $this->_data)) {
$this->_commentsCount = (int)$this->_data['commentsCount'];
unset($this->_data['commentsCount']);
}
}
public function getCommentsCount()
{
return $this->_commentsCount;
}
}
class Users extends Zend_Db_Table_Abstract
{
protected $_primary = 'id';
protected $_rowClass = 'User';
public function getAll()
{
$select = $this->select()
->from(array('u' => 'Users'))
->joinLeft(array('c' => 'Comments'), 'c.user_id = u.id', array(
'commentsCount' => new Zend_Db_Expr('COUNT(c.*)')
))
->group('u.id');
return $this->fetchAll($select);
}
}
При таком решении никаких изменений в контроллере не потребуется.
Не нравятся join'ы??? Можно и без них, если правильно настроено кэширование:
class User extends Zend_Db_Table_Row_Abstract
{
protected $_commentsCount;
public function getCommentsCount()
{
if ($this->_commentsCount === null) {
/**
* @var Zend_Db_Table_Abstract $comments
*/
$comments = $this->getTable()->getReference('Comments');
$select = $comments->select()
->columns(array('commentsCount' => new Zend_Db_Expr('COUNT(*)')))
->where('user_id = ?', $this->id);
$row = $comments->fetchRow($select);
$this->_commentsCount = (int)$row->commentsCount;
}
return $this->_commentsCount;
}
}
class Users extends Zend_Db_Table_Abstract
{
protected $_primary = 'id';
protected $_rowClass = 'User';
public function getAll()
{
return $this->fetchAll();
}
}
Как показывает опыт, новички сначала слизывают один в один, а потом уже в процессе работы начинают думать и понимать — в этом и заключается понятие «профессиональный рост». Да, в простейшем случае внутри getAllProducts будет только вызов fetchAll, но если позже потребуется добавить доп. функционал, то разработчик без опыта не станет рефакторить вызовы fetchAll в getAllProducts, а начнет добавлять копипастом новый функционал прямо в контроллер (или где у него будет этот fetchAll вызываться). Так вот если новичок все равно будет слизывать, так пусть он уже слизывает нормальный код и правильные подходы.
И я автора не отчитывал. Просто высказал свое мнение.
Два последних моих суждения, возможно, и не относятся к теме статьи, но я настаиваю на том, что применение fetchAll — это плохо. И совершенно ни к чему учить новичков сходу такой не очень хорошей практике. Впрочем, статья — ваша, а мнение — мое. Решать вам и вашим читателям.
Использовать встроенные методы Zend_Db_Table_Abstract — плохая практика с точки зрения моделирования. Лучше добавлять в свой класс методы getAllProducts и т.д.
А вообще, еще лучше не пользоваться напрямую Zend_Db, а отделять модель и маппер.
А кэш к таким моделям лучше делать декоратором — тогда вручную вызывать кэшер не нужно будет.
Да. Есть __set — этот метод модифицирует внутреннее состояние класса, а метод show по логике не должен модифицировать внутреннее состояние класса, так как его назначение на основании предопределенного внутреннего состояния выдать какой-то результат. Вы же создали путаницу, добавив в метод show изменение внутреннего состояния класса. Это не смертельно, но это очень нелогично и вносит путаницу. Лучше создать метод assign, который будет заносить данные из массива.
>> Вместо PDO написал некий класс, названный мной как Active Records
Это напоминает мне «принципиально новую ОС с нескучными обоями». Мало того, что PDO написан и оттестирован десятками разработчиков, так он еще и в разы быстрее, так как это native расширение. Итог: сэкономили на спичках.
>> Переписан немного класс Template, добавлена возможность делать вложенные шаблоны
Убейте меня, не нашел там вложенных шаблонов.
>> extract($this->vars);
Это сразу премия Дарвина в ИТ. Попробуйте ради интереса выполнить что-то типа $this->template->show('main_template', array('_get' => 'OLOLO'));
Template::__set определена, __get — нет. Зачем передавать еще один массив в функцию show? Почему вместо этого не сделать метод assign? Зато вызывается __set при передаче массива — лишний код и лишние вызовы.
Существование переменных и индексов автора вообще не интересует. Пробуем: $this->template->show('main_template', null);
Полная чехарда с ошибками и исключениями. Не найден каталог? Это исключение. Не найден файл? А это уже просто ошибка. Где логика? А в Loader::library, если нет файла — просто false возвращаем…
Везде обычный include. Таким образом $router->delegate()->delegate(); гарантированно вызывает падение.
Передача параметров по ссылке в метод класса!!! И это в 5-м PHP!!!
>> $class = 'Controller_'. $controller;
$controller = new $class();
Отлично! А если файл есть, а класса в нем нет? Где проверки на существование класса?
Зачем в контроллере loader и template сделаны публичными?
function __set($varname, $value) {$this->$varname = $value;
return true;
}
Что еще за бред?
1. Инициализация кэша не должна выполняться внутри данного класса. У ZF для этого есть bootstrap и конфиг. Лучше сделать статические методы getCache и setCache, которые бы запускались из bootstrap.
2. Было бы неплохо указать, что этот класс работает только в PHP 5.3
Ну и безапелляционный flash — тоже не радует. Могли бы в духе стартапа сделать поддержку html5 audio.
Это гугл спровоцировал утечку, чтобы потом показать, что: «Пользователям Google Chrome ничего не угрожает так как он проверяет валидность сертификатов онлайн.»
Огнелису еще обновляться нужно, а пользователи Хрома уже вне опасности.
[conspiracymode=«Off»]
weierophinney.net/matthew/archives/202-Model-Infrastructure.html
weierophinney.net/matthew/archives/201-Applying-ACLs-to-Models.html
weierophinney.net/matthew/archives/200-Using-Zend_Form-in-Your-Models.html
Если же говорить о конкретно вашем случае, с использованием только Table Gateway, то я бы делал так:
Пусть нам изначально ставят задачу вывести список юзеров. Нет ничего проще.
Казалось бы, ну что за идиотизм делать такую функцию, кому она нужна, если можно напрямую вызвать fetchAll???
Но тут начальство ставит нам задачу: выводить список юзеров + количество комментариев каждого юзера.
Все, что нам нужно, слегка модифицировать наш метод:
При таком решении никаких изменений в контроллере не потребуется.
Не нравятся join'ы??? Можно и без них, если правильно настроено кэширование:
И я автора не отчитывал. Просто высказал свое мнение.
А вообще, еще лучше не пользоваться напрямую Zend_Db, а отделять модель и маппер.
А кэш к таким моделям лучше делать декоратором — тогда вручную вызывать кэшер не нужно будет.
Перезапускает процесс node при каждом изменении исходников. Удобно применять на машине разработчика.