ViewHelper новая / вводимая дилемма - PullRequest
4 голосов
/ 15 января 2010

Я пытаюсь разработать приложение, следуя Misko Heverys insights . Это интересный эксперимент и вызов. В настоящее время я борюсь с моей реализацией 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 Ответ

4 голосов
/ 05 февраля 2010

Я не нашел сообщение в блоге, на которое вы ссылались, очень интересным или проницательным.

То, что вы описываете, больше похоже на 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);
    }
}

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

...