首页 理论 架构 工程 文档 白皮书 著作 研究 案例 下载 博客 关于 开始使用 →

第236章 Controller工程

第236章 Controller工程

236.1 提出背景

在 ICAI 工程体系中,Controller 是 MVC 架构中的请求控制层。

如果将整个 ICAI 请求处理过程表示为:

Request→Controller→Service→Engine→DomainObject→Repository→MySQLRequest \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL

那么 Controller 位于系统外部请求与内部业务运行机制之间。

Controller 的主要职责不是执行复杂的认知计算,而是完成:

Controller=RequestReceive+ParameterProcess+ServiceCall+ResultReturn+PageRedirectController= RequestReceive+ ParameterProcess+ ServiceCall+ ResultReturn+ PageRedirect

即:

  • 接收请求;
  • 处理请求参数;
  • 调用 Service;
  • 返回结果;
  • 执行页面跳转。

因此:

Controller≠ServiceController\neq Service Controller≠EngineController\neq Engine Controller≠RepositoryController\neq Repository

Controller 是请求协调层


236.2 Controller定义

**Controller(控制器)**是 MVC 架构中负责接收外部请求、组织请求参数、调用对应 Service、处理服务结果并向客户端返回响应或执行页面跳转的程序对象。

形式化表示:

Controller={Request,Parameter,Service,Result,Response,Redirect}Controller= \{ Request, Parameter, Service, Result, Response, Redirect \}

完整请求过程:

Request→Controller→Parameter→Service→Result→ResponseRequest \rightarrow Controller \rightarrow Parameter \rightarrow Service \rightarrow Result \rightarrow Response

如果需要页面跳转:

Result→Redirect→NewRequestResult \rightarrow Redirect \rightarrow NewRequest

因此 Controller 的核心任务是:

把外部请求转换成系统能够处理的 Service 调用,并把 Service 的结果转换成外部能够接收的响应。


236.3 Controller在ICAI工程中的位置

ICAI 工程完整结构:

User→Controller→Service→Engine→DomainObject→Repository→MySQLUser \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL

各层职责不同。

Controller

负责:

Request\rightarrowServiceRequest\rightarrowService

Service

负责:

BusinessProcessBusinessProcess

Engine

负责:

Calculation+Logic+ProcessingCalculation+Logic+Processing

Domain Object

负责:

ObjectStructure+ObjectState+ObjectBehaviorObjectStructure+ObjectState+ObjectBehavior

Repository

负责:

PersistencePersistence

MySQL

负责:

DataStorageDataStorage

因此:

Controller≠BusinessLogicController \neq BusinessLogic

Controller 不应该把 Service、Engine 和 Repository 的职责全部集中在一个类中。


236.4 请求接收

Controller 的第一项职责是请求接收(Request Receive)

外部请求可能来自:

GETGET POSTPOST PUTPUT DELETEDELETE

在传统 PHP MVC 系统中,最常见的是 GET 和 POST 请求。

请求可以表示为:

Request={Method,URI,Parameters,Headers,Session,Files}Request= \{ Method, URI, Parameters, Headers, Session, Files \}

Controller 首先确定:

RequestMethodRequestMethod

以及:

RequestRouteRequestRoute

例如:

GET /admin/individual/list

可以进入:

IndividualController::index()

而:

POST /admin/individual/create

可以进入:

IndividualController::create()

因此:

URI→Route→Controller→MethodURI \rightarrow Route \rightarrow Controller \rightarrow Method


236.5 请求路由与Controller

Controller 通常不会直接决定所有请求路径,而是由 Router 将请求映射到 Controller。

结构:

Request→Router→Controller→ActionRequest \rightarrow Router \rightarrow Controller \rightarrow Action

其中 Action 表示 Controller 中负责处理某一类请求的方法。

例如:

class IndividualController
{
    public function index()
    {
    }

    public function create()
    {
    }

    public function store()
    {
    }

    public function edit()
    {
    }

    public function update()
    {
    }

    public function delete()
    {
    }
}

可以形成:

/individual→index()/individual \rightarrow index() /individual/create→create()/individual/create \rightarrow create() /individual/store→store()/individual/store \rightarrow store() /individual/update→update()/individual/update \rightarrow update()

因此:

Route→ControllerActionRoute \rightarrow ControllerAction


236.6 参数处理

请求进入 Controller 后,第二项职责是处理请求参数。

参数可以来自:

GETGET POSTPOST FILESFILES SESSIONSESSION

或者系统内部产生的参数。

统一表示:

RequestParameter={Name,Value,Type,Source}RequestParameter= \{ Name, Value, Type, Source \}

