icanboogie/operation

专注于单一任务的丰富功能的控制器

5.0 2021-06-01 19:32 UTC

This package is auto-updated.

Last update: 2024-08-29 03:57:45 UTC


README

Release Build Status Code Quality Code Coverage Packagist

操作是针对单一任务的丰富功能的控制器,通常用于创建/更新/删除记录。

前言

本文件中的事件通常以 ICanBoogie\Operation::<event_type> 引用,其中 <event_type> 是事件的类型。例如,ICanBoogie\Operation::rescue 是一个类型为 rescue 的事件,在 ICanBoogie\Operation 的实例上触发。现在考虑一个从 ICanBoogie\Operation 继承的 SaveOperation 类。在它的一个实例上也可以触发 rescue 事件,可以将事件钩子附加到 SaveOperation::rescue 来恢复操作。

由于 ICanBoogie 的事件系统基于类层次结构,附加到 SaveOperation::rescue 的事件钩子仅用于恢复 SaveOperation 及其子类的实例,而附加到 ICanBoogie\Operation::rescue 的事件钩子用于恢复 ICanBoogie\Operation 及其子类(包括 SaveOperation)的实例。

因此,当您看到 ICanBoogie\Operation::rescue 时,请理解为“在 ICanBoogie\Operation 子类 I 想要监听的一个实例上触发了 'rescue' 类型的事件”。

请阅读 icanboogie/event 包的文档,了解更多关于事件系统的信息。

操作

Operation 的实例表示一个操作。尽管该类提供了许多控制方法和获取器,但操作的有效性和处理必须由子类根据其设计实现。

控制操作

在验证和处理操作之前,会运行控制。要运行的控制由操作定义。以下实现了控制,并可扩展:

  • CONTROL_AUTHENTICATION:控制用户的身份验证。
  • CONTROL_PERMISSION:控制用户关于操作的权利。
  • CONTROL_RECORD:控制与操作关联的记录。使用获取器 record 来检索记录。
  • CONTROL_OWNERSHIP:控制用户对记录的所有权。
  • CONTROL_FORM:控制与操作关联的表单。使用获取器 form 来检索表单。《FormNotFound》可以在找不到与操作关联的表单时抛出。《FormHasExpired》可以抛出以指示与操作关联的表单已过期。

通过 controls 魔法属性获取控制定义

<?php

use ICanBoogie\Module;
use ICanBoogie\Operation;

class SaveOperation extends Operation
{
    protected function get_controls()
    {
        return [

            self::CONTROL_PERMISSION => Module::PERMISSION_CREATE,
            self::CONTROL_RECORD => true,
            self::CONTROL_OWNERSHIP => true,
            self::CONTROL_FORM => true

        ] + parent::get_controls();
    }
}

以下事件在过程中触发

  • 在通过 control() 方法控制操作之前,触发类 BeforeControlEventICanBoogie\Operation::control:before 事件。第三方可以使用此事件来更改要运行的控制,或者完全清除它们。

  • 在控制之后,触发类 ControlEventICanBoogie\Operation::control 事件。第三方可以使用此事件来更改控制的输出。

  • 在失败时,会触发类 FailureEvent 的事件 ICanBoogie\Operation::failure,其中其 type 属性设置为 control

  • 如果未重写 form 获取器,则会触发类 GetFormEvent 的事件 ICanBoogie\Operation::get_form。这允许第三方提供表单以检查请求的参数。

验证操作

在处理操作之前,需要对其进行验证。通过调用 validate() 方法来验证操作。应在提供的 $errors 集合中收集错误。如果方法返回空值或定义了错误,则认为验证失败。

以下事件在过程中触发

  • 在验证之前,会触发类 BeforeValidateEvent 的事件 ICanBoogie\Operation::validate:before。第三方可以使用此事件来修改错误或验证状态。

  • 在验证之后,会触发类 ValidateEvent 的事件 ICanBoogie\Operation::validate。第三方可以使用此事件来修改错误或验证结果。

  • 在失败时,会触发类 FailureEvent 的事件 ICanBoogie\Operation::failure

处理操作

在控制和验证之后,通过调用其 process() 方法最终处理操作。如果方法返回 null 或定义了错误,则认为操作处理失败。

以下事件在过程中触发

  • 在处理之前,会触发类 BeforeProcessEvent 的事件 ICanBoogie\Operation::process:before。第三方可以使用此事件来修改请求、响应或错误。

  • 在处理之后,会触发类 ProcessEvent 的事件 ICanBoogie\Operation::process。第三方可以使用此事件来修改结果、请求或响应。

处理失败

在处理(控制/验证/处理)过程中抛出的异常将被捕获并转换为 Failure 异常。可以使用 getPrevious() 方法或 previous 属性访问原始异常。使用异常代码和消息更新操作的响应。

如果响应中有客户端或服务器错误,也会抛出 Failure 异常,在这种情况下,异常会被触发而无需先前的异常。

注意:失败的操作可以被调度器恢复。

转发操作

当使用请求参数 Operation::DESTINATIONOperation::NAME 定义实际目标操作名称时,操作被视为 转发。请求的 URL 对转发操作无关紧要,并且无论成功或失败,调度过程都会继续。例如,这允许将表单提交到它们的 view URL(而不是操作 URL),并在发生错误时再次显示。

