Table Of Contents

Previous topic

MVC架构

Next topic

使用模型(Working with Models)

This Page

控制器

控制器提供了一些方法,他们被叫做actions。Actions是控制器用来处理用户请求的方法。默认情况下,控制器的所有公有的方法都映射到一个可访问的URL。Actions是负责解释请求以及创建用户响应的。通过的反应是一个渲染视图的形式,但也有其他的形式来处理用户请求。

例如,当你访问一个这样的URL时 http://localhost/blog/posts/show/2012/the-post-title ,默认情况下,Phalcon是这样对URL进行分解的:

Phalcon Directory blog
Controller posts
Action show
Parameter 2012
Parameter the-post-title

在这个例子中,PostController控制器用于来接收用户请求。由于在应用程序中没有对controllers的存放指定存放位置,他们可以通过 autoloaders 来自动加载你的controllers目录。

所有的控制器都必须以“Controller”为结尾,所有的Actions都是以“Action”结尾。下面是一个控制器的示例:

译者注:也并非所有的控制器都必须以“Controller”为结尾的,比如我们一般会写一个名为 “ContollerBase”,让他继承自 PhalconMvcController. 同时我们自己应用程序中的其他控制器都再继承自 ContollerBase.这么来做的话,则控制器ContollerBase就不是以 “Controller”为结尾了。如果严谨一点来讲可以这么说,所以用于用户请求的控制器必须以“Controller”为结尾

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function showAction($year, $postTitle)
    {

    }

}

其他的URI参数将被定义为Action参数,因此你可以很容易的使用局部变量来访问这些参数。控制器继承自 Phalcon\Mvc\Controller 。 这样一来,你的控制器就很方便的提供应用服务了

Dispatch Loop

其他的URI参数将被定义为Action参数,因此你可以很容易的使用局部变量来访问这些参数。控制器继承自 Phalcon\Mvc\Controller 。 这样一来,你的控制器就很方便的访问应用程序中的其他服务了

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function showAction($year, $postTitle)
    {
        $this->flash->error("You don't have permission to access this area");

        // Forward flow to another action
        $this->dispatcher->forward(array(
            "controller" => "users",
            "action" => "signin"
        ));
    }

}

如果用户没有权限访问某个特定的动作,然后将被转发到UsersController控制器的signinAction

<?php

class UsersController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function signinAction()
    {

    }

}

应用程序中并没有限制分发器的跳转次数,只要他们不导致死循环,可以正常停止即可。如果程序逻辑中再没有跳转到其他的Action,程序将自动调用MVC的视图层 Phalcon\Mvc\View.

初始化控制器

Phalcon\Mvc\Controller 提供初始化的方法,它最先执行,注意:”__construct” 的初始化方法在这里不推荐使用。

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public $settings;

    public function initialize()
    {
        $this->settings = array(
            "mySetting" => "value"
        );
    }

    public function saveAction()
    {
        if ($this->settings["mySetting"] == "value") {
            //...
        }
    }

}

访问注入服务

如果控制器继承自 Phalcon\Mvc\Controller ,那么它将可以很方便的访问应用程序容器中的其他服务。例如,我们注册了一个这样的服务:

<?php

$di = new Phalcon\DI();

$di->set('storage', function(){
    return new Storage('/some/directory');
}, true);

然后,我们可以通过以下方式访问那些服务:

<?php

class FilesController extends \Phalcon\Mvc\Controller
{

    public function saveAction()
    {

        //Injecting the service by just accessing the property with the same name
        $this->storage->save('/some/file');

        //Accessing the service from the DI
        $this->di->get('storage')->save('/some/file');

        //Another way to access the service using the magic getter
        $this->di->getStorage()->save('/some/file');

        //Another way to access the service using the magic getter
        $this->getDi()->getStorage()->save('/some/file');
    }

}

如果你正在使用Phalcon框架,你可以阅读一下DI by default

请求和响应

假设,该框架已经提供了一组预置的服务。我们将解释他们如何与http相互协调工作。”request”服务是 Phalcon\Http\Request 的一个实例对象, “response”是 Phalcon\Http\Response 的一个实例对象,它负责向客户端发送响应内容。

<?php

class PostsController extends Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function saveAction()
    {

        // Check if request has made with POST
        if ($this->request->isPost() == true) {
            // Access POST data
            $customerName = $this->request->getPost("name");
            $customerBorn = $this->request->getPost("born");
        }
    }

}

