【问题标题】:mvc best practice view/controller/model in php and yiiphp 和 yii 中的 mvc 最佳实践视图/控制器/模型
【发布时间】:2012-06-06 05:27:24
【问题描述】:

这是一个最佳实践问题,而不是具体问题。 我对 MVC 方法和 Yii 相当陌生,并且已经在应用程序上开发了一段时间。我不断看到关于最佳实践以及将什么放入哪个文件(控制器、模型、视图、助手等)的讨论,但是我还没有找到任何具体的示例。

我目前在我的视图文件中有类似 Model::function() 的调用以及类似 $var = app()->request->getParam(value, false); 的检查

我的控制器文件中有调用,例如 Model::function() 和 Model::model()->scope1()->scope2()->findAll() 我也认为我的控制器文件有点厚,但不知道如何以及在哪里放置一些膨胀,我一直在阅读有关 DRY 的内容,我认为我并没有完全干燥我的代码。 你能给我一个更清楚的图片吗?什么去哪里,以及建议或原因:) 感谢任何建议,在此先感谢。

这是一个视图文件中的示例调用

<?php
$this->pageTitle = 'Edit Action';
$this->subTitle = '<i>for</i> <b>' . Vendors::getName($_GET['vendor']) . '</b>';
?>

<div class="wrapper">
<?php echo $this->renderPartial('_form', array('model' => $model)); ?>
</div>

getName 是我在模型中的函数,这是在视图中调用函数的好方法吗?

另一个示例视图文件:

<div class="wrapper">
    <?php 

    if($this->action->id != 'create') {
        $this->pageTitle = "New Media Contact";
         echo $this->renderPartial('_form', array('model'=>$model));
    } else {
        $this->pageTitle = "New Vendor";
         echo $this->renderPartial('_form', array('model'=>$model));
    }
    ?>
</div>

$model 在控制器中设置为类型... 同样的问题......可以这样做......更清洁......?在 MVC 和可重用性/DRY 方面更好?

编辑 在阅读了这里的一些回复之后,尤其是。 @Simone 我重构了我的代码,并想分享它现在的样子......

public function actionCreate() {
    $model = new Vendors;

    // Get and Set request params
    $model->type = app()->request->getParam('type', Vendors::VENDOR_TYPE);
    $vendorsForm = app()->request->getPost('Vendors', false);
    // Uncomment the following line if AJAX validation is needed
    $this->performAjaxValidation($model);
    if ($vendorsForm) {
        $model->attributes = $vendorsForm;
        if ($model->save())
            $this->redirect(array('/crm/vendors', array('type' => $model->type)));
    }
    $model->categories = Categories::getAllParents($model->type);
    $this->pageTitle = 'New ' . Lookup::item('VendorType', $model->type);
    $this->render('create', array(
        'model' => $model,
    ));
}

和视图 create.php

<div class="wrapper">
<?php echo $this->renderPartial('_form', array('model'=>$model));?>

感谢大家的回复

【问题讨论】:

  • 就您的问题而言,它可能会被关闭。也许发布一个具体的例子?
  • 你已经在使用 Yii .. 它本身就将最佳实践抛诸脑后
  • @tereško 请解释一下您的意思,yii 没有使用最佳实践?您建议改用哪个框架?我一直在看 Symfony,并且确实喜欢大量的文档等,但 yii 在大多数情况下都非常容易使用......
  • @SeventySix ,当然 ... 使用全局状态,使用 eval(),使用紧密耦合,使用 @ 进行错误抑制,深度继承层次结构,不明确的接口,计算__construct()方法,静态工厂方法的使用..等等
  • @teresko,这超出了我目前的理解......你有没有可以推荐的更好实践的框架?

标签: php model-view-controller yii


【解决方案1】:

我对 Yii 框架不太熟悉,但可以就你提到的一些具体事情提供一些建议:

