我对面向对象编程比较陌生。我非常理解这些概念,但实际上,我很难找到有关如何在我的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 Framework中使用模型的最佳做法是什么?任何人都可以推荐任何可以帮助我理解Zend Framework中的模型/视图困境的教程吗?
答案 0 :(得分:4)
一种可能性是在PHP中使用magic __set和__get方法。我在抽象的Model类中使用它们:
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中)更改为用户更紧凑和可读的格式。
至于控制器中的内容,我建议您查看this post以获取有关放置在控制器内的处理方式的具体反馈。
有些人觉得他们宁愿有一个帮手,可以自动将模型加载到视图中并完全绕过控制器。我个人会说,在Zend Framework和PHP的上下文中,将模型传递到控制器的视图是很有意义的,因为视图中模型的状态经常取决于来自请求的内容(应该绝对应该处理)在控制器中。)
更新:根据评论中的批评,我要指出的一件事是你的数据库访问层和域(或模型)层实际上是两个不同的东西,尽管有Active Record它们混合在一起。我曾经问this question一段时间,并收到了一些关于此事的有用反馈。无论您决定使用该模型,您都希望为所有域对象提供一致的API,无论模型的数据来自何处。
我认为Saem的答案提供的一个好处是它提供了将属性/函数返回值从一个或多个域对象直接映射到视图对象的功能。从理论上讲,视图中的用法如下所示:
// Mapped from Model_User::_data->last_name and Model_User::_data->first_name
$this->name
答案 1 :(得分:3)
如果只有其他开发人员使用模板,我建议只传入模型。以下是MVC Understanding Model-View-Controller
上Jeff Atwood帖子的链接答案 2 :(得分:3)
这不是特别针对zend框架,但在我看来,这个问题相当普遍。
似乎你在正确的道路上,而不是在控制器内部将模型硬连接到视图。你宁愿有这样的摘要,如果你要映射一吨模型,或者一遍又一遍地映射同一个模型,那就特别重要了。
一些简单的事情就是编写一堆映射函数,如果你所避免的只是一遍又一遍地映射相同的东西就没问题。
如果你想要一个更通用的解决方案,这也解决了避免编写锅炉板代码,并保持更干燥,我建议创建一个mapper类。
您可以创建一个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
}
}
然后你可以在你的控制器上实现这个,并设置映射,这样控制器仍然可以控制映射,但所有控制器映射都集中了所有的样板和编码逻辑,除了极少数例外。
答案 3 :(得分:1)
为了更好地阅读模型架构,read this post。它没有具体谈论这个观点,但它绝对值得一读。
我最终在我的模型中添加了getViewClass()
功能。控制器调用此函数来获取它本来无法访问的受保护变量,并且视图不必担心调用任何getter。
//controller
$object = new Object();
$object->setName('Foo Bar');
$this->view->object = $object->getViewClass();
//view template
<h2><?= $this->object->name ?></h2>
我不知道是否有更好的方法可以在Zend Framework中完成工作,但这是一个解决方案。