ViewHelper новая / вводимая дилемма
Я пытаюсь разработать приложение, следуя указаниям Misko Heverys. Это интересный эксперимент и вызов. В настоящее время я борюсь с моей реализацией ViewHelper.
ViewHelper отделяет модель от вида. В моей реализации он оборачивает модель и предоставляет API для представления. Я использую PHP, но я надеюсь, что реализация понятна для всех:
class PostViewHelper {
private $postModel;
public function __construct(PostModel $postModel) {
$this->postModel = $postModel;
}
public function title() {
return $this->postModel->getTitle();
}
}
В моем файле шаблона (представления) это можно назвать так:
<h1><?php echo $this->post->title(); ?></h1>
Все идет нормально. У меня проблема, когда я хочу прикрепить фильтр к ViewHelpers. Я хочу иметь плагины, которые фильтруют вывод вызова title(). Метод станет таким:
public function title() {
return $this->filter($this->postModel->getTitle());
}
Мне нужно, чтобы там присутствовали наблюдатели, или EventHandler, или какой-либо другой сервис (в том, что я считаю новым, так что его нужно передавать через стек). Как я могу сделать это, следуя принципам Misko Hevery? Я знаю, как я могу сделать это без этого. Меня интересует, как я могу это принять, и в настоящее время я не вижу решения. ViewHelper также может быть инъецируемым, но проблема в получении модели.
1 ответ
Я не нашел пост в блоге, на который вы ссылаетесь, очень интересным или проницательным.
То, что вы описываете, больше похоже на Decorator, чем на внедрение зависимостей. Внедрение зависимостей - это способ построения графов объектов, а не их состояния после создания.
Тем не менее, я бы предложил взять ваш шаблон Decorator и работать с ним.
interface PostInterface
{
public function title();
}
class PostModel implements PostInterface
{
public function title()
{
return $this->title;
}
}
class PostViewHelper implements PostInterface
{
public function __construct(PostInterface $post)
{
$this->post = $post;
}
public function title()
{
return $this->post->title();
}
}
class PostFilter implements PostInterface
{
public function __construct(PostInterface $post)
{
$this->post = $post;
}
public function title()
{
return $this->filter($this->post->title());
}
protected function filter($str)
{
return "FILTERED:$str";
}
}
Вы бы просто использовали любой DI-фреймворк для построения этого графа объектов следующим образом:
$post = new PostFilter(new PostViewHelper($model)));
Я часто использую этот подход при построении сложных вложенных объектов.
Одна из проблем, с которой вы можете столкнуться - это определение "слишком много" функций в вашем PostInterface
, Это может быть боль, чтобы реализовать их в каждом классе декоратора. Я использую магические функции PHP, чтобы обойти это.
interface PostInterface
{
/**
* Minimal interface. This is the accessor
* for the unique ID of this Post.
*/
public function getId();
}
class SomeDecoratedPost implements PostInterface
{
public function __construct(PostInterface $post)
{
$this->_post = $post;
}
public function getId()
{
return $this->_post->getId();
}
/**
* The following magic functions proxy all
* calls back to the decorated Post
*/
public function __call($name, $arguments)
{
return call_user_func_array(array($this->_post, $name), $arguments);
}
public function __get($name)
{
return $this->_post->get($name);
}
public function __set($name, $value)
{
$this->_post->__set($name, $value);
}
public function __isset($name)
{
return $this->_post->__isset($name);
}
public function __unset($name)
{
$this->_post->__unset($name);
}
}
Используя этот тип декоратора, я могу выборочно переопределить любой метод, который мне нужен для обеспечения декорированной функциональности. Все, что я не перезаписываю, передается обратно в базовый объект. Множество декораций может происходить при сохранении интерфейса нижележащего объекта.