不要太拘泥于“最佳实践”,因为所有设计模式 MVC 都可以实现,并且在某些情况下,不同的开发人员可以以多种不同的方式进行解释。那么这是什么意思?这意味着尽可能多地阅读 MVC,然后只需试一试 :o) 当你遇到问题时,你很快就会发现哪些插槽在哪里以及为什么会出现问题(通常是“这在哪里做的”属于,控制器还是模型?...'。

关于什么去哪里,你可以谷歌/搜索 stackoverflow 或阅读无数书籍,许多关于应该做什么和去哪里的解释,但是从你提供的代码 sn-p 我会建议:

查看文件:(除非这是 Yii 特定的东西)在我看来,您的查看文件有点脏。您正在直接与模型交谈(这实际上是 MVC 的经典方法,而不是某些 PHP 应用程序采用“控制器是唯一允许与模型交谈”的方法),但您的视图似乎正在尝试获取请求数据直接,对我来说,这不应该在视图附近的任何地方。控制器应该处理请求,使用模型进行验证,然后将输出传递到视图中。

Model:从小 sn-p 看来这似乎没问题,但总的来说,要记住的重要一点是 model != database(尽管有人建议它是)。

控制器: 从你的 sn-p 看来还是不错的,但要解决你的控制器中的膨胀问题,如果没有看到你的一个控制器,就很难提供建议。始终值得考虑的一件事是服务的使用。基本上,一项服务可以通过封装大量重复/复杂的模型内容来大大简化您的控制器。因此,您无需在控制器中调用单独的验证和持久性模型,只需实例化一个服务类,这可能只是调用一个方法的情况(通常返回一个布尔值以向您的控制器指示操作的成功或失败)然后你的控制器只需要处理它最擅长(并且应该只做)应用程序的流程(即重定向到另一个页面,显示错误等)。

【讨论】:

  • 谢谢 STeve,好的,所以我了解了如何将 $this 用于控制器,但如果我要从控制器调用不同的模型,而不是它链接到的模型。发布帖子控制器或在我的情况下供应商 - >供应商控制器,但我需要模型类别中的类别名称标签......我应该怎么做......? $this->getCategory() 但似乎我正在将特定于类别的代码放在供应商控制器中......??对不起,如果我没有得到它......
  • 您应该尽量不要将模型链接到控制器,确实可以在您的应用程序的同一文件夹/模块下找到类别模型和控制器(实际上是出于组织目的)。但是模型可以在任何控制器中调用,但是你需要阅读 Yii 的方法。通常,您必须确保为此设置了自动加载器。我认为您绝对应该对服务进行研究,因为这些会简化您的控制器。
  • 只是认为我上面对文件夹组织的评论可能不适用于所有应用程序。有些只是使用通用模型、控制器文件夹,有些则使用更多模块的组织方式。使用 MVC 有很多好处,但始终将其中之一视为在应用程序中组织代码库的一种方式。我认为你确实需要牢牢掌握 OOP,这将使 MVC 更容易理解。
  • Steve 再次感谢您抽出时间回复。我已经在我的应用程序的模块文件夹中的一个模块内开发了我的应用程序,我想这样做,因为这些功能都是相关的,但现在我开始看到它有多大,并且可能不了解使用模块正确...我会按照你的建议研究服务,看看我如何可以分离一些功能以实现可重用性。
  • Well 模块通常是独立的“迷你应用程序”,因为理想情况下它们应该能够在项目之间互换。不幸的是,并非所有框架都支持此功能,但至少应使用模块将您的代码库组织成逻辑部分,例如“博客”、“管理员”、“前端”,但取决于应用程序的大小,您甚至可能想要将模块分解成更小的块(再次由您选择)。使用服务的好处之一是它可以从控制器中抽象出很多东西,并有助于保持精简。
【解决方案2】:

我将向您展示一个重构代码的示例。这是你的代码

<div class="wrapper">
    <?php 
        if($this->action->id != 'create') {
            $this->pageTitle = "New Media Contact";
            echo $this->renderPartial('_form', array('model'=>$model));
        } else {
            $this->pageTitle = "New Vendor";
            echo $this->renderPartial('_form', array('model'=>$model));
        }
    ?>
</div>

第一个问题是:为什么要用renderPartial 在同一行写两次?第一次重构:

<div class="wrapper">
<?php
    if($this->action->id != 'create') {
        $this->pageTitle = "New Media Contact";
    } else {
        $this->pageTitle = "New Vendor";
    }
    echo $this->renderPartial('_form', array('model'=>$model));
?>
</div>

现在是第二步:

<?php $this->pageTitle = $this->action->id != 'create' ? "New Media Contact" "New Vendor"; ?>

<div class="wrapper">
 <?php echo $this->renderPartial('_form', array('model'=>$model)); ?>
</div>

FOR ME 更具可读性。我觉得有很多最佳实践。但可能会成为在不良环境中使用的不良做法。所以... 重写代码真的有用吗?对我来说是的!因为我的目标是代码的可维护性。易于阅读,易于管理。但是你需要找到你的标准或你的团队标准。另外,我更喜欢在控制器中移动任何类型的逻辑。例如我可以在控制器中设置一个默认的 pageTitle 并在 actionCreate 方法中重新定义它:

class SomeController extends CController
{

    public $pageTitle = "New Vendor";

    function actionCreate ()
    {
        $this->setPageTitle("New Media Contact")
        $this->render('view');
    }

}

我的视图文件将变为:

<div class="wrapper">
    <?php echo $this->renderPartial('_form', array('model'=>$model)); ?>
</div>

我想我们要明白事物的责任:视图只是一个视图。

【讨论】:

  • 谢谢 Simone,这很有帮助示例似乎是一种非常糟糕的做法,那么应该如何学习呢?
  • 读完后我回顾了我的代码,并尝试将所有逻辑来确定控制器中的输出,但如果有更多类型,也要保持它的灵活性,所以我使用了请求字符串中带有类型的 Lookup::item('VendorType', $type) 函数。现在我遇到了访问控制的问题,因为一个角色被允许访问一种类型而不是另一种,但是在 yii 中似乎访问控制仅限于操作,而不是参数......
【解决方案3】:

只需将视图视为显示数据的组件。它不应该进行数据库调用、与模型交互、创建新变量(或很少)等。如果您想进行检查或使用某些数据创建 HTML 块等,请为此目的使用帮助程序。 视图将显示的数据将来自控制器。

控制器是 maestro,他将在您的应用中完成大部分工作:它会响应请求、在需要时向模型询问数据、将数据传递给视图并呈现它,等等。

在您的第一个示例中,只需将 Vendors::getName($_GET['vendor']) 保存在控制器中的变量中,然后将其传递给视图。
另外,如果您不需要model 的所有数据,请不要传递整个对象。

关于您的第二个 sn-p,首先您可以将 echos 从 if 语句中移出,因为它们是相同的。
一件好事是在您的控制器中检查if ($this-&gt;action-&gt;id != 'create'),并为您的视图提供一个简单的布尔值:

if ($this->action->id != 'create') { // not sure if $this->action->id would remain the same, I don't know Yii
    $media = true;
    // or 
    // $page = 'media';
} else {
    $media = false;
    // or 
    // $page = 'vendor';
}

根据控制器返回的值渲染部分。

【讨论】:

  • 谢谢您的帮助,您能否提供一个示例,说明您如何调用上述函数以及如何将其传递给视图?再次感谢现在更有意义:)
  • 抱歉,我不知道 Yii 是如何工作的,所以我不能告诉你如何做事。我相信它的文档可以帮助你。祝你好运! :)
  • 我同意,但我会说视图以只读方式与模型交互肯定不错,绝对同意直接从视图调用数据库但简单的模型数据 - 为什么要打扰有这个的控制器?我猜每个人都有自己的;o)
  • @SteveH 如果您的视图与您的模型有某种联系,那么您将失去抽象,不再使用 MVC。或者至少,不像 PHP 框架应该做的那样做 popular MVC。
  • 好吧,我认为我们必须同意不同意这一点(我想这强化了我对 OP 所说的话 - 开发人员解释)
