{"id":15676918,"url":"https://github.com/zachflower/eloquent-interactions","last_synced_at":"2025-05-06T21:28:04.713Z","repository":{"id":57089023,"uuid":"79502028","full_name":"zachflower/eloquent-interactions","owner":"zachflower","description":"💼 Manage application specific business logic in Laravel (inspired by ActiveInteraction)","archived":false,"fork":false,"pushed_at":"2024-02-18T00:41:07.000Z","size":48,"stargazers_count":13,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-19T14:58:37.369Z","etag":null,"topics":["command-pattern","eloquent","laravel","laravel-package"],"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/zachflower.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","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}},"created_at":"2017-01-19T22:33:14.000Z","updated_at":"2024-02-18T00:39:19.000Z","dependencies_parsed_at":"2024-10-23T13:03:22.530Z","dependency_job_id":null,"html_url":"https://github.com/zachflower/eloquent-interactions","commit_stats":{"total_commits":40,"total_committers":3,"mean_commits":"13.333333333333334","dds":"0.30000000000000004","last_synced_commit":"a2af796de083769fe09a1c99bb5c35cd11954e5a"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachflower%2Feloquent-interactions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachflower%2Feloquent-interactions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachflower%2Feloquent-interactions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zachflower%2Feloquent-interactions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zachflower","download_url":"https://codeload.github.com/zachflower/eloquent-interactions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252771332,"owners_count":21801699,"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":["command-pattern","eloquent","laravel","laravel-package"],"created_at":"2024-10-03T16:07:12.679Z","updated_at":"2025-05-06T21:28:04.696Z","avatar_url":"https://github.com/zachflower.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Eloquent Interactions\n\nEloquent Interactions manages application-specific business logic. It's an implementation of the [command pattern](https://refactoring.guru/design-patterns/command) in PHP for Laravel, and is inspired by the [ActiveInteraction](https://github.com/AaronLasseigne/active_interaction) library in Ruby.\n\n[![Latest Stable Version](https://poser.pugx.org/zachflower/eloquent-interactions/version)](https://packagist.org/packages/zachflower/eloquent-interactions) [![CI](https://github.com/zachflower/eloquent-interactions/actions/workflows/main.yml/badge.svg)](https://github.com/zachflower/eloquent-interactions/actions/workflows/main.yml)\n\n---\n\nEloquent Interactions gives you a place to put your business logic. It also helps you write safer code by validating that your inputs conform to your expectations, and provides a platform for creating discrete, easily testable code.\n\n## Installation\n\nTo install Eloquent Interactions, require the library via [Composer](https://getcomposer.org/):\n\n```\ncomposer require zachflower/eloquent-interactions\n```\n\nEloquent Interactions is built with Laravel 7.0+ in mind, and has tests currently validating compatibility with Laravel 7, 8, 9, and 10 on PHP 7.2.5 through 8.3. If you find any issues with your specific version of Laravel or PHP, please [open an issue](https://github.com/zachflower/eloquent-interactions/issues/new) and I will do my best to address it.\n\n## Basic Usage\n\nTo get started with Eloquent Interactions, let's first create a new Interaction. Interactions typically live in the `app/Interactions` directory, but you are free to place them anywhere that can be auto-loaded according to your `composer.json` file. All Eloquent Interactions extend the `\\ZachFlower\\EloquentInteractions\\Interaction` abstract class.\n\nThe easiest way to create an Interaction is using the `make:interaction` [Artisan command](https://laravel.com/docs/master/artisan):\n\n```\nphp artisan make:interaction ConvertMetersToMiles\n```\n\nNow, let's take a look at the base Interaction that was created by the `make:interaction` command above:\n\n```php\n\u003c?php\n\nnamespace App\\Interactions;\n\nuse ZachFlower\\EloquentInteractions\\Interaction;\n\nclass ConvertMetersToMiles extends Interaction\n{\n    /**\n     * Parameter validations\n     *\n     * @var array\n     */\n    public $validations = [\n        //\n    ];\n\n    /**\n     * Execute the interaction\n     *\n     * @return void\n     */\n    public function execute() {\n        //\n    }\n}\n```\n\nOnce generated, every interaction will require the following two components:\n\n1. **Input Validations**. The class `$validations` property utilizes the built-in [Laravel validator](https://laravel.com/docs/master/validation) to define and validate the expected input of a given Interaction. Alternatively, the `$validations` property can be replaced with a `validations()` method.\n2. **Business Logic**. The `execute()` method takes the provided input—after it passes validation, of course—and executes any necessary business logic on it. Each input you defined will be available. If any of the inputs are invalid, `execute()` won't be run.\n\nGiven that information, let's update the generated Interaction into something usable:\n\n```php\n\u003c?php\n\nnamespace App\\Interactions;\n\nuse ZachFlower\\EloquentInteractions\\Interaction;\n\nclass ConvertMetersToMiles extends Interaction\n{\n    /**\n     * Parameter validations\n     *\n     * @var array\n     */\n    public $validations = [\n        'meters' =\u003e 'required|numeric|min:0',\n    ];\n\n    /**\n     * Execute the interaction\n     *\n     * @return void\n     */\n    public function execute() {\n        return $this-\u003emeters * 0.000621371;\n    }\n}\n```\n\nTo execute the Interaction, you can call the static `run()` method on the class. As the Interaction's `$validations` property defines the expected inputs, a simple key-value array should be passed to `run()` with the expected input. This method will return a new instance of the `\\ZachFlower\\EloquentInteractions\\Outcome` class. To check the success of the outcome, a boolean `$valid` property will be set on the `Outcome` object, with `TRUE` meaning the input validation passed, and `FALSE` meaning it failed. If the validation failed, all validation errors will be stored in the `$errors` property on the `Outcome` object. If validation passes, the value returned from the `execute()` method will be stored in the `$result` property on the `Outcome` object.\n\n```php\n\u003e\u003e\u003e $outcome = ConvertMetersToMiles::run(['meters' =\u003e 100]);\n\u003e\u003e\u003e $outcome-\u003evalid;\n=\u003e true\n\u003e\u003e\u003e $outcome-\u003eresult;\n=\u003e 0.0621371\n\n\u003e\u003e\u003e $outcome = ConvertMetersToMiles::run(['meters' =\u003e 'one hundred']);\n\u003e\u003e\u003e $outcome-\u003evalid;\n=\u003e false\n\u003e\u003e\u003e $outcome-\u003eerrors-\u003etoArray()\n=\u003e [\n     \"meters\" =\u003e [\n       \"The meters field must be a number.\",\n     ],\n   ]\n```\n\nIf you would rather deal with error handling on your own, you can pass `TRUE` as a second parameter to the `run()` method. This, for lack of a better word, will execute the Interaction \"dangerously,\" meaning that any defined errors will be thrown as exceptions of the type `\\ZachFlower\\EloquentInteractions\\Exceptions\\ValidationException` instead.\n\n```php\n\u003e\u003e\u003e $outcome = App\\Interactions\\Utility\\ConvertMetersToMiles::run(['meters' =\u003e 'one hundred'], TRUE);\nIlluminate\\Validation\\ValidationException with message 'The given data failed to pass validation.'\n\u003e\u003e\u003e $outcome-\u003eerrors-\u003etoArray();\n=\u003e [\n     \"meters\" =\u003e [\n       \"The meters field must be a number.\",\n     ],\n   ]\n```\n\n### Validations\n\nEloquent Interactions relies heavily on the build-in [Laravel validator](https://laravel.com/docs/master/validation). This means that any validation method available within a Laravel application will also be available to the Eloquent Interactions validator. That said, there is currently one custom validator (with more on the horizon) to better facilitate the backend-nature of Eloquent Interactions.\n\n### Advanced Validators\n\nIf the built-in validators aren't powerful enough for your needs, you can use a `validations()` method in lieu of the `$validations` property. For example, let's say that we want to use a class to validate the `meters` parameter in the above examples. Our interaction would change to look something like this:\n\n\n```php\n\u003c?php\n\nnamespace App\\Interactions;\n\nuse ZachFlower\\EloquentInteractions\\Interaction;\n\nclass ConvertMetersToMiles extends Interaction\n{\n    /**\n     * Execute the interaction\n     *\n     * @return void\n     */\n    public function execute() {\n        return $this-\u003emeters * 0.000621371;\n    }\n\n    /**\n     * Parameter validations\n     *\n     * @var array\n     */\n    public function validations()\n    {\n        return [\n            'meters' =\u003e ['required', new MyMetersRule()],\n        ];\n    }\n}\n```\n\n#### Objects\n\nIn some instances, it might be desireable to validate the **type** of an object. For example, if we wanted to validate that an input parameter is `User` model, the following validation rule may be used:\n\n```php\npublic $validations = [\n    'user' =\u003e 'required|object:App\\Models\\User'\n];\n```\n\nIn a nutshell, this validator checks the `instanceof` of an input parameter against the defined validation. This is especially useful when validating whether or not a provided object is a child of the defined validation object.\n\n### Errors\n\nIn addition to the built-in validation errors, Eloquent Interactions also has support for custom validation errors directly within the `execute()` method. This can be accomplished by utilizing the Laravel validator's own `add()` method directly on its `errors()` method:\n\n```php\npublic function execute() {\n    $this-\u003evalidator-\u003eerrors()-\u003eadd('entity', 'The entity object type is invalid.');\n}\n```\n\nIt is important to note that, while adding custom validation errors within the `execute()` method _will_ mark the `Outcome` as invalid and return the expected error messages, what it _won't_ do is halt Interaction execution, so any business logic in the `execute()` method will be executed as normal unless special steps are taken.\n\n## Contributing\n\nPlease read through the [contributing guidelines](https://github.com/zachflower/eloquent-interactions/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development.\n\nFor personal support requests, please use [Gitter](https://gitter.im/eloquent-interactions/Lobby) to get help.\n\n## Versioning\n\nFor transparency into the release cycle and in striving to maintain backward compatibility, Eloquent Interactions is maintained under [the Semantic Versioning guidelines](http://semver.org/). Sometimes I screw up, but I'll adhere to those rules whenever possible.\n\nSee [the Releases section of the GitHub project](https://github.com/zachflower/eloquent-interactions/releases) for changelogs for each release version of Eloquent Interactions.\n\n## Support\n\nThe [issue tracker](https://github.com/zachflower/eloquent-interactions/issues) is the preferred channel for bug reports, feature requests and submitting pull requests.\n\n## Copyright and License\n\nCode and documentation copyright 2024 Zachary Flower. Code released under the [MIT license](https://github.com/zachflower/eloquent-interactions/blob/master/LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzachflower%2Feloquent-interactions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzachflower%2Feloquent-interactions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzachflower%2Feloquent-interactions/lists"}