注意:具有 location 的成功响应不会被丢弃,它们将重定向请求。

注意:此功能目前是 icanboogie/module 包的基础,并且实际上是由该包处理转发操作。这可能会在未来发生变化。

<?php

use ICanBoogie\HTTP\Request;
use ICanBoogie\Operation;

$request = Request::from([

    'path' => '/',
    'request_params' => [

        Operation::DESTINATION => 'form',
        Operation::NAME => 'post',

        // …
    ]
]);

$operation = new SaveOperation;
$response = $operation($request);

$operation->is_forwarded; // true

响应

操作响应由一个 Response 实例表示。由 process() 方法返回的值设置为其 rc 属性。如果其值为 null,则认为操作失败,此时将操作的状态设置为“400 操作失败”。

响应位置

使用 Location 头部让浏览器加载不同的网页。这通常用于在执行操作(例如创建/删除资源)后重定向用户。响应的 location 属性用于设置该头部。

响应位置和XHR

重定向XHR不是理想的行为,因为尽管我们可能希望重定向用户,但我们仍然需要首先获取请求的结果。在这种情况下,location 属性的值将移动到 redirect_to 字段,并将 location 属性设置为 null。因此,禁用了浏览器重定向,返回响应,并由开发者决定是否应该遵守重定向。

分发器

该包提供了一个HTTP分发器来分发操作。它应该放在分发器链的顶部,在所有路由之前。分发器尝试从指定的请求创建一个 Operation 实例,如果失败则立即返回。

操作响应的处理

分发器丢弃转发操作的响应,除非请求是XHR或响应有位置。记住,失败的操作会抛出一个 Failure 异常,这可以被捕获。

捕获失败的操作

如果在操作的调度过程中抛出异常,分发器将尝试使用以下步骤来捕获它

  1. 触发 RescueEvent 类的 ICanBoogie\Operation::rescue 事件。附加到此事件的钩子事件可以替换异常或提供响应。如果提供了响应,则返回。
  2. 否则,如果异常不是 Failure 的实例,则重新抛出异常。
  3. 否则,如果请求是XHR,则返回操作响应。
  4. 否则,如果操作被转发,则将异常消息记录为错误,并返回方法。
  5. 否则,重新抛出异常。

总之,如果 ICanBoogie\Operation::rescue 事件期间提供了响应,或者稍后请求是XHR,则失败的操作将被捕获。尽管操作捕获可能成功,但返回的响应可以是错误响应。

注意:如果操作被转发并且操作无法被捕获,则请求调度过程将简单地继续。

定义操作

将操作定义为路由

因为操作是控制器,所以它们可以以相同的方式定义。

以下示例演示了 module Nodes 如何定义路由来设置/取消设置 is_online 属性

<?php

namespace Icybee\Modules\Nodes\Operation;

use ICanBoogie\HTTP\Request;
use ICanBoogie\Operation;

return [

    'api:nodes/online' => [

        'pattern' => '/api/:constructor/<nid:\d+>/is_online',
        'controller' => OnlineOperation::class,
        'via' => Request::METHOD_PUT,
        'param_translation_list' => [

            'constructor' => Operation::DESTINATION,
            'nid' => Operation::KEY

        ]
    ],

    'api:nodes/offline' => [

        'pattern' => '/api/:constructor/<nid:\d+>/is_online',
        'controller' => OfflineOperation::class,
        'via' => Request::METHOD_DELETE,
        'param_translation_list' => [

            'constructor' => Operation::DESTINATION,
            'nid' => Operation::KEY

        ]
    ]

];

操作的类定义为路由的控制器。注意请求方法如何用于相同的路由来区分操作类型。

param_translation_list 数组用于定义在执行操作之前,如何将从 pathinfo 中捕获的参数进行翻译。这个实用的功能允许从记录格式化路由,同时提供对操作关键特征的映射。

<?php

$node = $app->models['nodes']->one;
$path = $app->url_for('api:nodes/online', $node);

异常

该包中定义的异常类实现了 ICanBoogie\Operation\Exception 接口,以便于轻松识别。

<?php

try
{
    // …
}
catch (\ICanBoogie\Operation\Exception $e)
{
    // an Operation exception
}
catch (\Throwable $e)
{
    // some other exception
}

以下异常已定义:

  • Failure:当操作失败时抛出的异常。
  • FormHasExpired:当与操作关联的表单已过期时抛出的异常。
  • FormNotFound:当无法找到与操作关联的表单时抛出的异常。

要求

该包需要 PHP 7.2 或更高版本。

安装

composer require icanboogie/operation

文档

该包作为 [ICanBoogie][] 框架的一部分进行了文档记录 文档。您可以使用 make doc 命令生成包及其依赖项的文档。文档生成在 build/docs 目录中。需要 ApiGen。该目录可以通过 make clean 命令进行清理。

测试

运行 make test-container 创建并登录到测试容器,然后运行 make test 运行测试套件。或者,运行 make test-coverage 以带有测试覆盖率的运行测试套件。打开 build/coverage/index.html 查看代码覆盖率的分解。

许可证

icanboogie/operationNew BSD License 下发布。