【解决方案4】:

在我看来,没有“最佳实践”。只要您不是在团队中工作或希望将您的脚本作为开源发布(必须有数十人使用它),就可以根据您的喜好和需要使用该框架。即使您与其他人一起编写代码,也没有“上帝赐予”的规则。

如果您“真的被允许”在视图中使用静态函数,那么还有比问题更重要的事情。

【讨论】:

  • 谢谢,我实际上打算构建应用程序,以便团队可以参与开发,这就是我问的原因。既然我想在时机成熟时避免过多的重写,我不妨从一个好的笔记开始......
  • 如果你可以接受错误的(糟糕的?)方式做事,至少不要鼓励其他人也这样做。
  • @SamyDindane 您认为错误吗?在我看来错了吗?我的朋友迈克尔认为错了吗?在 yii 团队或 wordpress 团队看来?还是谁? @ SeventySix 只要您的团队使用相同的准则,这将没有问题。如果您使用 Yii,请尽可能遵循 Yii 指南。
  • @Oliver,是的,谢谢,但在您提到“没有最佳实践”时,我正在与一家拥有一百万美元开发预算的大公司的 CIO 交谈,他一直在告诉我最好的实践和关注点分离等,所以必须有一种方法来学习这些东西并应用它......
  • @Oliver,我感觉到了一些敌意,我之所以问,是因为我有兴趣找到一些建议,实用的建议,而 Stackoverflow 对我为各种障碍找到实用的解决方案提供了很大帮助,如我认为这是一个很棒的论坛,有才华横溢的人花时间帮助像我这样的新手。
猜你喜欢
  • 1970-01-01
  • 2015-10-22
  • 2014-03-09
  • 1970-01-01
  • 2011-09-16
  • 2011-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多