9

我对面向对象编程比较陌生。我非常了解这些概念,但实际上,我很难找到有关如何在我的 Zend Framework 应用程序中最好地使用模型的信息。

具体来说,我有一个不使用数据库表的模型(不扩展任何东西)。它使用 getter 和 setter 来访问其受保护的成员。我发现自己在为如何在视图中最好地显示这个模型而苦苦挣扎。我不想在我的视图模板中使用逻辑,但我发现自己处于以下情况:

在我的控制器中:

$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object;

在我的视图模板中:

<h2><?= $this->object->getName() ?></h2>

我真的不喜欢在我的视图模板中调用函数,但我不知道更好的方法来做到这一点。我不希望我的模型成员公开,但我基本上希望达到相同的结果:

<h2><?= $this->object->name ?></h2>

我不希望我的控制器完成所有必须了解模型的所有工作:

$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object;
$this->view->object->name = $object->getName();

在 Zend 框架中使用模型的最佳实践是什么?任何人都可以推荐任何可以帮助我理解 Zend 框架中的模型/视图困境的教程吗?

4

4 回答 4

4

一种可能性是在 PHP 中使用神奇的 __set 和 __get 方法。我在我的抽象模型类中使用它们:

abstract class Model_Abstract
{
    protected $_data;

    // Private Data Members assigned to protected $_data
    public function __construct($data = null)
    {
        // Makes it so that I can pass in an associative array as well as 
        // an StdObject.
        if(!is_object($data)) {
            $data = (object) $data;
        }

        $this->_data = $data;

    }

    public function __get($key)
    {
        if (method_exists($this, '_get' . ucfirst($key))) {
            $method = '_get' . ucfirst($key);
            return $this->$method();            
        }
        else {
            return $this->_data->$key;
        }   
    }

    public function __set($key, $val)
    {
        if ( method_exists( $this, '_set' . ucfirst($key) ) ) {
            $method = '_set' . ucfirst($key);
            return $this->$method($val);            
        }
        else {
            $this->_data->$key = $val;
            return $this->_data->$key;
        }
    }
}


class Model_User extends Model_Abstract
{
    //Example overriding method for the property firstName in the $_data collection.
    protected function _getFirstName()
    {
        // Do some special processing and then output the first name.
    }
}

这使得您可以根据需要为属性指定 getter 和 setter,但这样您就不必为每个属性定义样板函数,只需在返回之前对其进行某种处理的那些价值。例如,我在许多地方使用该功能将符合 ISO 标准的日期(存储在 MySQL 中)更改为更紧凑、更易于用户阅读的格式。

至于在您的控制器中放置什么,我建议您查看这篇文章以获取有关在控制器中放置什么处理的一些具体反馈。

有些人觉得他们宁愿有一个助手来自动将模型加载到视图中并完全绕过控制器。我个人会说,在 Zend Framework 和 PHP 的上下文中,将模型从控制器传递到视图中是很有意义的,因为视图中模型的状态通常取决于来自请求的内容(绝对应该处理在控制器中)。

更新:根据评论中的批评,我要指出的一件事是,您的数据库访问层和域(或模型)层实际上是两个不同的东西,尽管使用 Active Record,它们混合在一起。不久前我问了这个问题,并收到了一些关于这个问题的有用反馈。无论您决定对模型做什么,您都希望为所有域对象提供一致的 API,而不管模型的数据来自何处。

我想 Saem 的回答提供的一个好处是,它提供了将属性/函数返回值从一个或多个域对象直接映射到视图对象的能力。从理论上讲,视图中的用法如下所示:

// Mapped from Model_User::_data->last_name and Model_User::_data->first_name
$this->name 
于 2009-03-02T22:47:51.777 回答
3

如果只有其他开发人员要使用模板,我建议只传递模型。这是 Jeff Atwood 关于 MVC理解模型-视图-控制器的帖子的链接

于 2009-03-02T21:04:14.210 回答
3

这并不是特别适合 zend 框架,但在我看来,这个问题相当普遍。

看来您走在正确的道路上,而不是在控制器内部将模型硬连接到视图。如果您要映射大量模型或一遍又一遍地映射同一个模型,您宁愿拥有那个抽象,这一点尤其重要。

一些简单的方法是编写一堆映射函数,如果你要避免的只是一遍又一遍地映射相同的东西,那就没问题了。

如果您想要一个更通用的解决方案,同时也解决了避免编写样板代码并保持更干燥的问题,我建议创建一个映射器类。

您可以创建一个 ViewModelMapper,它将采用一个模型或几个模型并将它们映射到视图。

class ViewModelMapper
{
    public function __construct($view)
    {
        //set the properties
    }

    public function addModel($model, $overrideViewProperty = null)
    {
        //add the model to the list of models to map, use the view's property 
        // name to figure out what to map it to? Allow for an override just in case.
    }

    public function getMappedView()
    {
        //take the view, map all the models
    }
}

然后,您可以在控制器上实例化它,并设置映射,因此控制器仍然控制映射,但是对于所有控制器映射,所有样板和编码逻辑都是集中的,除了极少数例外。

于 2009-03-02T21:31:45.593 回答
1

要深入了解模型架构,请阅读这篇文章。它没有具体谈论观点,但绝对值得一读。

我最终getViewClass()为我的模型添加了一个功能。控制器调用此函数来获取它原本无法访问的受保护变量,并且视图不必担心调用任何 getter。

//controller
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object->getViewClass();

//view template
<h2><?= $this->object->name ?></h2>

我不知道是否有更好的方法可以在 Zend 框架中完成这项工作,但这是一种解决方案。

于 2009-03-10T05:14:07.733 回答