第238章 View工程
238.1 提出背景
第236章建立了 Controller 工程,第237章建立了 Model 工程。在 MVC 架构中,Controller 负责请求控制,Model 负责领域对象、业务流程、领域计算和数据持久化,而 View 负责将已经处理完成的数据转换为用户能够看到的页面。
ICAI MVC 的基本结构为:
MVC=Controller+Model+ViewMVC= Controller+ Model+ View
其中:
Controller→RequestController\rightarrow Request Model→BusinessModel\rightarrow Business View→PresentationView\rightarrow Presentation
因此完整流程为:
Request→Controller→Model→View→HTML\boxed{ Request \rightarrow Controller \rightarrow Model \rightarrow View \rightarrow HTML }
在 ICAI PHP OOP 工程中,View 通常由模板系统承担,例如 Smarty。
因此可以进一步表示:
Controller→ViewData→Smarty→Template→HTMLController \rightarrow ViewData \rightarrow Smarty \rightarrow Template \rightarrow HTML
View 的核心任务不是重新计算 ICAI 理论,而是:
把 Controller 提供的 View Data 按照模板结构组织成最终页面。
238.2 View定义
**View(视图)**是 MVC 架构中负责将系统处理后的数据按照页面结构、模板规则和显示要求转换为用户可见输出的工程部分。
定义:
View=ViewData+Template+RenderView= ViewData+ Template+ Render
其中:
- View Data:提供给页面的数据;
- Template:页面模板;
- Render:模板渲染过程。
完整过程:
Data→ViewData→Template→Render→HTMLData \rightarrow ViewData \rightarrow Template \rightarrow Render \rightarrow HTML
View 的核心职责是:
View=PresentationView=Presentation
因此:
View≠ServiceView\neq Service View≠EngineView\neq Engine View≠RepositoryView\neq Repository
View 不应该承担:
Goal→Capability→DecisionGoal\rightarrow Capability\rightarrow Decision
这种 ICAI 核心计算。
238.3 View在MVC中的位置
ICAI MVC 可以表示为:
Request
↓
Controller
↓
Model
├── Service
├── Engine
├── Domain Object
└── Repository
↓
View Data
↓
View
↓
Smarty
↓
HTML
因此:
Controller→Model→ViewController \rightarrow Model \rightarrow View
是主流程。
其中 Model 负责:
Data+Business+CalculationData+Business+Calculation
Controller 负责:
Request+ResponseRequest+Response
View 负责:
PresentationPresentation
三者职责必须保持独立。
238.4 View Data
**View Data(视图数据)**是 Controller 根据 Model 返回结果整理后,专门提供给 View 使用的数据结构。
定义:
ViewData={Name,Value,Type,Structure}ViewData= \{ Name, Value, Type, Structure \}
例如:
$viewData = array(
'individual' => $individual,
'title' => '机器个体',
'message' => '加载成功'
);
然后:
Controller→ViewDataController \rightarrow ViewData
再:
ViewData→SmartyViewData \rightarrow Smarty
View Data 的作用是建立:
Model→ViewModel \rightarrow View
之间的数据边界。
238.5 为什么需要View Data
Model 中的数据结构通常不是直接用于页面显示的最终结构。
例如 Domain Object:
MachineIndividual
├── ID
├── Type
├── State
├── Knowledge
├── Capability
├── Method
├── Behavior
└── Memory
页面可能只需要:
ID
Type
State
Status
因此:
DomainObject→ViewDataDomainObject \rightarrow ViewData
可以进行必要的数据组织。
例如:
$viewData = array(
'id' => $individual->getId(),
'type' => $individual->getType(),
'state' => $individual->getState(),
'status' => $individual->getStatus()
);
这样 View 不需要理解完整 Domain Object 的所有内部结构。
因此:
DomainObject≠ViewDataDomainObject\neq ViewData
238.6 页面数据
页面数据是 View Data 中实际用于页面显示的数据。
例如一个机器个体列表页面:
PageData={Title,Items,Pagination,Status,Message}PageData= \{ Title, Items, Pagination, Status, Message \}
其中:
Title
Items
Pagination
Status
Message
都属于页面所需要的数据。
Controller 可以构造:
$pageData = array(
'title' => '机器个体列表',
'items' => $result['data'],
'page' => $result['page'],
'total' => $result['total']
);
然后:
PageData→SmartyPageData \rightarrow Smarty
238.7 页面数据与业务数据
页面数据不能等同于业务数据。
BusinessData≠PageDataBusinessData\neq PageData
业务数据可能包含:
Individual+Knowledge+Capability+Method+HistoryIndividual+ Knowledge+ Capability+ Method+ History
而页面只需要:
ID+Name+Type+StatusID+ Name+ Type+ Status
因此:
BusinessData→ViewData→PageDataBusinessData \rightarrow ViewData \rightarrow PageData
这种转换可以降低 View 与 Model 的耦合。
238.8 Controller组织View Data
Controller 通常承担 View Data 的最终组织。
例如:
public function index()
{
$result =
$this->individualService->list();
$viewData = array(
'title' => '机器个体',
'items' => $result['data'],
'total' => $result['total']
);
return $this->render(
'individual/index.tpl',
$viewData
);
}
完整流程:
Request→ControllerRequest \rightarrow Controller Controller→ServiceController \rightarrow Service Service→ResultService \rightarrow Result Result→ViewDataResult \rightarrow ViewData ViewData→TemplateViewData \rightarrow Template
238.9 View Data的数据结构
View Data 可以使用数组:
$viewData = array(
'title' => '个体列表',
'items' => array(),
'page' => 1,
'total' => 0
);
也可以使用专门的数据对象。
例如:
class ViewData
{
protected $data;
public function __construct($data = array())
{
$this->data = $data;
}
public function get($name, $default = null)
{
if (isset($this->data[$name])) {
return $this->data[$name];
}
return $default;
}
public function all()
{
return $this->data;
}
}
无论采用数组还是对象,核心原则都是:
ViewData→ViewViewData \rightarrow View
而不是:
View→DatabaseView \rightarrow Database
238.10 模板
**Template(模板)**是描述页面结构和数据显示方式的文件。
在 ICAI PHP 工程中,可以使用 Smarty 模板。
例如:
templates/
└── individual/
├── index.tpl
├── create.tpl
├── edit.tpl
└── detail.tpl
模板负责:
- 页面结构;
- 数据显示;
- 条件显示;
- 列表循环;
- 表单结构;
- 页面链接;
- 页面基本布局。
例如:
<h1>{$title}</h1>
<table>
{foreach $items as $item}
<tr>
<td>{$item.id}</td>
<td>{$item.type}</td>
<td>{$item.status}</td>
</tr>
{/foreach}
</table>
这里模板只负责:
ViewData→HTMLViewData \rightarrow HTML
238.11 Smarty模板调用
Controller 将 View Data 交给 View 层以后,由 Smarty 完成模板渲染。
基本关系:
Controller→Smarty→TemplateController \rightarrow Smarty \rightarrow Template
例如:
return $this->view->display(
'individual/index.tpl',
$viewData
);
也可以先分配数据:
$this->view->assign(
'title',
'机器个体列表'
);
$this->view->assign(
'items',
$items
);
$this->view->display(
'individual/index.tpl'
);
因此:
assign→Template→displayassign \rightarrow Template \rightarrow display
形成页面渲染过程。
238.12 Smarty与View的关系
Smarty 是模板引擎,不等于整个 View。
Smarty≠ViewSmarty\neq View
更准确地说:
View→Smarty→TemplateView \rightarrow Smarty \rightarrow Template
View 是 MVC 中的显示职责。
Smarty 是完成模板解析和渲染的工程工具。
因此:
View=ViewData+Template+RenderView= ViewData+ Template+ Render
其中 Render 可以由 Smarty 完成。
238.13 页面输出
模板处理完成以后,最终产生 HTML。
完整过程:
ViewData→Smarty→Template→HTMLViewData \rightarrow Smarty \rightarrow Template \rightarrow HTML
例如:
View Data
{
title: "机器个体",
items: [...]
}
↓
Smarty
↓
individual/index.tpl
↓
HTML
最终:
<h1>机器个体</h1>
<table>
...
</table>
然后:
HTML→HTTPResponse→BrowserHTML \rightarrow HTTPResponse \rightarrow Browser
因此:
PageOutput=HTMLPageOutput=HTML
238.14 View中的数据循环
页面通常需要显示多个 Domain Object。
例如:
Items={I1,I2,…,In}Items=\{I_1,I_2,\ldots,I_n\}
Controller:
$viewData = array(
'items' => $items
);
Smarty:
{foreach $items as $item}
<div>
{$item.id}
{$item.type}
{$item.status}
</div>
{/foreach}
形成:
Items→TemplateLoop→HTMLItemsItems \rightarrow TemplateLoop \rightarrow HTMLItems
View 不需要自己查询数据库。
238.15 View中的条件显示
页面可能根据数据状态显示不同内容。
例如:
{if $item.status == 'active'}
<span>运行中</span>
{elseif $item.status == 'inactive'}
<span>未运行</span>
{else}
<span>未知状态</span>
{/if}
这是显示条件。
它与 ICAI 的领域规则不同。
ViewCondition≠DomainRuleViewCondition\neq DomainRule
例如:
ViewCondition:status=active→显示“运行中”ViewCondition: status=active \rightarrow 显示“运行中”
而:
DomainRule:CapabilityUnavailable→DecisionBlockedDomainRule: CapabilityUnavailable \rightarrow DecisionBlocked
后者必须由 Model/Engine 完成。
因此 View 可以判断显示状态,但不能替代领域规则计算。
238.16 View不承担业务计算
这是 ICAI View 工程的重要原则。
错误结构:
Smarty
↓
读取数据库
↓
计算能力
↓
判断风险
↓
进行决策
↓
输出页面
正确结构:
Controller
↓
Service
↓
Engine
↓
Domain Object
↓
Result
↓
ViewData
↓
Smarty
↓
HTML
因此:
View≠BusinessLogicView \neq BusinessLogic View≠CognitiveEngineView \neq CognitiveEngine View≠DecisionEngineView \neq DecisionEngine
238.17 View与Domain Object
View 可以显示 Domain Object 的数据,但不应该直接承担 Domain Object 的业务责任。
例如:
DomainObject→ViewData→ViewDomainObject \rightarrow ViewData \rightarrow View
而不是:
View→DomainObject→ModifyView \rightarrow DomainObject \rightarrow Modify
如果页面需要修改对象:
View→Form→Request→Controller→Service→DomainObjectView \rightarrow Form \rightarrow Request \rightarrow Controller \rightarrow Service \rightarrow DomainObject
因此页面上的修改操作必须重新进入 Controller 和 Model。
238.18 View与Service
View 不应该直接调用 Service。
不推荐:
View→ServiceView \rightarrow Service
正确:
Controller→Service→ViewData→ViewController \rightarrow Service \rightarrow ViewData \rightarrow View
View 只消费 Controller 已经准备好的数据。
因此:
ViewDependency→ViewDataViewDependency\rightarrow ViewData
而不是:
ViewDependency→ServiceViewDependency\rightarrow Service
这样可以避免模板中出现复杂业务逻辑。
238.19 View与Repository
View 更不能直接调用 Repository。
错误:
View→Repository→MySQLView \rightarrow Repository \rightarrow MySQL
正确:
Repository→DomainObject→Service→Controller→ViewData→ViewRepository \rightarrow DomainObject \rightarrow Service \rightarrow Controller \rightarrow ViewData \rightarrow View
数据库必须保持在 Model 内部。
因此:
View↛MySQLView\not\rightarrow MySQL View↛RepositoryView\not\rightarrow Repository
238.20 页面布局
大型 ICAI 后台系统通常需要统一页面布局。
可以建立:
templates/
├── layout/
│ ├── header.tpl
│ ├── sidebar.tpl
│ ├── footer.tpl
│ └── main.tpl
│
├── individual/
├── cognitive/
├── behavior/
├── memory/
└── maintenance/
页面结构:
Layout
├── Header
├── Sidebar
├── Content
└── Footer
业务页面只负责 Content。
因此:
Page=Layout+Content+ViewDataPage = Layout+ Content+ ViewData
Smarty 可以通过模板继承或包含机制组织公共页面结构。
238.21 View模板与Smarty变量
Controller 可以将数据传给 Smarty:
$viewData = array(
'title' => 'ICAI机器个体',
'individual' => $individual,
'status' => 'running'
);
模板:
<h1>{$title}</h1>
<div>
ID:{$individual.id}
</div>
<div>
状态:{$status}
</div>
形成:
ViewData.title→Smarty.title→HTMLViewData.title \rightarrow Smarty.title \rightarrow HTML
以及:
ViewData.individual→Smarty.individual→HTMLViewData.individual \rightarrow Smarty.individual \rightarrow HTML
238.22 View Data与安全输出
View Data 进入 HTML 前必须考虑输出安全。
例如用户输入:
<script>...</script>
不能未经处理直接进入页面。
因此:
Input→Validation→ViewData→Escape→HTMLInput \rightarrow Validation \rightarrow ViewData \rightarrow Escape \rightarrow HTML
模板引擎应根据具体配置对输出进行必要的 HTML 转义。
原则:
UserInput≠TrustedHTMLUserInput \neq TrustedHTML
页面输出必须区分:
- 普通文本;
- HTML;
- URL;
- JavaScript;
- 属性值。
View 的职责是安全地表达已经确定需要显示的数据,而不是把任何原始输入直接输出。
238.23 View与表单
View 通常需要生成用户操作表单。
例如机器个体创建:
<form method="post"
action="/admin/individual/store.php">
<input
type="text"
name="name">
<input
type="text"
name="type">
<button type="submit">
创建
</button>
</form>
页面只是生成:
Form→RequestForm \rightarrow Request
用户提交以后:
Request→ControllerRequest \rightarrow Controller
形成:
View→Request→ControllerView \rightarrow Request \rightarrow Controller
因此 View 是请求产生的终点,也是下一次请求产生的入口。
238.24 View与页面跳转
Controller 负责页面跳转:
Controller→RedirectController \rightarrow Redirect
View 负责页面中的链接:
View→Link→RequestView \rightarrow Link \rightarrow Request
例如:
<a href="/admin/individual/edit.php?id={$item.id}">
编辑
</a>
用户点击以后:
Link→GET→ControllerLink \rightarrow GET \rightarrow Controller
因此:
View→Request→ControllerView \rightarrow Request \rightarrow Controller
形成下一轮 MVC 请求。
238.25 View工程类
可以建立统一 View 对象。
class SmartyView
{
protected $smarty;
public function __construct($smarty)
{
$this->smarty = $smarty;
}
public function assign($name, $value)
{
$this->smarty->assign(
$name,
$value
);
}
public function render($template, $data = array())
{
foreach ($data as $name => $value) {
$this->assign($name, $value);
}
return $this->smarty->fetch(
$template
);
}
public function display($template, $data = array())
{
foreach ($data as $name => $value) {
$this->assign($name, $value);
}
$this->smarty->display(
$template
);
}
}
这样 Controller 不需要直接操作 Smarty 内部细节。
形成:
Controller→SmartyView→Smarty→TemplateController \rightarrow SmartyView \rightarrow Smarty \rightarrow Template
238.26 View工程目录
ICAI PHP OOP 工程可以组织为:
app/
├── controllers/
├── services/
├── engines/
├── domain/
├── repositories/
└── views/
templates/
├── layout/
├── individual/
├── cognitive/
├── behavior/
├── memory/
└── maintenance/
public/
├── assets/
│ ├── css/
│ ├── js/
│ └── images/
└── index.php
其中:
app/views/
负责 View 类和 View 管理。
templates/
负责 Smarty 模板。
public/assets/
负责页面静态资源。
因此:
View=ViewClass+Template+AssetView = ViewClass+ Template+ Asset
238.27 View与静态资源
页面除了 HTML,还需要 CSS、JavaScript 和图片等资源。
完整输出:
Page=HTML+CSS+JavaScript+ImagePage = HTML+ CSS+ JavaScript+ Image
例如:
HTML
↓
<link>
↓
CSS
HTML
↓
<script>
↓
JavaScript
HTML
↓
<img>
↓
Image
但静态资源不是 View Data。
Asset≠ViewDataAsset\neq ViewData
View Data 是动态数据:
Individual→ViewDataIndividual \rightarrow ViewData
静态资源则是:
CSS/JS/ImageCSS/JS/Image
两者职责不同。
238.28 View与页面状态
页面可以显示 ICAI Domain Object 当前状态。
例如:
LifecycleState=RunningLifecycleState=Running
页面可以显示:
运行中
但 View 不负责决定对象是否应该运行。
正确关系:
Engine→LifecycleState→ViewData→ViewEngine \rightarrow LifecycleState \rightarrow ViewData \rightarrow View
因此:
StateCalculation→ModelStateCalculation\rightarrow Model StateDisplay→ViewStateDisplay\rightarrow View
这是 Model 与 View 的重要边界。
238.29 View与ICAI认知结果
ICAI Engine 可能产生认知结果:
CognitiveResultCognitiveResult
例如:
Object→State→Relation→CognitionResultObject \rightarrow State \rightarrow Relation \rightarrow CognitionResult
Controller 获取:
CognitiveResultCognitiveResult
转换为:
ViewDataViewData
然后:
ViewData→Smarty→HTMLViewData \rightarrow Smarty \rightarrow HTML
因此:
CognitiveEngine
↓
CognitiveResult
↓
CognitiveService
↓
CognitiveController
↓
ViewData
↓
Smarty
↓
HTML
View 只负责把认知结果表达出来。
238.30 View与行为结果
同样,行为执行可以产生:
BehaviorResultBehaviorResult
例如:
ExpectedResult↔ActualResult→VerificationExpectedResult \leftrightarrow ActualResult \rightarrow Verification
Controller 可以将结果转换为:
$viewData = array(
'status' => $result['status'],
'expected' => $result['expected'],
'actual' => $result['actual'],
'verification' => $result['verification']
);
模板:
<div>
状态:{$status}
</div>
<div>
预期结果:{$expected}
</div>
<div>
实际结果:{$actual}
</div>
<div>
验证:{$verification}
</div>
因此:
BehaviorResult→ViewData→ViewBehaviorResult \rightarrow ViewData \rightarrow View
238.31 View工程的完整运行链
综合本章内容:
用户请求
↓
Router
↓
Controller
↓
Service
↓
Engine
↓
Domain Object
↓
Repository
↓
MySQL
↓
Result
↓
Controller
↓
View Data
↓
Smarty
↓
Template
↓
HTML
↓
Browser
形式化:
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\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject \rightarrow Engine \rightarrow Service \rightarrow Controller }
页面:
Controller→ViewData→Smarty→Template→HTML\boxed{ Controller \rightarrow ViewData \rightarrow Smarty \rightarrow Template \rightarrow HTML }
238.32 View工程与MVC统一模型
至此,ICAI MVC 可以完整表示为:
MVC=Controller+Model+View\boxed{ MVC= Controller+ Model+ View }
其中:
Controller=Request+Parameter+Response+RedirectController= Request+ Parameter+ Response+ Redirect Model=DomainObject+Service+Engine+RepositoryModel= DomainObject+ Service+ Engine+ Repository View=ViewData+Template+RenderView= ViewData+ Template+ Render
完整关系:
MVC
│
┌──────────┼──────────┐
↓ ↓ ↓
Controller Model View
│ │ │
│ ┌────┼────┐ │
│ ↓ ↓ ↓ │
│ Domain Service │
│ Object Engine │
│ Repository │
│ │ │
└──────────┼──────────┘
↓
ViewData
↓
Smarty
↓
HTML
238.33 View工程核心原则
ICAI View 工程需要遵循以下原则。
第一,View只负责显示
View=PresentationView=Presentation
第二,View不直接访问数据库
View↛MySQLView\not\rightarrow MySQL
第三,View不直接调用Repository
View↛RepositoryView\not\rightarrow Repository
第四,View不承担核心业务逻辑
View↛BusinessLogicView\not\rightarrow BusinessLogic
第五,View不替代Engine
View≠EngineView\neq Engine
第六,View通过View Data获得数据
Controller→ViewData→ViewController \rightarrow ViewData \rightarrow View
第七,模板负责页面结构
Template→HTMLTemplate \rightarrow HTML
第八,页面输出必须真实反映系统结果
ActualResult→ViewData→HTMLActualResult \rightarrow ViewData \rightarrow HTML
不能将失败结果显示为成功,也不能在 View 中虚构系统状态。
238.34 本章总结
View 是 ICAI MVC 工程体系中的页面表现层,其核心职责是将已经由 Model 和 Controller 处理的数据转换为用户可以看到的页面。
其基本结构为:
View=ViewData+Template+Render\boxed{ View= ViewData+ Template+ Render }
View Data 负责:
ModelResult→ViewDataModelResult \rightarrow ViewData
页面数据负责:
ViewData→PageDataViewData \rightarrow PageData
模板负责:
PageData→TemplatePageData \rightarrow Template
Smarty 负责:
Template→RenderTemplate \rightarrow Render
最终:
ViewData→Smarty→Template→HTML\boxed{ ViewData \rightarrow Smarty \rightarrow Template \rightarrow HTML }
完整 ICAI MVC 请求与输出闭环为:
Request→Controller→Service→Engine→DomainObject→Repository→MySQL→Result→Controller→ViewData→Smarty→HTML\boxed{ Request \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL \rightarrow Result \rightarrow Controller \rightarrow ViewData \rightarrow Smarty \rightarrow HTML }
因此:
Controller=控制请求\boxed{ Controller=控制请求 } Model=组织对象、业务、计算与持久化\boxed{ Model=组织对象、业务、计算与持久化 } View=表达结果\boxed{ View=表达结果 }
三者共同形成:
MVC=RequestControl+DomainProcessing+ResultPresentation\boxed{ MVC= RequestControl+ DomainProcessing+ ResultPresentation }
至此,第236章至第238章完成了 ICAI MVC 三个核心部分的工程对应:
Controller→Model→View\boxed{ Controller \rightarrow Model \rightarrow View }
即:
请求进入→系统处理→结果输出\boxed{ 请求进入 \rightarrow 系统处理 \rightarrow 结果输出 }
这使 ICAI 理论中的 Domain Object、Service、Engine、Repository 与实际 PHP MVC 页面运行结构建立了完整对应关系。