CakePHP 控制器 Controllers

Controllers

Controllers 是MVC中的“C”。经过路由找到应用程序中正确的控制器。您的控制器应处理解释请求数据,并确保正确的model被调用,并正用正确的试图显示相应的结果。 控制器可以被认为在Model和View之间的中间人。你要保持你的控制器简洁,和模型的丰满。这将帮助你更轻松地重用代码,使你的代码更容易测试。

通常,一个控制器,用于管理在个单一模型的逻辑。例如,如果你正在建设一个网站一个在线面包店,你可能有一个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 对象的创建完整响应。
当您使用的控制器方法 requestAction(),你会经常要返回的数据不是字符串。 如果有一个用于正常的requests + requestAction控制器的方法,你应该返回前检查请求的类型:
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()方法。您也可以决定使用哪个视图类,并查看文件应该从控制器呈现。

Controller::set(string $varmixed $value)

set() 方法是从你的控制器发送数据到视图的主要途径。 一旦你使用 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 $viewstring $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 $urlinteger $statusboolean $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 页面,您可以使用:

$this->redirect($this->referer());
该方法还支持基于名称的参数。如果你想重定向到一个URL像: http://www.example.com/orders/confirm/product:pizza/quantity:5  你可以使用:

$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


Controller::flash(string $messagestring|array $urlinteger $pausestring $layout)

看起来像 redirect(), flash() 方法是用来直接将操作之后的用户转到一个新的页面。flash() 方法不同,因为它显示了一个消息传递用户到另一个URL之前。

第一个参数应存储将要显示的消息,第二个参数是CakePHP的URL。CakePHP 显示 $message ,因为 $pause 在转发前会暂停几秒。

如果您想要你的信息显示在一个特定的模板中,您可以在$layout参数指定布局的名称。

对于页内快闪信息, 一定要检查 SessionComponent::setFlash() 方法。

回调

除了请求生命周期回调,CakePHP的还支持脚手架回调。

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 = nullboolean $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到本地服务器。

Controller::disableCache()

用来告诉用户的浏览器不缓存当前请求的结果。这与视图缓存,在后面的章节不同。

头文件发送到这个效果:

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

Controller::postConditions(array $datamixed $opstring $boolboolean $exclusive)

使用此方法可以把一组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中的字段将不会被包含在返回的条件。


Controller::paginate()

此方法用于分页结果通过你的模型提取。 您可以指定页面大小,型号查找条件等等。请参阅有关如何使用PAGINATE更多细节分页部分。

Controller::requestAction(string $urlarray $options)

这个函数调用控制器的动作从任何位置返回的数据。 $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 。 除了通过所有必需的参数,命名并传递参数必须按照上面所看到的第二个数组中完成。

Controller::loadModel(string $modelClassmixed $id)

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

HtmlHelperFormHelper, 和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)
            )
        )
    );
}








  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值