frontastic/common

2.48.5 2024-05-03 14:39 UTC

README

版权(C)Frontastic GmbH - 所有权利保留

这是一个包含Frontastic常见领域概念和功能的库。

关于Frontastic的文档可以在https://docs.frontastic.cloud/找到,而API文档可以在本存储库内部找到。API Documentation

API设计概念

TL;DR

  • 纯数据对象,无逻辑
  • 逻辑可替换的封装在DIC或工厂中的服务
  • 暴露所有后端共有的基础
  • dangerousInner* 用于原始数据
  • before* / after* 装饰器用于客户调整

领域模型

我们在API设计中相信的核心概念之一是 Qafoo博客中描述的Injectables vs Newables。这就是为什么我们有一些数据对象,这些对象通常没有任何方法,还有一些实现服务交互的对象。在本文档中,我们称它们为数据对象(Newables)和服务(Injectables)。

数据对象

领域对象表示数据结构。允许在数据对象上执行的唯一方法是任何人都不会以不同方式实现的方法。由于API是许多不同客户项目的基础,这些方法基本上将不存在。一个流行的例子是在领域对象中的邮件验证,而邮件验证正则表达式已经不同,你甚至可以考虑使用外部服务来验证电子邮件地址的有效性,这显然不应该在数据对象中发生。

我们的数据对象被建模为具有公开属性的类,该属性扩展了基DataObject,以确保PHP在访问不存在属性时抛出异常。我们这样做是为了简化创建和使用 - 我们不认为获取器和设置器是必需的,即使你可以在那里实现额外的类型检查。在不久的将来,PHP甚至可能添加对类型化属性的本地支持,这将进一步解决这个问题。

虽然我们通常认为数据对象的不可变性是一个优点,并且我们通常不应该自己修改它们,但我们的数据对象是有意可变的。这允许客户进行修改:例如,我们允许客户映射出额外的属性,并允许他们在变体中定义额外的属性(见装饰器)。

对于那些允许修改PHP代码的客户,我们允许他们扩展现有的数据对象来创建具有附加属性的对象。因此,没有类应该是 final

方法的所有参数和返回值(除构造函数外)应该是数据对象,我们很少使用标量值,这是不鼓励的。服务 不能 是参数(除构造函数或设置器注入外)或返回值。

服务

服务实现实际功能,例如实现针对特定端点的API接口。服务 始终 由我们的工厂(通过配置)或Symfony依赖注入容器创建。服务也可以被客户覆盖,但这应该是实现特定功能的最后手段。我们希望提供合理的扩展点(如装饰器)来实现所有功能。

除了API的一般实现(如 ProductApi\Commercetools)之外,还可能有任何数量的辅助服务(如映射器、客户端等)。

代码结构

主要有两种类型的包

  • API 抽象 *ApiBundle(例如 ProductApiBundle

    这些包只应包含接口和领域对象。目前,Commercetools 实现违反了这一原则,它是 API 抽象的一部分。这将相应地进行重构。

  • API 实现(例如 ShopwareBundle

    这些包实现了特定后端API,如果客户使用该后端,则可以启用。这些API实现包通常实现了API抽象包中的接口,并可能包含额外的辅助服务。它们通常不应定义任何领域对象。

除此之外,还有一些额外的包和基础设施代码,如通用的 Http-Client-Implementation,它允许我们以通用方式实现、监控和配置 HTTP 请求。

装饰器

装饰器结构在 Catwalk 中实现,但对这些API仍然相关:我们允许人们使用所有 API 方法的 before*after* 装饰器来挂钩到每个 API 调用。这允许人们修改对 API 的查询以及 API 的返回值。这是所有 API 的主要扩展点。在此之上,可能会有由 API 工厂处理的特定 API 配置。

危险的内部*

许多领域对象都有一个 dangerousInner* 属性(例如 dangerousInnerProduct),它是对相应 API 未修改返回值的直接引用。这允许我们的 API 的用户访问我们自己的映射器没有映射到我们自己的领域对象的额外数据。

我们理解我们没有涵盖所有映射 API 的潜在用例,这允许人们在他们的装饰器中访问原始数据。然而,后端为前端通常会将 dengerousInner* 属性去除,以防止泄露机密数据并减少数据大小。此外,某些实现可能使用的许多 API SDK 使用的是无法合理序列化的“领域对象”。