模型 - 视图 - 控制器新视角

时间:2013-06-24 06:29:57

标签: php

大家早上好。最近我读了一篇关于mvc模式的文章说大多数php框架都实现了mvc模式错误。 php master mvc pattern part 1 php master mvc pattern part 2 读完这篇文章并查看该实现后,出现了一个问题。 如何在视图中调用模型中调用的方法?我想说的就是这个。 这是本文的一段代码。

<?php
$model = $_GET['model'];
$view = $_GET['view'];
$controller = $_GET['controller'];
$action = $_GET['action'];

if (!(empty($model) || empty($view) || empty($controller) || empty($action))) {
    $m = new $model();
    $c = new $controller($m, $action);
    $v = new $view($m);
    echo $v->output();
} 

让我们说在阅读本文后我们已经编写了这个设计模式的一个小实现,我们有以下代码:

<?php
class Index extends Controller
{
   public function __construct(IndexModel $model, $action)
   {
       $this->model = $model;
   }
   public function someAction($id)
   {
       $this->model->getData($id);
   }
}
class Index extends View
{
   public function __construct(IndexModel $model, $action)
   {
       $this->model = $model;
   }
   public function someAction()
   {
       $this->model->getData();
   }
}
class Index extends Model
{
   public function __construct()
   {
        //Some Code Here
   }
   public function someAction()
   {
       // Inserting Data into database.
   }
}

正如您所看到的,我们在控制器和视图中调用相同的方法来从数据库中获取数据。但是,如果我知道正确的视图应该照顾控制器的工作,所以$ id不适合在视图中再次解析它或类似的东西。然后如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

  1. 控制器与模型部件之间没有1:1的相关性(注意:不是“模型”,但模型_ 的部分)。仅仅因为你有一个“索引控制器”并不意味着你需要一个“索引模型”和“索引视图”。
  2. M,V和C不是一起构造的。构造控制器,然后 it 决定加载/构造/调用哪个模型方法以及哪个视图应该响应请求。
    1. 讨论控制器是否应该调用视图,或者模型是否应该“更新”视图。由于Web请求是短暂的,并且没有“常量”视图,后者在PHP中没有多大意义;它更适合原始的SmallTalk或Obj-C或类似的环境。
  3. 第一个代码段使用了empty(请参阅here),同样不应该将所有部分组合在一起。
  4. MVC应该像这样接近:

    • 模型 应用。它不仅仅是一个“数据处理程序”或“数据存储”,它还是核心应用程序。应用程序所做的一切,业务逻辑明智,都是“模型”。这包括发送电子邮件通知,数据库维护工作和此类辅助工具,它们都在模型中。
    • 该视图负责产生各种形式的输出。视图应该能够与模型交互以获取完成其工作所需的数据。数据不应该“推入”视图,视图应该能够“拉”所需的数据;否则视图外部的东西需要知道视图需要什么数据,这意味着视图逻辑不再自包含在视图中。
    • 控制器只是为了响应传入的请求而调用正确的模型方法和视图的一点点胶水。

    我通常会像这样构建这些部分:

    • 该模型由各种部分组成,包括数据存储处理程序,“基元”(模拟各个业务对象的类)和“服务”。 “服务”包含您的应用可以执行的所有“操作”并形成模型API。无论何时你想在应用程序中“做”某些事情,比如“注册用户”或“获取日期范围X到Y的所有记录”,服务API中都有一个专用方法。只需查看此服务API,您就应该能够枚举应用程序“执行”的所有内容。
    • 有一个对象是“调度程序”或“服务定位器”,或者只是一个依赖注入容器,它简化了这些服务类的实例化并允许某人调用它们。控制器获取其中一个,视图也是如此。
    • 有一个路由器根据URL执行一些“粗略路由”,调用控制器方法。控制器进一步查看请求的详细信息,并决定调用模型方法和/或以视图进行响应。
    • 视图可以决定基于请求的细节呈现一些数据的最佳方式,例如,是否响应HTML页面或JSON数据blob。是的RESTful服务。

    粗略的伪代码:

    $r = new Router;
    $r->route($_GET, $_POST, $_SERVER); // or something like that
    

    这会发送到:

    class FooController {
    
        public function __construct(ServiceLocator $services) { ... }
    
        public function bar(Request $request) {
            $request->assertIsPost();
            $this->services->locate('Baz')->froogleTheWibbles($request->getPostParams());
            (new BarView($this->services))->displayWibbles($request);
        }
    
    }
    
    class BarView {
    
        public function __construct(ServiceLocator $services) { ... }
    
        public function displayWibbles(Request $request) {
            switch ($request->accepts()) {
                case 'html' :
                    $this->loadTemplate(...);
                    ...
                case 'json' :
                    echo json_encode($this->services->locate('Baz')->getWibbles());
            }
        }
    
    }
    

    模型可以做任何需要做的事情......

    class Baz {
    
        public function froogleTheWibbles(array $data) {
            foreach ($data as $wibbleData) {
                $wibble = new Wibble($wibbleData);
                $this->wibbleStore->save($wibble);
            }
            ...
        }
    
    }
    

    对于MVC没有“一个答案”,重要的是该模型包含您的应用程序“做”的所有内容,与输入和输出无关,视图可以根据请求尽可能独立地生成正确的输出,控制器是只是处理输入条件的一点胶水。有各种方法可以实现这一点。重要的设计原则应该是视图和控制器可以互换以适应不同的条件(网页,JSON API,XML API,SOAP API,CLI调用,ZeroMQ节点等),但“模型”不是。< / p>