ViewHelper新的/可注射的困境

时间:2010-01-15 19:47:21

标签: viewhelper injectable newable

我正在尝试按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 个答案:

答案 0 :(得分:4)

我没有发现您引用的博客文章非常有趣或富有洞察力。

您所描述的内容似乎更像是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中定义“太多”功能。在每个装饰器类中都必须实现这些 pain 。我利用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);
    }
}

使用这种类型的装饰器,我可以有选择地覆盖提供装饰功能所需的任何方法。我没有覆盖的任何东西都会传回给底层对象。在保持底层对象的界面的同时,可以发生多个装饰。