2017 © Pedro Peláez
 

library use-case

Use case library

image

openclassrooms/use-case

Use case library

  • Wednesday, November 2, 2016
  • by openclassrooms-admin
  • Repository
  • 18 Watchers
  • 5 Stars
  • 19,316 Installations
  • PHP
  • 1 Dependents
  • 0 Suggesters
  • 4 Forks
  • 5 Open issues
  • 2 Versions
  • 10 % Grown

The README.md

UseCase

Build Status SensioLabsInsight Coverage Status, (*1)

UseCase is a library that provides facilities to manage technical code over a Use Case in a Clean / Hexagonal / Use Case Architecture. - Security access - Cache management - Transactional context - Events - Logs, (*2)

The goal is to have only functional code on the Use Case and manage technical code in an elegant way using annotations., (*3)

More details on : - Clean Architecture. - Hexagonal Architecture. - Use Case Driven Development., (*4)

Installation

composer require openclassrooms/use-case or by adding the package to the composer.json file directly., (*5)

{
    "require": {
        "openclassrooms/use-case": "*"
    }
}

```php, (*6)

<?php require 'vendor/autoload.php';, (*7)

use OpenClassrooms\UseCase\Application\Services\Proxy\UseCases\UseCaseProxy;, (*8)

//do things, (*9)

<a name="install-nocomposer"/>

### Instantiation
The UseCaseProxy needs a lot of dependencies. 

The Dependency Injection Pattern is clearly helpful.

For an implementation with Symfony2, the UseCaseBundle is more appropriate.

UseCaseProxy can be instantiate as following:
```php

class app()
{
    /**
     * @var OpenClassrooms\UseCase\Application\Services\Proxy\UseCases\UseCaseProxyBuilder
     */
    private $builder;   

    /**
     * @var OpenClassrooms\UseCase\Application\Services\Security\Security;
     */
    private $security;

    /**
     * @var OpenClassrooms\Cache\Cache\Cache; 
     */
    private $cache;

    /**
     * @var OpenClassrooms\UseCase\Application\Services\Transaction\Transaction;
     */
    private $transaction;

    /**
     * @var OpenClassrooms\UseCase\Application\Services\EventSender\EventSender;
     */
    private $event;

    /**
     * @var OpenClassrooms\UseCase\Application\Services\EventSender\EventFactory
     */
    private $eventFactory;

    /**
     * @var Psr\Log\LoggerInterface
     */
     private $logger;

    /**
     * @var Doctrine\Common\Annotations\Reader
     */
    private $reader;

    public function method()
    {
        $useCase = $this->builder
                    ->create(new OriginalUseCase())
                    ->withReader($this->reader)
                    ->withSecurity($this->security)
                    ->withCache($this->cache)
                    ->withTransaction($this->transaction)
                    ->withEventSender($this->event)
                    ->withEventFactory($this->eventFactory)
                    ->withLogger($this->logger)
                    ->build();
    }                    
}                

Only UseCaseProxyBuilder::create(UseCase $useCase) and UseCaseProxyBuilder::withReader(AnnotationReader $reader) are mandatory., (*10)

Usage

A classic Use Case in Clean / Hexagonal / Use Case Architecture style looks like this:, (*11)


