{"id":35486979,"url":"https://github.com/adamnicholson/Chief","last_synced_at":"2026-01-09T05:01:37.010Z","repository":{"id":25352763,"uuid":"28780411","full_name":"adamnicholson/Chief","owner":"adamnicholson","description":"Command bus package for PHP","archived":false,"fork":false,"pushed_at":"2025-05-27T21:11:21.000Z","size":147,"stargazers_count":51,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-15T20:57:44.846Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adamnicholson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-04T17:12:30.000Z","updated_at":"2025-05-27T21:10:32.000Z","dependencies_parsed_at":"2023-02-13T00:45:18.636Z","dependency_job_id":null,"html_url":"https://github.com/adamnicholson/Chief","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/adamnicholson/Chief","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamnicholson%2FChief","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamnicholson%2FChief/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamnicholson%2FChief/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamnicholson%2FChief/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adamnicholson","download_url":"https://codeload.github.com/adamnicholson/Chief/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamnicholson%2FChief/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28253416,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2026-01-09T02:00:07.210Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-03T15:00:45.449Z","updated_at":"2026-01-09T05:01:37.003Z","avatar_url":"https://github.com/adamnicholson.png","language":"PHP","funding_links":[],"categories":["杂项 Miscellaneous","Configuration"],"sub_categories":["Miscellaneous"],"readme":"#Chief\n\n[![Build Status](https://scrutinizer-ci.com/g/adamnicholson/Chief/badges/build.png?b=master)](https://scrutinizer-ci.com/g/adamnicholson/Chief/build-status/master) [![Code Coverage](https://scrutinizer-ci.com/g/adamnicholson/Chief/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/adamnicholson/Chief/?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/adamnicholson/Chief/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/adamnicholson/Chief/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/2459f377-6af7-43b8-98df-c67f42138080/mini.png)](https://insight.sensiolabs.com/projects/2459f377-6af7-43b8-98df-c67f42138080)\n\nChief is a powerful standalone command bus package for PHP 5.4+.\n\n## Contents\n\n- [What is a command bus](#command-bus)\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Class-based command handlers](#automatic-handler-resolution)\n    - [Anonymous functions as command handlers](#handlers-as-anonymous-functions)\n    - [Self-handling commands](#self-handling-commands)\n    - [Decorators](#decorators)\n    - [Queued commands](#queued-commands)\n    - [Transactional commands](#transactional-commands)\n- [Dependcy injection container integration](#dependency-injection-container-integration)\n- [License](#license)\n- [Contributing](#contributing)\n- [Author](#author)\n\n## Command Bus?\n\n\u003e The most common style of interface to a module is to use procedures, or object methods. So if you want a module to calculate a bunch of charges for a contract, you might have a BillingService class with a method for doing the calculation, calling it like this `$billingService-\u003ecalculateCharges($contract);`. A command oriented interface would have a command class for each operation, and be called with something like this `$cmd = new CalculateChargesCommand($contract); $cmd-\u003eexecute();`. Essentially you have one command class for each method that you would have in the method-oriented interface. A common variation is to have a separate command executor object that actually does the running of the command. `$command = new CalculateChargesCommand($contract); $commandBus-\u003eexecute($command);`\n\n-- From [Martin Fowler's Blog](http://martinfowler.com/bliki/CommandOrientedInterface.html) (*code samples haven ported to PHP*):\n\nThat 'executor' Martin mentions is what we call the command bus. The pattern typically consists of 3 classes:\n\n1. `Command`: A tiny object containing some data (probably just some public properties or getters/setters)\n2. `CommandHandler`: Responsible for running the command through a `handle($command)` method\n3. `CommandBus`: All commands are passed to the bus `execute($command)` method, which is responsible for finding the right `CommandHandler` and calling the `handle($command)` method.\n\nFor every `Command` in your application, there should be a corresponding `CommandHandler`.\n\nIn the below example, we demonstrate how a command bus design could handle registering a new user in your system using Chief:\n\n```php\nuse Chief\\Chief, Chief\\Command;\n\nclass RegisterUserCommand implements Command {\n\tpublic $email;\n\tpublic $name;\n}\n\nclass RegisterUserCommandHandler {\n\tpublic function handle(RegisterUserCommand $command) {\n\t\tUsers::create([\n\t\t\t'email' =\u003e $command-\u003eemail,\n\t\t\t'name' =\u003e $command-\u003ename\n\t\t]);\n\t\tMailer::sendWelcomeEmail($command-\u003eemail);\n\t}\n}\n\n$chief = new Chief;\n\n$registerUserCommand = new RegisterUserCommand;\n$registerUserCommand-\u003eemail = 'adamnicholson10@gmail.com';\n$registerUserCommand-\u003ename = 'Adam Nicholson';\n\n$chief-\u003eexecute($registerUserCommand);\n```\n\n\n## Installation\n\nInstall the latest version with `composer require chief/chief`, or see [Packagist](https://packagist.org/packages/adamnicholson/chief).\n\nNo further setup is required, however if you're using a framework and want to make sure that we play nicely (with DI Containers, Event handlers, etc), then use the bridges below.\n\n#### Laravel\n\nAfter installing via composer, add the below to the `$providers` array in your `app/config/app.php`:\n\n```php\n'Chief\\Bridge\\Laravel\\LaravelServiceProvider'\n```\n\n## Usage\n\nWe'll use the below command/handler for the usage examples:\n\n```php\nuse Chief\\Chief, Chief\\Command;\n\nclass MyCommand implements Command {}\nclass MyCommandHandler {\n    public function handle(MyCommand $command) { /* ... */ }\n}\n```   \n   \n#### Automatic handler resolution\n\nWhen you pass a `Command` to `Chief::execute()`, Chief will automatically search for the relevant `CommandHandler` and call the `handle()` method:\n\n```php\n$chief = new Chief;\n$chief-\u003eexecute(new MyCommand);\n```\n\nBy default, this will search for a `CommandHandler` with the same name as your `Command`, suffixed with 'Handler', in both the current namespace and in a nested `Handlers` namespace. \n\nSo `Commands\\FooCommand` will automatically resolve to `Commands\\FooCommandHandler` or `Commands\\Handlers\\FooCommandHandler` if either class exists.\n\nWant to implement your own method of automatically resolving handlers from commands? Implement your own version of the `Chief\\CommandHandlerResolver` interface to modify the automatic resolution behaviour.\n    \n#### Handlers bound by class name\n\nIf your handlers don't follow a particular naming convention, you can explicitly bind a command to a handler by its class name:\n\n```php\nuse Chief\\Chief, Chief\\NativeCommandHandlerResolver, Chief\\Busses\\SynchronousCommandBus;\n\n$resolver = new NativeCommandHandlerResolver();\n$bus = new SynchronousCommandBus($resolver);\n$chief = new Chief($bus);\n\n$resolver-\u003ebindHandler('MyCommand', 'MyCommandHandler');\n\n$chief-\u003eexecute(new MyCommand);\n```\n    \n#### Handlers bound by object\n\nOr, just pass your `CommandHandler` instance:\n    \n```php\n$resolver-\u003ebindHandler('MyCommand', new MyCommandHandler);\n\n$chief-\u003eexecute(new MyCommand);\n```\n\n#### Handlers as anonymous functions\n\nSometimes you might want to quickly write a handler for your `Command` without having to write a new class. With Chief you can do this by passing an anonymous function as your handler:\n\n```php\t\n$resolver-\u003ebindHandler('MyCommand', function (Command $command) {\n    /* ... */\n});\n\n$chief-\u003eexecute(new MyCommand);\n```\n    \n#### Self-handling commands\n\nAlternatively, you may want to simply allow a `Command` object to execute itself. To do this, just ensure your `Command` class also implements `CommandHandler`:\n\n```php\nclass SelfHandlingCommand implements Command, CommandHandler {\n    public function handle(Command $command) { /* ... */ }\n}\n$chief-\u003eexecute(new SelfHandlingCommand);\n```\n\n## Decorators\nImagine you want to log every command execution. You could do this by adding a call to your logger in every `CommandHandler`, however a much more elegant solution is to use decorators.\n\nRegistering a decorator:\n\n```php\n$chief = new Chief(new SynchronousCommandBus, [new LoggingDecorator($logger)]);\n```\n    \nNow, whenever `Chief::execute()` is called, the command will be passed to `LoggingDecorator::execute()`, which will perform some log action, and then pass the command to the relevant `CommandHandler`.\n\nChief provides you with two decorators out-the-box:\n\n- *LoggingDecorator*: Log before and after all executions to a `Psr\\Log\\LoggerInterface`\n- *EventDispatchingDecorator*: Dispatch an event to a `Chief\\Decorators\\EventDispatcher` after every command execution.\n- *CommandQueueingDecorator*: Put the command into a Queue for later execution, if it implements `Chief\\QueueableCommand`. (Read more under \"Queued Commands\")\n- *TransactionalCommandLockingDecorator*: Lock the command bus when a command implementing `Chief\\TransactionalCommand` is being executed. (Read more under \"Transactional Commands\")\n    \nRegistering multiple decorators:\n\n```php\n// Attach decorators when you instantiate\n$chief = new Chief(new SynchronousCommandBus, [\n    new LoggingDecorator($logger),\n    new EventDispatchingDecorator($eventDispatcher)\n]);\n\n// Or attach decorators later\n$chief = new Chief();\n$chief-\u003epushDecorator(new LoggingDecorator($logger));\n$chief-\u003epushDecorator(new EventDispatchingDecorator($eventDispatcher));\n\n// Or manually stack decorators\n$chief = new Chief(\n    new EventDispatchingtDecorator($eventDispatcher,\n        new LoggingDecorator($logger, $context, \n            new CommandQueueingDecorator($queuer, \n                new TransactionalCommandLockingDecorator(\n                    new CommandQueueingDecorator($queuer, \n                        new SynchronousCommandBus()\n                    )\n                )\n            )\n        )\n    )\n);\n```\n    \n## Queued Commands\n\nCommands are often used for 'actions' on your domain (eg. send an email, create a user, log an event, etc). For these type of commands where you don't need an immediate response you may wish to queue them to be executed later. This is where the `CommandQueueingDecorator` comes in to play.\n\nFirstly, to use the `CommandQueueingDecorator`, you must first implement the `CommandQueuer` interface with your desired queue package:\n\n```php\ninterface CommandQueuer {\n    /**\n     * Queue a Command for executing\n     *\n     * @param Command $command\n     */\n    public function queue(Command $command);\n}\n```\n\n\u003e An implementation of `CommandQueuer` for illuminate/queue is [included](https://github.com/adamnicholson/Chief/blob/master/src/Bridge/Laravel/IlluminateQueuer.php).\n\nNext, attach the `CommandQueueingDecorator` decorator:\n\n```php\n$chief = new Chief();\n$queuer = MyCommandBusQueuer();\n$chief-\u003epushDecorator(new CommandQueueingDecorator($queuer));\n```\n    \nThen, implement `QueueableCommand` in any command which can be queued:\n\n```php\nMyQueueableCommand implements Chief\\QueueableCommand {}\n```\n\nThen use Chief as normal:\n\n```php\n$command = new MyQueueableCommand();\n$chief-\u003eexecute($command);\n```\n\nIf you pass Chief any command which implements `QueueableCommand` it will be added to the queue. Any commands which do *not* implement `QueueableCommand` will be executed immediately as normal.\n\nIf your commands implement `QueueableCommand` but you are not using the `CommandQueueingDecorator`, then they will be executed immediately as normal. For this reason, it is good practice to implement `QueueableCommand` for any commands which may be queued in the future, even if you aren't using the queueing decorator yet.\n\n## Cached Command Execution\n\nThe `CachingDecorator` can be used to store the execution return value for a given command.\n\nFor example, you may have a `FetchUerReportCommand`, and an associated handler which takes a significant time to generate the \"UserReport\". Rather than re-generating the report every time, simply make `FetchUserReport` implement `CacheableCommand`, and the return value will be cached.\n\nData is cached to a `psr/cache` (PSR-6) compatible cache library.\n\n\u003e Chief does not supply a cache library. You must require this yourself and pass it in as a consturctor argument to the `CachingDecorator`.\n\nExample:\n\n```php\nuse Chief\\CommandBus,\n    Chief\\CacheableCommand,\n    Chief\\Decorators\\CachingDecorator;\n\n$chief = new Chief();\n$chief-\u003epushDecorator(new CachingDecorator(\n\t$cache, // Your library of preference implementing PSR-6 CacheItemPoolInterface.\n\t3600 // Time in seconds that values should be cached for. 3600 = 1 hour.\n));\n\n\n    \nclass FetchUserReportCommand implements CacheableCommand { }\n\nclass FetchUserReportCommahdHandler {\n\tpublic function handle(FetchUserReportCommand $command) {\n\t\treturn 'foobar';\n\t}\n}\n\n$report = $chief-\u003eexecute(new FetchUserReportCommand); // (string) \"foo\" handle() is called\n$report = $chief-\u003eexecute(new FetchUserReportCommand); // (string) \"foo\" Value taken from cache\n$report = $chief-\u003eexecute(new FetchUserReportCommand); // (string) \"foo\" Value taken from cache\n\n\n```\n\n## Transactional Commands\n\nUsing the `TransactionalCommandLockingDecorator` can help to prevent more than 1 command being executed at any time. In practice, this means that you if you nest a command execution inside a command handler, the nested command will not be executed until the first command has completed.\n\nHere's an example:\n\n```php\nuse Chief\\CommandBus;\nuse Chief\\Command;\nuse Chief\\Decorators\\TransactionalCommandLockingDecorator;\n\nclass RegisterUserCommandHandler {\n\tpublic function __construct(CommandBus $bus, Users $users) {\n\t\t$this-\u003ebus = $bus;\n\t}\n\t\n\tpublic function handle(RegisterUserCommand $command) {\n\t\t$this-\u003ebus-\u003eexecute(new RecordUserActivity('this-will-never-be-executed'));\n\t\tUsers::create([\n\t\t\t'email' =\u003e $command-\u003eemail,\n\t\t\t'name' =\u003e $command-\u003ename\n\t\t]);\n\t\tthrow new Exception('Something unexpected; could not create user');\n\t}\n}\n\n$chief = new Chief();\n$chief-\u003epushDecorator(new TransactionalCommandLockingDecorator());\n\n$command = new RegisterUserCommand;\n$command-\u003eemail = 'foo@example.com';\n$command-\u003epassword = 'password123';\n\n$chief-\u003eexecute($command);\n```\n\nSo what's happening here? When `$chief-\u003eexecute(new RecordUserActivity('registered-user'))` is called, that command is actually dropped into an in-memory queue, which will not execute until `RegisterCommandHandler::handle()` has finished. In this example, because we're showing that an `Exception` is thrown before the method completes, the `RecordUserActivity` command is never actually executed.\n\n\n## Dependency Injection Container Integration\nChief uses a `CommandHandlerResolver` class which is responsible for finding and instantiating the relevant `CommandHandler` for a given `Command`. \n\nIf you want to use your own Dependency Injection Container to control the actual instantiation, just create your own class which implements `Chief\\Container` and pass it to the `CommandHandlerResolver` which is consumed by `SynchronousCommandBus`.\n\nFor example, if you're using Laravel:\n\n```php\nuse Chief\\Resolvers\\NativeCommandHandlerResolver,\n    Chief\\Chief,\n    Chief\\Busses\\SynchronousCommandBus,\n    Chief\\Container;\n\nclass IlluminateContainer implements Container {\n    public function make($class) {\n        return \\App::make($class);\n    }\n}\n\n$resolver = new NativeCommandHandlerResolver(new IlluminateContainer);\n$chief = new Chief(new SynchronousCommandBus($resolver));\n$chief-\u003eexecute(new MyCommand);\n```\n\nContainers have already been provided for :\n\n`Illuminate\\Container`:\n\n```php\n$container = new \\Illuminate\\Container\\Container;\n$resolver = new NativeCommandHandlerResolver(new \\Chief\\Bridge\\Laravel\\IlluminateContainer($container));\n$chief = new Chief(new \\Chief\\Busses\\SynchronousCommandBus($resolver));\n```\n\n`League\\Container`:\n\n```php\n$container = new \\League\\Container\\Container;\n$resolver = new NativeCommandHandlerResolver(new \\Chief\\Bridge\\League\\LeagueContainer($container));\n$chief = new Chief(new \\Chief\\Busses\\SynchronousCommandBus($resolver));\n```\n\n## Contributing\n\nWe welcome any contributions to Chief. They can be made via GitHub issues or pull requests.\n\n## License\n\nChief is licensed under the MIT License - see the `LICENSE.txt` file for details\n\n## Author\n\nAdam Nicholson - adamnicholson10@gmail.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamnicholson%2FChief","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadamnicholson%2FChief","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamnicholson%2FChief/lists"}