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

第238章 View工程

第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 页面运行结构建立了完整对应关系。

Leave a Reply

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