例如创建机器个体:

id
type
name
status

Controller 可以接收到:

$id = $_POST['id'];
$type = $_POST['type'];
$name = $_POST['name'];
$status = $_POST['status'];

但是不能简单地把原始请求参数直接传入整个系统。

应该经过:

Request→ParameterExtraction→ParameterValidation→ParameterNormalization→ServiceRequest \rightarrow ParameterExtraction \rightarrow ParameterValidation \rightarrow ParameterNormalization \rightarrow Service


236.7 参数提取

参数提取的职责是从 Request 中获取需要的数据。

例如:

$params = array(
    'id'     => isset($_POST['id']) ? $_POST['id'] : null,
    'type'   => isset($_POST['type']) ? $_POST['type'] : null,
    'name'   => isset($_POST['name']) ? $_POST['name'] : null
);

形成:

Request→ParametersRequest \rightarrow Parameters

参数提取本身不应该进行复杂业务判断。

例如 Controller 可以判断:

id≠∅id\neq\varnothing

但是不应该在 Controller 中实现复杂的能力匹配:

Goal→Capability→Method→DecisionGoal \rightarrow Capability \rightarrow Method \rightarrow Decision

这种计算应该交给 Service 和 Engine。


236.8 参数验证

参数提取以后必须进行基本验证。

定义:

ParameterValid=Required∧Type∧Format∧RangeParameterValid= Required \land Type \land Format \land Range

例如:

if (empty($params['type'])) {
    return $this->error('个体类型不能为空');
}

数字参数可以检查:

is_numeric(Parameter)is\_numeric(Parameter)

字符串参数可以检查:

strlen(Parameter)>0strlen(Parameter)>0

因此:

Request→Extract→ValidateRequest \rightarrow Extract \rightarrow Validate

如果参数无效:

InvalidParameter→ErrorResponseInvalidParameter \rightarrow ErrorResponse

而不是继续调用 Service。


236.9 参数规范化

不同来源的参数可能存在不同格式,因此 Controller 可以进行必要的参数规范化。

例如:

"  robot  "

规范化为:

"robot"

或者:

"001"

转换为:

1

形成:

RawParameter→NormalizedParameterRawParameter \rightarrow NormalizedParameter

但是 Controller 不应该承担复杂的数据转换逻辑。

如果转换涉及领域规则:

Parameter→DomainValueParameter \rightarrow DomainValue

则应该交给 Service 或 Domain Object。

因此:

SimpleNormalization→ControllerSimpleNormalization\rightarrow Controller DomainTransformation→Service/DomainObjectDomainTransformation\rightarrow Service/DomainObject


236.10 Service调用

Controller 最重要的职责之一是调用 Service。

核心关系:

Controller→ServiceController \rightarrow Service

例如:

class IndividualController
{
    protected $service;

    public function __construct($service)
    {
        $this->service = $service;
    }

    public function create()
    {
        $params = array(
            'type' => isset($_POST['type']) ? $_POST['type'] : null,
            'name' => isset($_POST['name']) ? $_POST['name'] : null
        );

        return $this->service->create($params);
    }
}

Controller 不直接调用 MySQL:

Controller
    ↓
MySQL

而应该:

Controller
    ↓
Service
    ↓
Repository
    ↓
MySQL

如果需要复杂计算:

Controller
↓
Service
↓
Engine
↓
Domain Object
↓
Repository
↓
MySQL

236.11 Controller与Service职责边界

Controller 与 Service 必须保持清晰边界。

Controller:

Request→Parameter→ServiceRequest \rightarrow Parameter \rightarrow Service

Service:

Parameter→BusinessProcess→ResultParameter \rightarrow BusinessProcess \rightarrow Result

因此:

Controller=RequestCoordinationController= RequestCoordination Service=BusinessCoordinationService= BusinessCoordination

例如用户创建机器个体:

Controller
↓
接收 type、name
↓
验证基础参数
↓
调用 MachineIndividualService

然后:

MachineIndividualService
↓
创建个体
↓
初始化结构
↓
调用 Engine
↓
Repository 保存
↓
返回结果

Controller 不应该自己完成整个创建流程。


236.12 ICAI Controller与Service

ICAI 的 Controller 可以调用不同的 Service。

例如:

IndividualController
├── IndividualService
├── CognitiveService
├── GoalService
├── CapabilityService
├── MethodService
├── DecisionService
├── BehaviorService
├── MemoryService
└── MaintenanceService

请求:

Request→IndividualControllerRequest \rightarrow IndividualController

