ionews/light-service-php

通过一系列简单操作实现复杂动作的简单接口

v0.4.2 2017-10-23 19:07 UTC

This package is not auto-updated.

Last update: 2024-09-28 16:09:59 UTC


README

Latest Stable Version License Build Status Coverage Status Dependency Status HHVM Status

一个小型软件,旨在强制在PHP应用程序中实施SRP,被认为“轻量级”且不使用任何依赖项。高度基于两个ruby gems提出的思想

概念

每个动作应该有一个单一的责任,必须在 perform 方法中实现。一个动作可以访问数据库、发送电子邮件、调用服务等等。当执行一个动作时,它会接收到一个可以读取和修改的上下文。

要执行更复杂的操作,您必须使用组织器链接多个动作,这些动作在执行期间将共享相同的上下文。实际上,组织器不过是一个具有特定实现的动作,这意味着动作和组织器共享完全相同的接口。这很有用,因此您可以将组织器作为动作包含在另一个组织器中。

动作示例

class GenerateRandomPassword extends Action {
  protected function perform() {
    $length = 8;
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $password = '';

    for ($i = 0; $i < $length; $i++) {
      $password .= $chars[rand(0, strlen($chars) - 1)];
    }

    $this->context->password = $password;
  }
}

class UpdateUserPassword extends Action {
  protected function perform() {
    $user_id = $this->context->user_id;
    $password = $this->context->password;
    // access the database using the method of your choice and update the password
  }
}

组织器示例

class ResetUserPassword extends Organizer {
  protected $organize = ['GenerateRandomPassword', 'UpdateUserPassword', 'EmailUserWithPassword'];
}

调用示例(从MVC控制器中)

class UserController extends BaseController {
  public function resetPassword() {
    $result = ResetUserPassword::execute(['user_id' => $this->request->id]);

    if ($result->success()) {
      // use $result->getContext() to access the results and redirect the app
    } else {
      // error, use $result->getFailureMessage() to access any failure message
    }
  }
}

请注意,您不应该在应用程序的每个地方都使用这种方法,而只在其真正复杂的部分中使用。

失败、停止和异常

一个动作可能会失败,意味着它无法实现其目标。要使一个动作失败,只需调用 fail 方法(可选地传递一个消息)。

class SomeAction extends Action {
  protected function perform() {
    $this->fail('Oh noes');
  }
}

$result = SomeAction::execute([]);
$result->success(); // false
$result->failure(); // true
$result->halted(); // false
$result->getFailureMessage(); // 'Oh noes'

如果动作在组织器内部执行并失败,它将阻止后续动作的执行。如果动作实现了 rollback 方法,则在后续动作失败后调用它。例如:如果 EmailUserWithPassword 无法向用户发送电子邮件,我们可以在 UpdateUserPassword 中实现一个 rollback 方法来撤销更新。在 rollback 方法中,您可以以与 perform 相同的方式访问上下文。

class UpdateUserPassword extends Action {
  protected function perform() {
    $user_id = $this->context->user_id;
    $password = $this->context->password;
    // access the database using the method of your choice and update the password
  }

  protected function rollback() {
    // undo the update password
  }
}

除非您真的知道自己在做什么,否则不要重新实现组织器的 rollback 方法。

可以使用 halt 停止执行链而不会失败:基本它会阻止执行后续的动作,但结果仍然是成功的。您可以使用 halted 方法测试动作/组织器是否已停止。

class SomeAction extends Action {
  protected function perform() {
    $this->halt();
  }
}

$result = SomeAction::execute([]);
$result->success(); // true
$result->failure(); // false
$result->halted(); // true

在执行动作时发生的所有异常都会自动捕获并传递给 caught 方法。默认情况下,动作会重新抛出,另一方面,组织器首先调用 rollback 方法然后再重新抛出。这样做是为了在异常传播之前回滚所有执行的动作。您可以通过重新实现 caught 方法来更改此行为。

之前和之后

如果您需要在执行之前进行任何设置,可以实施一个 before 方法。如果在 before 中调用 fail 方法,则 perform 将永远不会被调用。同样,您可以实施一个 after 方法,以便可以在执行后进行任何清理,但请注意,如果 beforeperform 失败,它将永远不会被调用。

class SomeAction extends Action {
  protected function before() {
    // any setup
  }

  protected function perform() {
    // perform
  }

  protected function after() {
    // cleanup
  }
}

期望和承诺

可以为每个动作定义期望和承诺。如果动作有一组期望,那么如果这些期望未满足,它将自动失败。

class UpdateUserPassword extends Action {
  protected $expects = ['user_id', 'password'];

  protected function perform() {
    $user_id = $this->context->user_id;
    $password = $this->context->password;
    // access the database using the method of your choice and update the password
  }
}

$result = UpdateUserPassword::execute(['user_id' => 1]);
$result->success(); // false
$result->getFailureMessage(); // 'Expectations were not met'

同样,如果定义了一组承诺,并且这些承诺在执行结束时不在上下文中,动作将失败。

class GenerateRandomPassword extends Action {
  protected $promises = ['password'];

  protected function perform() {
    $length = 8;
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $password = '';

    for ($i = 0; $i < $length; $i++) {
      $password .= $chars[rand(0, strlen($chars) - 1)];
    }

    //$this->context->password = $password;
  }
}

$result = GenerateRandomPassword::execute([]);
$result->success(); // false
$result->getFailureMessage(); // 'Promises were not met'

此功能特别有用,可以显式定义动作之间的接口。

迭代器动作

它是一个将在数组上执行的动作。

class SomeAction extends IteratorAction {
  protected $over = 'key_of_the_array_in_context'

  protected function each($key, $value) {
    ...
  }
}

需求

  • PHP 5.3+

安装和用法

贡献

你知道怎么做!

许可证

在GPLv2下发布