refactor: Cleanup git state - commit all staged changes
Major refactoring cleanup: - Add new controller architecture (class-controller-*.php) - Add new settings-v2 UI (views/settings-v2/) - Add new CSS architecture (agentic-sidebar.css, tokens) - Add esbuild build pipeline (scripts/build.js, package.json) - Add composer dependencies (vendor/) - Add frontend src directory (assets/js/src/index.jsx) - Add documentation files - Remove old/obsolete files (class-settings.php, old CSS) This commits all pending changes from previous refactoring efforts.
This commit is contained in:
43
vendor/league/tactician/.github/workflows/ci.yml
vendored
Normal file
43
vendor/league/tactician/.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: ['ubuntu-latest']
|
||||
php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.4', '8.5']
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
coverage: pcov
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composercache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.composercache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Check Composer configuration
|
||||
run: composer validate --strict
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Run code sniffer
|
||||
run: vendor/bin/phpcs --standard=PSR2 src tests
|
||||
|
||||
- name: Run unit tests
|
||||
run: vendor/bin/phpunit
|
||||
38
vendor/league/tactician/composer.json
vendored
Normal file
38
vendor/league/tactician/composer.json
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "league/tactician",
|
||||
"description": "A small, flexible command bus. Handy for building service layers.",
|
||||
"keywords": ["command", "command bus", "service layer"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ross Tuck",
|
||||
"homepage": "http://tactician.thephpleague.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3",
|
||||
"phpunit/phpunit": "^7.5.20 || ^9.3.8",
|
||||
"squizlabs/php_codesniffer": "^3.5.8"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Tactician\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"League\\Tactician\\Tests\\": "tests/"
|
||||
},
|
||||
"files": [
|
||||
"tests/Fixtures/Command/CommandWithoutNamespace.php"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
68
vendor/league/tactician/src/CommandBus.php
vendored
Normal file
68
vendor/league/tactician/src/CommandBus.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician;
|
||||
|
||||
use League\Tactician\Exception\InvalidCommandException;
|
||||
use League\Tactician\Exception\InvalidMiddlewareException;
|
||||
|
||||
/**
|
||||
* Receives a command and sends it through a chain of middleware for processing.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class CommandBus
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $middlewareChain;
|
||||
|
||||
/**
|
||||
* @param Middleware[] $middleware
|
||||
*/
|
||||
public function __construct(array $middleware)
|
||||
{
|
||||
$this->middlewareChain = $this->createExecutionChain($middleware);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given command and optionally returns a value
|
||||
*
|
||||
* @param object $command
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($command)
|
||||
{
|
||||
if (!is_object($command)) {
|
||||
throw InvalidCommandException::forUnknownValue($command);
|
||||
}
|
||||
|
||||
$middlewareChain = $this->middlewareChain;
|
||||
return $middlewareChain($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Middleware[] $middlewareList
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
private function createExecutionChain($middlewareList)
|
||||
{
|
||||
$lastCallable = function () {
|
||||
// the final callable is a no-op
|
||||
};
|
||||
|
||||
while ($middleware = array_pop($middlewareList)) {
|
||||
if (! $middleware instanceof Middleware) {
|
||||
throw InvalidMiddlewareException::forMiddleware($middleware);
|
||||
}
|
||||
|
||||
$lastCallable = function ($command) use ($middleware, $lastCallable) {
|
||||
return $middleware->execute($command, $lastCallable);
|
||||
};
|
||||
}
|
||||
|
||||
return $lastCallable;
|
||||
}
|
||||
}
|
||||
39
vendor/league/tactician/src/Exception/CanNotDetermineCommandNameException.php
vendored
Normal file
39
vendor/league/tactician/src/Exception/CanNotDetermineCommandNameException.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a CommandNameExtractor cannot determine the command's name
|
||||
*/
|
||||
class CanNotDetermineCommandNameException extends \RuntimeException implements Exception
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* @param mixed $command
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function forCommand($command)
|
||||
{
|
||||
$type = is_object($command) ? get_class($command) : gettype($command);
|
||||
|
||||
$exception = new static('Could not determine command name of ' . $type);
|
||||
$exception->command = $command;
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command that could not be invoked
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
}
|
||||
46
vendor/league/tactician/src/Exception/CanNotInvokeHandlerException.php
vendored
Normal file
46
vendor/league/tactician/src/Exception/CanNotInvokeHandlerException.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a specific handler object can not be used on a command object.
|
||||
*
|
||||
* The most common reason is the receiving method is missing or incorrectly
|
||||
* named.
|
||||
*/
|
||||
class CanNotInvokeHandlerException extends \BadMethodCallException implements Exception
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* @param mixed $command
|
||||
* @param string $reason
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function forCommand($command, $reason)
|
||||
{
|
||||
$type = is_object($command) ? get_class($command) : gettype($command);
|
||||
|
||||
$exception = new static(
|
||||
'Could not invoke handler for command ' . $type .
|
||||
' for reason: ' . $reason
|
||||
);
|
||||
$exception->command = $command;
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command that could not be invoked
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCommand()
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
}
|
||||
10
vendor/league/tactician/src/Exception/Exception.php
vendored
Normal file
10
vendor/league/tactician/src/Exception/Exception.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Exception;
|
||||
|
||||
/**
|
||||
* Marker interface for all Tactician exceptions
|
||||
*/
|
||||
interface Exception
|
||||
{
|
||||
}
|
||||
37
vendor/league/tactician/src/Exception/InvalidCommandException.php
vendored
Normal file
37
vendor/league/tactician/src/Exception/InvalidCommandException.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when the command bus is given an non-object to use as a command.
|
||||
*/
|
||||
class InvalidCommandException extends \RuntimeException implements Exception
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $invalidCommand;
|
||||
|
||||
/**
|
||||
* @param mixed $invalidCommand
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function forUnknownValue($invalidCommand)
|
||||
{
|
||||
$exception = new static(
|
||||
'Commands must be an object but the value given was of type: ' . gettype($invalidCommand)
|
||||
);
|
||||
$exception->invalidCommand = $invalidCommand;
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInvalidCommand()
|
||||
{
|
||||
return $this->invalidCommand;
|
||||
}
|
||||
}
|
||||
19
vendor/league/tactician/src/Exception/InvalidMiddlewareException.php
vendored
Normal file
19
vendor/league/tactician/src/Exception/InvalidMiddlewareException.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when the CommandBus was instantiated with an invalid middleware object
|
||||
*/
|
||||
class InvalidMiddlewareException extends \InvalidArgumentException implements Exception
|
||||
{
|
||||
public static function forMiddleware($middleware)
|
||||
{
|
||||
$name = is_object($middleware) ? get_class($middleware) : gettype($middleware);
|
||||
$message = sprintf(
|
||||
'Cannot add "%s" to middleware chain as it does not implement the Middleware interface.',
|
||||
$name
|
||||
);
|
||||
return new static($message);
|
||||
}
|
||||
}
|
||||
35
vendor/league/tactician/src/Exception/MissingHandlerException.php
vendored
Normal file
35
vendor/league/tactician/src/Exception/MissingHandlerException.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Exception;
|
||||
|
||||
/**
|
||||
* No handler could be found for the given command.
|
||||
*/
|
||||
class MissingHandlerException extends \OutOfBoundsException implements Exception
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $commandName;
|
||||
|
||||
/**
|
||||
* @param string $commandName
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function forCommand($commandName)
|
||||
{
|
||||
$exception = new static('Missing handler for command ' . $commandName);
|
||||
$exception->commandName = $commandName;
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandName()
|
||||
{
|
||||
return $this->commandName;
|
||||
}
|
||||
}
|
||||
73
vendor/league/tactician/src/Handler/CommandHandlerMiddleware.php
vendored
Normal file
73
vendor/league/tactician/src/Handler/CommandHandlerMiddleware.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler;
|
||||
|
||||
use League\Tactician\Middleware;
|
||||
use League\Tactician\Exception\CanNotInvokeHandlerException;
|
||||
use League\Tactician\Handler\CommandNameExtractor\CommandNameExtractor;
|
||||
use League\Tactician\Handler\Locator\HandlerLocator;
|
||||
use League\Tactician\Handler\MethodNameInflector\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* The "core" CommandBus. Locates the appropriate handler and executes command.
|
||||
*/
|
||||
class CommandHandlerMiddleware implements Middleware
|
||||
{
|
||||
/**
|
||||
* @var CommandNameExtractor
|
||||
*/
|
||||
private $commandNameExtractor;
|
||||
|
||||
/**
|
||||
* @var HandlerLocator
|
||||
*/
|
||||
private $handlerLocator;
|
||||
|
||||
/**
|
||||
* @var MethodNameInflector
|
||||
*/
|
||||
private $methodNameInflector;
|
||||
|
||||
/**
|
||||
* @param CommandNameExtractor $commandNameExtractor
|
||||
* @param HandlerLocator $handlerLocator
|
||||
* @param MethodNameInflector $methodNameInflector
|
||||
*/
|
||||
public function __construct(
|
||||
CommandNameExtractor $commandNameExtractor,
|
||||
HandlerLocator $handlerLocator,
|
||||
MethodNameInflector $methodNameInflector
|
||||
) {
|
||||
$this->commandNameExtractor = $commandNameExtractor;
|
||||
$this->handlerLocator = $handlerLocator;
|
||||
$this->methodNameInflector = $methodNameInflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a command and optionally returns a value
|
||||
*
|
||||
* @param object $command
|
||||
* @param callable $next
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws CanNotInvokeHandlerException
|
||||
*/
|
||||
public function execute($command, callable $next)
|
||||
{
|
||||
$commandName = $this->commandNameExtractor->extract($command);
|
||||
$handler = $this->handlerLocator->getHandlerForCommand($commandName);
|
||||
$methodName = $this->methodNameInflector->inflect($command, $handler);
|
||||
|
||||
// is_callable is used here instead of method_exists, as method_exists
|
||||
// will fail when given a handler that relies on __call.
|
||||
if (!is_callable([$handler, $methodName])) {
|
||||
throw CanNotInvokeHandlerException::forCommand(
|
||||
$command,
|
||||
"Method '{$methodName}' does not exist on handler"
|
||||
);
|
||||
}
|
||||
|
||||
return $handler->{$methodName}($command);
|
||||
}
|
||||
}
|
||||
17
vendor/league/tactician/src/Handler/CommandNameExtractor/ClassNameExtractor.php
vendored
Normal file
17
vendor/league/tactician/src/Handler/CommandNameExtractor/ClassNameExtractor.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\CommandNameExtractor;
|
||||
|
||||
/**
|
||||
* Extract the name from the class
|
||||
*/
|
||||
class ClassNameExtractor implements CommandNameExtractor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extract($command)
|
||||
{
|
||||
return get_class($command);
|
||||
}
|
||||
}
|
||||
23
vendor/league/tactician/src/Handler/CommandNameExtractor/CommandNameExtractor.php
vendored
Normal file
23
vendor/league/tactician/src/Handler/CommandNameExtractor/CommandNameExtractor.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\CommandNameExtractor;
|
||||
|
||||
use League\Tactician\Exception\CanNotDetermineCommandNameException;
|
||||
|
||||
/**
|
||||
* Extract the name from a command so that the name can be determined
|
||||
* by the context better than simply the class name
|
||||
*/
|
||||
interface CommandNameExtractor
|
||||
{
|
||||
/**
|
||||
* Extract the name from a command
|
||||
*
|
||||
* @param object $command
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws CannotDetermineCommandNameException
|
||||
*/
|
||||
public function extract($command);
|
||||
}
|
||||
54
vendor/league/tactician/src/Handler/Locator/CallableLocator.php
vendored
Normal file
54
vendor/league/tactician/src/Handler/Locator/CallableLocator.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace League\Tactician\Handler\Locator;
|
||||
|
||||
use League\Tactician\Exception\MissingHandlerException;
|
||||
|
||||
/**
|
||||
* This locator loads Handlers from a provided callable.
|
||||
*
|
||||
* At first glance, this might seem fairly useless but it's actually very
|
||||
* useful to encapsulate DI containers without having to write a custom adapter
|
||||
* for each one.
|
||||
*
|
||||
* Let's say you have a Symfony container or similar that works via a 'get'
|
||||
* method. You can pass in an array style callable such as:
|
||||
*
|
||||
* $locator = new CallableLocator([$container, 'get'])
|
||||
*
|
||||
* This is easy to set up and will now automatically pipe the command name
|
||||
* straight through to the $container->get() method without having to write
|
||||
* the custom locator.
|
||||
*
|
||||
* Naturally, you can also pass in closures for further behavior tweaks.
|
||||
*/
|
||||
class CallableLocator implements HandlerLocator
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $callable;
|
||||
|
||||
/**
|
||||
* @param callable $callable
|
||||
*/
|
||||
public function __construct(callable $callable)
|
||||
{
|
||||
$this->callable = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHandlerForCommand($commandName)
|
||||
{
|
||||
$callable = $this->callable;
|
||||
$handler = $callable($commandName);
|
||||
|
||||
// Odds are the callable threw an exception but it always pays to check
|
||||
if ($handler === null) {
|
||||
throw MissingHandlerException::forCommand($commandName);
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
}
|
||||
25
vendor/league/tactician/src/Handler/Locator/HandlerLocator.php
vendored
Normal file
25
vendor/league/tactician/src/Handler/Locator/HandlerLocator.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\Locator;
|
||||
|
||||
use League\Tactician\Exception\MissingHandlerException;
|
||||
|
||||
/**
|
||||
* Service locator for handler objects
|
||||
*
|
||||
* This interface is often a wrapper around your frameworks dependency
|
||||
* injection container or just maps command names to handler names on disk somehow.
|
||||
*/
|
||||
interface HandlerLocator
|
||||
{
|
||||
/**
|
||||
* Retrieves the handler for a specified command
|
||||
*
|
||||
* @param string $commandName
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @throws MissingHandlerException
|
||||
*/
|
||||
public function getHandlerForCommand($commandName);
|
||||
}
|
||||
79
vendor/league/tactician/src/Handler/Locator/InMemoryLocator.php
vendored
Normal file
79
vendor/league/tactician/src/Handler/Locator/InMemoryLocator.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\Locator;
|
||||
|
||||
use League\Tactician\Exception\MissingHandlerException;
|
||||
|
||||
/**
|
||||
* Fetch handler instances from an in-memory collection.
|
||||
*
|
||||
* This locator allows you to bind a handler object to receive commands of a
|
||||
* certain class name. For example:
|
||||
*
|
||||
* // Wire everything together
|
||||
* $myHandler = new TaskAddedHandler($dependency1, $dependency2);
|
||||
* $inMemoryLocator->addHandler($myHandler, 'My\TaskAddedCommand');
|
||||
*
|
||||
* // Returns $myHandler
|
||||
* $inMemoryLocator->getHandlerForCommand('My\TaskAddedCommand');
|
||||
*/
|
||||
class InMemoryLocator implements HandlerLocator
|
||||
{
|
||||
/**
|
||||
* @var object[]
|
||||
*/
|
||||
protected $handlers = [];
|
||||
|
||||
/**
|
||||
* @param array $commandClassToHandlerMap
|
||||
*/
|
||||
public function __construct(array $commandClassToHandlerMap = [])
|
||||
{
|
||||
$this->addHandlers($commandClassToHandlerMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a handler instance to receive all commands with a certain class
|
||||
*
|
||||
* @param object $handler Handler to receive class
|
||||
* @param string $commandClassName Command class e.g. "My\TaskAddedCommand"
|
||||
*/
|
||||
public function addHandler($handler, $commandClassName)
|
||||
{
|
||||
$this->handlers[$commandClassName] = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to add multiple handlers at once.
|
||||
*
|
||||
* The map should be an array in the format of:
|
||||
* [
|
||||
* AddTaskCommand::class => $someHandlerInstance,
|
||||
* CompleteTaskCommand::class => $someHandlerInstance,
|
||||
* ]
|
||||
*
|
||||
* @param array $commandClassToHandlerMap
|
||||
*/
|
||||
protected function addHandlers(array $commandClassToHandlerMap)
|
||||
{
|
||||
foreach ($commandClassToHandlerMap as $commandClass => $handler) {
|
||||
$this->addHandler($handler, $commandClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the handler bound to the command's class name.
|
||||
*
|
||||
* @param string $commandName
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getHandlerForCommand($commandName)
|
||||
{
|
||||
if (!isset($this->handlers[$commandName])) {
|
||||
throw MissingHandlerException::forCommand($commandName);
|
||||
}
|
||||
|
||||
return $this->handlers[$commandName];
|
||||
}
|
||||
}
|
||||
28
vendor/league/tactician/src/Handler/MethodNameInflector/ClassNameInflector.php
vendored
Normal file
28
vendor/league/tactician/src/Handler/MethodNameInflector/ClassNameInflector.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* Assumes the method is only the last portion of the class name.
|
||||
*
|
||||
* Examples:
|
||||
* - \MyGlobalCommand => $handler->myGlobalCommand()
|
||||
* - \My\App\CreateUser => $handler->createUser()
|
||||
*/
|
||||
class ClassNameInflector implements MethodNameInflector
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($command, $commandHandler)
|
||||
{
|
||||
$commandName = get_class($command);
|
||||
|
||||
// If class name has a namespace separator, only take last portion
|
||||
if (strpos($commandName, '\\') !== false) {
|
||||
$commandName = substr($commandName, strrpos($commandName, '\\') + 1);
|
||||
}
|
||||
|
||||
return strtolower($commandName[0]) . substr($commandName, 1);
|
||||
}
|
||||
}
|
||||
23
vendor/league/tactician/src/Handler/MethodNameInflector/HandleClassNameInflector.php
vendored
Normal file
23
vendor/league/tactician/src/Handler/MethodNameInflector/HandleClassNameInflector.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* Assumes the method is handle + the last portion of the class name.
|
||||
*
|
||||
* Examples:
|
||||
* - \MyGlobalCommand => $handler->handleMyGlobalCommand()
|
||||
* - \My\App\TaskCompletedCommand => $handler->handleTaskCompletedCommand()
|
||||
*/
|
||||
class HandleClassNameInflector extends ClassNameInflector
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($command, $commandHandler)
|
||||
{
|
||||
$commandName = parent::inflect($command, $commandHandler);
|
||||
|
||||
return 'handle' . ucfirst($commandName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace League\Tactician\Handler\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* Returns a method name that is handle + the last portion of the class name
|
||||
* but also without a given suffix, typically "Command". This allows you to
|
||||
* handle multiple commands on a single object but with slightly less annoying
|
||||
* method names.
|
||||
*
|
||||
* The string removal is case sensitive.
|
||||
*
|
||||
* Examples:
|
||||
* - \CompleteTaskCommand => $handler->handleCompleteTask()
|
||||
* - \My\App\DoThingCommand => $handler->handleDoThing()
|
||||
*/
|
||||
class HandleClassNameWithoutSuffixInflector extends HandleClassNameInflector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $suffix;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $suffixLength;
|
||||
|
||||
/**
|
||||
* @param string $suffix The string to remove from end of each class name
|
||||
*/
|
||||
public function __construct($suffix = 'Command')
|
||||
{
|
||||
$this->suffix = $suffix;
|
||||
$this->suffixLength = strlen($suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $command
|
||||
* @param object $commandHandler
|
||||
* @return string
|
||||
*/
|
||||
public function inflect($command, $commandHandler)
|
||||
{
|
||||
$methodName = parent::inflect($command, $commandHandler);
|
||||
|
||||
if (substr($methodName, $this->suffixLength * -1) !== $this->suffix) {
|
||||
return $methodName;
|
||||
}
|
||||
|
||||
return substr($methodName, 0, strlen($methodName) - $this->suffixLength);
|
||||
}
|
||||
}
|
||||
17
vendor/league/tactician/src/Handler/MethodNameInflector/HandleInflector.php
vendored
Normal file
17
vendor/league/tactician/src/Handler/MethodNameInflector/HandleInflector.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* Handle command by calling the "handle" method.
|
||||
*/
|
||||
class HandleInflector implements MethodNameInflector
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($command, $commandHandler)
|
||||
{
|
||||
return 'handle';
|
||||
}
|
||||
}
|
||||
18
vendor/league/tactician/src/Handler/MethodNameInflector/InvokeInflector.php
vendored
Normal file
18
vendor/league/tactician/src/Handler/MethodNameInflector/InvokeInflector.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* Handle command by calling the __invoke magic method. Handy for single
|
||||
* use classes or closures.
|
||||
*/
|
||||
class InvokeInflector implements MethodNameInflector
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($command, $commandHandler)
|
||||
{
|
||||
return '__invoke';
|
||||
}
|
||||
}
|
||||
20
vendor/league/tactician/src/Handler/MethodNameInflector/MethodNameInflector.php
vendored
Normal file
20
vendor/league/tactician/src/Handler/MethodNameInflector/MethodNameInflector.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Handler\MethodNameInflector;
|
||||
|
||||
/**
|
||||
* Deduce the method name to call on the command handler based on the command
|
||||
* and handler instances.
|
||||
*/
|
||||
interface MethodNameInflector
|
||||
{
|
||||
/**
|
||||
* Return the method name to call on the command handler and return it.
|
||||
*
|
||||
* @param object $command
|
||||
* @param object $commandHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function inflect($command, $commandHandler);
|
||||
}
|
||||
24
vendor/league/tactician/src/Middleware.php
vendored
Normal file
24
vendor/league/tactician/src/Middleware.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician;
|
||||
|
||||
/**
|
||||
* Middleware are the plugins of Tactician. They receive each command that's
|
||||
* given to the CommandBus and can take any action they choose. Middleware can
|
||||
* continue the Command processing by passing the command they receive to the
|
||||
* $next callable, which is essentially the "next" Middleware in the chain.
|
||||
*
|
||||
* Depending on where they invoke the $next callable, Middleware can execute
|
||||
* their custom logic before or after the Command is handled. They can also
|
||||
* modify, log, or replace the command they receive. The sky's the limit.
|
||||
*/
|
||||
interface Middleware
|
||||
{
|
||||
/**
|
||||
* @param object $command
|
||||
* @param callable $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute($command, callable $next);
|
||||
}
|
||||
71
vendor/league/tactician/src/Plugins/LockingMiddleware.php
vendored
Normal file
71
vendor/league/tactician/src/Plugins/LockingMiddleware.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Plugins;
|
||||
|
||||
use League\Tactician\Middleware;
|
||||
|
||||
/**
|
||||
* If another command is already being executed, locks the command bus and
|
||||
* queues the new incoming commands until the first has completed.
|
||||
*/
|
||||
class LockingMiddleware implements Middleware
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isExecuting;
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
private $queue = [];
|
||||
|
||||
/**
|
||||
* Execute the given command... after other running commands are complete.
|
||||
*
|
||||
* @param object $command
|
||||
* @param callable $next
|
||||
*
|
||||
* @throws \Throwable
|
||||
*
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function execute($command, callable $next)
|
||||
{
|
||||
$this->queue[] = function () use ($command, $next) {
|
||||
return $next($command);
|
||||
};
|
||||
|
||||
if ($this->isExecuting) {
|
||||
return;
|
||||
}
|
||||
$this->isExecuting = true;
|
||||
|
||||
try {
|
||||
$returnValue = $this->executeQueuedJobs();
|
||||
} catch (\Throwable $e) {
|
||||
$this->isExecuting = false;
|
||||
$this->queue = [];
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->isExecuting = false;
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process any pending commands in the queue. If multiple, jobs are in the
|
||||
* queue, only the first return value is given back.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function executeQueuedJobs()
|
||||
{
|
||||
$returnValues = [];
|
||||
while ($resumeCommand = array_shift($this->queue)) {
|
||||
$returnValues[] = $resumeCommand();
|
||||
}
|
||||
|
||||
return array_shift($returnValues);
|
||||
}
|
||||
}
|
||||
16
vendor/league/tactician/src/Plugins/NamedCommand/NamedCommand.php
vendored
Normal file
16
vendor/league/tactician/src/Plugins/NamedCommand/NamedCommand.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Plugins\NamedCommand;
|
||||
|
||||
/**
|
||||
* Exposes a name for a command
|
||||
*/
|
||||
interface NamedCommand
|
||||
{
|
||||
/**
|
||||
* Returns the name of the command
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandName();
|
||||
}
|
||||
24
vendor/league/tactician/src/Plugins/NamedCommand/NamedCommandExtractor.php
vendored
Normal file
24
vendor/league/tactician/src/Plugins/NamedCommand/NamedCommandExtractor.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Plugins\NamedCommand;
|
||||
|
||||
use League\Tactician\Exception\CanNotDetermineCommandNameException;
|
||||
use League\Tactician\Handler\CommandNameExtractor\CommandNameExtractor;
|
||||
|
||||
/**
|
||||
* Extract the name from a NamedCommand
|
||||
*/
|
||||
class NamedCommandExtractor implements CommandNameExtractor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extract($command)
|
||||
{
|
||||
if ($command instanceof NamedCommand) {
|
||||
return $command->getCommandName();
|
||||
}
|
||||
|
||||
throw CanNotDetermineCommandNameException::forCommand($command);
|
||||
}
|
||||
}
|
||||
45
vendor/league/tactician/src/Setup/QuickStart.php
vendored
Normal file
45
vendor/league/tactician/src/Setup/QuickStart.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace League\Tactician\Setup;
|
||||
|
||||
use League\Tactician\CommandBus;
|
||||
use League\Tactician\Handler\CommandNameExtractor\ClassNameExtractor;
|
||||
use League\Tactician\Handler\Locator\InMemoryLocator;
|
||||
use League\Tactician\Handler\MethodNameInflector\HandleInflector;
|
||||
use League\Tactician\Handler\CommandHandlerMiddleware;
|
||||
use League\Tactician\Plugins\LockingMiddleware;
|
||||
|
||||
/**
|
||||
* Builds a working command bus with minimum fuss.
|
||||
*
|
||||
* Currently, the default setup is:
|
||||
* - Handlers instances in memory
|
||||
* - The expected handler method is always "handle"
|
||||
* - And only one command at a time can be executed.
|
||||
*
|
||||
* This factory is a decent place to start trying out Tactician but you're
|
||||
* better off moving to a custom setup or a framework bundle/module/provider in
|
||||
* the long run. As you can see, it's not difficult. :)
|
||||
*/
|
||||
class QuickStart
|
||||
{
|
||||
/**
|
||||
* Creates a default CommandBus that you can get started with.
|
||||
*
|
||||
* @param array $commandToHandlerMap
|
||||
*
|
||||
* @return CommandBus
|
||||
*/
|
||||
public static function create($commandToHandlerMap)
|
||||
{
|
||||
$handlerMiddleware = new CommandHandlerMiddleware(
|
||||
new ClassNameExtractor(),
|
||||
new InMemoryLocator($commandToHandlerMap),
|
||||
new HandleInflector()
|
||||
);
|
||||
|
||||
$lockingMiddleware = new LockingMiddleware();
|
||||
|
||||
return new CommandBus([$lockingMiddleware, $handlerMiddleware]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user