use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCase; use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCaseRequest; use OpenClassrooms\UseCase\BusinessRules\Responders\UseCaseResponse; class AUseCase implements UseCase { /** * @return UseCaseResponse */ public function execute(UseCaseRequest $useCaseRequest) { // do things return $useCaseResponse; } }

The library provides a Proxy of the UseCase., (*12)

Security

@Security annotation allows to check access., (*13)


use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCase; use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCaseRequest; use OpenClassrooms\UseCase\BusinessRules\Responders\UseCaseResponse; use OpenClassrooms\UseCase\Application\Annotations\Security; class AUseCase implements UseCase { /** * @Security (roles = "ROLE_1") * * @return UseCaseResponse */ public function execute(UseCaseRequest $useCaseRequest) { // do things return $useCaseResponse; } }

"roles" is mandatory., (*14)

Other options :, (*15)

/**
 * @Security (roles = "ROLE_1, ROLE_2")
 * Check the array of roles
 *
 * @Security (roles = "ROLE_1", checkRequest = true)
 * Check access for the object $useCaseRequest
 *
 * @Security (roles = "ROLE_1", checkField = "fieldName")
 * Check access for the field "fieldName" of the object $useCaseRequest
 */

Cache

@Cache annotation allows to manage cache., (*16)


use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCase; use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCaseRequest; use OpenClassrooms\UseCase\BusinessRules\Responders\UseCaseResponse; use OpenClassrooms\UseCase\Application\Annotations\Cache; class AUseCase implements UseCase { /** * @Cache * * @return UseCaseResponse */ public function execute(UseCaseRequest $useCaseRequest) { // do things return $useCaseResponse; } }

The key is equal to : md5(serialize($useCaseRequest)) and the TTL is the default one., (*17)

Other options:, (*18)

/**
 * @Cache (lifetime=1000)
 * Add a TTL of 1000 seconds
 *
 * @Cache (namespacePrefix="namespace_prefix")
 * Add a namespace to the id with a namespace id equals to "namespace_prefix" 
 *
 * @Cache (namespacePrefix="namespace prefix", namespaceAttribute="fieldName")
 * Add a namespace to the id with a namespace id equals to "namespace_prefix" . "$useCaseRequest->fieldName"
 */

Transaction

@Transaction annotation gives a transactional context around the Use Case. - begin transaction - execute() - commit - rollback on exception, (*19)


use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCase; use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCaseRequest; use OpenClassrooms\UseCase\BusinessRules\Responders\UseCaseResponse; use OpenClassrooms\UseCase\Application\Annotations\Transaction; class AUseCase implements UseCase { /** * @Transaction * * @return UseCaseResponse */ public function execute(UseCaseRequest $useCaseRequest) { // do things return $useCaseResponse; } }

Event

@Event annotation allows to send events., (*20)

An implementation of OpenClassrooms\UseCase\Application\Services\EventSender\EventFactory must be written in the application context., (*21)

use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCase;
use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCaseRequest;
use OpenClassrooms\UseCase\BusinessRules\Responders\UseCaseResponse;
use OpenClassrooms\UseCase\Application\Annotations\EventSender;

class AUseCase implements UseCase
{
    /**
     * @Event
     *
     * @return UseCaseResponse
     */
    public function execute(UseCaseRequest $useCaseRequest)
    {
        // do things

        return $useCaseResponse;
    }
}

The message can be send: - pre execute - post execute - on exception or all of them., (*22)

Post is default., (*23)

The name of the event is the name of the use case with underscore, prefixed by the method. For previous example, the name would be : use_case.post.a_use_case, (*24)

Prefixes can be : - use_case.pre. - use_case.post. - use_case.exception., (*25)

/**
 * @Event(name="event_name")
 * Send an event with event name equals to *prefix*.event_name
 * (note: the name is always converted to underscore)
 *
 * @Event(methods="pre")
 * Send an event before the call of UseCase->execute()
 *
 * @Event(methods="pre, post, onException")
 * Send an event before the call of UseCase->execute(), after the call of UseCase->execute() or on exception
 * 
 * @Event(name="first_event")
 * @Event(name="second_event")
 * Send two events
 */

Log

@Log annotation allows to add log following the PSR standard., (*26)

use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCase;
use OpenClassrooms\UseCase\BusinessRules\Requestors\UseCaseRequest;
use OpenClassrooms\UseCase\BusinessRules\Responders\UseCaseResponse;
use OpenClassrooms\UseCase\Application\Annotations\Log;

class AUseCase implements UseCase
{
    /**
     * @Log
     *
     * @return UseCaseResponse
     */
    public function execute(UseCaseRequest $useCaseRequest)
    {
        // do things

        return $useCaseResponse;
    }
}

The log can be: - pre execute - post execute - on exception or all of them., (*27)

On exception is default., (*28)

Level can be specified following PSR's levels. Warning is default., (*29)

/**
 * @Log(level="error")
 * Log with the level 'error'
 * 
 * @Log (message="message with context {foo}", context={"foo":"bar"})
 * Log with standard message
 *
 * @Log(methods="pre")
 * Log before the call of UseCase->execute()
 *
 * @Log(methods="pre, post, onException")
 * Log before the call of UseCase->execute(), after the call of UseCase->execute() or on exception
 * 
 * @Log(methods="pre", level="debug")
 * @Log(methods="onException", level="error")
 * Log before the call of UseCase->execute() with debug level and on exception with error level
 */

Workflow

The execution order is the following:, (*30)

Pre Excecute: - log (pre) - security - cache (fetch) - transaction (begin transaction) - event (pre), (*31)

Post Excecute: - cache (save if needed) - transaction (commit) - event (post) - log (post), (*32)

On Exception: - log (on exception) - transaction (rollback) - event (on exception), (*33)

Utils

The library provide a generic response for paginated collection., (*34)

The Versions

02/11 2016

dev-master

9999999-dev

Use case library

  Sources   Download

MIT

The Requires

 

The Development Requires

by OpenClassrooms
by Romain Kuzniak

design

16/10 2014

dev-CLEAN_CS

dev-CLEAN_CS

Use case library

  Sources   Download

MIT

The Requires

 

The Development Requires

by OpenClassrooms
by Romain Kuzniak

design