{"id":34795704,"url":"https://github.com/artisansdk/cqrs","last_synced_at":"2026-04-20T21:02:05.799Z","repository":{"id":44888831,"uuid":"140894336","full_name":"artisansdk/cqrs","owner":"artisansdk","description":"A foundational package for Command Query Responsibility Segregation (CQRS) compatible with Laravel.","archived":false,"fork":false,"pushed_at":"2025-09-10T21:57:42.000Z","size":191,"stargazers_count":81,"open_issues_count":0,"forks_count":11,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-11T06:27:11.829Z","etag":null,"topics":["command-builder","command-bus","cqrs","dispatcher","event-handlers","event-listener","laravel","php7","query-builder"],"latest_commit_sha":null,"homepage":"","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/artisansdk.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-07-13T21:26:43.000Z","updated_at":"2026-02-05T19:53:30.000Z","dependencies_parsed_at":"2024-06-17T22:19:35.706Z","dependency_job_id":"f1506a6c-1b1f-4e99-8857-4d5e32f6b893","html_url":"https://github.com/artisansdk/cqrs","commit_stats":{"total_commits":54,"total_committers":6,"mean_commits":9.0,"dds":0.2592592592592593,"last_synced_commit":"c467ff59006825f3b261edfefe5dda2b0c5903c0"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/artisansdk/cqrs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artisansdk%2Fcqrs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artisansdk%2Fcqrs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artisansdk%2Fcqrs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artisansdk%2Fcqrs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artisansdk","download_url":"https://codeload.github.com/artisansdk/cqrs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artisansdk%2Fcqrs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32065584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["command-builder","command-bus","cqrs","dispatcher","event-handlers","event-listener","laravel","php7","query-builder"],"created_at":"2025-12-25T10:45:00.854Z","updated_at":"2026-04-20T21:02:05.774Z","avatar_url":"https://github.com/artisansdk.png","language":"PHP","readme":"# CQRS\n\nA foundational package for Command Query Responsibility Segregation (CQRS) compatible with Laravel.\n\n## Table of Contents\n\n- [Installation](#installation)\n  - [Peer Dependencies](#peer-dependencies)\n  - [Framework Helper Functions](#framework-helper-functions)\n- [Usage Guide](#usage-guide)\n  - [Commands](#commands)\n    - [How to Create a Command](#how-to-create-a-command)\n    - [How to Run a Command](#how-to-run-a-command)\n      - [Run a Command Using the Dispatcher](#run-a-command-using-the-dispatcher)\n      - [Run a Command Statically](#run-a-command-statically)\n      - [Run a Command From Anywhere](#run-a-command-from-anywhere)\n      - [Run a Command Manually (Without the Command Bus)](#run-a-command-manually-without-the-command-bus)\n    - [How to Create an Evented Command](#how-to-create-an-evented-command)\n      - [Silencing an Evented Command](#silencing-an-evented-command)\n    - [How to Run a Command in a Transaction](#how-to-run-a-command-in-a-transaction)\n      - [Aborting a Transactional Command](#aborting-a-transactional-command)\n      - [Silencing After Events With Abort](#silencing-after-events-with-abort)\n      - [Checking If a Command Was Aborted](#checking-if-a-command-was-aborted)\n    - [How to Use a Command as an Event Handler](#how-to-use-a-command-as-an-event-handler)\n    - [How to Queue a Command as a Job](#how-to-queue-a-command-as-a-job)\n    - [How to Run a Command on a Queue as a Job](#how-to-run-a-command-on-a-queue-as-a-job)\n    - [How to Invalidate Queries from Commands](#how-to-invalidate-queries-from-commands)\n      - [Invalidating Only a Subkey Cache](#invalidating-only-a-subkey-cache)\n  - [Queries](#queries)\n    - [How to Create a Query](#how-to-create-a-query)\n      - [Flat File Implementation](#flat-file-implementation)\n      - [HTTP API Implementation](#http-api-implementation)\n      - [Database Implementation](#database-implementation)\n    - [How to Get Query Results](#how-to-get-query-results)\n    - [How to Create an Evented Query](#how-to-create-an-evented-query)\n    - [How to Create a Cached Query](#how-to-create-a-cached-query)\n    - [How to Bust a Cached Query](#how-to-bust-a-cached-query)\n  - [Events](#events)\n    - [How Auto-resolution of Events Work](#how-auto-resolution-of-events-work)\n    - [How to Customize the Before and After Events](#how-to-customize-the-before-and-after-events)\n    - [Recommended Conventions for Command and Event Naming](#recommended-conventions-for-command-and-event-naming)\n  - [Concerns](#concerns)\n    - [Using CQRS in Your Classes](#using-cqrs-in-your-classes)\n    - [Using Argument Validators](#using-argument-validators)\n    - [Using Option Defaults](#using-option-defaults)\n    - [Saving Models Within Commands](#saving-models-within-commands)\n    - [Using the Silencer](#using-the-silencer)\n  - [Extending](#extending)\n    - [Using Macros on the Builder](#using-macros-on-the-builder)\n    - [Using Mixins on the Builder](#using-mixins-on-the-builder)\n- [Running the Tests](#running-the-tests)\n- [Licensing](#licensing)\n\n# Installation\n\nThe package installs into a PHP application like any other PHP package:\n\n```bash\ncomposer require artisansdk/cqrs\n```\n\n## Peer Dependencies\n\nThis package has some peer dependencies on Laravel packages. Rather than depending\non the entire framework, it is up to the developer to meet the peer dependencies\nif the dependent features are going to be used. While Laravel does provide out the\nbox packages for these dependencies, if you install outside of Laravel then you\nmay need to configure your application to implement the dependent interfaces.\n\nThe following explains which packages you should additionally install should you\nneed the corresponding features outside of Laravel:\n\n- `illuminate/container`: An IoC container must be provided by the framework and\ninjected into the `ArtisanSdk\\CQRS\\Dispatcher`. Laravel will do this automatically\nvia a typehinted interface in the constructor, but the `Dispatcher` technically\nrelies directly on `Illuminate\\Container\\Container` if you use `Dispatcher::make()`\nmanually or rely on `Command::make()` or similar static functions.\n\n- `illuminate/bus`: Queueable jobs that get chained rely upon a command bus within\n  Laravel. While not strictly needed, if you intend to do sophisticated queueing then\n  you will need this peer dependency for the actual job dispatching. See also\n  [Framework Helper Functions](#framework-helper-functions).\n\n- `illuminate/events`: Using the `ArtisanSdk\\CQRS\\Buses\\Transaction` command wrapper\n  will require this package which ships with Laravel. Essentially the dependency\n  relies on the ability for the framework to dispatch the events to the framework\n  layers and back down to the CQRS package level.\n\n- `illuminate/database`: Using the `ArtisanSdk\\CQRS\\Buses\\Transaction` or\n  `ArtisanSdk\\CQRS\\Query` classes will require this database package to\n  provide database transactions and querying statements.\n\n- `illuminate/pagination`: Using `ArtisanSdk\\CQRS\\Query::paginate()` method\n  will require the use of this package to return the paginated results.\n\n- `illuminate/queue`: Using any queueing functions of the Laravel framework will\n  require this package. This would include any serialization of the models for jobs\n  and events or for interacting with queues from jobs and commands.\n\n- `illuminate/validation`: You only need to install this peer-dependency if you\n  wish to have arguments passed to queries and command automatically validated\n  against an array of validation rules or against a custom passed validator. The\n  CQRS package provides support for this Laravel validation package but it is\n  not strictly required.\n\n## Framework Helper Functions\n\nLaravel includes several `helpers.php` files which expose global functions that\ntechnically any framework could implement. This further decouples this package\nfrom Laravel. If this package is therefore use outside of Laravel you will need\nto implement these helpers (much like this package did for testing purposes):\n\n- `app()` is used to resolve dependencies to make static calls like `Command::make()`\n  able to auto-resolve commands out of an IoC container. When passed a string that\n  references a class name bound in the container, the function should return a\n  built instance of that class.\n\n- `dispatch()` is used primarily used by chainable, queued commands via the\n  `ArtisanSdk\\CQRS\\Concerns\\Queueable` trait helper `dispatchNextJobInChain()`.\n  The function should accept a class and pass it along the framework's command\n  bus. For Laravel-based applications this can be met by installing `illuminate\\bus`\n  which provides `Illuminate\\Bus\\Dispatcher` as the command bus.\n\n# Usage Guide\n\n## Commands\n\nA command implements the `ArtisanSdk\\Contract\\Runnable` interface which\nmakes it both invokable and runnable. The intended use of a command is to perform\nsome sort of \"write\" operation or complete a unit of work and return its results.\nAn asynchronous command would return a promise while a synchronous command would\nreturn the result itself or nothing at all.\n\n### How to Create a Command\n\nA basic example of using a command is to create a class that extends the\n`ArtisanSdk\\CQRS\\Command` class and implementing the `run()` method\nreturning whatever value you want after the command is ran. You can use the constructor\nmethod to inject any command dependencies. Argument dependencies are implicitly\nrequired and the caller must satisfy the requirements or else the developer must\nthrow an exception to ensure all required arguments are passed and validated\nprior to execution of critical command logic.\n\n```php\nnamespace App\\Commands;\n\nuse App\\User;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass SaveUser extends Command\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function run()\n    {\n        $user = $this-\u003emodel;\n        $user-\u003eemail = $this-\u003eargument('email');\n        $user-\u003esave();\n\n        return $user;\n    }\n}\n```\n\n### How to Run a Command\n\nThere are multiple ways to dispatch a command. The first way is to simply create\nan instance of the `ArtisanSdk\\CQRS\\Dispatcher` and then call `command()` on it\nwhich will return an new instance of the command wrapped inside of an arguments\nbuilder class. You can then chain any arbitrary arguments onto the command before\ncalling `run()` or invoking the builder directly. You could also call `arguments()`\non the builder passing an array of arguments.\n\n#### Run a Command Using the Dispatcher\n\n```php\n$user = ArtisanSdk\\CQRS\\Dispatcher::make()\n    -\u003ecommand(App\\Commands\\SaveUser::class)\n    -\u003eemail('johndoe@example.com')\n    -\u003erun();\n```\n\n#### Run a Command Statically\n\nAlternatively you could just make the command statically which will also create\nan instance of the command builder:\n\n```php\n$user = App\\Commands\\SaveUser::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003erun();\n```\n\n#### Run a Command From Anywhere\n\nUsing `ArtisanSdk\\CQRS\\Concerns\\CQRS` helper trait on any class (e.g.: a controller)\nallows you to dispatch commands directly by simply calling `$this-\u003edispatch()`\nor `$this-\u003ecommand()` passing the command's class name as the argument. This will\nreturn an instance of the command builder. The base `ArtisanSdk\\CQRS\\Command`\nuses this trait and therefore subcommands can be executed within a command in\nthe same way:\n\n```php\nnamespace App\\Http\\Controllers;\n\nuse App\\Commands\\SaveUser;\nuse App\\Http\\Controllers\\Controller;\nuse ArtisanSdk\\CQRS\\Concerns\\CQRS;\nuse Illuminate\\Http\\Request;\n\nclass UserController extends Controller\n{\n    use CQRS;\n\n    public function post(Request $request)\n    {\n        return $this-\u003ecommand(SaveUser::class)\n            -\u003eemail($request-\u003einput('email'))\n            -\u003erun();\n    }\n}\n```\n\n#### Run a Command Manually (Without the Command Bus)\n\nCommands executed like the above examples all end up routing the command through\nthe dispatcher which implements a basic command bus for a few support scenarios\nthat many command-based applications need including eventing, queueing, and\ntransactions. While you can and probably should always dispatch a command, you can\nalso manually execute a command by simply constructing it either using auto-resolution\nfrom the container or manually and then calling the `run()` method on the command\nor directly invoking the class:\n\n```php\n$user = (new App\\Commands\\SaveUser(new App\\User))\n    -\u003earguments([\n        'email' =\u003e 'johndoe@example.com',\n    ])\n    -\u003erun();\n```\n\nThis will bi-pass the command bus setup by the dispatcher and therefore skip any\nadded wrapper functionality the dispatcher offers.\n\n### How to Create an Evented Command\n\nSometimes you want the rest of your code to be made aware of the processing of a\nparticular command. You may want to execute some code before the command or after\nthe command based on the result of the command. Using the dispatcher this is\ntrivially done by simply implementing the `ArtisanSdk\\Contract\\Eventable`\ninterface on any command that should be evented:\n\n```php\nnamespace App\\Commands;\n\nuse App\\User;\nuse ArtisanSdk\\Contract\\Eventable;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass SaveUser extends Command implements Eventable\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function run()\n    {\n        $user = $this-\u003emodel;\n        $user-\u003eemail = $this-\u003eargument('email');\n        $user-\u003esave();\n\n        return $user;\n    }\n}\n```\n\nWith the addition of the eventable contract implemented, an event will be fired\nbefore and another after the command is ran. The before event will be given the\narguments passed to the command while the after event will be given the results\nof the command itself. The event fired is an instance of `ArtisanSdk\\CQRS\\Events\\Event`.\n\n#### Silencing an Evented Command\n\nWhile firing events before and after a command is executed can be useful, sometimes\nyou want to run an evented command silently so listeners are not fired. Evented\ncommands have helper methods on the command and also the command builder to make\nthis use case easier. You can call `silence()` to silence the command, `silenced()`\nto check if a command is silenced, and `silently()` to run silently.\n\n```php\n$user = App\\Commands\\SaveUser::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003esilently();\n```\n\n### How to Run a Command in a Transaction\n\nOften you'll create a command that performs multiple database writes to different\ntables or multiple records. Alternatively you may have a command that executes\nmultiple subcommands and there needs to be a certain level of atomicity relating\nthe command's overall execution. If a subcommand or secondary write fails, you'll\nwant to roll back the command. This boilerplate logic is annoying to have to\nwrite into each command so this package provides a trivial way to do this by\nimplementing the `ArtisanSdk\\Contract\\Buses\\Transactional` interface on any\ncommand that should be transactional:\n\n```php\nnamespace App\\Commands;\n\nuse ArtisanSdk\\Contract\\Buses\\Transactional;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass SaveUser extends Command implements Transactional\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function run()\n    {\n        $user = $this-\u003emodel;\n        $user-\u003eemail = $this-\u003eargument('email');\n        $user-\u003esave();\n\n        return $user;\n    }\n}\n```\n\nNow if for any reason the command throws an exception, the queries executed within\nthe command or subcommands will be rolled back. If everything works as expected then\nthe transactions are committed like normal. The benefit of this approach is that it\nmakes it easy to bypass the transactional model for testing purposes by simply\ninvoking the commands manually which bypasses the transactional wrapper.\n\n#### Aborting a Transactional Command\n\nSometimes you want to rollback your transaction without throwing an exception and\nyet still return a result that satisfies your caller's response expectations. For\nsuch cases the command should call `abort()` and then return the result. The\ntransactional wrapper will still rollback but will not bubble any exception:\n\n```php\nnamespace App\\Commands;\n\nuse App\\User;\nuse ArtisanSdk\\Contract\\Buses\\Transactional;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass ChangePassword extends Command implements Transactional\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function run()\n    {\n        if( ! $user = $this-\u003euser($email) ) {\n            $this-\u003eabort();\n\n            return false;\n        }\n\n        $user-\u003epassword = $this-\u003eargument('password');\n        $user-\u003esave();\n\n        return $user;\n    }\n\n    protected function user() : User\n    {\n        return $this-\u003emodel\n            -\u003ewhere('email', $this-\u003eargument('email'))\n            -\u003efirst();\n    }\n}\n```\n\nThe above example changes the password of the user that matches the email address.\nIf the email does not match any known user, rather than throwing an exception, we\njust abort and return `false` instead. Had we performed any other write queries\nthen those would have been rolled back.\n\n#### Silencing After Events With Abort\n\nThe main benefit of aborting a command however is that the after events are not\nfired if the command is aborted. This is handy when a command is actually queued\nas a job and the job has already been handled or is no longer needed and therefore\nshould not fire an exception and risk being marked as a failed job but can instead\nsimply be aborted and still be treated as a successful job by the worker. Imagine\nfor example that an email was queued to be sent out 15 minutes later but within that\n15 minutes an action occurred that would make such an email irrelevant or redundant:\nthen when the command is being executed as a queued job to send the email out,\na pre-check could be performed to determine if the command should still be ran\nand if not, the command could be aborted.\n\n#### Checking If a Command Was Aborted\n\nThe `abort()` and `aborted()` methods are public methods of the command and can\nalso be used in circumstances where you might want to abort multiple commands in\na command pool based on when one command in the pool is aborted. You can also use\nthe `aborted()` method to check if a command has been aborted to better determine\nwhat to do with the command's result.\n\n### How to Use a Command as an Event Handler\n\nWhen the application fires events, event subscribers can broadcast the event to\nall bound event listeners. Each listener provides a `handle()` method which receives\nthe event as argument and then executes some arbitrary logic. This handler is\nessentially the same as a command and therefore commands can be used as command\nhandlers. The default behavior of `handle()` is to extract the `payload` property\nfrom the event object and pass that as arguments to a command builder and then\nself-execute by invoking the command's `run()` method.\n\nFirst you'll need to create a custom event that should fire. These events need\nto extend `ArtisanSdk\\CQRS\\Events\\Event` which provides the payload of arguments\nthat will be passed to the command. In our example event we accept a type hinted\n`App\\User` model as the only argument to the constructor to ensure that the event\nis created with the right kind of payload. We then assign this model to the `user`\nkey in an array that is passed to the parent constructor. This parent will correctly\nassign to this argument to the payload property.\n\n```php\nnamespace App\\Events;\n\nuse App\\User;\nuse ArtisanSdk\\CQRS\\Events\\Event;\n\nclass UserSaved extends Event\n{\n    public function __construct(protected User $user)\n    {\n    }\n}\n```\n\nNext, we'll need to create a command that fires this event when it is done running.\nFor a non-conventional event name, you'll need to provide the dispatcher with the\ncustom event name in the `beforeEvent()` and `afterEvent()` methods of the command.\nIn our case we just return the class name as a string which the dispatcher will\nconstruct and pass the `App\\User` returned by `run()` to the event's constructor.\n\n```php\nnamespace App\\Commands;\n\nuse App\\Events\\UserSaved;\nuse ArtisanSdk\\Contract\\Eventable;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass SaveUser extends Command implements Eventable\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function run()\n    {\n        $user = $this-\u003emodel;\n        $user-\u003eemail = $this-\u003eargument('email');\n        $user-\u003esave();\n\n        return $user;\n    }\n\n    public function afterEvent()\n    {\n        return UserSaved::class;\n    }\n}\n```\n\nWhile the dispatcher handles all the indirection automatically, it can be summarized\nas having accomplished the same as manually constructing and calling the following:\n\n```php\n$command = (new App\\Commands\\SaveUser(new App\\User()));\n$builder = new ArtisanSdk\\CQRS\\Builder($command);\n$user = $builder-\u003eemail('johndoe@example.com')-\u003erun();\n$event = new App\\Events\\UserSaved($user);\n```\n\nNext we'll need create another command which we will bind as the event handler\nfor any `App\\Events\\UserSaved` events that are fired:\n\n```php\nnamespace App\\Commands;\n\nuse ArtisanSdk\\CQRS\\Command;\n\nclass SendUserWelcomeEmail extends Command\n{\n    public function run()\n    {\n        $user = $this-\u003eargument('user');\n\n        // ... the $user is an instance of `App\\User` and can be used in a Mailable\n    }\n}\n```\n\nThe actual logic of sending the email has been omitted but as you can see it is\npossible to get the `App\\User` model from the arguments that will be automatically\npassed to the command when the `handle()` method is called. This is accomplished\nby simply wiring up a listener. It's recommended that you follow Laravel's documentation\non wiring up listeners within the `App\\Providers\\EventServiceProvider` class using\nthe `$listen` property but the following demonstrates manually subscribing a event\nhandler to an event as an event listener:\n\n```php\nevent()-\u003elisten(App\\Events\\UserSaved::class, App\\Commands\\SendUserWelcomeEmail::class);\n```\n\nNow whenever the `App\\Events\\UserSaved` event is fired the `App\\Commands\\SendUserWelcomeEmail`\ncommand's `handle()` method will be called with the event passed as argument. This\nin turn will unwrap the event and provide the event's payload as arguments to the\ncommand and then self-execute. Firing the event is the equivalent of manually calling:\n\n```php\n$command = (new App\\Commands\\SaveUser(new App\\User()));\n$builder = new ArtisanSdk\\CQRS\\Builder($command);\n$user = $builder-\u003eemail('johndoe@example.com')-\u003erun();\n$event = new App\\Events\\UserSaved($user);\n$handler = (new App\\Commands\\SendUserWelcomeEmail());\n$result = $handler-\u003ehandle($event);\n```\n\n### How to Queue a Command as a Job\n\nIn the case above, we're sending an email and this is often considered a background\nprocess that is not critical to response success. Usually a queued job would be\nused in this case. If you think about it though, a job is really just the definition\nof an event and it's handler which is queued for later execution rather than\nimmediate execution. Since commands can be these self-executing event handlers,\nthe handler can also be queued as a job instead. This package makes it trivial to\nqueue the handler by simply implementing the `ArtisanSdk\\Contract\\CQRS\\Queueable` interface\nand adding the `ArtisanSdk\\CQRS\\Concerns\\Queues` trait on the command you want to\nbe queued and support queue interactions:\n\n```php\nnamespace App\\Commands;\n\nuse ArtisanSdk\\CQRS\\Command;\nuse ArtisanSdk\\CQRS\\Traits\\Queue;\nuse ArtisanSdk\\Contract\\CQRS\\Queuable;\n\nclass SendUserWelcomeEmail extends Command implements Queueable\n{\n    use Queues;\n\n    // ... same as before but it'll now be queued\n}\n```\n\nNow whenever the `App\\Events\\UserSaved` event is fired, the `App\\Commands\\SendUserWelcomeEmail`\ncommand will be queued and then executed by a queue worker. All the same methods\nand properties like `$connection`, `$queue`, and `$delay` are supported on the\ncommand now and you can therefore configure your commands with defined defaults\nor let the caller decide via `onConnection()`, `onQueue()`, etc.\n\n### How to Run a Command on a Queue as a Job\n\nWhile it's more common to have an event handler be queued since events are by\nnature asynchronous, some commands also lend themselves to background processing.\nThese commands are not ran but rather queued. So this package makes it trivial\nto explicitly queue a command that implements `ArtisanSdk\\Contract\\CQRS\\Queueable`:\n\n```php\n$job = App\\Commands\\SendUserWelcomeEmail::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003equeue();\n```\n\nInstead of calling `run()` on the command, you simply call `queue()`. The magic\nof this method is that the `ArtisanSdk\\CQRS\\Builder` class is wrapping the queueable\ncommand to pass the arguments to a generic `ArtisanSdk\\Contract\\Event\\Event`\nimplementation. This event is a polyfill for the real underlying\n`ArtisanSdk\\Contract\\CQRS\\Queueable::queue($event)` method.\n\nWhile the dispatcher handles all the indirection automatically, it can be summarized\nas having accomplished the same as manually constructing and calling the following:\n\n```php\n$job = (new App\\Commands\\SendUserWelcomeEmail())\n    -\u003equeue(new ArtisanSdk\\CQRS\\Events\\Event([\n        'email' =\u003e 'johndoe@example.com',\n    ]));\n```\n\nThe pending job is returned and the framework dispatcher will push to the queue\nwhen the object is destructed. Having access to the job allows for further\ncustomization of the job prior to dispatch including calling familiar methods\nlike `onConnection`, `onQueue`, `delay`, and `chain`.\n\n### How to Invalidate Queries from Commands\n\n\u003e **Note:** You might want to read up on [Queries](#queries) and [Events](#events)\n\u003e before reading this section as it will make more sense when you understand\n\u003e how query caching works and how to make commands event driven.\n\nOften a command will write to the database, and eventually you'll want the queries\nreading from the same data to reflect those changes. If the queries are uncached, then\nthey are always up to date, but for high traffic applications, you'd want to cache the\nquery results until they grow scale. This can be tricky because of the way the `$key`\nand computed `$subkey` logic works within the `Cached` bus. Fortunately, we've added\na helper method for use on `Cacheable` classes to help with that.\n\nOn any `Cacheable` class you can add `use ArtisanSdk\\CQRS\\Concerns\\Bust` trait to expose\na public static method `bust()` that invalidates the entire cache map for that query.\nYou can call it from anywhere like this:\n\n```php\n$busted = MostPopularPosts::bust();\n```\n\nIf you want to invalidate the query as a response to an event being fired by the\napplication you can register the event handler to call `bust()`. For example, take\nthe following query that gets the most popular posts from a blog:\n\n```php\nnamespace App\\Queries;\n\nuse ArtisanSdk\\Contract\\Cacheable;\nuse ArtisanSdk\\CQRS\\Query;\n\nclass MostPopularPosts extends Query implements Cacheable\n{\n    public $ttl = 60 * 60 * 24 * 7; // 1 week cache\n\n    // ... logic to get the most popular posts\n}\n```\n\nSince we cache the above query for 1 week, we would want to invalidate the most\npopular posts results every time we publish a new post. All we have to do is fire\nthe `PostPublished` event and listen for it in the `App\\Providers\\EventServiceProvider`\nto map it back to the `MostPopularPosts` query that needs to be invalidated. The\nfollowing is an example of a command that publishes the `Post` and fires the `PostPublished`\nevent when it's done.\n\n```php\nnamespace App\\Commands;\n\nuse App\\Post;\nuse App\\Events\\PostPublished;\nuse ArtisanSdk\\Contract\\Eventable;\nuse ArtisanSdk\\CQRS\\Command;\nuse Carbon\\Carbon;\n\nclass PublishPost extends Command implements Eventable\n{\n    public function run()\n    {\n        $post = $this-\u003eargument('post', Post::class);\n        $post-\u003epublished_at = Carbon::now();\n        $post-\u003esave();\n\n        return $post;\n    }\n\n    public function afterEvent()\n    {\n        return PostPublished::class;\n    }\n}\n```\n\nYou can register the cache busting listener logic in the `EventServiceProvider` class like so:\n\n```php\nprotected $listen = [\n    PostPublished::class =\u003e [\n        [MostPopularPosts::class, 'bust']\n    ],\n    ...\n];\n```\n\nIn the above example anytime a `Post` is published, the `MostPopularPosts` query results will\nbe cache busted. The next time the query is executed, it will miss the cache and hit the\ndatabase. The results will then be cached again for subsequent calls until the next time the\nquery cache is invalidated or expired.\n\n#### Invalidating Only a Subkey Cache\n\nIf you needed to invalidate only a particular `$subkey` cache, then the best way to do that\nis within the `EventServiceProvider::boot()` method. Instead of calling the\n`bust()` method on the query, you would instead instantiate the query bus and pass the\n`$arguments` like normal to make the query bus and then call `bust()`. This will clear\nonly the `$subkey` cache. You can call `refresh()` instead if you want to invalidate the\ncache and prime it with the latest results at the same time.\n\n```php\npublic function boot()\n{\n    Event::listen(PostPublished::class, fn ($event) =\u003e MostPopularPosts::make(['type' =\u003e $event-\u003etype])-\u003ebust());\n}\n```\n\n## Queries\n\nA query implements the `ArtisanSdk\\Contract\\Query` interface which makes it\nboth invokable and runnable, therefore indistinguishable from a command. The\nintended use of a query is to perform some sort of \"read\" operation or get a\nresult from a data store. An asynchronous query would return a promise while a\nsynchronous command would block program execution until the result is returned.\n\n### How to Create a Query\n\nA basic example of using a query is to create a class that extends the\n`ArtisanSdk\\CQRS\\Query` class. This abstract class forwards `__invoke()` to\n`run()`. The class also includes a shorthand `get()` method which forwards to\n`run()` to make it feel more similar to working with the `DB::table()-\u003eget()` or\n`Eloquent::query()-\u003eget()` method. implementing the `builder()` method returning\nwhatever query builder you want to be executed by the `get()` method. So\nimplementing a `run()` method that returns query results is all that is\nnecessary to take advantage of the query bus.\n\nYou can use the constructor method to inject any query dependencies such as an\nEloquent model, a service class, etc. Argument dependencies are implicitly\nrequired and the caller must satisfy the requirements or else the developer must\nthrow an exception to ensure all required arguments are passed and validated\nprior to execution of critical query logic.\n\n\u003e **Important:** While using Eloquent ORM may sanitize or escape arguments, this\n\u003e package makes no assumptions that the arguments passed to the query class are\n\u003e safe. Make sure you validate and sanitize values before executing against the\n\u003e data backend.\n\nThe abstract `ArtisanSdk\\CQRS\\Query` class actually assumes you are using\nLaravel's Database ORM and query builder. The `run()` method therefore calls to\nan abstract `builder()` to get the SQL builder. You will need to implement this\n`builder()` method or stub it out if you are using, for example a RESTful API as\nthe query backend.\n\n#### Flat File Implementation\n\nAssuming you had a `resources/lang/en/states.php` file containing a PHP array\nof state abbreviations and names then the following query would be the minimal\nimplementation required. Note that we do not need to use a database as the\nresults can be loaded from a flat file on the system disk.\n\n```php\nnamespace App\\Queries;\n\nuse ArtisanSdk\\CQRS\\Query;\n\nclass GetStates extends Query\n{\n    public function run()\n    {\n        return trans('states');\n    }\n}\n```\n\nHere's how you could call this query to get the states:\n\n```php\n$states = App\\Queries\\GetStates::make()-\u003eget();\n```\n\n#### HTTP API Implementation\n\nAgain instead of a database, you could have your data backed by an HTTP API and\nuse an HTTP client like Guzzle to fetch the results:\n\n```php\nnamespace App\\Queries;\n\nuse ArtisanSdk\\CQRS\\Query;\nuse GuzzleHttp\\Client as Guzzle;\n\nclass GeocodeIP extends Query\n{\n    public function __construct(protected Guzzle $http)\n    {\n    }\n\n    public function run()\n    {\n        // Require the argument and validate as an IPv4 address\n        $ip = $this-\u003eargument('ip', ['ipv4']);\n\n        // Generate a URL to injected with the IP address\n        $url = sprintf('https://freegeoip.app/json/%s', $ip);\n\n        // Use Guzzle to get the geocoded response\n        $response = $this-\u003ehttp-\u003eget($url);\n\n        // Parse the JSON body of the response\n        return json_decode($response-\u003egetBody()-\u003egetContent());\n    }\n}\n```\n\nIn this example we use a dynamic query argument to build up the HTTP request when\nwe make the `get()` call to execute the request. Remember `get()` is forwarded to\nour custom `run()` implementation so it all just works. Everything you know about\nhow fluently building up command arguments applies to queries as well.\n\n```php\n$result = App\\Queries\\GeocodeIP::make()\n    -\u003eip('104.131.182.33')\n    -\u003eget();\n\necho $result-\u003ezip_code; // 07014\n```\n\n#### Database Implementation\n\nThis package assumes you will be using Eloquent ORM or at minimum a database\nabstraction and so the `builder()` method is intended to be used to return a\nquery builder. Therefore an implementation of a model backed query would look like this:\n\n```php\nnamespace App\\Queries;\n\nuse App\\User;\nuse ArtisanSdk\\CQRS\\Query;\n\nclass ListUsers extends Query\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function builder()\n    {\n        $query = $this-\u003emodel-\u003equery();\n\n        $order = $this-\u003eoption('order', 'id', ['in:id,name,email,created_at,updated_at']);\n        $sort = $this-\u003eoption('sort', 'desc', ['in:asc,desc']);\n\n        $query-\u003eorderBy($order, $sort);\n\n        if( $keyword = $this-\u003eoption('keyword', null, ['string', 'max:64']) ) {\n            $this-\u003escopeKeyword($query, $keyword);\n        }\n\n        return $query;\n    }\n\n    // This method could be called anything, but naming it similar to Eloquent\n    // helps clarify the intent of such builder abstractions to protected methods.\n    protected scopeKeyword($query, string $keyword)\n    {\n        $wildcard = sprintf('%%s%', $keyword);\n\n        return $query-\u003ewhere(function($query) use ($wildcard) {\n            return $query\n                -\u003eorWhere('name', 'LIKE', $wildcard)\n                -\u003eorWhere('email', 'LIKE', $wildcard);\n        });\n    }\n}\n```\n\nWe don't need to define the `run()` method because the parent class\nautomatically executes `$this-\u003ebuilder()-\u003eget()` to return the\nresult of the query when we run it. Passing arguments to the query lets you\ncustomize the results at call time.\n\n```php\n// Get the users with default arguments: sort desc by name\n$users = App\\Queries\\ListUsers::make()-\u003eget();\n\n// Get the users using custom arguments which are validated in the builder\n$users = App\\Queries\\ListUsers::make()\n    -\u003eorder('name')\n    -\u003esort('asc')\n    -\u003ekeyword('john')\n    -\u003eget();\n```\n\n### How to Get Query Results\n\nThe base query implements `get()` but also implements the convenient method of `paginate()`.\n\n```php\n// Get the ?page=# results of users with only the name and email columns\n$paginator = App\\Queries\\ListUsers::make()-\u003epaginate(10, ['name', 'email']);\n```\n\nFurthermore if your query uses an ORM and you need to inspect the query, you can call\n`toSql()` instead of `get()` or `builder()` directly to customize the query further\nfor one-off query executions:\n\n```php\n// select * from `users` order by `name` desc\n$sql = App\\Queries\\ListUsers::make()\n    -\u003eorder('name')\n    -\u003etoSql();\n\n// Bypass the run() method and execute against the builder directly\n$users = App\\Queries\\ListUsers::make()\n    -\u003eorder('name')\n    -\u003ebuilder()\n    -\u003elimit(10)\n    -\u003eget();\n\n// Customize the builder outside of the query\n$query = App\\Queries\\ListUsers::make();\n$query-\u003eorder('name');\n$builder = $query-\u003ebuilder(); // get the builder outside of the query\n$builder-\u003ewhereIn('id', [1, 2, 3]); // a customization to the query\n$users = $query-\u003eget(); // since $builder is referenced, query executes against customized builder\n```\n\nIt is common practice to create base classes to help with common queries\ninvolving just one result including expanding the interface to include `first()`\nor `firstOrFail()` among other query execution methods.\n\n```php\nnamespace App\\Queries;\n\nuse App\\User;\nuse ArtisanSdk\\CQRS\\Query;\n\nclass FindUserByEmail extends Query\n{\n    public function __construct(protected User $model)\n    {\n    }\n\n    public function builder()\n    {\n        return $this-\u003emodel-\u003equery()\n            -\u003ewhere('email', $this-\u003eargument('email', ['email']));\n    }\n\n    public function run()\n    {\n        return $this-\u003ebuilder()-\u003efirst();\n    }\n\n    public function firstOrFail()\n    {\n        return $this-\u003ebuilder()-\u003efirstOrFail();\n    }\n\n    public static function find(string $email)\n    {\n        return static::make()-\u003eemail($email)-\u003erun();\n    }\n\n    public static function findOrFail(string $email)\n    {\n        return static::make()-\u003eemail($email)-\u003efirstOrFail();\n    }\n}\n```\n\nThere are a lot of ways to run this query including:\n\n```php\n$user = ArtisanSdk\\CQRS\\Dispatcher::make()\n    -\u003equery(App\\Queries\\FindUserByEmail::class)\n    -\u003eemail('johndoe@example.com')\n    -\u003erun(); // or get()\n\n$user = App\\Queries\\FindUserByEmail::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003eget();\n\n// Throw Illuminate\\Database\\Eloquent\\ModelNotFoundException if not found\n$user = App\\Queries\\FindUserByEmail::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003efirstOrFail();\n\n// Returns null if not found\n$user = App\\Queries\\FindUserByEmail::find('johndoe@example.com');\n\n// Throw Illuminate\\Database\\Eloquent\\ModelNotFoundException if not found\n$user = App\\Queries\\FindUserByEmail::findOrFail('johndoe@example.com');\n```\n\nA query can also be executed from within a controller or any service that includes the uses the `ArtisanSdk\\CQRS\\Concerns\\CQRS` trait:\n\n```php\nnamespace App\\Http\\Controllers;\n\nuse App\\Commands\\FindUserByEmail;\nuse App\\Http\\Controllers\\Controller;\nuse ArtisanSdk\\CQRS\\Concerns\\CQRS;\nuse Illuminate\\Http\\Request;\n\nclass UserController extends Controller\n{\n    use CQRS;\n\n    public function show(Request $request, string $email)\n    {\n        return $this-\u003equery(FindUserByEmail::class)\n            -\u003eemail($email)\n            -\u003efirstOrFail();\n    }\n}\n```\n\n### How to Create an Evented Query\n\nSometimes you want the rest of your code to be made aware that a particular\nquery was executed. You may want to execute some code before the query or after\nthe query based on the result of the query. Using the dispatcher this is\ntrivially done by simply implementing the `ArtisanSdk\\Contract\\Eventable`\ninterface on any query that should be evented:\n\n```php\nnamespace App\\Queries;\n\nuse App\\Post;\nuse ArtisanSdk\\Contract\\Eventable;\nuse ArtisanSdk\\CQRS\\Query;\n\nclass MostPopularPosts extends Query implements Eventable\n{\n    public function __construct(protected Post $model)\n    {\n    }\n\n    public function builder()\n    {\n        return $this-\u003equery()\n            -\u003eorderBy('views', 'desc')\n            -\u003etake($this-\u003eoption('limit', 10, 'is_integer'));\n    }\n}\n```\n\nWith the addition of the eventable contract implemented, an event will be fired\nbefore and another after the command is ran. The before event will be given the\narguments passed to the query while the after event will be given the results of\nthe query itself. The event fired is an instance of `ArtisanSdk\\CQRS\\Events\\Event`.\n\nAs an example use case for the above query, the post authors could be notified\nthat their post is now being featured on the website using an after event\nhandler. Alternatively instrumentation could be started prior to the execution\nand then captured after in the after event as the elapsed time the query took to\nexecute.\n\nAll other event bus behaviors relating to eventable commands also apply to commands.\nSee documentation on eventable commands for more details.\n\n### How to Create a Cached Query\n\nMaybe you want the results of a query to be cached since the result does not\nchange very often given the same query arguments. This package makes that a\ntrivial effort by simply implementing `ArtisanSdk\\Contract\\Cacheable` and\nsetting a `public $ttl` property, set in seconds, on the query class. The query\nbus will handle all the cache key creation and cache busting using the default\ncache drivers of Laravel.\n\n```php\nnamespace App\\Queries;\n\nuse App\\Post;\nuse ArtisanSdk\\Contract\\Cacheable;\nuse ArtisanSdk\\CQRS\\Query;\n\nclass MostPopularPosts extends Query implements Cacheable\n{\n    public $ttl = 60 * 60 * 24 * 7; // 1 week cache\n\n    // ... same logic as above\n}\n```\n\nYou can also dynamically call `-\u003ettl($seconds)` on the query builder to customize the TTL of the\ncache results when querying. You can customize `public $key` property or call `-\u003ekey($key)` and\noptionally `-\u003esubKey($subKey)` to set a custom key for the query but by default the value will be\ngenerated based on a hash of the query itself. This makes unique queries cacheable under separate\nauto-generated keys.\n\n### How to Bust a Cached Query\n\nWhile caching is great, sometimes you need to bypass the cache or clear the cache.\n\n```php\n// Get the results and cache them for future query execution\n$posts = MostPopularPosts::make()-\u003eget();\n\n// Secondary calls return the cached results\n$cached = MostPopularPosts::make()-\u003eget();\n\n// Bust the cache then get the results\n$busted = MostPopularPosts::make()-\u003ebust()-\u003eget();\n\n// This is shorthand for cache busted results\n$busted = MostPopularPosts::make()-\u003erefresh();\n\n// Skip the cache and get the results: fresh results are not peristed to cache\n$uncached = MostPopularPosts::make()-\u003enocache()-\u003eget();\n\n// This is shorthand for bypassing the cached results\n$uncached = MostPopularPosts::make()-\u003efresh();\n```\n\nSee the `ArtisanSdk\\CQRS\\Buses\\Cached` class for more public methods that can be\nused to customize the query's caching mechanisms including bypassing cache,\nsetting a custom key, using tag based caches, and using a different cache\ndriver. The cache bus is probably the most compelling reason to use the query\nbus when using an Eloquent model because while Eloquent models are Active Record\nimplementations with lots of query builder capabilities, they don't handle\ndomain argument validation nor caching out of the box and with ease.\n\n\u003e **Note:** See [How to Invalidate Queries from Commands](#how-to-invalidate-queries-from-commands)\n\u003e  for more techniques on query busting related queries when commands make changes to data that\n\u003e  those queries need to fetch.\n\n\n## Events\n\n### How Auto-resolution of Events Work\n\nEvent naming follows a convention of conjugating the present imperative tense\nof the command name into a progressive future tense before event and a past tense\nafter event name. This is handled by the `Evented` wrapper and specifically by\nthe `resolveProgressiveTense()` and `resolvePastTense()` methods. Using a regex\nmapping between common endings for action verbs, the command name can be transformed\nfairly reliably. For example \"create\" becomes \"creating\" and \"created\". If no\nconjugation can be found to map to then the resolver will default to \"executing\"\nand \"executed\" as generic event names.\n\n\u003e **Help Wanted:** If you come across a conjugation case that could use improving\nplease take a look at `Evented::$progressiveMap` and `Evented::$pastMap` and\nsubmit an issue or pull request with recommended changes for your use case.\n\nThe auto-resolution logic is not perfect, so you'll still need to customize\nyour event names from time to time and this package provides that functionality.\n\n### How to Customize the Before and After Events\n\nSometimes you'll use a command name that is non-conventional or is simply hard\nto conjugate event names for because of the weirdness of the English language.\nIn these cases (and in all cases where explicitness is preferred) you can add\nthe `beforeEvent` and `afterEvent` methods to an `Eventable` command. The following\nillustrates how to customize the before and after events for a custom event\nnaming convention:\n\n```php\nnamespace App\\Commands;\n\nuse App\\Events\\NewPasswordSet;\nuse App\\Events\\ChangingPassword;\nuse ArtisanSdk\\Contract\\Eventable;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass ChangePassword extends Command implements Eventable\n{\n    public function beforeEvent(array $arguments)\n    {\n        return ChangingPassword::class;\n    }\n\n    public function run()\n    {\n        $user = $this-\u003eargument('user');\n        $user-\u003epassword = $this-\u003eargument('password');\n\n        return $this-\u003esave($user);\n    }\n\n    public function afterEvent($result)\n    {\n        return NewPasswordSet::class;\n    }\n}\n```\n\nAll it takes to modify the event used is to return the class name for the event\nas a string. Alternatively if you want to construct the event yourself or need\nto perform event switching based on the result of the command's execution, then\nyou can inspect the `$arguments` passed to the before event or the `$result` passed\nto the after event and simply return an event object. If you do not compose the\nevent objects yourself then the convention is that the arguments and results are\ninjected into the constructor of the event class referenced.\n\nAgain this all illustrates that it's possible to customize the events. In practice\nit would be recommended instead to follow a simpler naming convention such that\nthe command would be `App\\Commands\\Password\\Change` and the events would be\n`App\\Events\\Password\\Changing` and `App\\Events\\Password\\Changed` instead.\n\n### Recommended Conventions for Command and Event Naming\n\nWhile you are free to use the `beforeEvent()` and `afterEvent()` methods to customize\nthe dispatching of any event to suit a namespace or naming convention of your choice,\nit is often easier to follow a reasonable convention and let the auto-resolution\ndo its thing. The following is a recommended convention for naming your commands\nand before and after events using namespacing to delineate the classes:\n\n- Commands should be one word action verbs written in present imperative tense\n- Queries can be worded like commands or as a noun that defines the result set\n- Events should be progressive tense (before events) and past tense (after\n  events) conjugates of the command name\n- Namespaces should be used for uniqueness when multiple classes otherwise have\n  the same name.\n\nThese basic rules are further explained below:\n\nCommands should be worded in a present imperative tense following the form of\nan action. The command should be the action only and the namespace should organize\nthe logical use of the action. For example naming a command that registers the user\n`RegisterUser` consider naming it simply `Register`. The arguments to the command\nare a name and email and not a user model after all so if anything it would be\n`RegisterWithNameAndEmail` and the returned value would be the user model.\n\nNow to distinguish this register command from say registering a team or other domain\nmodel, consider using the namespace. You could use `App\\Commands\\User` as the name\nspace which results in `App\\Commands\\User\\Register` which follows a logical grouping\nof related classes under the `App\\Commands` namespace. Or you could use a service\noriented grouping of the class under `App\\User\\Commands\\Register` which creates\na service boundary under the `App\\User` namespace.\n\nNow it follows that query gets something so it likewise is a command but can instead\nbe worded as a more concrete synonym for abstract `Query` and generic \"get\" such\nas `App\\Queries\\User\\Find` or `App\\Queries\\User\\Search`. You are after all finding\nthe one user or searching for a collection of users and getting the results of that\nquery. You can also organize under a service boundary like `App\\User\\Queries\\Find`\nand `App\\User\\Queries\\Search` if you rather.\n\nYou may also find it more fluent to name your queries based on the result. For\nexample you might want to get the recently registered users as a standard query.\nThis could be `App\\Queries\\User\\RecentlyRegistered` or `App\\User\\Queries\\RecentlyRegistered`.\nYou might decide to parametize the column such that it's just `Recent` instead\nso then it can be used for recently registered, recently updated, etc. In following\nthis convention you might consider the queries as `GetRecentlyRegistered` and\ninstead just drop the prefix `Get` from the queries since the fluent code would\nbe written with `get()` in the syntax: `$this-\u003equery(RecentlyRegistered::class)-\u003eget()`.\n\nIf a command or query is evented then the events are auto resolved unless customized\nwith the `beforeEvent()` and `afterEvent()` methods. To help auto-resolution of\nevents, first make sure that the command is a single action word such as `Create`,\n`Register`, `Modify`, etc. Again make sure it's worded in the present tense. Since\na before event is indicative of something about to happen, or in an async system\nthat is happening, it makes sense that before events are transformed from the\npresent tense command name to a progressive tense event name. So the `Register`\ncommand fires a `Registering` event when it starts.\n\nFurthermore when the command is done, the action is complete and the after event\nshould therefore represent what happened. The after events are transformed from\nthe present tense command name to a past tense event name. So the `Register`\ncommand fires a `Registered` event when it is done. The same goes for strange\ncommands like `Modify` which transforms into before and after events of `Modifying`\nand `Modified`. The auto-resolution logic works pretty well but doesn't always\nget the event names right so always log your events during development to verify\nwhat is being fired and that your commands are firing the right events.\n\nSometimes you'll have awkward command names like `App\\Commands\\User\\SetStatus`.\nWhile you could try to figure out how to namespace it such that the command were\n`App\\Commands\\User\\Status\\Set` that often leads to unnecessary and artificial\nexpansion of the code base in a way the domain doesn't really care about. Plus\nauto-resolution will get the past tense sort of wrong with `Setted` anyways.\nCommands like `SetStatus` are still worded in the present tense and so the natural\nprogressive tense event name would be `SettingStatus` and the past tense event\nwould be `StatusSet`. As you can see the before event conjugates the verb\nand keeps it in front of the noun, while the after event places it after the noun.\nThe weirdness of English makes the past and present tense verb form of \"set\" the\nsame and that is something auto-resolution cannot work out. Therefore you'll need\nto define these events if needed yourself using `beforeEvent()` and `afterEvent()`\nmethods on your command.\n\nA past event can therefore become argument to another command such that domain\nlogic can be encoded with \"When [past event] then [present command]\" rules.\nFor example, \"When user registered then send activation email\". This aids in\nunderstanding that just because an event has been fired (e.g.: user registered)\ndoesn't mean that the command handler for the event (e.g.: send activation email)\nhas to be executed immediately. This delayed or deferred (technically queued)\ncommand still takes the past event payload as present argument to it's own\ndeferred execution. It is therefore possible to completely ignore the return\nvalue of a command and build an evented system that relies on the after events\ninstead of the command responses to continue program execution in an async style.\n\nYou may also find that you would prefer to name the actual root or aggregate model\nsimply `Model` which then requires further separation of the namespace to indicate\nwhich model it is. For example instead of `App\\User` you might organize as\n`App\\Models\\User` or `App\\User\\Models\\User`. When you have a lot of models however\nit can be hard to see where the service boundary is between the `User` model aggregate\nand all the related models. Therefore it would be better to organize as\n`App\\Models\\User\\User` and to remove the redundancy for `User` simplify to\n`App\\Models\\User\\Model`. In the `App\\User\\Models` case the aggregate and all\nrelated models are organized under the `App\\User\\Models` service boundary so the\nonly reason to rename `App\\User\\Models\\User` to `App\\User\\Models\\Model` is to\nhighlight that that model is the root aggregate for the `App\\User` service boundary.\n\nUsing a logical grouping of classes into namespaces (a common web app architecture\nconvention) would look like:\n\n```\nApp\n├─ Commands\n    └─ User\n        └─ Register\n├─ Events\n    └─ User\n        ├─ Registered\n        └─ Registering\n├─ Models\n    └─ User\n        └─ Model\n└─ Queries\n    └─ User\n        ├─ Find\n        └─ Search\n```\n\nAlternatively a grouping of classes into namespaces around the service boundary\n(a service-oriented architecture convention) would look like:\n\n```\nApp\n└─ User\n    ├─ Commands\n        └─ Register\n    ├─ Events\n        ├─ Registered\n        └─ Registering\n    ├─ Models\n        └─ Model\n    └─ Queries\n        ├─ Find\n        └─ Search\n```\n\nThis package doesn't care how you organize things but you might find that organizing\ninto service boundaries will help reduce naming and organizing decisions and give\nyou clean separation for later service packaging.\n\n## Concerns\n\nThe package's primary functionality is exposed as a set of base classes but these\nclasses are composed from a set of base traits. You can use these traits directly\nin your application code even where CQRS may not be fully needed but the traits\nprove to be a useful and consistent API for your application.\n\n### Using CQRS in Your Classes\n\n`ArtisanSdk\\CQRS\\Concerns\\Arguments` is a trait that provides arguments and options\nto a class including all the relevant validation logic and default resolvers.\nThe public methods of the trait are:\n\n- `Arguments::arguments($arguments)` to get or set the arguments fluently\n- `Arguments::argument($name, $validator)` to get an argument and validate it\n- `Arguments::option($name, $default, $validator)` to get an optional argument and provide a default\n- `Arguments::hasOption($name)` to check if the optional argument is present\n\n`ArtisanSdk\\CQRS\\Concerns\\CQRS` is the trait that provides the main interactive\nAPI for the CQRS pattern. This is the trait that is typically included on a controller,\nconsole command, or other class in order to directly dispatch commands using the\ncommand builder and dispatcher. The usable methods (most are protected) of the trait are:\n\n- `CQRS::dispatcher()` gets an instance of the `Dispatcher`. Instances are not singletons\n  so every command that is dispatched is ran through an unique dispatcher (command bus).\n  This is typically used like `$this-\u003edispatcher()-\u003edispatch($class)-\u003erun()` to compose\n  the runnable class then run it. It can also be used to dynamically forward events\n  like `$this-\u003edispatcher()-\u003ecreating($user)` which will fire a `Creating` event\n  with the user as argument.\n- `CQRS::call($class, $arguments)` directly composes then runs the class with the\n  passed arguments.\n- `CQRS::command($class)` to compose a command using the dispatcher but not run it (use `call()` instead).\n- `CQRS::query($class)` to compose a query using the dispatcher but not run it (use `call()` instead).\n- `CQRS::event($event, $payload)` to compose an after event with the payload and fire it using the dispatcher.\n- `CQRS::until($event, $payload)` to compose a before event with the payload and fire it using the dispatcher.\n\n`ArtisanSdk\\CQRS\\Concerns\\Handle` is a trait that can be used by commands to implement\nthe `ArtisanSdk\\Contract\\CQRS\\Handler` interface such that an event object may be passed\nto the `handle()` method of a command and the command be ran through the command\ndispatcher using the properties of the event as the arguments. Additionally if the\ncommand is queueable then the execution of the command will be deferred as a queued\njob instead. When the job is resolved out of the queue, the command will be directly\ninvoked, bypassing the handler yet still using the event properties as arguments.\n\n`ArtisanSdk\\CQRS\\Concerns\\Queues` is a wrapper trait for Laravel compatibility of\nmaking an event or command behave like a queued job. It also lets the command interact\nwith the command much like a queued job can. The intended use for this trait is\nto make the class it is used on a queueable job. See Laravel's documentation on\nhow to customize properties such as `$connection`, `$queue`, and `$delay` or\nto perform chaining of commands as queued jobs.\n\n`ArtisanSdk\\CQRS\\Concerns\\Save` is a trait that helps with saving of Eloquent models,\nespecially self-validating models like [`artisansdk\\model`](http://github.com/artisansdk/model) provides. It simply provides\na `save($model)` public method which ensures that the model is saved or throws an\nexception and if saved will return the saved model. See also [Saving Models Within Commands](#saving-models-within-commands).\n\n`ArtisanSdk\\CQRS\\Concerns\\Silencer` is a trait that the prevents the firing of events\nwhen a command or query is ran. The public methods of the trait are:\n\n- `Silencer::silence()`: set the silence flag on the command so that events are\n  not fired.\n- `Silence::silenced()`: a boolean check to see if the command is silenced. This\n  is used by the evented command wrapper to determine if events should be fired.\n- `Silence::silently()`: a shorthand method for `$command-\u003esilence()-\u003erun()` such\n  that you can silently run a command with just `$command-\u003esilently()`.\n\n### Using Argument Validators\n\nCommands and queries that require arguments often have a lot of boilerplate code\nthat handles validating the values of the arguments passed. To abstract this away,\nthe package includes a simple way to inline common validators and pass more\ndomain-specific validators using callables. You can use a simple closure that\nreturns a boolean value, a class or interface name to check the argument matches,\nan array of Laravel validation rules for the argument, or a pre-built Laravel\nvalidator instance.\n\n```php\nnamespace App\\Commands;\n\nuse App\\Invoice;\nuse App\\Coupon;\nuse ArtisanSdk\\CQRS\\Command;\nuse Illuminate\\Validation\\Factory as Validator;\n\nclass CalculateInvoice extends Command\n{\n    public function run()\n    {\n        // Validate the argument is simply set with a non empty value\n        $number = $this-\u003eargument('number');\n\n        // Validate the argument matches the Invoice class\n        $invoice = $this-\u003eargument('invoice', Invoice::class);\n\n        // Validate the argument against a rule of validation rules...\n        $subtotal = $this-\u003eargument('subtotal', ['integer', 'min:0'])\n\n        // ...or construct it manually yourself for something more complicated\n        $subtotal = $this-\u003eargument('subtotal', Validator::make($this-\u003earguments(), [\n            'subtotal' =\u003e ['integer', 'min:0', 'lte:total'],\n        ]));\n\n        // Validate the argument against a custom callable...\n        $coupon = $this-\u003eargument('coupon', function(string $code, string $argument) {\n            return $this-\u003ecouponExists($code, $argument);\n        });\n\n        // ... or just reference a method on a callable class\n        $coupon = $this-\u003eargument('coupon', [$this, 'couponExists']);\n    }\n\n    public function couponExists(string $code, string $argument)\n    {\n        return Coupon::where('code', $code)-\u003eexists();\n    }\n}\n```\n\n### Using Option Defaults\n\nThe following code demonstrates the use of an option instead of an argument. Based\non the presence of the option alone (a flag essentially) you could perform some\nguarded code or based on explicit check of the option's value if present. In the\nfollowing example, the default behavior if the option is not set is that the\ninvoice is not saved:\n\n```php\nnamespace App\\Commands;\n\nuse App\\Invoice;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass CalculateInvoice extends Command\n{\n    public function run()\n    {\n        $invoice = $this-\u003eargument('invoice', Invoice::class);\n\n        if( $this-\u003ehasOption('save') \u0026\u0026 true === $this-\u003eoption('save')) {\n            $invoice-\u003esave();\n        }\n\n        return $invoice;\n    }\n}\n```\n\nThe default value for an option is `null` by default. You can also set an explicit\ndefault value for an option that is not present in the list of arguments. This\nis demonstrated below using the same example as above. The result is that the\ninvoice is always saved unless explicitly set to false.\n\n```php\nnamespace App\\Commands;\n\nuse App\\Invoice;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass CalculateInvoice extends Command\n{\n    public function run()\n    {\n        $invoice = $this-\u003eargument('invoice', Invoice::class);\n\n        if( $this-\u003eoption('save', true) ) {\n            $invoice-\u003esave();\n        }\n\n        return $invoice;\n    }\n}\n```\n\nOccasionally you will want to perform some logical work that is more expensive\nwhen an option is not set and the default value needs to be resolved. For example\nyou may want to default to the authenticated user when no user is passed to a\ncommand or query as an option. In Laravel this incurs a hit against the database\nwhich is considered expensive and unnecessary if the default option is not actually\nused. Therefore it's preferred to defer this expensive work. This\npackage supports a resolver callable for the default option which ensures that\nthe work is lazily deferred until indeed the default is needed.\n\n```php\nnamespace App\\Commands;\n\nuse App\\Invoice;\nuse App\\User;\nuse ArtisanSdk\\CQRS\\Command;\n\nclass CalculateInvoice extends Command\n{\n    public function run()\n    {\n        $invoice = $this-\u003eargument('invoice', Invoice::class);\n\n        // This is wasteful since you have to resolve the user even when not used\n        // $editor = $this-\u003eoption('editor', auth()-\u003euser());\n\n        // Resolve the authenticated user as the default using a closure...\n        $editor = $this-\u003eoption('editor', function(string $option) {\n            return auth()-\u003euser();\n        });\n\n        // ... or just reference a method on a callable class\n        $editor = $this-\u003eoption('editor', [$this, 'resolveUser']);\n\n        $invoice-\u003eeditor()-\u003eassociate($user);\n\n        $invoice-\u003esave();\n\n        return $invoice;\n    }\n\n    public function resolveUser(string $option) : User\n    {\n        return auth()-\u003euser();\n    }\n}\n```\n\n### Saving Models Within Commands\n\nIf you use the `ArtisanSdk\\CQRS\\Concerns\\Save` trait or the `ArtisanSdk\\CQRS\\Command`\nwhich includes this trait, then you can quickly save Eloquent models including\nself-validating models like those provided by [`artisansdk\\model`](http://github.com/artisansdk/model).\nSimply call `save()` from within the command or controller and pass in the model\nthat should be saved. If the model does not save because it cannot be validated,\nthen an exception will be raised. If the model can be saved then the saved instance\nis returned. The use of this helper trait can streamline commands considerably\nand ensure that saves are being performed consistently.\n\n```php\nnamespace App\\Commands;\n\nuse ArtisanSdk\\CQRS\\Command;\n\nclass CalculateInvoice extends Command\n{\n    public function run()\n    {\n        $invoice = $this-\u003eargument('invoice');\n        $invoice-\u003etotal = 100;\n\n        return $this-\u003esave($invoice);\n    }\n}\n```\n\nIn addition to simply saving the models, the trait also formats the errors for\nCLI applications like Artisan commands and PHPUnit so they are more readable.\n\n### Using the Silencer\n\nSometimes you just don't want your evented commands to fire events. As an example,\nsay that you were sending out an email using `SendPasswordResetEmail` command which\nis normally triggered by the `UserPasswordReset` event. Let's say however that during\nuser registration, the `ResetUserPassword` command is called and yet you do not\nwant to send out the normal email for password resets. Instead you wish to trigger\nthe logic of resetting a password for an account and instead use `SendAccountActivationEmail`\ncommand to send an account activation in response to `UserRegistered` event. This\nis all possible using the `ArtisanSdk\\CQRS\\Concerns\\Silencer` trait which is already\nused by the base `ArtisanSdk\\CQRS\\Command` class.\n\nIn order to accomplish the above example you might write the following:\n\n```php\nnamespace App\\Commands;\n\nuse App\\User;\nuse App\\Commands\\ResetUserPassword;\nuse App\\Events\\UserPasswordReset;\nuse App\\Events\\UserRegistered;\nuse ArtisanSdk\\CQRS\\Command;\nuse ArtisanSdk\\Contract\\Eventable;\n\nclass RegisterUser extends Command implements Eventable\n{\n    public function __construct(protected User $user)\n    {\n    }\n\n    public function run()\n    {\n        $user = new User();\n        $user-\u003eemail = $this-\u003eargument('email');\n        $this-\u003esave($user);\n\n        return $this-\u003ecommand(ResetUserPassword::class)\n            -\u003euser($user)\n            -\u003esilently();\n    }\n\n    public function afterEvent()\n    {\n        return UserRegistered::class;\n    }\n}\n\nclass ResetUserPassword extends Command implements Eventable\n{\n    public function run()\n    {\n        $user = $this-\u003eargument('user');\n        $user-\u003epassword = null;\n\n        return $this-\u003esave($user);\n    }\n\n    public function afterEvent()\n    {\n        return ResetUserPassword::class;\n    }\n}\n```\n\n## Extending\n\n### Using Macros on the Builder\n\nIn the `App\\Providers\\AppServiceProvider@boot` (a Laravel default location):\n\n```php\nArtisanSdk\\CQRS\\Builder::macro('attempt');\n```\n\nNow you can call `attempt()` on any invokable that supports the method and any arguments\npassed will be forwarded.\n\nThe `ArtisanSdk\\CQRS\\Builder::macro()` method supports a second argument however\nthat accepts a callable or closure. Closures passed have `$this` bound into the\ncontext of the builder and therefore behave exactly as if they were a method\non the builder already with access to other protected methods of the builder\nsuch as `forwardToBase()`. You can therefore customize the builder using closure\nbased macros:\n\n```php\nArtisanSdk\\CQRS\\Builder::macro('attempt', function(...$arguments) {\n    try {\n        return $this-\u003erun();\n    } catch (Exception $error) {\n        throw new App\\Exceptions\\Error(sprintf($arguments[0], $error-\u003egetMessage()));\n    }\n});\n```\n\nFrom your app code you would then be able to attempt execution of any command and\nreturn a contextual exception without writing ugly try/catch logic everywhere:\n\n```php\n$user = App\\Commands\\SaveUser::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003eattempt('User could not be saved: %s');\n```\n\n### Using Mixins on the Builder\n\nExpanding upon [Using Macros on the Builder](#using-macros-on-the-builder), the ability\nto add mixed in behaviors from other classes is quite handy. Whereas a `macro($name, $closure)`\nare for one off functions, the `mixin($class)` takes all the public methods of the `$class`\nand makes them macros of the builder.\n\nFor example, say you wanted to add some debug macros to your builder but didn't want\nto register them one at a time. You could instead write a class with public methods like so:\n\n```php\nnamespace App\\Mixins;\n\nuse ArtisanSdk\\CQRS\\Builder;\nuse Psr\\Log\\LoggerInterface;\n\nclass Debug\n{\n    public function __construct(protected LoggerInterface $logger)\n    {\n    }\n\n    public function info(string $message) : Builder\n    {\n        $this-\u003elogger-\u003einfo($message);\n\n        return $this;\n    }\n\n    public function error(Throwable $error) : Builder\n    {\n        $this-\u003elogger-\u003eerror($error-\u003egetMessage());\n\n        return $this;\n    }\n\n    public function dd() : void\n    {\n        dd($this);\n    }\n}\n```\n\nThen you would register the mixin within the `App\\Providers\\AppServiceProvider@boot` method.\n\n```php\nuse App\\Mixins\\Debug;\nuse ArtisanSdk\\CQRS\\Builder;\nuse Illuminate\\Support\\Facades\\Log;\n\nBuilder::mixin(new Debug(Log::getFacadeRoot()));\n```\n\nAs you can see, you can construct the mixin class with all its dependencies (or use Laravel's\ncontainer to do the same), and then all the public methods of `info()`, `error()`, and `dd()`\nare made available as macros on the `Builder`. Now you can do something like:\n\n```php\n$user = SaveUser::make()\n    -\u003eemail('johndoe@example.com')\n    -\u003einfo('Saving the User')\n    -\u003edd()\n    -\u003erun();\n```\n\nIf you were to attempt to run that code, \"Saving the User\" would be printed to the\nerror logs even before the command is actually `run()`. The `info()` macro from the\n`Debug` mixin returns its own object `$this` so the builder is chained and so you\ncan repeat calls to the builder by continuing the chain.\n\nThe use of `dd()` on the other hand does die and dump the object `$this` which is\nthe builder. Therefore the `run()` never gets called as the program dies earlier.\nThis is similar to the behavior of Laravel's Collection class's `dd()` macro and\nyou'll be able to inspect the builder, it's command, and all the arguments like\nthe email \"johndoe@example.com\".\n\n# Running the Tests\n\nThe package is unit tested with 100% line coverage and path coverage. You can\nrun the tests by simply cloning the source, installing the dependencies, and then\nrunning `./vendor/bin/phpunit`. Additionally included in the developer dependencies\nare some Composer scripts which can assist with Code Styling and coverage reporting:\n\n```bash\ncomposer test\ncomposer watch\ncomposer fix\ncomposer report\n```\n\nSee the `composer.json` for more details on their execution and reporting output.\nNote that `composer watch` relies upon [`watchman-make`](https://facebook.github.io/watchman/docs/install.html).\nAdditionally `composer report` assumes a Unix system to run line coverage reporting.\nConfigure the command setting the value for `min = 80` to set your minimum line\ncoverage requirements.\n\n# Licensing\n\nCopyright (c) 2018-2025 [Artisan Made, Co](http://artisanmade.io)\n\nThis package is released under the MIT license. Please see the LICENSE file\ndistributed with every copy of the code for commercial licensing terms.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartisansdk%2Fcqrs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartisansdk%2Fcqrs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartisansdk%2Fcqrs/lists"}