{"id":20338208,"url":"https://github.com/openclassrooms/usecase","last_synced_at":"2025-04-11T23:11:47.312Z","repository":{"id":16852448,"uuid":"19612347","full_name":"OpenClassrooms/UseCase","owner":"OpenClassrooms","description":"Use Case Library","archived":false,"fork":false,"pushed_at":"2025-02-06T11:01:45.000Z","size":253,"stargazers_count":6,"open_issues_count":5,"forks_count":5,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-04-11T23:11:45.415Z","etag":null,"topics":[],"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/OpenClassrooms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2014-05-09T13:40:54.000Z","updated_at":"2025-02-06T11:01:20.000Z","dependencies_parsed_at":"2022-07-15T10:30:34.143Z","dependency_job_id":"dec38a88-8bf6-42b9-9f74-4f6aa39908c6","html_url":"https://github.com/OpenClassrooms/UseCase","commit_stats":{"total_commits":84,"total_committers":6,"mean_commits":14.0,"dds":"0.33333333333333337","last_synced_commit":"36e9611376643f1fec302e3f6c325beae4a5d47c"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenClassrooms%2FUseCase","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenClassrooms%2FUseCase/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenClassrooms%2FUseCase/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenClassrooms%2FUseCase/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenClassrooms","download_url":"https://codeload.github.com/OpenClassrooms/UseCase/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248492877,"owners_count":21113163,"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":[],"created_at":"2024-11-14T21:12:03.111Z","updated_at":"2025-04-11T23:11:47.284Z","avatar_url":"https://github.com/OpenClassrooms.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"UseCase\n=======\n[![Build Status](https://travis-ci.org/OpenClassrooms/UseCase.svg?branch=master)](https://travis-ci.org/OpenClassrooms/UseCase)\n[![SensioLabsInsight](https://insight.sensiolabs.com/projects/5b05eef1-7457-434e-8a8c-44013a6675a1/mini.png)](https://insight.sensiolabs.com/projects/5b05eef1-7457-434e-8a8c-44013a6675a1)\n[![Coverage Status](https://coveralls.io/repos/OpenClassrooms/UseCase/badge.png?branch=master)](https://coveralls.io/r/OpenClassrooms/UseCase?branch=master)\n\nUseCase is a library that provides facilities to manage technical code over a Use Case in a Clean / Hexagonal / Use Case Architecture.\n- Security access\n- Cache management\n- Transactional context\n- Events\n- Logs\n\nThe goal is to have only functional code on the Use Case and manage technical code in an elegant way using annotations.\n\nMore details on :\n- [Clean Architecture](http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html).\n- [Hexagonal Architecture](http://alistair.cockburn.us/Hexagonal+architecture).\n- [Use Case Driven Development](http://www.ivarjacobson.com/Use_Case_Driven_Development/).\n\n## Installation\n```composer require openclassrooms/use-case```\nor by adding the package to the composer.json file directly.\n\n```json\n{\n    \"require\": {\n        \"openclassrooms/use-case\": \"*\"\n    }\n}\n```\n```php\n\n\u003c?php\nrequire 'vendor/autoload.php';\n\nuse OpenClassrooms\\UseCase\\Application\\Services\\Proxy\\UseCases\\UseCaseProxy;\n\n//do things\n```\n\u003ca name=\"install-nocomposer\"/\u003e\n\n### Instantiation\nThe UseCaseProxy needs a lot of dependencies. \n\nThe Dependency Injection Pattern is clearly helpful.\n\nFor an implementation with Symfony2, the UseCaseBundle is more appropriate.\n\nUseCaseProxy can be instantiate as following:\n```php\n\nclass app()\n{\n    /**\n     * @var OpenClassrooms\\UseCase\\Application\\Services\\Proxy\\UseCases\\UseCaseProxyBuilder\n     */\n    private $builder;   \n    \n    /**\n     * @var OpenClassrooms\\UseCase\\Application\\Services\\Security\\Security;\n     */\n    private $security;\n    \n    /**\n     * @var OpenClassrooms\\Cache\\Cache\\Cache; \n     */\n    private $cache;\n    \n    /**\n     * @var OpenClassrooms\\UseCase\\Application\\Services\\Transaction\\Transaction;\n     */\n    private $transaction;\n    \n    /**\n     * @var OpenClassrooms\\UseCase\\Application\\Services\\EventSender\\EventSender;\n     */\n    private $event;\n    \n    /**\n     * @var OpenClassrooms\\UseCase\\Application\\Services\\EventSender\\EventFactory\n     */\n    private $eventFactory;\n    \n    /**\n     * @var Psr\\Log\\LoggerInterface\n     */\n     private $logger;\n\n    /**\n     * @var Doctrine\\Common\\Annotations\\Reader\n     */\n    private $reader;\n\n    public function method()\n    {\n        $useCase = $this-\u003ebuilder\n                    -\u003ecreate(new OriginalUseCase())\n                    -\u003ewithReader($this-\u003ereader)\n                    -\u003ewithSecurity($this-\u003esecurity)\n                    -\u003ewithCache($this-\u003ecache)\n                    -\u003ewithTransaction($this-\u003etransaction)\n                    -\u003ewithEventSender($this-\u003eevent)\n                    -\u003ewithEventFactory($this-\u003eeventFactory)\n                    -\u003ewithLogger($this-\u003elogger)\n                    -\u003ebuild();\n    }                    \n}                \n```\nOnly ```UseCaseProxyBuilder::create(UseCase $useCase)``` and ```UseCaseProxyBuilder::withReader(AnnotationReader $reader)``` are mandatory.\n\n## Usage\nA classic Use Case in Clean / Hexagonal / Use Case Architecture style looks like this:\n\n```php\n\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCase;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCaseRequest;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Responders\\UseCaseResponse;\n\nclass AUseCase implements UseCase\n{\n    /**\n     * @return UseCaseResponse\n     */\n    public function execute(UseCaseRequest $useCaseRequest)\n    {\n        // do things\n        \n        return $useCaseResponse;\n    }\n}\n```\nThe library provides a Proxy of the UseCase.\n\n### Security\n@Security annotation allows to check access.\n\n```php\n\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCase;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCaseRequest;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Responders\\UseCaseResponse;\nuse OpenClassrooms\\UseCase\\Application\\Annotations\\Security;\n\nclass AUseCase implements UseCase\n{\n    /**\n     * @Security (roles = \"ROLE_1\")\n     *\n     * @return UseCaseResponse\n     */\n    public function execute(UseCaseRequest $useCaseRequest)\n    {\n        // do things\n        \n        return $useCaseResponse;\n    }\n}\n```\n\"roles\" is mandatory.\n\nOther options :\n```php\n/**\n * @Security (roles = \"ROLE_1, ROLE_2\")\n * Check the array of roles\n *\n * @Security (roles = \"ROLE_1\", checkRequest = true)\n * Check access for the object $useCaseRequest\n *\n * @Security (roles = \"ROLE_1\", checkField = \"fieldName\")\n * Check access for the field \"fieldName\" of the object $useCaseRequest\n */\n```\n\n### Cache\n@Cache annotation allows to manage cache.\n\n```php\n\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCase;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCaseRequest;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Responders\\UseCaseResponse;\nuse OpenClassrooms\\UseCase\\Application\\Annotations\\Cache;\n\nclass AUseCase implements UseCase\n{\n    /**\n     * @Cache\n     *\n     * @return UseCaseResponse\n     */\n    public function execute(UseCaseRequest $useCaseRequest)\n    {\n        // do things\n        \n        return $useCaseResponse;\n    }\n}\n```\nThe key is equal to : ```md5(serialize($useCaseRequest))``` and the TTL is the default one.\n\nOther options:\n```php\n/**\n * @Cache (lifetime=1000)\n * Add a TTL of 1000 seconds\n *\n * @Cache (namespacePrefix=\"namespace_prefix\")\n * Add a namespace to the id with a namespace id equals to \"namespace_prefix\" \n *\n * @Cache (namespacePrefix=\"namespace prefix\", namespaceAttribute=\"fieldName\")\n * Add a namespace to the id with a namespace id equals to \"namespace_prefix\" . \"$useCaseRequest-\u003efieldName\"\n */\n```\n### Transaction\n\n@Transaction annotation gives a transactional context around the Use Case.\n- begin transaction\n- execute()\n- commit\n- rollback on exception\n \n\n```php\n\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCase;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCaseRequest;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Responders\\UseCaseResponse;\nuse OpenClassrooms\\UseCase\\Application\\Annotations\\Transaction;\n\nclass AUseCase implements UseCase\n{\n    /**\n     * @Transaction\n     *\n     * @return UseCaseResponse\n     */\n    public function execute(UseCaseRequest $useCaseRequest)\n    {\n        // do things\n        \n        return $useCaseResponse;\n    }\n}\n```\n### Event\n\n@Event annotation allows to send events.\n\nAn implementation of OpenClassrooms\\UseCase\\Application\\Services\\EventSender\\EventFactory must be written in the application context.\n\n```php\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCase;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCaseRequest;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Responders\\UseCaseResponse;\nuse OpenClassrooms\\UseCase\\Application\\Annotations\\EventSender;\n\nclass AUseCase implements UseCase\n{\n    /**\n     * @Event\n     *\n     * @return UseCaseResponse\n     */\n    public function execute(UseCaseRequest $useCaseRequest)\n    {\n        // do things\n        \n        return $useCaseResponse;\n    }\n}\n```\n\nThe message can be send:\n- pre execute\n- post execute\n- on exception\nor all of them.\n\nPost is default.\n\nThe name of the event is the name of the use case with underscore, prefixed by the method.\nFor previous example, the name would be : use_case.post.a_use_case\n\nPrefixes can be :\n- use_case.pre.\n- use_case.post.\n- use_case.exception.\n\n```php\n/**\n * @Event(name=\"event_name\")\n * Send an event with event name equals to *prefix*.event_name\n * (note: the name is always converted to underscore)\n *\n * @Event(methods=\"pre\")\n * Send an event before the call of UseCase-\u003eexecute()\n *\n * @Event(methods=\"pre, post, onException\")\n * Send an event before the call of UseCase-\u003eexecute(), after the call of UseCase-\u003eexecute() or on exception\n * \n * @Event(name=\"first_event\")\n * @Event(name=\"second_event\")\n * Send two events\n */\n```\n\n### Log\n\n@Log annotation allows to add log following the [PSR standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md).\n\n\n```php\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCase;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Requestors\\UseCaseRequest;\nuse OpenClassrooms\\UseCase\\BusinessRules\\Responders\\UseCaseResponse;\nuse OpenClassrooms\\UseCase\\Application\\Annotations\\Log;\n\nclass AUseCase implements UseCase\n{\n    /**\n     * @Log\n     *\n     * @return UseCaseResponse\n     */\n    public function execute(UseCaseRequest $useCaseRequest)\n    {\n        // do things\n        \n        return $useCaseResponse;\n    }\n}\n```\n\nThe log can be:\n- pre execute\n- post execute\n- on exception\nor all of them.\n\nOn exception is default.\n\nLevel can be specified following [PSR's levels](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel).\nWarning is default.\n\n\n```php\n/**\n * @Log(level=\"error\")\n * Log with the level 'error'\n * \n * @Log (message=\"message with context {foo}\", context={\"foo\":\"bar\"})\n * Log with standard message\n *\n * @Log(methods=\"pre\")\n * Log before the call of UseCase-\u003eexecute()\n *\n * @Log(methods=\"pre, post, onException\")\n * Log before the call of UseCase-\u003eexecute(), after the call of UseCase-\u003eexecute() or on exception\n * \n * @Log(methods=\"pre\", level=\"debug\")\n * @Log(methods=\"onException\", level=\"error\")\n * Log before the call of UseCase-\u003eexecute() with debug level and on exception with error level\n */\n```\n\n\n### Workflow\nThe execution order is the following:\n\nPre Excecute:\n- log (pre)\n- security\n- cache (fetch)\n- transaction (begin transaction)\n- event (pre)\n\nPost Excecute:\n- cache (save if needed)\n- transaction (commit)\n- event (post)\n- log (post)\n\nOn Exception:\n- log (on exception)\n- transaction (rollback)\n- event (on exception)\n\n### Utils\nThe library provide a generic response for paginated collection.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenclassrooms%2Fusecase","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenclassrooms%2Fusecase","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenclassrooms%2Fusecase/lists"}