Controllers
通常,一个控制器,用于管理在个单一模型的逻辑。例如,如果你正在建设一个网站一个在线面包店,你可能有一个RecipesController管理你的食谱和IngredientsController管理你的成分。然而,它也可以管理一个以上的模型,让其能正常的工作。在CakePHP中,控制器是以它要处理的模型的名字而命名的。
您的应用程序控制器继承了 AppController 类型, 从而继承了核心的 Controller 类型。AppController 类定义在 /app/Controller/AppController.php 它应该包含被所有应用程序的控制器之间共享的方法。
控制器提供了若干处理请求的方法。 这些被称为动作。默认情况下,在一个控制器的每个公共方法是一个动作,并通过URL访问。 一个动作是负责解释请求并创建响应。通常反应是在渲染视图的形式,但也有其他的方法来创建响应。
App Controller
正如引言所述, AppController 的父类是所有应用程序的控制器。AppController 的本身继承自 Controller 类包含在 CakePHP 核心库中。 AppController 定义在 /app/Controller/AppController.php 如下:
class AppController extends Controller {
}
在 AppController 中控制器的属性和方法将提供给你应用程序中的所有控制器。 组件(你将会了解到)最好用于那些在很多控制器中被引用的代码(但不一定是全部)。
而正常的面向对象的继承规则,在CakePHP中会有些额外的工作,当涉及到特殊的控制器属性时。 控制器使用的组件和助手被特殊处理。在这些情况下,AppController 数组值将被合并到子类控制器的数组中。在子类中的值将始终覆盖那些在 AppController 中的值。
CakePHP将AppController中的变量合并到你的应用程序控制器中如下:
$components
$helpers
$uses
记得添加默认的HTML和Form助手,如果你要定义 AppController 的 $helpers 的属性。
记得调用 AppController 子类控制器的回调函数如下所示:
public function beforeFilter() {
parent::beforeFilter();
}
Request 参数
当一个请求发送到一个CakePHP的应用程序是,CakePHP的 Router 和 Dispatcher 类通过 Routes 配置 找到并建产正确的控制器。 该请求的数据被封装在一个请求对象中。CakePHP中把所有重要的请求信息保存在 $this->request 属性中。 请参阅参考资料 CakeRequest 关于CakePHP 的请求对象的详细信息。
Controller 动作
控制器动作是负责将请求参数为用于浏览器/用户提出请求的响应。 CakePHP的使用约定来自动完成这个过程,并删除某些,否则你将需要编写模板代码。
按照惯例,CakePHP提供一个视图屈折版的动作名称。回到我们的在线面包店的例子,我们的 RecipesController 可能包含 view(), share(), 和search() 动作。该控制器被发现包含在 /app/Controller/RecipesController.php 中:
# /app/Controller/RecipesController.php
class RecipesController extends AppController {
public function view($id) {
//action logic goes here..
}
public function share($customerId, $recipeId) {
//action logic goes here..
}
public function search($query) {
//action logic goes here..
}
}
这些动作的视图文件在 app/View/Recipes/view.ctp , app/View/Recipes/share.ctp , 和 app/View/Recipes/search.ctp 文中。常规视图文件名是动作名称的小写和下划线的版本。
控制器动作一般使用 set() 来创建一个View 用来显示视图的上下文。正因为如此CakePHP中使用的约定,你不需要手动创建并渲染视图。相反,一旦控制器动作完成后,将CakePHP的渲染处理并传递给视图。
如果由于某种原因你想跳过的默认行为,同时满足以下两个技术将绕过默认的视图渲染行为。
- 如果你返回一个字符串,或可以从你的控制器动作转换为字符串的对象,它将被用来作为响应体。
- 你可以返回一个 CakeResponse 对象的创建完整响应。
class RecipesController extends AppController {
public function popular() {
$popular = $this->Recipe->popular();
if (!empty($this->request->params['requested'])) {
return $popular;
}
$this->set('popular', $popular);
}
}
上述控制器的动作一个例子是一个方法可以使用 requestAction() 和正常请求。返回数组的数据到一个non-requestaction请求将导致错误应该避免。请参阅部分 requestAction() 要了解更多有关使用 requestAction()
为了让你在自己的应用程序中使用一个有效的控制器,我们将一些核心属性和方法通过CakePHP控制器提供。
Request Life-cycle callbacks
-
class
Controller
CakePHP控制器配有回调可以用来插入逻辑在请求生命周期:
-
Controller::beforeFilter()
-
该函数是在控制器的每一次动作之前执行。这是一个检查活动的会话或用户的权限进行方便的地方。
beforeFilter() 方法调用丢失动作脚手架动作
-
Controller::beforeRender()
-
调用控制器动作逻辑在后, 但在视图渲染之前。这个回调是不经常使用, 但可能如果要调用 render() 方法给定动作结束前手动是必要的。
-
Controller::afterFilter()
-
在每个控制器动作调用后,渲染完成后。这是最后一个控制器方法来运行。
除了控制器生命周期回调 Components 还提供了一组类似的回调。
Controller 方法
对于控制方法及其说明的完整列表,请访问 CakePHP API.
与视图进行交互
控制器,视图通过多种方式进行互动。 首先,他们能够将数据传递到视图,使用set()方法。您也可以决定使用哪个视图类,并查看文件应该从控制器呈现。
// First you pass data from the controller:
$this->set('color', 'pink');
// Then, in the view, you can utilize the data:
?>
You have selected <?php echo $color; ?> icing for the cake.
set() 方法有一个关联数组作为第一个参数。这通常是一个快速的方法来将一组信息分配给视图:
$data = array(
'color' => 'pink',
'type' => 'sugar',
'base_price' => 23.95
);
// make $color, $type, and $base_price
// available to the view:
$this->set($data);
属性 $pageTitle 已不复存在。 使用 set() 设置标题:
$this->set('title_for_layout', 'This is the page title');
Controller:: render ( string $view, string $layout )
render() 方法被自动调用在每个请求的控制器的动作结束后。此方法执行所有的视图逻辑 (你所使用的数据,使用 set() 方法提交),里面放置了 $layout视图,并回显给最终用户。
使用渲染的默认视图文件是由惯例确定的。 如果请求 RecipesController search() 动作,视图文件在 /app/View/Recipes/search.ctp :
class RecipesController extends AppController {
// ...
public function search() {
// Render the view in /View/Recipes/search.ctp
$this->render();
}
// ...
}
尽管CakePHP执行每一个动作的逻辑后,会自动调用它 (除非你设置 $this->autoRender 的值为 false), 你可以使用它通过使用$action在控制器中指定动作名称来指定一个备用的视图文件。
如果 $view 开头使用 “/”, 它被假定为一个视图或相对元素文件 /app/View 文件夹中。 这允许元素,使用AJAX直接渲染调用。
// Render the element in /View/Elements/ajaxreturn.ctp
$this->render('/Elements/ajaxreturn');
$layout 参数允许您指定该视图显示的布局。
渲染一个特定的视图
在控制器中,您可能希望呈现不同的视图。您可以通过调用 render() 做来这一点。一旦你调用 render(),CakePHP不会尝试重新渲染视图:
class PostsController extends AppController {
public function my_action() {
$this->render('custom_file');
}
}
这会导致 app/View/Posts/custom_file.ctp 代替 app/View/Posts/my_action.ctp
你也可以在渲染视图插件中使用以下语法: $this->render('PluginName.PluginController/custom_file')。比如说:
class PostsController extends AppController {
public function my_action() {
$this->render('Users.UserDetails/custom_file');
}
}
这将使 app/Plugin/Users/View/UserDetails/custom_file.ctp
流控制
-
Controller::redirect(mixed $url, integer $status, boolean $exit)
-
流控制方法最常用的是 redirect()。该方法它的第一个参数在CakePHP相对URL的形式。 当用户成功下了订单,您可能希望将它们重定向到指定的画面。:
-
public function place_order() { // Logic for finalizing order goes here if ($success) { return $this->redirect( array('controller' => 'orders', 'action' => 'thanks') ); } return $this->redirect( array('controller' => 'orders', 'action' => 'confirm') ); }
您也可以使用相对或绝对URL作为$url参数:
-
$this->redirect('/orders/thanks'); $this->redirect('http://www.example.com');
你也可以将数据传递到动作:
-
$this->redirect(array('action' => 'edit', $id));
redirect() 的第二个参数允许你定义重定向的HTTP状态代码。 你可能要使用301(永久移动)或303(见其他),根据重定向的性质。
该方法,除非您设置的第三个参数设置为 false重定向后执行exit() 方法退出。
如果您需要重定向到的 referer 页面,您可以使用:
该方法还支持基于名称的参数。如果你想重定向到一个URL像: http://www.example.com/orders/confirm/product:pizza/quantity:5 你可以使用:$this->redirect($this->referer());
-
$this->redirect(array( 'controller' => 'orders', 'action' => 'confirm', 'product' => 'pizza', 'quantity' => 5) );
使用查询字符串和哈希的例子看起来像这样:
-
$this->redirect(array( 'controller' => 'orders', 'action' => 'confirm', '?' => array( 'product' => 'pizza', 'quantity' => 5 ), '#' => 'top') );
生成的URL会是:
-
http://www.example.com/orders/confirm?product=pizza&quantity=5#top
看起来像 redirect(), flash() 方法是用来直接将操作之后的用户转到一个新的页面。flash() 方法不同,因为它显示了一个消息传递用户到另一个URL之前。
第一个参数应存储将要显示的消息,第二个参数是CakePHP的URL。CakePHP 显示 $message ,因为 $pause 在转发前会暂停几秒。
如果您想要你的信息显示在一个特定的模板中,您可以在$layout参数指定布局的名称。
对于页内快闪信息, 一定要检查 SessionComponent::setFlash() 方法。
回调
-
Controller::beforeScaffold($method)
-
$method 方法称为例如 index, edit, etc。
-
Controller::afterScaffoldSave($method)
-
$method 方法中调用编辑或更新的名称。
-
Controller::afterScaffoldSaveError($method)
-
$method 方法称为编辑或更新名称。
-
Controller::scaffoldError($method)
-
$method 方法称为例如 index, edit, etc。
其他有用的方法
-
Controller::constructClasses()
-
该方法加载的控制器所需的模型。这个加载过程是由CakePHP进行,但这个方法是方便时访问控制器从不同的角度。如果你需要在一个命令行脚本中或其他外部使用, constructClasses() 可能会派上用场。
-
Controller::referer(mixed $default = null, boolean $local = false)
-
返回当前请求的URL。 参数 $default 可以用来提供一个默认的URL,当HTTP_REFERER无法从头部读取时。所以,不要这样做:
-
class UserController extends AppController { public function delete($id) { // delete code goes here, and then... if ($this->referer() != '/') { return $this->redirect($this->referer()); } return $this->redirect(array('action' => 'index')); } }
你可以这样做:
-
class UserController extends AppController { public function delete($id) { // delete code goes here, and then... return $this->redirect( $this->referer(array('action' => 'index')) ); } }
如果 $default 没有设置, 该功能默认为您的域的根目录 - '/'。
能数 $local 如果设置为 true,限制引用URL到本地服务器。
用来告诉用户的浏览器不缓存当前请求的结果。这与视图缓存,在后面的章节不同。
头文件发送到这个效果:
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Last-Modified: [current datetime] GMT
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Pragma: no-cache
使用此方法可以把一组POST模型数据(从在HtmlHelper兼容输入)转换为一组查找条件的模型。 此功能提供了构建搜索逻辑的快速捷径。例如,管理员用户可能希望能够知道哪些物品需要运送搜索命令。 您可以使用 CakePHP的 FormHelper 和 HtmlHelper 创建基于订单模式的快速形式。然后一个控制器动作可以使用数据发布的形式查找条件的数据:
public function index() {
$conditions = $this->postConditions($this->request->data);
$orders = $this->Order->find('all', compact('conditions'));
$this->set('orders', $orders);
}
如果$this->request->data['Order']['destination'] 等于 ”Old Towne Bakery“, postConditions 这个条件转换成一个数组中使用兼容 Model->find() 方法。在这种情况下,array('Order.destination' => 'Old Towne Bakery')。
如果您要使用术语之间不同的SQL操作符,使用第二个参数:
/*
Contents of $this->request->data
array(
'Order' => array(
'num_items' => '4',
'referrer' => 'Ye Olde'
)
)
*/
// Let's get orders that have at least 4 items and contain 'Ye Olde'
$conditions = $this->postConditions(
$this->request->data,
array(
'num_items' => '>=',
'referrer' => 'LIKE'
)
);
$orders = $this->Order->find('all', compact('conditions'));
第三个参数允许你告诉CakePHP的查找条件之间使用什么SQL布尔运算符。 像字符串 “AND”,“OR” 和 “XOR” 都是有效的值。
最后,如果最后一个参数设置为true,并且$op参数是一个数组,不包含在$op中的字段将不会被包含在返回的条件。
此方法用于分页结果通过你的模型提取。 您可以指定页面大小,型号查找条件等等。请参阅有关如何使用PAGINATE更多细节分页部分。
这个函数调用控制器的动作从任何位置返回的数据。 $url 是一个CakePHP的相对URL (/controllername/actionname/params)。通过额外的数据接收控制器动作添加到 $options 数组。
你可以使用 requestAction() 检索一个充分渲染视图通过 ‘return’ 选项返回: requestAction($url, array('return'));。 需要注意的是采用控制器返回一个requestAction()可能会导致脚本和CSS标签无法正常工作是非常重要的。
如果没有缓存使用 requestAction() 可能会导致性能不佳。 它不太适合在一个控制器或模型中使用。
requestAction() 最适用于(缓存)的元素结合作为一种方法在渲染之前获取一个元素的数据。让我们将 “latest comments” 元素放置到一个例子中。 首先,我们需要创建一个控制器,将返回数据:
// Controller/CommentsController.php
class CommentsController extends AppController {
public function latest() {
if (empty($this->request->params['requested'])) {
throw new ForbiddenException();
}
return $this->Comment->find(
'all',
array('order' => 'Comment.created DESC', 'limit' => 10)
);
}
}
你应该总是包含检查,以确保您的 requestAction() 方法是源于 requestAction()的。如果不这样做将允许 requestAction() 方法直接从一个URL访问,这通常是不可取的。
如果我们现在创建一个简单的元素来调用该函数:
// View/Elements/latest_comments.ctp
$comments = $this->requestAction('/comments/latest');
foreach ($comments as $comment) {
echo $comment['Comment']['title'];
}
然后,我们可以把这个元素在任何地方采用,以得到输出:
echo $this->element('latest_comments');
写入该方法中,每当元素呈现,请求将向控制器获取数据,该数据将被处理,并返回。 但是按照上述的警告,最好利用元素的缓存,以防止不必要的处理。 通过修改调用元素,看起来像这样:
echo $this->element('latest_comments', array(), array('cache' => true));
requestAction() 的调用将不会在进行,缓存元素视图的文件存在并且是有效的。
此外, requestAction()现在采取基于阵列的cake样式的URL:
echo $this->requestAction(
array('controller' => 'articles', 'action' => 'featured'),
array('return')
);
充许 requestAction() 调用绕过 Router::url() 它可以提高性能。 基于URL的数组是相同的 HtmlHelper::link() 使用一个差异的 - 如果您使用的是命名或传递的参数,你必须把它们放在一个第二个数组,并使用正确的密钥包装他们。因为 requestAction() 会合并命名 args 数组(requestAction’s 的第2个参数) 关于 Controller::params 成员数组 并没有明确将名为args数组到 ‘named’键; 在 $option 数组的其它成员也将所有请求操作提供给 Controller::params 数组:
echo $this->requestAction('/articles/featured/limit:3');
echo $this->requestAction('/articles/view/5');
在 requestAction() 的数组将被:
echo $this->requestAction(
array('controller' => 'articles', 'action' => 'featured'),
array('named' => array('limit' => 3))
);
echo $this->requestAction(
array('controller' => 'articles', 'action' => 'view'),
array('pass' => array(5))
);
不像其他地方数组的URL类似于字符串的URL, requestAction() 对待他们不同。
当使用一个数组中的URL与
requestAction()
结合,你必须指定你需要在请求的操作的所有参数。
这包括像参数
$this->request->data
。 除了通过所有必需的参数,命名并传递参数必须按照上面所看到的第二个数组中完成。
loadModel() 函数变得方便,当你需要使用一个模型而不是控制器的默认模型或其相关型号:
$this->loadModel('Article');
$recentArticles = $this->Article->find(
'all',
array('limit' => 5, 'order' => 'Article.created DESC')
);
$this->loadModel('User', 2);
$user = $this->User->read();
Controller 属性
对于控制器的属性及其说明的完整列表,请访问 CakePHP API.
-
property Controller::$name
-
$name 属性应设置为控制器的名称。通常这只是主要模型的控制器使用复数形式。此属性可以省略,但从它节省了CakePHP的影响:
-
// $name controller attribute usage example class RecipesController extends AppController { public $name = 'Recipes'; }
$components, $helpers 和 $uses
下一个最常用的属性将告诉CakePHP什么是 $helpers, $components, 和 models 你将会于当前控制器一起使用。使用这些属性使由 $components和 $uses 提供给控制器作为类变量 ($this->ModelName, 例如) 并且那些由$helpers 给视图做为一个对像引用 ($this->{$helpername})。
每个控制器都有一些默认提供的这些类的,所以你可能不需要配置控制器。
property Controller::$uses
-
控制器默认访问他们的主要模型。我们的 RecipesController 将有配方模型类的使用 $this->Recipe, 并且我们的 ProductsController 还采用了产品模型$this->Product。然而,允许控制器通过 $uses访问其它模型, 还必须包含当前控制器的模型的名称。这一点在下面的例子。
如果您不希望使用一个模型在控制器中,设置 public $uses = array()。 这将允许你使用一个控制器而不需要一个相应的模型文件。然而,在 AppController中定义的模型仍然被加载。 你可以使用 false 不加载任何模型。即使是那些在AppController中定义。
已变更在2.1版本: $uses 现在有一个新的默认值,它也可以处理不同的错误。
property Controller::$helpers
-
HtmlHelper, FormHelper, 和SessionHelper 在默认情况下可用,由于是 SessionComponent。但是,如果您选择定义自己的 $helpers 数组在 AppController中,一定要包括 HtmlHelper和 FormHelper 如果你想让他们仍然可以默认在你的控制器中。要了解更多有关这些类时,请务必在本手册后面要看看他们各自的部分。
让我们来看看如何告诉一个CakePHP Controller 你打算使用额外的MVC类:
class RecipesController extends AppController { public $uses = array('Recipe', 'User'); public $helpers = array('Js'); public $components = array('RequestHandler'); }
这些变量的合并与继承的值, 因此,没有必要(例如)再声明 FormHelper , 或者说是在宣告你的东西 AppController 。
property Controller::$components¶
-
元件阵列允许你设置的组件将使用一个控制器。像 $helpers 和 $uses在你的控制器组件合并与那些在 AppController。关于 $helpers 你可以通过设置 $components。 查看 组件配置 更多信息。
其它属性
虽然你可以检查出所有控制器的属性在 API中,还有一些值得自己部分的手册中其他控制器的属性。
-
property Controller::$cacheAction
-
该cacheAction属性用于定义有关全页面缓存的持续时间等信息。你可以阅读更多关于 CacheHelper 文档中的全页面缓存。
-
property Controller::$paginate
-
paginate 是一个废弃的兼容属性。 使用它装载和配置 PaginatorComponent。 建议您更新您的代码中使用正常的组件设置:
class ArticlesController extends AppController { public $components = array( 'Paginator' => array( 'Article' => array( 'conditions' => array('published' => 1) ) ) ); }
-
-
-