The response object is not usually used directly, but is built up before the execution of the action, sometimes - like in an afterDispatch event - it can be useful to access the response directly:

<?php

class PostsController extends Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function notFoundAction()
    {
        // Send a HTTP 404 response header
        $this->response->setStatusCode(404, "Not Found");
    }

}

学习更多的关于HTTP环境相关的文章,请查阅 request 以及 response.

Session 数据

Sessions help us maintain persistent data between requests. You could access a Phalcon\Session\Bag from any controller to encapsulate data that need to be persistent.

<?php

class UserController extends Phalcon\Mvc\Controller
{

    public function indexAction()
    {
        $this->persistent->name = "Michael";
    }

    public function welcomeAction()
    {
        echo "Welcome, ", $this->persistent->name;
    }

}

注入服务替代控制器

控制器可以注册成为服务,这样的话,用户的请求都会从注册的控制器获得。因此,用此种办法可以很容易的取代其他控制器。

<?php

//Register a controller as a service
$di->set('IndexController', function() {
    $component = new Component();
    return $component;
});

译者注:

以上例来说明,如果要访问 /index/index 的话,则需要在类 Component 中编写 indexAction() 方法。即和控制器中的action写法是相同的。同时,即使控制器目录存在 IndexController,也将不再访问。而是直接输出 Component中indexAction()的内容

创建一个基础控制器类

在应用程序的控制器中经常会需要访问控制列表,多语言,缓存,模板引擎等。在这种情况下,我们一般建议你创建一个 “base controller”,以防重复造轮子,保持代码 DRY .控制器只是一个简单的类文件,他要继承自 Phalcon\Mvc\Controller ,其他的控制器再继承自 “base controller”,这样就可以拥有基类控制器中的通用功能了,你的代码就会更整洁一些。

这个类可以放到任何目录下,但按照一般的规则来讲,我们推荐你把它放到控制器文件夹中,比如 apps/controllers/ControllerBase.php 。我们可能会需要这个文件,你可以直接在程序中引入,或者通过Phalcon的autoloader引入:

<?php

require "../app/controllers/ControllerBase.php";

一般通用的功能组件,我们可以写到这个文件中,比如 (actions,methods, properties等):

<?php

class ControllerBase extends \Phalcon\Mvc\Controller
{

  /**
   * This action is available for multiple controllers
   */
  public function someAction()
  {

  }

}

其他继承自ControllerBase的控制器,会自动获得通用组件。

译者注: 只要明白类继承是怎么回事,这块就非常好理解了。

<?php

class UsersController extends ControllerBase
{

}

译者补充:

我在这里多加一个例子,你就可以很容易的明白 base controller的用处了。

比如,我们一般会在控制器中做跳转操作,一般会用到 dispatcher的 forward方法。但这个forward方法的参数是一个数组,需要这样写:

<?php
class UsersController extends ControllerBase
{
    public function authAction()
    {
        ..... //valiate code
        $this->dispatcher->forward(array(
              'controller' => 'users',
              'action' => 'login'
           )
        );
    }
}

以上面示例中的写法来说,会有些麻烦。那么我们需要在 base controller中加入一个自定义的 forward 方法。

<?php
class ControllerBase extends \Phalcon\Mvc\Controller
{
   protected function forward($uri){
     $uriParts = explode('/', $uri);
     return $this->dispatcher->forward(
        array(
           'controller' => $uriParts[0],
           'action' => $uriParts[1]
        )
     );
   }
}

再次来修改 UsersController中的authAction方法:

<?php
class UsersController extends ControllerBase
{
    public function authAction()
    {
        ..... //valiate code

        $this->forward('users/login');
    }
}

是不是非常方便了?

控制器中的事件

控制器本身也可以充当监听的身份,通过 dispatcher 事件,在控制器中实现 dispatcher的事件方法,控制器的方法名要与事件名相同。这样的话,你就可以很方便的在actions执行前后通过钩点执行其他内容:

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function beforeExecuteRoute($dispatcher)
    {
        // This is executed before every found action

        if ($dispatcher->getActionName() == 'save') {
            $this->flash->error("You don't have permission to save posts");
            return false;
        }
    }

    public function afterExecuteRoute($dispatcher)
    {
        // Executed after every found action
    }

}