{"id":22092082,"url":"https://github.com/krakphp/effects","last_synced_at":"2025-09-10T00:46:00.197Z","repository":{"id":57009014,"uuid":"327379379","full_name":"krakphp/effects","owner":"krakphp","description":"Safely handle side effects via generators","archived":false,"fork":false,"pushed_at":"2021-02-05T16:07:46.000Z","size":13,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"v0.x","last_synced_at":"2025-07-25T00:09:13.222Z","etag":null,"topics":["ddd","generators","side-effects"],"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/krakphp.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}},"created_at":"2021-01-06T17:12:23.000Z","updated_at":"2024-08-02T14:43:51.000Z","dependencies_parsed_at":"2022-08-21T13:10:46.878Z","dependency_job_id":null,"html_url":"https://github.com/krakphp/effects","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/krakphp/effects","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Feffects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Feffects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Feffects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Feffects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/krakphp","download_url":"https://codeload.github.com/krakphp/effects/tar.gz/refs/heads/v0.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krakphp%2Feffects/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274390719,"owners_count":25276408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-09T02:00:10.223Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ddd","generators","side-effects"],"created_at":"2024-12-01T03:08:15.213Z","updated_at":"2025-09-10T00:46:00.165Z","avatar_url":"https://github.com/krakphp.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Effects\n\nThe effects library is a small set of utilities to help enable side effects in code that you expect to remain pure using PHP generators to transfer ownership.\n\nThis is helpful in terms of Domain Driven Design and maintaining a pure domain model.\n\n## Usage\n\n```php\n\u003c?php\n\nuse function Krak\\Effects\\{handleEffects, expect};\n\n// Domain Entity\nfinal class ShoppingCart\n{\n    public function checkOut(CheckOutShoppingCart $checkOutShoppingCart) {\n        // ... build up captueCharge command\n        $capturedCharge = expect(CapturedCharge::class, yield new CaptureCharge(/* args */));\n    }\n}\n\n// Domain Commands/Effects\nfinal class CheckOutShoppingCart {}\nfinal class CaptureCharge {}\nfinal class CapturedCharge {}\n\n// Application Command Handler\nfinal class HandleCheckOutShoppingCart\n{\n    public function __invoke(CheckOutShoppingCart $checkOutShoppingCart): void {\n        $shoppingCart = $this-\u003eshoppingCarts-\u003eget($checkOutShoppingCart-\u003eshoppingCart());\n        handleEffects($shoppingCart-\u003echeckOut($checkOutShoppingCart), [\n            CaptureCharge::class =\u003e function(CaptureCharge $captureCharge) {\n                return $this-\u003epaymentGateway-\u003ecapture($captureCharge); // returns a CapturedCharge instance\n            }\n        ]);\n    }\n}\n```\n\n### How it Works\n\nThis works by leveraging the fact that PHP generators allow sending values back to a yielded result. The `handleEffects` function simply just iterates over the domain method pulling all of the commands, passing them to the command handler map, and then taking the responses and sending them back to the domain method.\n\nThe expect function is just a safety helper to provide type auto completion and assert the expected class in case there was a mapping error to make debugging a bit nicer. It's technically not needed, so if you don't care about auto-completion help with psalm and PHPStorm, then feel free to just use the yield keyword without the `expect` function.\n\n### Nested Effects with yield from\n\nIf you end up needing to raise a few effects with one method, it may make sense to have specific methods used to manage and raise those effects. \n\nYou can use the `yield from` statement to raise effects from child methods. here's an example:\n\n```php\nfinal class Product\n{\n    public function checkout() {\n        yield from $this-\u003eraiseEffects();\n    }\n    \n    private function raiseEffects() {\n        $result = yield new Effect1();\n    }\n}\n```\n\n### Prewk\\Result Integration\n\nIf you are working with more complex domain methods/services, it can be helpful to structure individual parts of the code in separate functions that return results and can short circuit operations like one would use with a normal Result class.\n\nLet's see how we can acheive that with the MapEffectResults class.\n\n```php\n\nuse Prewk\\Result;\nuse Krak\\Effects\\Bridge\\Result\\MapEffectResults;\nuse function Krak\\Effects\\expect;\n\nfinal class Product\n{\n    public function syncInventory() {\n        expect(Result::class, yield from MapEffectResults::map(\n            $this-\u003efetchInventoryFromERP(),\n            $this-\u003efetchPricingRules(),\n            $this-\u003epushInventoryToThirdParty()\n        ))-\u003emapErr(function() {\n            // set some error state maybe.\n        })-\u003emap(function() {\n            // set some success state maybe.\n        });\n    }\n    \n    public function fetchInventoryFromERP(){\n        return function() {\n            return expect(Result::class, yield new FetchInventoryFromERP($this-\u003eproductId));\n        };\n    }\n    \n    public function fetchPricingRules(){\n        return function(InventoryFromERP $inventoryFromERP) {\n            return expect(Result::class, yield new FetchPricingRulesForProduct($this-\u003eproductId))\n                -\u003emap(function(PricingRules $pricingRules) use ($inventoryFromERP) {\n                    return [$inventoryFromERP, $pricingRules];\n                });\n        };\n    }\n    \n    public function pushInventoryToThirdParty() {\n        return function(array $tup) {\n            [$inventoryFromERP, $pricingRules] = $tup;\n            // calculate final inventory using special logic\n            return expect(Result::class, yield new PushInventoryToThirdParty($finalInventory));\n        };\n    }\n}\n\n// in some application service\n\\Krak\\Effects\\handleEffects($product-\u003esyncInventory(), []); // with handlers accordingly\n```\n\n## Installation\n\nInstall with composer at `krak/effects`\n\n## Inspiration\n\nThis design is inspired from the Elm language design around maintaining pure application code while leaving side effects to be managed by the runtime.\n\nHere are some other helpful resources around domain model purity and side effects:\n\n- [Side Effects in Elm](https://elmprogramming.com/side-effects.html)\n- [Domain model purity vs. domain model completeness](https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrakphp%2Feffects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkrakphp%2Feffects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrakphp%2Feffects/lists"}