caseyamcl/sortable-tasks

动态编译和排序任务的抽象层

v0.6.1 2021-03-02 16:15 UTC

This package is auto-updated.

Last update: 2024-08-29 05:37:52 UTC


README

Latest Version on Packagist Software License Build Coverage Status Quality Score Total Downloads

A simple, un-opinionated PHP 7.4+ abstraction library to allow for the ordering of tasks. Features

  • 任务是可以定义其他任务作为依赖项的服务类实例
  • 适用于设置程序、确保HTTP中间件按顺序运行等库,其中任务的排序是任意确定的,但需要确定性地运行
  • 基于 marcj/topsort library 来启用对任务的排序,每个任务都定义在其自己的类中
  • 不针对任务的实际运行方式;只是根据依赖关系排序它们,并按顺序运行
  • PSR-4 和 PSR-12 兼容

结构

此库只包含两个文件

| SortableTask.php | 任务的接口;包含两个定义依赖项的方法,depeondsOnmustRunBefore | | SortableTasksIterator.php | 执行排序和其他工作的迭代器类;实现了 IterableCountable |

安装

通过 Composer

$ composer require caseyamcl/sortable-tasks

用法

有关完整功能的示例,请参阅 tests/Fixture 目录。

展示此库的最佳方式是使用示例,因此我们将使用设置应用程序。在我们的假设应用程序中,设置任务可以按任何顺序注册,但它们将根据一组显式定义的依赖项以特定顺序运行。

首先,我们必须定义一个实现 SortableTask 接口的类

use SortableTasks\SortableTask;

abstract class SetupStep implements SortableTask
{
    abstract public function __invoke(): bool;
}
 

请注意,我们不在抽象的 SetupStep 类中实现 dependsOn()mustRunBefore() 方法。这意味着每个具体实现步骤都必须定义其依赖项。这是可选的,取决于实现 SortableTasks 的库。

如果大多数步骤不需要排序,则可以这样做

use SortableTasks\SortableTask;

abstract class SetupStep implements SortableTask
{
    abstract public function __invoke(): bool;

    // Provide default implementations of `dependsOn` and `mustRunBefore` that return empty arrays
    public static function dependsOn() : iterable
    {
        return [];
    }
    public static function mustRunBefore() : iterable
    {
        return [];
    }
}

现在让我们创建一些设置步骤

class CheckConfigStep extends SetupStep
{
    public static function dependsOn(): iterable
    {
       return []; // depends on nothing; can run anytime in the order of operations
    }
    
    public function __invoke(): bool
    {
        // do stuff, then..
        return true;
    }
}

class CheckDbConnectionStep extends SetupStep
{
    private DbConnector $dbConnector;
    
    public function __construct(DbConnector $dbConnector)
    {    
        $this->dbConnector = $dbConnector;
    }

    public static function dependsOn(): iterable
    {
        return [CheckConfigStep::class];
    }

    public static function mustRunBefore(): iterable
    {
        return [BuildContainerStep::class];
    }

    public function __invoke(): bool
    {
        // do stuff, then..
        return $this->dbConnector->checkConnection();
    }
}

class BuildContainerStep extends SetupStep
{
    private ContainerBuilder $containerBuilder;

    public function __construct(ContainerBuilder $containerBuilder)
    {
        $this->containerBuilder = $containerBuilder;
    }

    public static function dependsOn(): iterable
    {
        return [CheckConfigStep::class, CheckDbConnection::class];
    }

    public function __invoke(): bool
    {
        // do stuff, then..
        return $this->containerBuilder->buildContainer();
    }
}

现在我们已经有一些具体类,让我们将它们添加到 SortableTasksIterator 中

use SortableTasks\SortableTasksIterator;

$iterator = new SortableTasksIterator();

// Notice that it doesn't matter in what order we add the steps; they will get sorted at runtime
$iterator->add(new BuildContainerStep());
$iterator->add(new CheckDbConnectionStep());
$iterator->add(new CheckConfigStep());

// Tasks are sorted upon calling the iterator
// Class names are the keys
foreach ($iterator as $setupStepClassName => $setupStep) {
    if (! $setupStep()->__invoke()) {
        throw new SetupFailedException('Setup failed on step: ' . $setupStepClassName);
    }
}

错误处理

在任务执行过程中可能会出现两个问题,它们都会抛出异常

  1. 循环依赖项;例如,任务 "A" 依赖于任务 "B",任务 "B" 依赖于任务 "A"。在这种情况下,会抛出 MJS\TopSort\CircularDependecyException
  2. 不存在的依赖项;例如,任务 "A" 依赖于任务 "B",但任务 "B" 未定义。在这种情况下,会抛出 MJS\TopSort\ElementNotFoundException

变更日志

有关最近更改的更多信息,请参阅 CHANGELOG

测试

$ composer test

贡献

有关详细信息,请参阅 CONTRIBUTING

安全

如果您发现任何安全相关的问题,请通过电子邮件 me@caseymclaughlin.com 而不是使用问题跟踪器。

鸣谢

许可

MIT 许可证(MIT)。有关更多信息,请参阅 许可文件