最佳MVC实践
最佳MVC实践(Best MVC Practices)
Although Model-View-Controller (MVC) is known by nearly every Web developer, how to properly use MVC in real application development still eludes many people. The central idea behind MVC is code reusability and separation of concerns. In this section, we describe some general guidelines on how to better follow MVC when developing a Yii application.
虽然MVC已经被几乎所有的web开发者所熟知, 然而如何更好地应用到具体开发中仍然难倒了很多人. MVC的核心是代码重用和解耦. 围绕这个思想, 我们可以总结出一些关于更好遵循MVC去开发YII应用的基本方针.
为了更好的解释这些方针, 我们假设如下一个由多个子程序组成的web应用程序:
- front end: a public-facing website for normal end users;
- back end: a website that exposes administrative functionality for managing the application. This is usually restricted to administrative staff;
- console: an application consisting of console commands to be run in a terminal window or as scheduled jobs to support the whole application;
- Web API: providing interfaces to third parties for integrating with the application.
- 前台: 一个可以由普通用户公开访问的站点.
- 后台: 一个用于对你的web程序进行管理和函数化配置的站点, 一般仅限管理员访问.
- 控制台: 一个由在终端窗口执行的控制台语句或支撑整个应用的调度任务组成的程序.
- web api: 对第三方提供的接口.
子程序可以用模块来实现, 或者可以作为一个可以喝其它子程序共享代码的YII应用.
Models represent the underlying data structure of a Web application. Models are often shared among different sub-applications of a Web application. For example, a LoginForm model may be used by both the front end and the back end of an application; a News model may be used by the console commands, Web APIs, and the front/back end of an application. Therefore, models
1 模型
模型代表一个web应用的基础数据结构.模型通常被web应用中的不同子程序所共享.例如, 一个登陆表单模型可以被用在程序中的所有前端和后端; 一个新的模型可以被用在控制台命令, web apis, 以及程序的前端和后端,因此, 模型有以下特点:
- should contain properties to represent specific data;
- should contain business logic (e.g. validation rules) to ensure the represented data fulfills the design requirement;
- may contain code for manipulating data. For example, a SearchForm model, besides representing the search input data, may contain a search method to implement the actual search.
- 应该包含属性来代表特殊的数据
- 应该包含业务逻辑来保证被代表的数据满足设计需要.
- 应当包含数据操纵代码. 例如, 一个查询表单模型, 除了代表查询输入数据, 还需要包含一个方法来实现实际的查询动作.
一些时候, 根据上边最后一条规则, 让一个简单的类包含太多的代码, 会让模型变得很臃肿. 如果一个类包含很多目的,会变得很难维护. 例如, 一个新闻模型应该包含一个名叫获取最后一条新闻的方法, 这条方法仅被前台网站用到, 同时它还包括一个叫删除新闻的方法, 这个方法仅被后台使用对于一个小型或者中型应用来说, 上边的这种设计已经算不错了. 但对于一个大型应用, 下边的策略可以让你的model更易维护.
- Define a NewsBase model class which only contains code shared by different sub-applications (e.g. front end, back end);
- In each sub-application, define a News model by extending from NewsBase. Place all of the code that is specific to the sub-application in this News model.
- 定义一个新新基类model, 它仅仅包含被前后台都使用的代码.
- 在每一个子程序中, 定义一个新的model来继承基类model. 通过这种方法来实现子程序独有的特定功能/代码
假如我们在之前的例子中使用上边的策略, 就应该在前台网站创建一个model, 它包含一个获取最后一条新闻的方法, 同时我们也需要在后台添加一个model, 包含删除新闻的方法.
一般来说, models不应该包含直接被最终用户执行的逻辑. 比如下边这些model的特例:
model不应该使用$_GET, $_POST, 或其他直接从最终用户请求中获取的类似变量.请记住模型应该服务于不同的子程序, 它们不需要用到这些变量来模拟用户. 用户变量由控制器来负责更为合适.
Views are responsible for presenting models in the format that end users desire. In general, views
视图负责model在最终用户面前的展示.一般来说,视图具有下边特点:
- should mainly contain presentational code, such as HTML, and simple PHP code to traverse, format and render data;
- should avoid containing code that performs explicit DB queries. Such code is better placed in models.
- should avoid direct access to $_GET, $_POST, or other similar variables that represent the end user request. This is the controller's job. The view should be focused on the display and layout of the data provided to it by the controller and/or model, but not attempting to access request variables or the database directly.may access properties and methods of controllers and models directly. However, this should be done only for the purpose of presentation.
- 应当主要由表现代码构成, 例如HTML, 其间穿插一些简单的PHP代码,格式和渲染数据.
- 应该避免出现直接的数据库查询代码, 这类代码应当放在model中
- 应当避免直接使用$_GET,$_POST 或者其它的来自用户的简单变量, 这应当是控制器的工作. 视图应该专注于显示控制器或模型提供的数据以及页面布局,且不要尝试直接使用request变量或数据库中的数据.可以直接访问控制器和model中的方法, 但应当是只读的.
视图可以通过不同的方法来重用
- Layout: common presentational areas (e.g. page header, footer) can be put in a layout view.
- Partial views: use partial views (views that are not decorated by layouts) to reuse fragments of presentational code. For example, we use _form.php partial view to render the model input form that is used in both model creation and updating pages.
- Widgets: if a lot of logic is needed to present a partial view, the partial view can be turned into a widget whose class file is the best place to contain this logic. For widgets that generate a lot of HTML markup, it is best to use view files specific to the widget to contain the markup.
- Helper classes: in views we often need some code snippets to do tiny tasks such as formatting data or generating HTML tags. Rather than placing this code directly into the view files, a better approach is to place all of these code snippets in a view helper class. Then, just use the helper class in your view files. Yii provides an example of this approach. Yii has a powerful CHtml helper class that can produce commonly used HTML code. Helper classes may be put in an autoloadable directory so that they can be used without explicit class inclusion.
- 布局: 通用的表现层(比如页眉,页尾等)可以放在布局中
- 局部视图: 使用局部视图可以重用表现层的代码碎片.例如, 我们使用_form.php局部视图来渲染创建和更新页面中的模型输入表单.
- 窗口小部件: 如果一些逻辑需要表现为局部视图, 这些局部视图应该被转化为小部件, 小部件的类文件是最好的存放逻辑代码的地方. 小部件所需的HTML标签可以放在小部件的视图文件中.
- 帮助类: 在视图中我们有时候需要一些代码片段来完成一些简单的任务, 比如格式化数据或组织html标签. 相比把这些代码直接放在视图文件中, 更好的实现方式是把所有这些代码片段一个视图帮助类中. 我仅仅需要在视图中调用这个帮助类. YII提供一个这种实现的例子. YII有一个强大的CHtml帮助类, 它提供了一些通用的HTML操作代码. 帮助类应该放入一个自动加载目录, 这样他们就不需要在使用的时候指定加载.
Controllers are the glue that binds models, views and other components together into a runnable application. Controllers are responsible for dealing directly with end user requests. Therefore, controllers
控制器是把模型,视图和其它组件绑定到可运行程序的粘合剂.控制器负责直接处理用户端额请求. 因此 控制器
- may access $_GET, $_POST and other PHP variables that represent user requests;
- may create model instances and manage their life cycles. For example, in a typical model update action, the controller may first create the model instance; then populate the model with the user input from $_POST; after saving the model successfully, the controller may redirect the user browser to the model detail page. Note that the actual implementation of saving a model should be located in the model instead of the controller.
- should avoid containing embedded SQL statements, which are better kept in models.
- should avoid containing any HTML or any other presentational markup. This is better kept in views.
- 可以访问$_GET,$_POST和其它来自用户请求的PHP变量
- 可以创建model实例, 以及管理它们的生命周期. 例如, 在一个典型的模型更新动作中, 控制器会先创建一个模型实例, 然后从用户输入变量$_POST中获取数据进行填充, 最后成功保存这个模型, 最后, 控制器会让用户的浏览器跳转到模型详情页面.注意, 保存模型的实际代码位于模型实例而非控制器中.
- 应当避免包含SQL语句, SQL应该写在model中.
- 应该避免包含任何的HTML, 或者任何其它的视觉标记. 这些都应该放在视图中.
在一个设计良好的MVC程序里, 控制器通常很苗条, 可能仅仅包含几十行代码; 然而model会变得很臃肿,包含很多数据操作代码. 这是因为model包含很多针对特定程序的数据结构和业务逻辑, 并且需要按复杂的用户需要呈现; 然而控制器逻辑通常位于程序访问之后, 可以作为框架和基类的基础.