【问题标题】:How to correctly pass data from controller to view?如何正确地将数据从控制器传递到视图?
【发布时间】:2013-09-22 23:34:12
【问题描述】:

我目前的实现:

class SomeController extends AppController
{
    function someaction()
    {   
        $d['text'] = "ahoy!";
        $this->render("someactionView", $d);
    }
}

AppController:

function render($file, $data = "")
{
    require "views/" . $file . ".php";
}

$data 将在视图文件中可用。这是一个正确的实现吗?这个实现有什么谬误吗?

【问题讨论】:

  • 如果 Controller 负责绘制/需要 HTML(如您的示例中所示),那么控制器已经侵犯了 View 的责任。如果视图可以具有表示逻辑(例如,用于绘制表格的循环),那么该逻辑应该在视图中,可以在类的方法中。

标签: php model-view-controller


【解决方案1】:

$data 将在视图文件中可用。这是一个正确的 执行?这个实现有什么谬误吗?

基本上你确实像大多数框架一样实现它。这样做有几个问题:

  • 控制器接受输入并发送输出(这违反了单一职责原则)
  • 视图与 HTML 紧密耦合。因此,您不能将相同的视图重复用于其他内容,例如 XML、JSON。
  • 如果您在render() 方法中执行require "views/" . $file . ".php"; - 您再次紧密耦合它。如果更改视图的位置怎么办?然后你将不得不稍微重写你的方法。这种方法只会扼杀重用能力。

刷新你的基础知识:

控制器(也称为编辑器)

仅用于单一目的。它改变模型状态——也就是说,它应该接受来自$_POST$_GET$_FILES$_COOKIE的输入。在控制器中,只应完成变量分配,仅此而已

class Controller
{
   public function indexAction()
   {
        $this->view->setVar('age', $this->request->getPostParam('age'));
        $this->view->setVar('user', $this->request->getPostParam('user'));
        //...
   }
}

查看

视图可以直接访问模型。为了使视图更具可重用性和可维护性,您最好将所需的东西作为函数参数(或通过 setter)传递

class View
{
   public function render($templateFile, array $vars = array())
   {
      ob_start();
      extract($vars);
      require($templateFile);

      return ob_get_clean();
   }
}

应该如何初始化视图以及如何将变量传递给它?

首先 - 视图应该在 MVC-triad 之外实例化。由于控制器写入视图或模型 - 您可以通过控制器将变量传递给视图。

$model = new Model();
$view = new View($model);

$controller = new Controller($view);

// This will assign variables to view
$controller->indexAction();

echo $view->render();

注意:在现实世界的场景中,模型不是类,而是抽象层。我称之为Model 用于演示目的。

【讨论】:

  • 很高兴在这里看到一些更新。您能解释一下示例中视图如何与模型通信吗?初始化视图、模型和控制器的组件是如何调用的?
  • @hek2mgl 1) 视图直接与模型通信 - 通过factories/service locators 2) 它被称为Front Controller。它由几个组件组成(Router、Dispatcher、Response sender)。问题是:它通过一个地方管理所有请求。你可以在Zend Framework/library/Mvc 看到它的整体实现。至于一个好的开始,我推荐这个r.je/mvc-in-php.html
  • 首先,目前我更多的是一个shell脚本编码器。上次我编写网络代码时,我有:路由器根据请求创建控制器,控制器(演示者,我学到了)然后与模型通信并将结果传递给视图。视图封装了模板渲染、翻译、动态 javascript 等功能。我读过那个MVP,这正是我的意思。模型和视图的初始化在该级别中编码,但演示者负责创建它们
  • 我仍然看不到视图与模型通信的位置在您的示例中。你只是从控制器传递$vars,就像我打电话给assign()。您还传递了一个像我这样的模板名称。区别在哪里(在您的示例中)?我看到的不同之处在于,您从FrontController 调用render() .. 这看起来很有趣..
  • @DaveJust ,它应该是 $controller = new Controller($model, $view); 除非同一模型有多个演示文稿,并且在一种特定情况下,用户无法影响模型层。
【解决方案2】:

IMO render() 方法属于视图而不属于控制器。代码应如下所示:

控制器:

class SomeController extends AppController
{
    function someaction()
    {   
        $d['text'] = "ahoy!";
        $view = new SomeActionView();
        $view->assign('data', $d);
        echo $view->render();
    }
}

查看基类:

class View
{

    protected $data;

    function render($template) {
        ob_start();
        // you can access $this->data in template
        require "views/" . $template . ".php";
        $str = ob_get_contents();
        ob_end_clean();
        return $str;
    }


    function assign($key, $val) {
        $this->data[$key] = $val;
    }
}

扩展视图类

class SomeActionView extends View
{

    public function render($template = 'someActionTemplate') {
        return parent::render($template);
    }

}

【讨论】:

  • 我认为 your 的尝试是错误的,但没有否决。尽管一些文献表明视图可以与模型通信,但我不会这样做。另外我认为有多种方法可以给猫剥皮。
  • 是的,“一些文学”是由 Fowler、Burbeck、Evans 和 Cunningham 等人创作的。你的文学作品是由 37signals 制作的。
  • 我只是把问题简单化了。当然模板加载会有它自己的逻辑。
【解决方案3】:

这是一个正确的实现吗?这个实现有什么谬误吗?

简短的回答:没有和几个。

首先,你所拥有的没有一个视图。这只是一个愚蠢的php template。 MVC 中的视图是实例,包含应用程序的 UI 逻辑。他们从模型层提取信息,并根据收到的信息创建响应。此响应可以是简单的文本、JSON 文档、由多个模板组合而成的 HTML 页面或只是一个 HTTP 标头。

对于控制器,它的唯一任务是改变模型层的状态和(在极少数情况下)当前视图。控制器初始化视图也不填充模板。

【讨论】:

  • 那么视图应该如何初始化,变量应该如何传递给它呢?
  • 我不会确认这一点。如果您不将数据从控制器填充到视图,则视图不再是独立的,并且视图和模型之间存在强耦合。
  • @evening ,视图将在控制器外部实例化并作为依赖项传入。视图的数据不会被传入,而是视图会从模型层调用服务并获取它需要的所有数据。这也意味着视图是为模型层的特定接口制作的。
  • @tereško 这是一个非常值得怀疑的设计。可以做到,但正如我所说,这会给视图和模型之间的强耦合。
  • 请去阅读“紧耦合”到底是什么以及原因是什么,因为你显然不知道你在说什么。
猜你喜欢
  • 1970-01-01
  • 2013-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多