【问题标题】:PHP MVC design - multiple actions to same url/controllerPHP MVC 设计 - 对同一 url/控制器的多个操作
【发布时间】:2012-07-20 21:01:34
【问题描述】:

在 MVC 模式中,当单个视图可能具有多个相同类型的操作(例如 POST)时,最好的处理方式是什么?

例如在 TODO 列表应用程序中。您可能允许用户创建多个列表。每个列表可以有多个项目。因此,用户导航到 site.com/list/1,它向他们显示了第一个列表中的所有项目(1 是 GET 参数)。然后此页面上有 2 个表单 (POST) 允许用户:

  1. 创建一个新项目
  2. 删除现有项目

如果引导程序创建一个“listcontroller”,检查 POST 变量,然后调用类似的适当方法:

$lc = new ListController();    
if(strtolower($request->verb) === 'post'):
    if(isset($_POST['title'])) :
        $data = $lc->newItem($_POST);
        $load->view('newitem.php', $data);
    else if(isset($_POST['delete']) && isset($_POST['id'])):
        $data = $lc->deleteItem($_POST);
        $load-view('deleteitem.php', $data);                    
    endif;// End if post title
else:
    //GET request here so show view for single list
endif; //

还是做类似的事情会更好

$lc = new ListController();
if(isset($_POST)):
    //controller handles logic about what function to call
    $data =  $lc->PostAction($_POST); 
    // $data could also potentially hold correct view name based on post
    $load->view(); 
else:
    //again just show single list
endif;

我只是在苦苦思索如何最好地让控制器处理多个不同的操作,因为可能有很多嵌套的 if/else 或 case 语句来处理不同的场景。我知道这些必须放在某个地方,但哪里最干净?

我知道那里有很多框架,但我正在经历它背后的整个“想了解最佳实践”阶段。或者这完全是错误的方法?控制器实际上应该采用不同的结构吗?

【问题讨论】:

    标签: php model-view-controller controller


    【解决方案1】:

    我认为后一种方法在某种程度上是正确的。但是,您不应该在引导程序中对动作调用进行硬编码。引导程序应该解释 URL 并通过使用像 call_user_func_array 这样的函数动态调用操作方法。

    另外,我建议您将视图的呈现留给操作代码,以便操作逻辑自给自足且灵活。这将允许该操作分析输入的正确性并适当地呈现错误或视图。此外,您的控制器上有“deleteItem”方法,但这应该是模型的工作。也许你应该在尝试实现自己的框架之前阅读更多关于 MVC 的内容并尝试使用现有框架来更好地理解这些概念(我建议你使用 Yii 框架)。

    这是一个我认为您的逻辑应该如何在一个好的 MVC 框架中实现的示例。

    class ListController extends BaseController
    {
        public function CreateAction($title){
            if(ctype_alnum($title))
            {
                $list = new List();
                $list->Title = $title;
                if($list->insert())
                {
                    $this->render_view('list/create_successful');
                }
                else
                {
                    $this->render_view('list/create_failed');
                }
            }
            else
            {
                $this->render_view('list/invalid_title');
            }
        }
    
        public function DeleteAction($id){
            $list = List::model()->getById($id);
    
            if($list == null)
            {
                $this->render_view('list/errors/list_not_found');
            }
            elseif($list->delete())
            {
                $this->render_view('list/delete_successful');
            }
            else
            {
                $this->render_view('list/delete_failed');
            }
        }
    }
    

    here is a great tutorial on how to write your own MVC framework

    【讨论】:

    • 谢谢。为了清楚起见,上面的 controller->deleteItem 方法只会调用一个处理删除的 DAO 对象。我没有明确调用控制器中的数据库函数。我对同一页面的多个请求的位置有点困惑,但我想这更多的是关于我如何处理“动作”以及我在我的 url 中构建它们的位置
    • 哦,好的,我明白了。无论如何,我认为您的引导程序在决定执行哪个控制器和操作时应该只分析 URL 请求,POST 数据不应该参与其中(在我看来)。正如你所说,更多的是关于你如何选择构建你的动作,我认为拥有DeleteCreate 动作而不是Post 动作更有意义,因为它们确实是两个不同的动作。您应该尝试研究 CRUD 模式,它与 MVC 配合得很好,可能会给您新的想法。
    【解决方案2】:

    首先,我真的很喜欢您如何处理 MVC 的实现。没有任何类似 rails 的模仿,其中视图是在控制器内部管理的。

    我认为这是您问题的根源:您仍在使用“愚蠢的视图”方法。

    视图不应该是“模板”的同义词。相反,它应该是一个完整的对象,它具有处理多个模板的知识和能力。此外,在大多数MVC-inspired 设计模式中,视图实例能够从model layer 请求信息。

    在您的代码中,问题可以追溯到视图的工厂($load->view() 方法),它只获取控制器发送的内容。相反,控制器应该只更改视图的名称,并且可能发送一些会更改 视图状态的内容。

    对您来说最好的解决方案是创建完整的视图实现。这样视图本身就可以从模型层请求数据,并根据它收到的数据决定使用哪个模板以及是否需要模型层的额外信息。

    【讨论】:

    • 我从来没有想过这样的观点。我总是习惯于对所有内容进行内联编码,但它变得一团糟,显然我喜欢并欣赏 MVC 结构带来的东西。我想在 PHP 中以这种风格编码时更多地理解概念和最佳实践,我很欣赏你在你提到的其他帖子中所写的内容。正如我在上面评论的那样,甚至可能通过 url 中的操作使其更具动态性可能有助于改善事情
    猜你喜欢
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多