{"id":13395602,"url":"https://github.com/bitExpert/adroit","last_synced_at":"2025-03-13T22:30:34.047Z","repository":{"id":62494577,"uuid":"46212281","full_name":"bitExpert/adroit","owner":"bitExpert","description":"[DEPRECATED] ADR/PSR-7 middleware","archived":true,"fork":false,"pushed_at":"2017-12-25T09:12:19.000Z","size":247,"stargazers_count":27,"open_issues_count":3,"forks_count":6,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-07-31T18:15:19.252Z","etag":null,"topics":["adr","container-interop","domain","hacktoberfest","middleware","php","psr-11","psr-7"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitExpert.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-15T09:49:20.000Z","updated_at":"2022-12-30T15:11:45.000Z","dependencies_parsed_at":"2022-11-02T09:31:44.815Z","dependency_job_id":null,"html_url":"https://github.com/bitExpert/adroit","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitExpert%2Fadroit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitExpert%2Fadroit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitExpert%2Fadroit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitExpert%2Fadroit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitExpert","download_url":"https://codeload.github.com/bitExpert/adroit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243493050,"owners_count":20299589,"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":["adr","container-interop","domain","hacktoberfest","middleware","php","psr-11","psr-7"],"created_at":"2024-07-30T18:00:25.635Z","updated_at":"2025-03-13T22:30:33.526Z","avatar_url":"https://github.com/bitExpert.png","language":"PHP","readme":"# bitexpert/adroit\nThis package provides a [PSR-7](http://www.php-fig.org/psr/psr-7/) compatible [ADR](http://pmjones.io/adr/) middleware. \n\n[![Build Status](https://travis-ci.org/bitExpert/adroit.svg?branch=master)](https://travis-ci.org/bitExpert/adroit)\n[![Coverage Status](https://coveralls.io/repos/github/bitExpert/adroit/badge.svg?branch=master)](https://coveralls.io/github/bitExpert/adroit?branch=master)\n\nInstallation\n------------\n\nThe preferred way of installing `bitexpert/adroit` is through Composer. Simply add `bitexpert/adroit` as a dependency:\n\n```\ncomposer.phar require bitexpert/adroit\n```\n\nUsage\n-----\n\nThe configure the \\bitExpert\\Adroit\\AdroitMiddleware middleware you need provide an array of \n\\bitExpert\\Adroit\\Action\\Resolver\\ActionResolver, an array of \\bitExpert\\Adroit\\Responder\\Resolver\\ResponderResolver and\na action request attribute telling adroit where to look for the action identifier.\n\nActionResolver\n--------------\n\nAs the name implies ActionResolvers are responsible for resolving an action class instance from the so-called actionToken.\nThe actionToken is basically used to identify a route. Adroit comes with a default implementation of an [ActionResolver](src/bitExpert/Adroit/Action/Resolver/ContainerActionResolver.php) which uses any \n[container-interop](https://github.com/container-interop/container-interop) compatible DI container as a backend.\n\nOf course you may implement your own ActionResolvers using the (\\bitExpert\\Adroit\\Action\\ActionResolver) interface.\n\n```php\n/** @var \\Interop\\Container\\ContainerInterface $container */\n$actionResolver = new \\bitExpert\\Adroit\\Action\\Resolver\\ContainerActionResolver($container);\n```\n\nResponderResolver\n-----------------\n\nSimilar to the ActionResolvers the ResponderResolvers are responsible for resolving an responder class instance from the\n$type defined in the DomainPayload instance. Adroit comes with a default implementation of an ResponderResolver \n(\\bitExpert\\Adroit\\Responder\\Resolver\\ContainerAwareResponderResolver) which uses any \n[container-interop](https://github.com/container-interop/container-interop) compatible DI container as a backend.\n\nOf course you may implement your own ResponderResolvers using the [ResponderResolver](src/bitExpert/Adroit/Responder/ResponderResolver.php) interface.\n\n```php\n/** @var \\Interop\\Container\\ContainerInterface $container */\n$responderResolver = new \\bitExpert\\Adroit\\Responder\\Resolver\\ContainerAwareResponderResolver($container);\n```\n\n(Domain)Payload\n---------------\nYou may define your own payload class(es) by implementing the \\bitExpert\\Adroit\\Domain\\Payload interface.\nThis gives you the opportunity to freely define the payload according to your needs.\nThis example implementation will be used in the documentation as follows:\n\n```php\n\u003c?php\nnamespace Acme\\Domain;\nuse bitExpert\\Adroit\\Domain\\Payload;\n\nclass CustomPayload implements Payload\n{\n    protected $type;\n    protected $data;\n\n    public function __construct($type, array $data = [])\n    {\n        $this-\u003etype = $type;\n        $this-\u003edata = $data;\n    }\n\n    public function getType()\n    {\n        return $this-\u003etype;\n    }\n\n    public fuction getValue($name)\n    {\n        return isset($this-\u003edata[$name]) ? $this-\u003edata[$name] : null;\n    }\n}\n```\n\n\n\nActions\n-------\n\nIn case you want to implement your own action logic (who does not want that?) you may use any callable following the signature of the [Action](src/bitExpert/Adroit/Action/Action.php) interface or create your own Action class and implement the interface. \n\nAction classes are allowed to either return an object which implements the [Payload](src/bitExpert/Adroit/Domain/Payload.php) interface or an PSR-7 response object implementing the \\Psr\\Http\\Message\\ResponseInterface interface. By default you should aim to return a \nPayload object. The PSR-7 response might come in handy when you have to deal with file downloads where you most \nlikely not want to read the file in your action class, push the content to the responder just to to write it to the response message body.\n\n\n```php\n\u003c?php \nuse Acme\\Domain\\CustomPayload;\nuse bitExpert\\Adroit\\Action\\Action;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\nclass HelloWorldAction implements Action\n{\n    /**\n     * @inheritdoc\n     */\n    protected function __invoke(ServerRequestInterface $request, ResponseInterface $response)\n    {\n        return new CustomPayload('hello', ['name' =\u003e 'World']);\n    }\n}\n\n```\n\nResponders\n----------\n\nResponders have to return a PSR-7 response object. Responders are not forced to implement the [Responder](src/bitExpert/Adroit/Responder/Responder.php) interface\nso you **may** use Closures as well but implementing the interface is recommended:\n\n```php\n\u003c?php \nnamespace Acme\\Responder\\HelloResponder;\n\nuse bitExpert\\Adroit\\Responder\\Responder;\nuse bitExpert\\Adroit\\Domain\\Payload;\nuse Psr\\Http\\Message\\ResponseInterface;\n\nclass HelloResponder implements Responder\n{\n    /**\n     * @inheritdoc\n     */\n    public function __invoke(Payload $domainPayload, ResponseInterface $response)\n    {\n        $response-\u003egetBody()-\u003erewind();\n        $response-\u003egetBody()-\u003ewrite('Hello ' . $domainPayload-\u003egetValue('name'));\n        \n        return $response-\u003ewithStatus(200)\n    }\n}\n\n```\n\nUsage\n-----\n\nSince Adroit provides a handy set of middlewares to achieve ADR you simply have to configure your ActionResolver(s) and\nResponderResolver(s). For the following example we use the ArrayContainer of [bitexpert/specialist](https://github.com/bitExpert/specialist)  which are configured using\nan array of mappings between the action identifier and the action and the domain payload type to the appropriate responder:\n\n\n```php\n\u003c?php\nuse bitExpert\\Specialist\\Container\\ArrayContainer;\n\n$container = new ArrayContainer([\n    'helloAction' =\u003e function (ServerRequestInterface $request, ResponseInterface $response) {\n        return new CustomPayload('hello', [\n            'name' =\u003e 'World'\n        ]);\n    },\n    'hello' =\u003e function (Payload $domainPayload, ResponseInterface $response) {\n        $response-\u003egetBody()-\u003erewind();\n        $response-\u003egetBody()-\u003ewrite('Hello ' . $domainPayload-\u003egetValue('name'));\n        return $response;\n    };    \n]);\n\n// create the action resolver\n$actionResolver = new ContainerActionResolver($container);\n\n\n// create the responder resolver\n$responderResolver = new ContainerResponderResolver($container);\n\n// Provide the request attribute where the routing result identifier is kept\n// and your resolvers\n$adroit = new AdroitMiddleware('action', [$actionResolver], [$responderResolver]);\n\n// create a request containing an action identifier inside the routing result attribute\n$request = ServerRequestFactory::fromGlobals()-\u003ewithAttribute('action', 'helloAction');\n\n// and run adroit\n$response = $adroit($request, new Response());\n$emitter = new SapiEmitter();\n$emitter-\u003eemit($response);\n\n```\nAs you can see, you also may use simple callables as actions and responders.\n\nAdroit itself does not depend on a concrete PSR-7 implementation which means you should be able to use it in your set-up\nwithout running into problems. Just for the unit tests Adroit depends on zendframework/zend-diactoros as a PSR-7 implementation.\n\nMiddleware hooks\n----------------\nAdroit provides several hooks to be as flexible as a standard middleware pipe while\nimplementing the ADR paradigm.\n\nYou may use the following hooks to manipulate things in between the execution of\nthe middlewares needed for ADR itself:\n\n```php\n// Gets piped in front of the ActionResolverMiddleware\n$adroit-\u003ebeforeResolveAction($yourMiddleware);\n\n// Gets piped in front of the ActionExecutorMiddleware\n$adroit-\u003ebeforeExecuteAction($yourMiddleware);\n\n// Gets piped in front of the ResponderResolverMiddleware\n$adroit-\u003ebeforeResolveResponder($yourMiddleware);\n\n// Gets piped in front of the ResponderExecutorMiddleware\n$adroit-\u003ebeforeExecuteResponder($yourMiddleware);\n```\n\nThese hooks allow great flexibility but with great flexibility also comes\ngreat responsibility ;-) Please note that the hooks are named \"before\"\nand so are to implement the middlewares:\n\n```php\n\nfunction (ServerRequestInterface $request, ResponseInterface $response, callable $next = null) {\n\n    // Your awesome code\n\n    if ($next)\n        $response = $next($request, $response);\n    }\n\n    return $response;\n}\n\n```\n\nOf course you may implement it different, but that would not hit the \"before\" in the hook name.\nPlease be aware of that!\n\n\nRouting\n-------\nTo avoid external dependencies we removed routing from Adroit since this may be achieved by using any routing mechanism you like.\nYou just need to ensure that action identifying value will be set to a request attribute of your choice and tell the\nActionMiddleware where to look for it.\n\nLicense\n-------\n\nAdroit is released under the Apache 2.0 license.\n","funding_links":[],"categories":["Middleware dispatcher"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FbitExpert%2Fadroit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FbitExpert%2Fadroit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FbitExpert%2Fadroit/lists"}