PSR 13 超媒体链接
超媒体链接正在日益成为 Web 中重要的一部分,常见于 HTML 上下文和各种 API 格式上下文中
但是,没有单一的通用超媒体格式,也没有通用的方法来表示格式之间的链接
本规范旨在为 PHP 开发人员提供一种表示超媒体链接的简单而通用的方法,这种方法用于独立于所使用的序列化格式
当然了,反过来说,又允许系统将超媒体链接的响应序列化为一种或多种格式,而不依赖于这些链接应该是什么
本篇规范中的 必须,不得,需要,应,不应,应该,不应该,推荐,可能 和 可选 等词按照 [RFC 2119]RFC 2119 中的描述进行解释
参考文档
1. 规范
1.1 基本连接
超媒体链接至少包含:
- 一个用于表示被引用的目标资源的 URI
- 一个用于关联目标资源与源的关系
链接中可以存在大量的其它的属性,具体取决于所使用的格式。 这些附加的属性并没有很好的标准化或通用性,本规范也不会试图对它们进行标准化
就本规范而言,我们定义了定义了以下术语
-
- 「 实现对象 」( Implementing Object )
- 实现了此规范中定义的某个接口的对象
-
- 「 序列化器 」( Serializer )
- 接受一个或多个链接对象和并根据一些已经存在的格式生成一个已序列化的内容的库或者其它系统
1.2 属性
除了 URI 和 关系 属性外,所有链接 可以 包含零个或多个其它的属性。
因为没有任何规范来指定允许或禁止哪些属性或值,所以值的有效性取决于上下文,通常取决于特定的序列化格式,通常支持的属性包括 「 hreflang 」、 「 title 」 和 「 type 」
-
如果序列化格式有要求,序列化时 可以 忽略链接对象上的属性
-
序列化时应该对所有提供的属性进行编码,以便允许用户扩展,除非序列化格式中明令禁止
-
某些属性 ( 通常是
hreflang
) 可能会在其上下文中出现多次。因此,一个属性值可以是一个值的数组而不是一个简单的值。
序列化时 可以 以任何序列化格式支持的格式 ( 例如空格分隔列表,逗号分隔列表等 ) 对该数组进行编码。
如果给定属性不允许在特定上下文中有多个值,序列化时 必须 使用第一个值并忽略后续所有的值
-
如果属性值为布尔值
true
,在适当的情况下,可以 使用序列化格式支持的缩写形式例如,当属性的存在具有布尔含义时,HTML 允许属性没有值
当且仅当属性为布尔值
true
时,此规则才适用,并不适用于 PHP 中的其它任何「 truthy 」值,例如整数 1 -
如果一个属性值是布尔值
false
,序列化时应该完全忽略该属性,除非它会改变结果的语义含义当且仅当该属性为布尔值
false
时,此规则才适用,并不适用于 PHP 中的任何其它的 「 truthy 」 值,例如整型 0
1.3 关系
链接关系是字符串类型,可以是公开注册机构中定义的简写关键字,也可以是私有注册机构中定义的 绝对 URI
如果使用了简写的关键字,那么它 应该 在 IANA 注册管理机构中有一个相应的匹配
http://www.iana.org/assignments/link-relations/link-relations.xhtml
还可以选择使用 microformats.org 注册管理机构,但并不保证在每种况下都有效
http://microformats.org/wiki/existing-rel-values
未在上述注册管理机构或类似的公共注册管理机构中定义的关系都被视为 「 私有 」,即特供于特定应用程序或用例,这种关系必须使用绝对 URI
1.4 链接模板
RFC 6570 为 URI 模板定义了一种格式,这种格式的 URI 可以使用客户端工具提供的值来填充。
一些超媒体格式支持模板化的链接且可以有一个特殊方式将链接表示模板,而另一些则不支持,
不支持 URI 模板格式的序列化程序 必须 忽略任何模板化的链接
1.5 可伸缩的提供者
在某些情况下,链接提供者可能需要添加其它链接的功能,另一些情况下,链接提供者必须是只读的,且可以在运行时从其它数据源中派生而来。 出于这个原因,可修改的提供者是可自由选择是否实现的次要接口
此外,某些链接提供者对象 ( 例如 PSR-7 Response 对象 ) 被设计为不可变更的,也就是说,在对象上添加链接的方式是行不通的。
因此,EvolvableLinkProviderInterface
的单一方法需要返回一个新对象,与原始对象相同,但是包含一个附加链接对象
1.6 可伸缩的链接对象
链接对象在大多数情况下是值对象,允许它们以与 PSR-7 中的值对象相同的方式伸缩是一个有用的选择。
所以,此规范还包含一个额外的 EvolvableLinkInterface
接口, 提供了一次变更中生成新对象实例的方法。
这种模型与 PSR-7 使用的相同,由于 PHP 的写时复制行为,这显然是 CPU 和内存都高效的方式
模版化没有可伸缩的方法,因为链接的模板化值完全基于 href 值,因此它 绝对不能单独设置,只能从 href 值中派生而来,而不管 href 是否是 RFC 6570 链接模板的
2. 包
此规范定义的接口和类都在 psr/link 命名空间下
3. 接口
3.1 Psr\Link\LinkInterface
<?php namespace Psr\Link; /** * 一个可读的链接对象 */ interface LinkInterface { /** * 返回链接对象的链接地址 * * 链接对象的链接地址必须是以下列表中的一种: * - RFC 5988 中定义的绝对网址 * - RFC 5988 中定义的相对网址,基础网址必须是基于客户端的上下文而已知的 * - RFC 5988 中定义的 URI 模板 * * 如果返回的是 URL 模板,那么 isTemplated() 必须返回真值 * * @return string */ public function getHref(); /** * 返回对象的链接地址是否是一个 URL 模板 * * @return bool 如果链接对象是模板化的,返回真,否则返回假 */ public function isTemplated(); /** * 返回链接的关系类型 * * 此方法返回链接的 0 个或多个字符串类型的关系类型,返回的是一个数组格式 * * @return string[] */ public function getRels(); /** * 返回描述目标 URI 的属性列表 * * @return array * 属性的键值对列表, 键是字符串且值可以是 PHP 的原始类型或由 PHP 字符串组成的数组。 * 如果没有找到任何属性,则 **必须** 返回一个空数组 */ public function getAttributes(); }
3.2 Psr\Link\EvolvableLinkInterface
<?php namespace Psr\Link; /** * 一个可伸缩的链接值对象 */ interface EvolvableLinkInterface extends LinkInterface { /** * 返回一个包含了指定 href 的实例 * * @param string $href * 要包含的 href 值,它必须是以下格式之一: * - RFC 5988 中定义的绝对 URL * - RFC 5988 中定义的相对 URL 。相对链接的基础应该是此客户端上下文所周知的 * - RFC 6570 中定义的 URL 模板 * - 一个能提供以上值的实现了 __toString() 方法的对象 * * 实现库 **应该** 立即执行传递的对象转换为字符串,而不是等到以后返回的时候再转换 * * @return static */ public function withHref($href); /** * 返回设置了指定关系的新实例 * * 如果指定的关系已经存在,不应该重复,此方法 **必须** 正常返回而不能抛出任何错误 * * @param string $rel * 要被添加的关系值 * @return static */ public function withRel($rel); /** * 返回删除了指定关系的实例 * * 如果指定的关系不存在,此方法 **必须** 正常返回而不是抛出任何错误 * * @param string $rel * 要删除的关系值 * @return static */ public function withoutRel($rel); /** * 返回增加了指定属性的实例 * * 如果指定的属性已经存在,则可能被新的属性值代替 * * @param string $attribute * 要设置的属性 * @param string $value * 要设置的属性值 * @return static */ public function withAttribute($attribute, $value); /** * 返回排除指定属性的实例 * * 如果不存在指定的属性,此方法 **必须** 正常返回而不能抛出任何错误 * * @param string $attribute * 要移除的属性 * @return static */ public function withoutAttribute($attribute); }
3.2 Psr\Link\LinkProviderInterface
<?php namespace Psr\Link; /** * 一个链接提供者对象 */ interface LinkProviderInterface { /** * 返回一个包含链接实例的迭代器 * * 迭代器可以是一个数组或任何 PHP \Traversable 对象 * * 如果没有包含任何链接,**必须** 返回一个空的数组或者 空的 \Traversable * * @return LinkInterface[]|\Traversable */ public function getLinks(); /** * 返回包含指定引用的链接实例组成的迭代器 * * 迭代器可以是一个数组或任何 PHP \Traversable 对象 * * 如果没有包含任何链接,**必须** 返回一个空的数组或者 空的 \Traversable * * @return LinkInterface[]|\Traversable */ public function getLinksByRel($rel); }
3.3 Psr\Link\EvolvableLinkProviderInterface
<?php namespace Psr\Link; /** * 一个可伸缩的链接提供者的值对象 */ interface EvolvableLinkProviderInterface extends LinkProviderInterface { /** * 返回包含指定链接的实例 * * 如果指定的链接不存在,该方法 **必须** 返回一个正常的值而不是错误 * * 如果 $link === 集合中已经存在的某个链接,那么该链接就存在 * * @param LinkInterface $link 要被添加进集合的链接的实例 * @return static */ public function withLink(LinkInterface $link); /** * 返回已经删除的指定链接的实例 * * 如果指定的链接不存在,该方法 **必须** 返回一个正常的值而不是错误 * * 如果 $link === 集合中已经存在的某个链接,那么该链接就存在 * * @param LinkInterface $link 要删除的链接的实例 * @return static */ public function withoutLink(LinkInterface $link); }