lucinda / abstract_mvc
基于STDIN类型(URL请求、异常)进行扩展的抽象MVC API
Requires
- php: ^8.1
Requires (Dev)
- lucinda/unit-testing: ^2.0
README
目录
关于
此API是一个 框架(需要开发者进行绑定),用于包含与STDIN类型(控制台、URL请求或异常)无关的MVC API部分。它作为以下API的基础:
- STDOUT MVC API:其中STDIN来自URL请求
- STDERR MVC API:其中STDIN来自URL/控制台请求的STDERR
- 控制台MVC API(待完成):其中STDIN来自控制台请求
API完全遵循PSR-4规范,仅需要PHP8.1+解释器和SimpleXML扩展。要快速了解其工作原理,请查看
- 配置:设置XML文件以配置此API
- 绑定点:将用户在XML/代码中定义的自定义组件绑定到API原型,以获得必要的功能
- 参考指南:描述所有与开发者相关的API类、方法和字段
- 单元测试:API具有100%的单元测试覆盖率,使用UnitTest API而不是PHPUnit,以获得更大的灵活性
所有类都属于 Lucinda\MVC 命名空间!
配置
要配置此API,您必须有一个包含以下标签的XML文件
应用程序
此标签的最大语法是
<application default_format="..." default_route="..." version="..."> <paths views="..."/> </application>
其中
- application:(必填)包含根据属性和标签配置应用程序的设置
标签示例
<application default_format="html" default_route="" version="1.0.1"> <paths views="application/views"/> </application>
解析器
此标签的基本语法是
<resolvers> <resolver format="..." content_type="..." class="..."/> ... </resolvers>
其中
- 解析器: (必填) 包含根据响应格式(扩展名)解析视图的设置。为每个支持的格式持有子元素
- 解析器: (必填) 根据属性配置一个特定格式的视图解析器
- 格式: (必填) 定义视图解析器处理的显示格式(扩展名)。
示例: "html" - 内容类型: (必填) 定义与上述显示格式匹配的内容类型。
示例: "text/html" - 类名: (必填) 用户定义的PS-4自动加载兼容类(包括命名空间)的名称,该类将解析视图。
必须是一个ViewResolver实例!
- 格式: (必填) 定义视图解析器处理的显示格式(扩展名)。
- 解析器: (必填) 根据属性配置一个特定格式的视图解析器
标签示例
<resolvers> <resolver format="html" content_type="text/html" class="Lucinda\Project\Resolvers\Html" charset="UTF-8"/> <resolver format="json" content_type="application/json" class="Lucinda\Project\Resolvers\Json" charset="UTF-8"/> </resolvers>
路由
此标签的最大语法是
<routes> <route id="..." controller="..." view="..." format="..."/> ... </routes>
其中
- 路由: (必填) 包含处理请求的路由规则
- 路由: (可选) 包含基于属性的特定于请求URI的路由规则
- id: (必填) 唯一路由标识符(例如:请求的资源URL,不带尾随斜杠)
示例: "users/(name)" - 控制器: (可选) 用户定义的PS-4自动加载兼容类(包括命名空间)的名称,该类将根据模型减轻请求和响应。
必须是一个Runnable实例! - 视图: (可选) 包含用户定义的模板文件,该文件包含请求的响应配方。示例:"homepage"
- 格式: (可选) 包含响应格式,如果与application中的default_format不同。
必须与解析器中的format属性匹配!
- id: (必填) 唯一路由标识符(例如:请求的资源URL,不带尾随斜杠)
- 路由: (可选) 包含基于属性的特定于请求URI的路由规则
标签示例
<routes> <route id="index" controller="HomepageController" view="index"/> <route id="user/(id)" controller="UserInfoController" view="user-info" format="json"/> </routes>
绑定点
为了保持灵活性和实现最佳性能,API所做的假设不超过绝对必要的!相反,它通过XML提供了将原型绑定到其上的能力
程序性绑定
它为开发人员提供了一种通过FrontController构造函数程序性地将其原型绑定到其上的能力
单元测试
为了测试和示例,请检查API源中的以下文件/文件夹
- test.php:在控制台运行单元测试
- unit-tests.xml:设置单元测试并模拟 "loggers" 标签
- tests:来自src文件夹的类的单元测试
参考指南
这些类由API完全实现
- Application:读取配置 XML文件并在其中封装信息
- Application\Route:封装与请求处理的id匹配的路由XML标签
- Application\Format:封装与请求处理的响应format匹配的解析器XML标签
- Response:封装要发送回调用者的响应
- Response\Status:封装响应HTTP状态
- Response\View:封装将绑定到响应正文的视图模板和数据
以下抽象类需要由开发人员扩展,以便获得以下能力
- Runnable:定义可以运行的逻辑组件的蓝图
- ViewResolver:封装将 Response\View 转换为 Response 主体
类 Application
类 Application 封装从 XML 中检测到的信息,并定义以下与开发者相关的公共方法
其他公共方法仅与在此之上构建的 API 相关
类 Application Route
类 Application\Route 封装从匹配的 route XML 标签中检测到的信息,并定义以下公共方法
类 Application Format
类 Application\Format 封装从匹配的 resolver XML 标签中检测到的信息,并定义以下公共方法
为了更好地了解视图最终将如何解析,请查看以下 如何解析视图 文档!
类 Response
类 Response 封装用于生成响应的操作。它定义了以下与开发者相关的公共方法
当 API 完成处理时,它将调用 commit 方法将头信息和响应体发送回调用者!
类 Response Status
类 Response\Status 封装响应 HTTP 状态,并定义以下与开发者相关的公共方法
类 Response View
类 Response\View 实现 \ArrayAccess 并封装将后来绑定到响应体的模板和数据。它定义了以下与开发者相关的公共方法
通过实现 \ArrayAccess,开发者可以像处理数组一样处理此对象
$this->response->view()["hello"] = "world";
类 Response Redirect
类 Response\Redirect 是一个 Runnable,它封装了带有其选项的 http 状态 301/302 重定向。它定义了以下与开发者相关的公共方法
示例
$redirection = new Lucinda\\MVC\\Redirect("https://www.google.com");
$redirection->setPermanent(false);
$redirection->run();
接口 Runnable
接口 Runnable 它实现,该类包含以下公共方法
使用示例
https://github.com/aherne/lucinda-framework/blob/master/src/Controllers/SecurityPacket.php
抽象类 ViewResolver
抽象类 ViewResolver 实现了 Runnable 并封装将 Response\View 转换为最终响应格式的响应体
开发者需要为每个解析器实现 run 方法,在方法中,他们可以通过构造函数访问 API 注入的以下受保护字段
使用示例
https://github.com/aherne/lucinda-framework/blob/master/src/ViewResolvers/Html.php
为了更好地了解视图解析器的工作方式,请查看以下 如何定位视图解析器 部分!
规格说明
由于此 API 是构建 MVC API 的框架,因此它包含一系列规范,这些规范可能或可能不会在此自动实现
如何检测响应格式
为了更好地理解在 application XML 标签中 default_format 和 default_route 属性如何与 routes 标签中的 format 属性和 resolvers 标签中的 format 属性一起工作,让我们以这个 XML 为例。
<application default_route="index" default_format="html" ...> ... </application> <routes> <route id="index" .../> <route id="blog" format="json" .../> <route id="users" .../> ... </routes> <resolvers> <resolver format="html" .../> <resolver format="json" .../> ... </resolvers>
以上将出现以下情况:
这种逻辑需要由子 API 实现,因为解析器的本质取决于 STDIN 类型!
视图解析器是如何定位的
为了更好地理解在 application XML 标签中 default_format 属性如何与 resolvers 标签中的 format 和 class 属性一起工作,让我们以这个 XML 为例。
<application default_format="html" ...> ... </application> ... <resolvers> <resolver format="html" class="Lucinda\Project\ViewResolvers\Html" .../> </resolvers>
在这种情况下,如果 composer.json 中的 "psr-4" 属性将 "Lucinda\Project\" 与 "src/" 文件夹关联,那么
- 自动加载的文件将是 src/ViewResolvers/Html.php
- 那里找到的类必须
- 命名为: "Html"
- 属于命名空间: "Lucinda\Project\ViewResolvers"
- 扩展 ViewResolver
这个逻辑完全由这个 API 实现!开发者只需要在 XML 中插入合适的 ViewResolver 类。
如何检测路由
为了更好地理解在 application XML 标签中 default_route 属性如何与 routes 标签中的 id 属性一起工作,让我们以这个 XML 为例。
<application default_route="index" ...> ... </application> <routes> <route id="index" .../> <route id="blog" .../> ... </routes>
假设 STDIN 来自 HTTP 请求,以上将出现以下情况:
这个逻辑需要由子 API 实现,因为请求的逻辑取决于 STDIN 类型!
如何定位控制器
为了更好地理解在 application XML 标签中 default_route 属性如何与 routes 标签中的 id 和 controller 属性一起工作,让我们以这个 XML 为例。
<application default_route="index" ...> ... </application> ... <routes> <route id="index" controller="Lucinda\Project\Controllers\Homepage" .../> </routes>
在这种情况下,如果 composer.json 中的 "psr-4" 属性将 "Lucinda\Project\" 与 "src/" 文件夹关联,那么
- 自动加载的文件将是: "src/Controllers/Homepage.php"
- 那里找到的类必须
- 命名为: "Homepage"
- 属于命名空间: "Lucinda\Project\Controllers"
- 扩展 Lucinda**???**\Controller
如你所见,控制器命名空间被省略了,因为控制器本身必须由子 API 实现(因为它依赖于 STDIN 类型)。
如何定位视图
为了更好地理解在 application XML 标签中 views 属性如何与 routes 标签中的 id 和 view 属性一起工作,让我们以这个 XML 为例。
<application ...> <paths views="application/views"/> </application> ... <routes> <route id="user/info" view="user-info" .../> </routes>
在这种情况下,如果路由 "user/info" 与 STDIN 请求匹配,那么
- 自动加载的文件将是: "application/views/user-info.???"
如你所见,视图扩展被省略了,因为视图本身必须由子 API 实现(因为它依赖于 STDIN 类型)。