New from Chevere is the Action package. This software provides an object oriented convention around Parameter.
The package source is available at chevere/action.
# What it does?
Consider the class MyAction
as described below.
class MyAction
{
public function main(string $var): int
{
if (! preg_match('/^ok/', $var)) {
throw new InvalidArgumentException();
}
$return = mb_strlen($var);
if ($return < 0 || $return > 100) {
throw new InvalidArgumentException();
}
return $return;
}
}
$action = new MyAction();
$action->main($value);
For the code above validation for $var
argument and $return
value is expressed within the function body.
Using the Action package the code above could be transformed and leverage the function body in a single line.
use Chevere\Action\Action;
use Chevere\Parameter\Attributes\IntAttr;
use Chevere\Parameter\Attributes\ReturnAttr;
use Chevere\Parameter\Attributes\StringAttr;
class MyAction extends Action
{
#[ReturnAttr(
new IntAttr(min: 0, max: 100)
)]
protected function main(
#[StringAttr('/^ok/')]
string $var
): int {
return mb_strlen($var);
}
}
$action = new MyAction();
$action($var);
Validation rules are the same, what changes is how and where you define those.
# How it works?
The Action package wraps a convention around Parameter which denotes the usage of a main
method which will be called at __invoke
where I sandwich (1) Arguments validation, (2) Run main logic, (3) Return value validation.
// src/Traits/ActionTrait.php
public function __invoke(mixed ...$argument): mixed
{
try {
// Assert no logic errors in Parameter rules
$reflection = static::assert();
// (1) Arguments validation
$arguments = $reflection->parameters()->__invoke(...$argument);
} catch (Throwable $e) {
throw new ActionException();
}
// (2) Run main logic
$result = $this->main(...$arguments->toArray());
try {
// (3) Return value validation
$reflection->return()->__invoke($result);
} catch (Throwable $e) {
throw new ActionException();
}
return $result;
}
The ActionException
is a special exception forwarding file:code
location for the conflicting argument, not the wrapped call.
# Building block
The Action package is extensible and can be used to build on top of it. For example, at the Workflow package every Job is defined from an Action.
In the Http package every HTTP controller extends Controller class which extends Action to restrict main
parameters for type string.
# Wrapping up
The convention on Action is simple to follow and provides a predictable, tested way to work with Parameter. Its application is trivial and it can fit many different use needs.