Liberte-se

do framework

Daniel Gimenes

  • Engenheiro de Software @ Maestrooo
  • Sistemas de Informação @ UNISAL
  • Open source contributor
  • blockchains, smart contracts, cryptoeconomics...

@Danizord

Frameworks

They all suck

Rasmus Lerdorf

Frameworks

  • Vêm acompanhados de decisões prematuras
  • Adicionam overhead desnecessário
  • Ficam no seu caminho
  • Limitam o ecossistema
  • Aumentam a curva de aprendizado
  • Dificultam a evolução

Mhmm, e aí?

Frameworks fullstack?

nope

Microframeworks?

é... Mas e a interoperabilidade?

Componentes padronizados?

Yep!
Falando em padrões...

HTTP

SAPI

  • $_GET
  • $_POST
  • $_SERVER
  • $_FILES
  • $_COOKIES
  • fopen('php://input');
  • header('HTTP/1.1 404 Not Found');
  • header('Content-type: text/html');
  • echo 'Not found';

PSR-7

  • ServerRequestInterface
  • ResponseInterface

Implementações PSR-7

  • guzzlehttp/psr7
  • symfony/psr-http-message-bridge
  • slim/slim
  • zendframework/zend-diactoros
  • ...

SAPI <-> Zend\Diactoros


use Zend\Diactoros\Response\JsonResponse;            
use Zend\Diactoros\Response\SapiEmitter;
use Zend\Diactoros\ServerRequestFactory;

$request  = ServerRequestFactory::fromGlobals();
$response = new JsonResponse([
  'greeting' => 'Hello ' . $request->getQueryParams()['name']
]);

(new SapiEmitter())->emit($response);
          

Business logic


interface TodoServiceInterface
{
    public function addTodo(int $id, string $title): void;

    public function markTodoAsDone(int $id);
}
          

PSR-15: Server request handler


namespace Psr\Http\Server;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

interface RequestHandlerInterface
{
    public function handle(
      ServerRequestInterface $request
    ): ResponseInterface;
}
          

AddTodo


final class AddTodo implements RequestHandlerInterface
{
  private $todoService;

  public function __construct(TodoServiceInterface $service)
  {
      $this->todoService = $todoService;
  }

  public function handle(ServerRequestInterface $request)
  {
    $data = $request->getParsedBody();

    $this->todoService->addTodo(
      $data['id'],
      $data['title']
    );

    return new JsonResponse(['message' => 'Todo added']);
  }
}
          

MarkTodoAsDone


final class MarkTodoAsDone implements RequestHandlerInterface
{
  // ... Dependency Injection ... //

  public function handle(ServerRequestInterface $request)
  {
    $data = $request->getParsedBody();

    $this->todoService->markTodoAsDone($data['id']);

    return new JsonResponse(['message' => 'Todo done']);
  }
}
          

Injeção de dependência


namespace Psr\Container;

interface ContainerInterface
{
    public function get(string $id): mixed;
    public function has(string $id): bool;
}
          

$ composer require psr/container

Injeção de dependência

  • symfony/dependency-injection
  • bitexpert/disco
  • zendframework/zend-servicemanager
  • php-di/php-di
  • league/container
  • ...

Configurando o container

  • Symfony Flex
  • Zend Component Installer

Refatorando


$container = new Container();
$handler = $container->get(AddTodo::class);

$request = ServerRequestFactory::fromGlobals();
$response = $handler->handle($request);

(new SapiEmitter())->emit($response);
          
  • Tratamento de erros
  • Roteamento
  • Autenticação
  • Controle de acesso
  • Prevenção contra ataques
  • Validação de entrada
  • Tratamento de saída
  • Controle de sessão
  • Cache HTTP
  • Log de acessos
  • Negociação de conteúdo
  • ...

Middlewares

PSR-15: Middleware


namespace Psr\Http\Server;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

interface MiddlewareInterface
{
  public function process(
    ServerRequestInterface $request,
    RequestHandlerInterface $handler
  ): ResponseInterface;
}
          

Implementações middleware pipeline

  • zendframework/zend-stratigility
  • slim/slim
  • mindplay/middleman
  • middleland/dispatcher
  • danizord/mid
  • ...

Configurando rotas


// Configure routes
$router = new Router($container);

$router->post('/todos', AddTodo::class);
$router->post('/todos/{id}/done', MarkTodoAsDone::class);
          

Configurando pipeline


// Configure middleware pipeline              
$pipeline = new MiddlewarePipeline($container);

$pipeline->pipe(ErrorHandler::class);
$pipeline->pipe(Authentication::class);
$pipeline->pipe($router);
$pipeline->pipe(Authorization::class);
$pipeline->pipe(InputValidation::class);
$pipeline->pipe(RequestHandler::class);
          

Refatorando


$request = ServerRequestFactory::fromGlobals();
$response = $pipeline->handle($request);

(new SapiEmitter())->emit($response);
          

Bonus points

  • Single Page App
  • Firebase
  • CQRS

Perguntas?!

Obrigado!

@Danizord