根据请求类型:

Controller→IndividualServiceController \rightarrow IndividualService

或者:

Controller→CognitiveServiceController \rightarrow CognitiveService

或者:

Controller→BehaviorServiceController \rightarrow BehaviorService

因此 Controller 是不同系统功能之间的请求入口。


236.13 返回结果

Service 执行完成以后,会返回处理结果。

定义:

ServiceResult={Status,Data,Message,Code,Errors}ServiceResult= \{ Status, Data, Message, Code, Errors \}

例如:

$result = array(
    'status'  => true,
    'data'    => $individual,
    'message' => '创建成功',
    'code'    => 200
);

Controller 接收到:

ServiceResultServiceResult

以后,根据请求类型决定如何输出。

如果是页面请求:

Result→ViewResult \rightarrow View

如果是 API 请求:

Result→JSONResult \rightarrow JSON

因此:

Controller→ResponseController \rightarrow Response


236.14 HTML页面返回

传统后台管理系统通常需要返回 HTML 页面。

流程:

Request→Controller→Service→Result→ViewData→Smarty→HTMLRequest \rightarrow Controller \rightarrow Service \rightarrow Result \rightarrow ViewData \rightarrow Smarty \rightarrow HTML

例如:

public function index()
{
    $result = $this->service->list();

    return $this->view->display(
        'individual/index.tpl',
        array(
            'data' => $result
        )
    );
}

Controller 负责把 Service 结果转换为 View 所需要的数据。

因此:

ServiceResult→ViewData→SmartyServiceResult \rightarrow ViewData \rightarrow Smarty


236.15 JSON结果返回

如果请求来自 API 或 AJAX,则 Controller 可以返回 JSON。

例如:

public function apiCreate()
{
    $params = $this->getRequestParams();

    $result = $this->service->create($params);

    header('Content-Type: application/json; charset=utf-8');

    echo json_encode($result);
}

形成:

Request→Controller→Service→Result→JSONRequest \rightarrow Controller \rightarrow Service \rightarrow Result \rightarrow JSON

因此 Controller 需要根据请求类型决定结果表达方式,而不是改变 Service 的核心业务结果。


236.16 页面跳转

Controller 的另一项重要职责是页面跳转。

例如:

POST→Create→Success→Redirect→ListPOST \rightarrow Create \rightarrow Success \rightarrow Redirect \rightarrow List

PHP 中可以使用:

header('Location: /admin/individual/index.php');
exit;

形成:

提交表单
↓
Controller
↓
Service
↓
创建成功
↓
页面跳转
↓
列表页面

页面跳转通常用于避免用户刷新页面时重复提交数据。

典型流程:

POST→Process→Redirect→GETPOST \rightarrow Process \rightarrow Redirect \rightarrow GET

这可以形成清晰的请求生命周期。


236.17 成功与失败处理

Controller 必须能够处理 Service 的不同结果。

定义:

ResultStatus∈{Success,Failed,Invalid,Blocked,NotFound,Unauthorized,Error}ResultStatus\in \{ Success, Failed, Invalid, Blocked, NotFound, Unauthorized, Error \}

成功:

Success→View/RedirectSuccess \rightarrow View/Redirect

失败:

Failed→ErrorResponseFailed \rightarrow ErrorResponse

参数错误:

Invalid→ParameterErrorInvalid \rightarrow ParameterError

对象不存在:

NotFound→404NotFound \rightarrow 404

权限不足:

Unauthorized→403Unauthorized \rightarrow 403

因此:

ServiceResult→ControllerResultHandler→ResponseServiceResult \rightarrow ControllerResultHandler \rightarrow Response


236.18 Controller错误处理

Controller 不应该隐藏 Service 或 Engine 的真实错误。

例如:

Service→ErrorService \rightarrow Error

Controller 应该将错误转换成明确的系统响应:

if (!$result['status']) {
    return $this->error(
        $result['message']
    );
}

但不应该:

try {
    // ...
} catch (Exception $e) {
    return '操作成功';
}

因为:

RealError≠SuccessRealError\neq Success

ICAI 工程要求:

真实结果→真实返回真实结果 \rightarrow 真实返回

不能把失败结果伪装成成功结果。


236.19 Controller不承担核心认知计算

ICAI Controller 必须严格保持职责边界。

例如:

Controller
↓
读取请求
↓
调用 CognitiveService

而不是:

Controller
↓
对象识别
↓
属性计算
↓
状态计算
↓
关系计算
↓
知识计算
↓
需求判断
↓
目标形成
↓
能力匹配
↓
决策

