# 4.2 控制器

控制器是MVC的核心,是连接Model和View的桥梁,是程序处理逻辑的起始代码。

## Controller基类

框架内置控制器基类`\PG\MSF\Controllers\Controller`,任何控制器都应该继承它,如:

示例代码:

[./php-msf-demo/app/Controllers/Demo.php](https://github.com/pinguo/php-msf-demo/blob/master/app/Controllers/Demo.php)

```php
<?php
/**
 * 示例控制器
 *
 * @author camera360_server@camera360.com
 * @copyright Chengdu pinguo Technology Co.,Ltd.
 */

namespace App\Controllers;

use PG\MSF\Controllers\Controller;

class Demo extends Controller
{
    public function actionGetMockIds()
    {
        $ids = $this->getConfig()->get('params.mock_ids', []);
        $this->outputJson($ids);
    }
}
```

- $this->getConfig()->get('params.mock_ids', []);

获取Server运行实例的配置对象，也可以通过数组的形式访问，比如`$this->getConfig()['params']['mock_ids']`

- $this->outputJson($data)

Controller::outputJson()方法是响应用户请求并格式化json输出,`curl http://127.0.0.1:8000/Demo/GetMockIds | jq .`如:

```json
[
    "581af00d4b58d59d22e8d7a6",
    "581198754b58d54465ef4cad",
    "580c7fa44b58d53f43e21c43",
    "57ef6aec4b58d50d24e21a2a",
    "57ee28ed4b58d52f24e21969",
    "57eb6a484b58d50e3d078076",
    "57e23b444b58d52f1e6689fc",
    "57dfc9fc4b58d5581e668918",
    "57de06b74b58d5471e66882f",
    "57d8b78f4b58d5311e6686d5"
]
```
## __construct

控制器的构造方法原型：

```php
<?php
/**
 * Web Controller控制器基类
 *
 * @author camera360_server@camera360.com
 * @copyright Chengdu pinguo Technology Co.,Ltd.
 */

namespace PG\MSF\Controllers;

use PG\Exception\Errno;
use PG\Exception\ParameterValidationExpandException;
use PG\Exception\PrivilegeException;
use PG\AOP\Wrapper;
use PG\AOP\MI;
use PG\MSF\Base\Core;
use Exception;
use PG\MSF\Coroutine\CException;

/**
 * Class Controller
 * @package PG\MSF\Controllers
 */
class Controller extends Core
{
    // 略...
    /**
     * Controller constructor.
     *
     * @param string $controllerName controller标识
     * @param string $methodName method名称
     */
    public function __construct($controllerName, $methodName)
    {
        // 支持自动销毁成员变量
        MI::__supportAutoDestroy(static::class);
        $this->requestStartTime = microtime(true);
    }
    // 略...
}
```

如用户业务控制器有其他构造逻辑，需要如下调用基类的构造方法：

```php
    /**
     * Controller constructor.
     *
     * @param string $controllerName controller标识
     * @param string $methodName method名称
     */
    public function __construct($controllerName, $methodName)
    {
        parent::__construct($controllerName, $methodName);
        // 业务逻辑
    }
```

## 动作

控制器由动作组成,他是用户请求的最小单元逻辑。控制器动作前缀为`action`。

这样访问:

http://127.0.0.1:8000/Demo/GetMockIds

这样的URL时,正在执行的控制器动作为: `Demo::actionGetMockIds()`。

## 获取对象

在控制器的动作中加载模型或者创建对象是常见的需求,php-msf实现了对象池的设计模式，创建任何对象都需要通过调用`$this->getObject($className)`方法如:

- Demo模型

```php
<?php
/**
 * Demo模型
 */
namespace App\Models;

use PG\MSF\Models\Model;

class Demo extends Model
{
    public $pro1;
    public $pro2;

    public function __construct($pro1, $pro2)
    {
        parent::__construct();
        $this->pro1 = $pro1;
        $this->pro2 = $pro2;
    }

    public function getMockIds()
    {
        // 读取配置后返回
        return $this->getConfig()->get('params.mock_ids', []);
    }
}
```

如示例所示,`App\Models\Demo`类文件:

[./php-msf-demo/app/Models/Demo.php](https://github.com/pinguo/php-msf-demo/blob/master/app/Models/Demo.php)

- 调用Demo模型方法

```php
<?php
/**
 * 示例控制器
 *
 * @author camera360_server@camera360.com
 * @copyright Chengdu pinguo Technology Co.,Ltd.
 */

namespace App\Controllers;

use PG\MSF\Controllers\Controller;
use App\Models\Demo as DemoModel;

class Demo extends Controller
{
    // 略
    public function actionGetMockFromModel()
    {
        /**
         * @var DemoModel $demoModel
         */
        $demoModel = $this->getObject(DemoModel::class, [1, 2]);
        $ids       = $demoModel->getMockIds();
        $this->outputJson($ids);
    }
}
```

- 获取对象时的构造参数

`$this->getObject($className, ['构造参数1', '构造参数2', ...]);`

第二个参数为构造参数列表，即数组，它会一一映射到类的构造方法。


## 命令行模式

除了处理web请求的Controller,框架还支持命令行模式,需要继承`\PG\MSF\Console\Controller`,如:

```php
<?php
namespace App\Console;

use PG\MSF\Console\Controller;

class Batch extends Controller
{
    public function actionRun()
    {
        echo '命令行示例';
    }
}
```

```bash
>console.php Batch/Run
令行示例
```

示例代码:

[./php-msf-demo/app/Console/Batch.php](https://github.com/pinguo/php-msf-demo/blob/master/app/Console/Batch.php)

和其他处理web请求的controller一样,命令行模式也支持协程。

## 其他特性

- 访问请求上下文

$this->getContext()

- 获取请求的输入对象

$this->getContext()->getInput()

- 获取请求的响应对象

$this->getContext()->getOutput()

- 获取对象池并获取一个业务对象

$this->getContext()->getObjectPool()->get(Class::Name)

- 获取Redis连接池

$this->getRedisPool($poolName)

- 获取Redis代理

$this->getRedisProxy($proxyName)

- 获取MySQL连接池

$this->getMysqlPool($poolName)

- 响应json数据格式

$this->outputJson($data, $status)

- 响应视图

$this->outputView($data, $view)

# links
  * [目录](../README.md)
  * 上一节: [结构概述](4.1-结构概述.md)
  * 下一节: [模型](4.3-模型.md)