{"id":19300036,"url":"https://github.com/kirschbaum-development/laravel-actions","last_synced_at":"2025-04-22T10:31:15.408Z","repository":{"id":43686575,"uuid":"460121743","full_name":"kirschbaum-development/laravel-actions","owner":"kirschbaum-development","description":null,"archived":false,"fork":false,"pushed_at":"2022-12-21T23:20:50.000Z","size":65,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":15,"default_branch":"main","last_synced_at":"2024-11-01T11:37:39.322Z","etag":null,"topics":["hacktoberfest"],"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/kirschbaum-development.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-16T18:09:18.000Z","updated_at":"2023-08-30T21:14:08.000Z","dependencies_parsed_at":"2023-01-30T05:01:20.052Z","dependency_job_id":null,"html_url":"https://github.com/kirschbaum-development/laravel-actions","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirschbaum-development%2Flaravel-actions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirschbaum-development%2Flaravel-actions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirschbaum-development%2Flaravel-actions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirschbaum-development%2Flaravel-actions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kirschbaum-development","download_url":"https://codeload.github.com/kirschbaum-development/laravel-actions/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223893052,"owners_count":17220834,"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","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":["hacktoberfest"],"created_at":"2024-11-09T23:13:28.312Z","updated_at":"2025-04-22T10:31:15.386Z","avatar_url":"https://github.com/kirschbaum-development.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[//]: # (![Mail Intercept banner]\u0026#40;screenshots/banner.jpg\u0026#41;)\n\n# Laravel Actions\n### A package for handling simple actions with eventing.\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/kirschbaum-development/laravel-actions)](https://packagist.org/packages/kirschbaum-development/laravel-actions)\n[![Total Downloads](https://img.shields.io/packagist/dt/kirschbaum-development/laravel-actions)](https://packagist.org/packages/kirschbaum-development/laravel-actions)\n[![Actions Status](https://github.com/kirschbaum-development/laravel-actions/workflows/CI/badge.svg)](https://github.com/kirschbaum-development/laravel-actions/actions)\n\nLaravel Actions are simple job-like classes that don't interact with the queue. Actions are great to leverage when you have some simple functionality that you need to reuse.\n\nBut why would you want to use Actions you ask? Actions are great when you have small bits of code that you want to extract into small, testable classes. Actions can also take the place of queued jobs when you don't want or need that kind of power, or if you need the results of the code right now.\n\nBut the real power is with eventing.\n\nThis package exposes two events during your Action:\n- Before the Action begins\n- After the Action completes\n\nThe special sauce here is that you get to tell the Action which events you want triggered!\n\n## Requirements\n\n| PHP Version  | Laravel Actions Version |\n|--------------|-------------------------|\n| `^6.0, ^7.0` | `^0.1.0`                |\n| `^8.0`       | `^0.2.0`                |\n\n## Installation\n\n```bash\ncomposer require kirschbaum-development/laravel-actions\n```\n\n## Creating and Preparing the Action\n\nCreate a new Action with artisan command:\n\n```bash\nphp artisan make:action ChuckNorris\n```\n\nThis will create a new Action class at `app/Actions/ChuckNorris.php`. You are, of course, free to move the action wherever you want. Just make sure you update the namespace!\n\nThere are two public properties ready for your events: `$before` and `$after`. You can use one or both of these, and you can remove either of them if you don't use them in your Action class.\n\n```php\n /**\n  * Event to dispatch before action starts.\n  *\n  * @var string\n  */\n public $before = ChuckNorrisWillBlowYourMind::class;\n\n /**\n  * Event to dispatch after action completes.\n  *\n  * @var string\n  */\n public $after = ChuckNorrisBlewYourMind::class;\n```\n\nNext place your required arguments within the `__construct()` method and your Action code within the `__invoke()` method. You are free to return anything you might need from the invokeable method. Now we're ready to use the Action!\n\n```php\n/**\n * Create a new action instance.\n *\n * @return void\n */\npublic function __construct()\n{\n    // Pass any arguments you need.\n}\n\n/**\n * Execute the action.\n *\n * @return mixed\n */\npublic function __invoke()\n{\n    // Handle your action here.\n}\n```\n\n## Usage\n\nThere are two different ways we can call our newly created Action.\n\n### From the Action\n\nWe can call one of three methods on the Action itself as long as the class is using the `CanAct` trait.\n\n```php\nChuckNorris::act($data);\nChuckNorris::actWhen($isChuckNorrisMighty, $data);\nChuckNorris::actUnless($isChuckNorrisPuny, $data);\n```\n\nThe `$data` is passed into the Action's constructor. You can pass as many arguments as needed in your use case.\n\nThe second two methods, `actWhen` and `actUnless` require a condition as the first variable. These work like other Laravel methods such as `throw_if()` and `throw_unless()`. Finally, you can pass as many arguments as needed for your Action after the condition.\n\n### Facade\n\nThe package also has a facade. Here's the syntax:\n\n```php\nuse Kirschbaum\\Actions\\Facades\\Action;\n\nAction::act(ChuckNorris::class, $data);\nAction::actWhen($isChuckNorrisMighty, ChuckNorris::class, $data);\nAction::actUnless($isChuckNorrisPuny, ChuckNorris::class, $data);\n```\n\nThe usage is nearly identical to calling the methods directly on the Action as mentioned in the section above. The benefit here is that you can easily test actions using `Action::shouldReceive('act')`, `Action::shouldReceive('actWhen')` or `Action::shouldReceive('actUnless')`.\n\n### Helpers\n\nThe package also has a few handy helpers to get Chuck in action. Here's the syntax:\n\n```php\nact(ChuckNorris::class, $data);\nact_when($isChuckNorrisMighty, ChuckNorris::class, $data);\nact_unless($isChuckNorrisPuny, ChuckNorris::class, $data);\n```\n\n### Dependency Injection\n\nYou can even inject Actions as a dependencies inside your application!\n\n```php\nuse Kirschbaum\\Actions\\Action;\n\npublic function index (Action $action)\n{\n    $action-\u003eact(ChuckNorris::class, $data);\n    $action-\u003eactWhen($isChuckNorrisMighty, ChuckNorris::class, $data);\n    $action-\u003eactUnless($isChuckNorrisPuny, ChuckNorris::class, $data);\n}\n```\n\n## Macros\n\nThere are times when you may want to add something extra to your actions. We can leverage macros for this!\n\nHere is an example were we are leveraging Inertia's defer functionality directly on our action. The macro then just calls `act()` on the action class when the deferred prop is requested!\n\n```php\n// In your service provider\nAction::macro('defer', function($action, ...$arguments) {\n    return Inertia::defer(fn () =\u003e $action::act(...$arguments));\n});\n\n// In your controller\nreturn Inertia::render('Users/Index')\n    -\u003ewith('users', GetUsers::defer());\n```\n\nNote how the originating class is passed into the macro function as the first parameter. This is very important, otherwise the macro will be unaware of which action you are actually running as macros are technically run on the parent action class. You are also free to do what you want regarding the subsequent $arguments, but it is considered best practice to pack/unpack the arguments with the spread operator to ensure the actions are as flexible as possible.\n\nAlso take note the `defer()` is defined on the `Kirschbaum\\Actions\\Action` class, not on the `GetUsers` action class. Individual actions are not macroable in and of themselves. The macro `defer()` will also be available to every action in your application, not just the `GetUsers` action! \n\nBefore and after events will not be fired when using macros. They will get fired however if you use an action's `act()`, `actWhen()`, or `actUnless()` methods with the macro function.\n\n## Handling Failures\n\nWe all know Chuck Norris isn't going to fail us, but he isn't the only one using this... Handling failures is pretty easy with Actions. Out of the box, any exceptions thrown by your Action classes get handled by Laravel's exception handler. If you'd rather implement your own logic during a failure, add a `failed()` method to your Action. It's that easy! You can return data from your `failed()` method if you choose as well.\n\n```php\n/**\n * Handle failure of the action.\n *\n * @throws Throwable\n *\n * @return mixed\n */\npublic function failed(Throwable $exception)\n{\n    event(new VanDammeFailedEvent);\n}\n```\n\nHashtag #BAM!\n\n### Custom Exceptions\n\nAnother option for handling failures is to tell the Action to throw its own exception. If you don't need the extra overhead of writing your own `failed()` method, you can just tell your Action to throw a custom exception. It's as simple as just defining the exception you want thrown from the Action.\n\n```php\n/**\n * Event to dispatch if action throws an exception.\n *\n * @var string\n */\npublic $exception = SeagalFailedException::class;\n```\n\n## Auto-Discovery and Configuration\n\nOut of the box, actions are automatically discovered and bound to Laravel's container, which allows for easier testing of your actions. If you need to add a custom path if you are placing your actions somewhere other than `app/Actions`, make sure to publish the configs.\n\n```bash\nphp artisan vendor:publish --tag laravel-actions\n```\n\nIf you want to disable auto-discovery, publish the config and return an empty array from the `paths` key.\n\n```php\nreturn [\n    'paths' =\u003e [],\n];\n```\n\n## Testing\n\nHave no fear. Testing all of this is very straightforward. There are two approaches to testing built in.\n\n### Testing Facades\n\nIf you are using Facades to implement your Actions, you can use the standard `shouldReceive()` method directly from the Facade.\n\n```php\nuse Kirschbaum\\Actions\\Facades\\Action;\n\nAction::shouldReceive('act')\n    -\u003eonce()\n    -\u003eandReturnTrue();\n```\n\n### Mocking\n\nIf you are using helpers, the `CanAct` trait, or dependency injection, you can easily mock the `Action` class with Laravel's mocking tools.\n\n```php\nuse Kirschbaum\\Actions\\Action;\n\n$this-\u003emock(Action::class, function ($mock) {\n    $mock-\u003eshouldReceive('act')\n        -\u003eonce()\n        -\u003eandReturnTrue();\n});\n```\n\nBecause actions are bound into Laravel's container by default, you can test specific actions as well.\n\n```php\nuse App\\Actions\\ChuckNorris;\n\n$this-\u003emock(ChuckNorris::class, function ($mock) {\n    $mock-\u003eshouldReceive('act')\n        -\u003eonce()\n        -\u003eandReturnTrue();\n});\n```\n\n## Last thoughts\n\nIf for some reason you'd prefer not to use the cool Eventing system, Facades, Mocking, etc., that's fine. Just call your Action like this:\n\n```php\nnew ChuckNorris($data);\n```\n\nThis will bypass all the magic and call the invoke method automagically, letting Chuck do his thing without anyone knowing, but why? ;)\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n### Security\n\nIf you discover any security related issues, please email brandon@kirschbaumdevelopment.com or nathan@kirschbaumdevelopment.com instead of using the issue tracker.\n\n## Credits\n\n- [Brandon Ferens](https://github.com/brandonferens)\n- Inspired in part by [Luke Downing's](https://github.com/lukeraymonddowning) Laracon Online Winter '22 [talk](https://www.youtube.com/watch?v=0Rq-yHAwYjQ\u0026t=1678s). \n\n## Sponsorship\n\nDevelopment of this package is sponsored by Kirschbaum, a developer driven company focused on problem solving, team building, and community. Learn more [about us](https://kirschbaumdevelopment.com) or [join us](https://careers.kirschbaumdevelopment.com)!\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkirschbaum-development%2Flaravel-actions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkirschbaum-development%2Flaravel-actions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkirschbaum-development%2Flaravel-actions/lists"}