后者会造成 Controller 业务膨胀。

正确结构:

Controller→CognitiveService→CognitiveEngineController \rightarrow CognitiveService \rightarrow CognitiveEngine

例如:

Object→Attribute→State→Relation→Scene→KnowledgeObject \rightarrow Attribute \rightarrow State \rightarrow Relation \rightarrow Scene \rightarrow Knowledge

由 CognitiveEngine 负责。

Controller 只负责把请求送入正确的 Service。


236.20 Controller工程类模型

基础 Controller 可以定义为:

class BaseController
{
    protected $request;
    protected $response;
    protected $view;

    public function __construct(
        $request,
        $response,
        $view
    ) {
        $this->request = $request;
        $this->response = $response;
        $this->view = $view;
    }

    protected function getParam($name, $default = null)
    {
        return $default;
    }

    protected function json($data)
    {
        return $data;
    }

    protected function redirect($url)
    {
        return $url;
    }

    protected function render($template, $data = array())
    {
        return $this->view->display(
            $template,
            $data
        );
    }
}

具体 Controller:

class IndividualController extends BaseController
{
    protected $individualService;

    public function __construct(
        $request,
        $response,
        $view,
        $individualService
    ) {
        parent::__construct(
            $request,
            $response,
            $view
        );

        $this->individualService =
            $individualService;
    }

    public function index()
    {
        $result =
            $this->individualService->list();

        return $this->render(
            'individual/index.tpl',
            array(
                'result' => $result
            )
        );
    }

    public function create()
    {
        return $this->render(
            'individual/create.tpl'
        );
    }

    public function store()
    {
        $params = array(
            'type' => $this->getParam('type'),
            'name' => $this->getParam('name')
        );

        $result =
            $this->individualService
                 ->create($params);

        if (!$result['status']) {
            return $this->json($result);
        }

        return $this->redirect(
            '/admin/individual/index.php'
        );
    }
}

这里的关键关系是:

IndividualController→IndividualServiceIndividualController \rightarrow IndividualService

而不是:

IndividualController→MySQLIndividualController \rightarrow MySQL


236.21 Controller生命周期

Controller 本身也可以具有简单的运行过程:

Request→Instantiate→Receive→Validate→CallService→ProcessResult→ResponseRequest \rightarrow Instantiate \rightarrow Receive \rightarrow Validate \rightarrow CallService \rightarrow ProcessResult \rightarrow Response

完整过程:

请求
↓
路由
↓
Controller实例化
↓
接收请求
↓
读取参数
↓
参数验证
↓
Service调用
↓
获得结果
↓
结果判断
├── 成功 → 返回/跳转
├── 失败 → 错误返回
└── 异常 → 异常处理
↓
Response

因此:

ControllerRuntime=Receive+Process+Call+Return+RedirectControllerRuntime= Receive+ Process+ Call+ Return+ Redirect


236.22 Controller与页面跳转关系

后台系统通常存在多个页面:

列表页
↓
创建页
↓
提交
↓
详情页
↓
编辑页
↓
更新
↓
列表页

Controller 可以承担页面之间的请求协调。

例如:

GET/Create→CreatePageGET/Create \rightarrow CreatePage POST/Create→CreateServicePOST/Create \rightarrow CreateService Success→Redirect/ListSuccess \rightarrow Redirect/List

编辑:

GET/Edit→EditPageGET/Edit \rightarrow EditPage POST/Update→UpdateServicePOST/Update \rightarrow UpdateService Success→Redirect/ListSuccess \rightarrow Redirect/List

因此页面跳转本质上属于:

Controller→NavigationController \rightarrow Navigation

而不是 Service 的核心职责。


236.23 Controller与Service与Engine三级关系

ICAI 工程可以建立三级职责:

Controller→Service→EngineController \rightarrow Service \rightarrow Engine

Controller:

Request ProcessingRequest\ Processing

Service:

Business ProcessBusiness\ Process

Engine:

Domain CalculationDomain\ Calculation

例如能力请求:

Request→CapabilityControllerRequest \rightarrow CapabilityController

然后:

CapabilityController→CapabilityServiceCapabilityController \rightarrow CapabilityService

再:

CapabilityService→CapabilityEngineCapabilityService \rightarrow CapabilityEngine

Engine 执行:

Goal→CapabilityRequirement→CapabilityMatchingGoal \rightarrow CapabilityRequirement \rightarrow CapabilityMatching

最后:

CapabilityEngine→CapabilityService→CapabilityController→ResponseCapabilityEngine \rightarrow CapabilityService \rightarrow CapabilityController \rightarrow Response


