celestriode/constructure

用于验证任何潜在类型的结构的容器,例如 JSON 或 NBT。

v0.6.6 2021-12-24 08:28 UTC

This package is auto-updated.

Last update: 2024-09-24 14:11:16 UTC


README

Constructure 库是一个通用模板,它标准化了由此派生的结构验证库。它具有很少的功能,更注重描述所有扩展库应遵循的最基本内容。

扩展库

以下库使用 Constructure 来验证特定数据结构

Constructure 用于什么?

从用户输入中进行结构评估和验证,例如用户提交的 JSON 或 SNBT 字符串应该遵循高度特定的结构。由于这侧重于用户输入,而用户输入往往是字符串,因此通常需要与扩展库一起提供解析器,具体取决于正在验证的结构语言。

基本扩展

AbstractConstructure 对象

首先,你应该扩展这个类。它包含一个预设的 validate() 方法来比较两个结构(输入和预期结构)。当你实例化对象时,必须提供一个事件处理器。事件处理器由库提供,但你可以自由扩展它或通过 EventHandlerInterface 实现自己的。

必须向扩展的 Constructure 类添加一个方法:toStructure(),它将接受某种形式的输入(通常是字符串)并将其转换为 Constructure 定义的架构。那个结果结构必须是 StructureInterface 的实例。

$constructure = new class(new EventHandler()) extends AbstractConstructure {

    public function toStructure($input): StructureInterface
    {
        // Put code to transform the input into a Constructure structure.
    }
};

结构

所有结构都需要实现 StructureInterface 或扩展 AbstractStructure 类,该类实现了大多数必需的方法。默认情况下,Constructure 不对数据结构的结构做出太多假设。使用 JSON Constructure 库,每个数据类型都是其自己的结构。它还包括其他专用结构来定义预期结构,例如用户定义键的占位符和递归结构的重定向。

AbstractStructure 不提供的方法是 toString(),你可以用它将 StructureInterface 转换回字符串。如果用户输入字符串,这应该能够还原到相同的字符串。由于 JSON Constructure 库对每个数据类型使用结构,这意味着你可以使用 toString() 方法为用户输入的不正确部分提供上下文。

$structure = new class extends AbstractStructure {

    public function toString(PrettifierInterface $prettifier = null): string
    {
        return "";
    }
};

你需要两个结构来进行验证:一个是由用户输入并使用 $constructure->toStructure() 构建的,另一个是描述用户输入必须匹配的结构。那个预期结构应该事先构建。使用 $constructure->validate() 方法进行比较。

结构验证使用审计,而反馈使用事件处理。

美化

当使用 toString() 方法时,可以提供自定义美化器以将结构转换为更漂亮的字符串(例如,向压缩的 JSON 结构添加换行符和制表符)。此库旁边没有提供美化类。

事件处理

事件可以在验证过程中触发。事件做什么完全取决于您,因为事件是一个纯粹的可调用对象。您可以使用EventHandlerInterface接口创建自己的事件处理器,或者使用预先制作的EventHandler类。给到$constructure对象的事件处理器实例将包含所有必要的事件。

可以使用addEvent()方法添加事件。匿名函数的可选输入取决于触发器,因此请确保您的事件与触发器匹配。可以添加具有相同名称的多个事件,并且它们将同时触发。

$eventHandler = (new EventHandler())->addEvent("event_name", function ($input1, $input2, $input3) {
    
    // Do something here.
});

触发事件涉及在trigger()方法中调用事件名称,并根据需要提供任何输入。

$eventHandler->trigger("event_name", 1, "two", 3);

您可以在SampleEvents中找到示例事件函数。

事件静音

事件处理器可以被静音以防止触发事件,就像这些事件不存在一样。这用于运行断言,这些断言应该是静默的。

事件处理器的mute()方法将静音它,而unmute()将取消静音(而silent()将返回是否静音)。

事件捕获

与其完全忽略事件,不如捕获它们并确定是否应该忽略它们可能更有用。例如,BitwiseAudits 审计使用事件捕获来延迟触发事件,直到确定审计失败。

当使用capture()启用捕获时,任何触发的事件将被暂时搁置。完成捕获后,您执行以下两种操作之一:

  1. 使用clear()方法,它将清除所有捕获的事件而不会运行它们。
  2. 使用release()方法,它将禁用捕获并运行捕获期间捕获的事件。

捕获的事件通过EventHandler::CAPTURED_RELEASED默认事件触发。作为一个默认事件,您可以在释放时更改捕获事件的处理方式。

默认事件

默认事件是任何EventHandler实例默认包含的事件。使用new EventHandler(false)实例化事件处理器将禁用默认事件的包含。

目前,唯一的默认事件是用于释放捕获的事件。如果您想获取该特定事件的函数,可以使用getReleaseCapturedEvent()静态方法。

审计

审计是验证输入结构的程序。为了使输入结构被认为是正确的,必须在将其与预期结构进行比较时,使所有审计通过输入。

所有审计都必须实现AuditInterface,尽管有一个提供大多数功能的AbstractAudit类。您必须实现2个方法

  1. audit(),它将检查输入结构,并返回true或false,具体取决于输入是否根据审计正确。Constructure对象也提供,它提供对事件处理器的访问,以及额外的验证预期结构。
  2. getName(),它返回审计的友好名称,可以显示给最终用户,如果基于失败(或成功)的审计提供反馈。
$audit = new class extends AbstractAudit {

    public function audit(AbstractConstructure $constructure, StructureInterface $input, StructureInterface $expected): bool
    {
        return true;
    }

    public static function getName(): string
    {
        return "user-friendly name of the audit";
    }
};

审计应根据对输入结构的发现触发事件。事件可用于日志记录或用户反馈。

默认情况下,AbstractStructure 类在比较过程中运行审计,不做其他操作。如果没有审计,输入和预期结构将被视为完美匹配。有关审计的更多示例,请参阅JSON Constructure库。

提供了一个示例 IsNumber 审计,展示了如何使用审计进行输入验证和事件触发。但通常不应使用它。然而,还有四个其他审计可供使用

  1. AlwaysTrue,这是一个始终通过的审计。
  2. AlwaysFalse,这是一个始终失败的审计。
  3. TriggerEvent,它与其说是审计,不如说是事件注入器。这是一个延迟审计,它在非延迟审计之后运行。这可以在审计后分析结构时很有用。
  4. BitwiseAudits,它接收一个运算符(OR、XOR或AND)和一组审计,然后根据这组审计的结果执行运算。这个审计将根据该操作通过或失败,而不是根据每个单独的审计通过或失败。因为默认情况下审计就是按照这种方式工作的,所以不包括AND。

谓词

谓词是一个审计,作为必须通过另一个审计才能运行的条件。谓词运行时静默,不触发事件,并返回谓词是否通过。如果谓词失败,主审计将不会运行(因此不会用于通过或失败输入结构)。如果它通过了,主审计将随后运行。

可以使用addPredicates()addPredicate()将谓词添加到审计实例中。AbstractStructure类(不是AbstractAudit)将处理谓词,所以如果你正在创建自己的StructureInterface实现,务必也要处理它。