236.24 Controller与Repository的边界

Controller 不应该直接访问 Repository。

错误结构:

Controller→RepositoryController \rightarrow Repository

正确结构:

Controller→Service→RepositoryController \rightarrow Service \rightarrow Repository

如果存在 Engine:

Controller→Service→Engine→RepositoryController \rightarrow Service \rightarrow Engine \rightarrow Repository

这样可以避免 Controller 与数据库结构产生直接耦合。

例如数据库表发生变化:

MySQL→RepositoryMySQL \rightarrow Repository

只需要调整 Repository 和相关 Service,而不应该让所有 Controller 都直接修改数据库操作。


236.25 Controller与Domain Object的边界

Controller 可以接收或输出 Domain Object 的数据,但不应该承担 Domain Object 的核心领域责任。

例如:

Controller
↓
IndividualService
↓
MachineIndividual

而不是:

Controller
↓
直接修改 MachineIndividual 所有内部状态

Domain Object 自身负责:

Identity+State+Relation+ResponsibilityIdentity+ State+ Relation+ Responsibility

Controller 负责:

Request+ResponseRequest+ Response

因此:

ControllerResponsibility∩DomainResponsibilityControllerResponsibility \cap DomainResponsibility

应该尽量减少。


236.26 Controller工程统一模型

将本章五项职责统一起来:

RequestReceive→ParameterProcess→ServiceCall→ResultReturn→PageRedirect\boxed{ RequestReceive \rightarrow ParameterProcess \rightarrow ServiceCall \rightarrow ResultReturn \rightarrow PageRedirect }

其中:

请求接收

Request→ControllerRequest\rightarrow Controller

参数处理

Controller→ParameterController\rightarrow Parameter

Service调用

Parameter→ServiceParameter\rightarrow Service

返回结果

ServiceResult→ResponseServiceResult\rightarrow Response

页面跳转

Success→RedirectSuccess\rightarrow Redirect

最终:

Request→Controller→Parameter→Service→Result→Response\boxed{ Request \rightarrow Controller \rightarrow Parameter \rightarrow Service \rightarrow Result \rightarrow Response }

页面请求增加:

Result→Redirect→NewRequestResult \rightarrow Redirect \rightarrow NewRequest


236.27 ICAI Controller完整工程链

ICAI 的 Controller 最终进入完整工程体系:

HTTPRequest→Router→Controller→Service→Engine→DomainObject→Repository→MySQL\boxed{ HTTPRequest \rightarrow Router \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

返回:

MySQL→Repository→DomainObject→Engine→Service→Controller→Response\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject \rightarrow Engine \rightarrow Service \rightarrow Controller \rightarrow Response }

页面:

Controller→ViewData→Smarty→HTMLController \rightarrow ViewData \rightarrow Smarty \rightarrow HTML

跳转:

Controller→Redirect→NewRequestController \rightarrow Redirect \rightarrow NewRequest

由此形成完整 MVC 请求闭环。


236.28 本章总结

Controller 是 ICAI MVC 工程体系中的请求控制层,其核心职责可以概括为:

接收请求→处理参数→调用Service→返回结果→页面跳转\boxed{ 接收请求 \rightarrow 处理参数 \rightarrow 调用Service \rightarrow 返回结果 \rightarrow 页面跳转 }

Controller 不负责替代 Service,也不负责替代 Engine,更不负责直接承担数据库操作。

完整职责边界为:

Controller=请求控制\boxed{ Controller=请求控制 } Service=业务流程\boxed{ Service=业务流程 } Engine=领域计算\boxed{ Engine=领域计算 } DomainObject=领域对象\boxed{ DomainObject=领域对象 } Repository=数据持久化\boxed{ Repository=数据持久化 } MySQL=数据存储\boxed{ MySQL=数据存储 }

因此 ICAI 的 MVC 工程最终形成:

Request→Controller→Service→Engine→DomainObject→Repository→MySQL\boxed{ Request \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

返回方向:

MySQL→Repository→DomainObject→Engine→Service→Controller→Response\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject \rightarrow Engine \rightarrow Service \rightarrow Controller \rightarrow Response }

而页面显示进一步形成:

Controller→ViewData→Smarty→HTMLController \rightarrow ViewData \rightarrow Smarty \rightarrow HTML

至此,Controller 完成了 ICAI 理论模型进入实际 Web/MVC 运行环境的重要入口,使外部请求能够按照明确的工程层次进入 ICAI 的 Service、Engine、Domain Object 和数据持久化体系。

Leave a Reply

Your email address will not be published. Required fields are marked *