Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

O que esperar do Zend Framework 3

1,677 views

Published on

Mini-curso ministrado na PHP Conference Brasil 2015

Published in: Technology

O que esperar do Zend Framework 3

  1. 1. O que esperar do Zend Framework 3 Flávio Gomes da Silva Lisboa www.fgsl.eti.br
  2. 2. Quem sou eu? ● Bacharel em Ciência da Computação com pós-graduação em Aplicações Corporativas usando Orientação a Objetos e Tecnologia Java pela Universidade Tecnológica Federal do Paraná. Programador formado pelo Centro Estadual de Educação Tecnológica Paula Souza. ● Chefe do setor de adequação da solução e mobilidade do projeto Expresso 3 na Coordenação Estratégica de Ações Governamentais do Serviço Federal de Processamento de Dados (Serpro). ● Zend PHP Certified Engineer, Zend Framework Certified Engineer e Zend Framework 2 Certified Architect.
  3. 3. Autor de 20132012201020092008 http://www.novatec.com.br/autores/flaviogomes/
  4. 4. Saindo do forno...
  5. 5. E em breve... Zend Framework Componentes Poderosos para PHP 3ª edição Criando Aplicações PHP com Zend e ExtJS
  6. 6. Autor também de http://www.perse.com.br
  7. 7. Escreve no blog http://romocavaleirodoespaco.blogspot.com.br/
  8. 8. Sumário ● Componentes ● HTTP, PSR-7 e Middleware ● PHP 7 e PHP 5.5
  9. 9. ZF3 ● Ênfase em componentes
  10. 10. ZF3 ● Ênfase em componentes ● Foco em HTTP, via PSR-7 e middleware
  11. 11. ZF3 ● Ênfase em componentes ● Foco em HTTP, via PSR-7 e middleware ● Otimizado para PHP 7, mas suporta PHP 5.5+
  12. 12. ZF3 ● Ênfase em componentes ● Foco em HTTP, via PSR-7 e middleware ● Otimizado para PHP 7, mas suporta PHP 5.5+ ● Lançamento previsto para...
  13. 13. Componentes
  14. 14. ZF1: o passado ● Componentes eram desenvolvidos dentro do repositório do framework, e
  15. 15. ZF1: o passado ● Componentes eram desenvolvidos dentro do repositório do framework, e ● Eram instaláveis somente com o framework inteiro.
  16. 16. ZF2: o presente ● Componentes são desenvolvidos dentro do repositório do framework, e ● Podem ser instalados individualmente (Composer, GIT).
  17. 17. ZF 2.5: o presente ● Não há mais pacotes de instalação. ● O repositório ZF depende dos componentes.
  18. 18. Instale só o que vai usar { "require": { "zendframework/zend-authentication": "^2.5", "zendframework/zend-cache": "^2.5", "zendframework/zend-captcha": "^2.5", "etc": "*" } }
  19. 19. Por que?
  20. 20. Fácil manutenção ● Permite mais times com direitos de alterar código de componentes ● Permite um destino determinístico de repositórios
  21. 21. Esqueletos específicos para casos de uso ● Entrega somente serviços? ● Precisa de desempenho? ● Precisa de tudo? Haverá um esqueleto para isso!
  22. 22. HTTP, PSR-7 e Middleware
  23. 23. HTTP é o fundamento da Web ● Um cliente envia uma requisição ● Um servidor devolve uma resposta
  24. 24. Mensagens HTTP GET /path HTTP/1.1 Host: example.com Accept: application/json HTTP/1.1 200 OK Content-Type: application/json {"foo":"bar"} Requisição Resposta
  25. 25. Frameworks modelam mensagens Mas cada framework faz isso diferente $method = $request->getMethod(); $method = $request->getRequestMethod(); $method = $request->method;
  26. 26. Requisição $method = $request->getMethod(); $accept = $request->getHeader('Accept'); $path = $request->getUri()->getPath(); $controller = $request->getAttribute('controller');
  27. 27. Resposta $response->getBody()->write('Hello world!'); $response = $response ->withStatus(200, 'OK') ->withHeader('Content-Type', 'text/plain');
  28. 28. Middleware Entre a requisição e a resposta function (Request $request, Response $response) { // do some work return $response; // same, or a new instance. }
  29. 29. Uma arquitetura de terceirização
  30. 30. Isso parece...
  31. 31. Tipos de Middleware
  32. 32. Pilhas ou Condutores $pipeline->pipe($middleware1); // always evaluate $pipeline->pipe('/path', $middleware2); // only if path matches $pipeline->pipe('/different/path', $middleware3); $response = $pipeline->run();
  33. 33. Estilo Cebola class Outer { public $inner; public function __invoke($request, $response) { // do some work $response = ($this->inner)($request, $response); // do some work return $response; } } $response = $outer($request, $response);
  34. 34. Estilo Lambda function (Request $request) { // do some work return $response; } $response = $middleware($request);
  35. 35. Consumindo Middleware ZF permitirá despachar o seguinte middleware: … e controladores ZF serão middleware. /** * @return Response */ public function (Request $request, Response $response);
  36. 36. Encapsulador de Middleware para ZF $middleware = new MvcMiddlewareWrapper( require 'config/application/config.php' ); class MvcMiddlewareWrapper { public function __invoke($request, $response) { $app = Application::init($this->config); return $app->dispatch($request, $response); } }
  37. 37. Middleware como alternativa para tempo de execução ● Desempenho ● Experiência do desenvolvedor ● Reusabilidade entre frameworks
  38. 38. Exemplo $app = new Middleware(); $app->pipe('/', $homepage); // Static! $app->pipe('/customer', $zf2Middleware); // ZF2! $app->pipe('/products', $zf1Middleware); // ZF1! $app->pipe('/api', $apigility); // Apigility! $app->pipe('/user', $userMiddleware); // 3rd party! $server->listen($app);
  39. 39. PSR-7 e Middleware provêem... ● Caminhos para otimização de desempenho ● Interfaces para web mais simples ● Maior interoperabilidade e potencial reuso
  40. 40. PHP 7 e PHP 5.5
  41. 41. Atualização para o PHP 5.5 ● Conseguimos usar traits! ● Conseguimos usar a sintaxe curta de array! ● Conseguimos usar callable type hint! ● Conseguimos usar finally! ● Podemos usar a constante mágica ::class! ● Conseguimos usar generators! ● Conseguimos um PHP mais rápido, mais seguro!
  42. 42. PHP 7 Impressionante melhoria de desempenho! Novo gerenciamento de estruturas de dados no motor do PHP Novas funcionalidades como declarações de tipo para argumento e retorno
  43. 43. PHP 7 : Benchmark PHP 5.6 PHP 7 Uso de memória 428 MB 33 MB Tempo de execução 0.49 sec 0.06 sec $a = array(); for ($i = 0; $i < 1000000; $i++) { $a[$i] = array("hello"); } echo memory_get_usage(true);
  44. 44. Bench.php
  45. 45. Wordpress
  46. 46. Frameworks
  47. 47. ZF3: Otimizado para PHP 7 Atualizar PHP provê melhor segurança, melhora o desempenho e permite melhorar o framework
  48. 48. Certo, mas e onde está esse ZF3?
  49. 49. Não existe Zend Framework 3
  50. 50. Mas não tema!
  51. 51. Zend Expressive Expressive permite que você escreva aplicações middleware PSR-7 para a web. É um simples micro- framework construído no topo do Stratigility, fornecendo: ● Roteamento dinâmico; ● Injeção de dependência via interoperabilidade de containers; ● Templating; ● Manipulação de erros.
  52. 52. Hello World (para index.php no web root) // In index.php use ZendExpressiveAppFactory; use PsrHttpMessageResponseInterface; use PsrHttpMessageRequestInterface; require 'vendor/autoload.php'; $app = AppFactory::create(); $app->route('/', function (RequestInterface $request, ResponseInterface $response, $next) { $response->getBody()->write('Hello, world!'); return $response; }); $app->run(); php -S 0.0.0.0:8080 -t
  53. 53. Instalação com Composer via composer.json { "require": { "zendframework/zend-expressive" : "*", "zendframework/zend-servicemanager" : "*", "zendframework/zend-expressive- fastroute" : "*" } }
  54. 54. Se a rota não casar... Cannot GET http://[URL DO PROJETO]]
  55. 55. Instalação com Composer via terminal composer require zendframework/zend- expressive aura/router zendframework/zend- servicemanager
  56. 56. Anatomia
  57. 57. Comparação com ZF2
  58. 58. Próximas funcionalidades Um esqueleto de aplicação; Criptografia de sessão; Suporte a cache de HTTP; Autenticação de usuário (via OAuth2 e/ou outros mecanismos de autenticação).
  59. 59. Criando uma galeria de fotos com ZendExpressive
  60. 60. Criando um novo projeto composer create-project -s rc zendframework/zend-expressive-skeleton <project-directory>
  61. 61. Removendo o código desnecessário rm public/favicon.ico rm public/zf-logo.png rm src/Action/* rm test/Action/* rm templates/app/* rm templates/layout/*
  62. 62. Configuração do Container <?php return [ 'dependencies' => [ 'factories' => [ ZendExpressiveApplication::class => ZendExpressiveContainerApplicationFactory::class, ], ], ]; config/autoload/dependencies.global.php
  63. 63. Configuração das Rotas <?php return [ 'dependencies' => [ 'invokables' => [ ZendExpressiveRouterRouterInterface::class => ZendExpressiveRouterFastRouteRouter::class, ], 'factories' => [ AppActionIndexAction::class => AppActionIndexFactory::class, ] ], 'routes' => [ [ 'name' => 'index', 'path' => '/', 'middleware' => AppActionIndexAction::class, 'allowed_methods' => ['GET'], ], ], ]; config/autoload/routes.global.php
  64. 64. Controlador ● <?php ● ● namespace AppAction; ● ● use PsrHttpMessageServerRequestInterface; ● use PsrHttpMessageResponseInterface; ● use ZendExpressiveTemplateTemplateRendererInterface; ● use ZendStratigilityMiddlewareInterface; ● ● class IndexAction implements MiddlewareInterface ● { ● private $templateRenderer; ● ● public function __construct(TemplateRendererInterface $templateRenderer) ● { ● $this->templateRenderer = $templateRenderer; ● } ● ● public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null) ● { ● $html = $this->templateRenderer->render('app::index'); ● $response->getBody()->write($html); ● return $response->withHeader('Content-Type', 'text/html'); ● } ● } ● src/Action/IndexAction.php
  65. 65. Fábrica <?php namespace AppAction; use InteropContainerContainerInterface; use ZendExpressiveTemplateTemplateRendererInterface; class IndexFactory { public function __invoke(ContainerInterface $container) { $templateRenderer = $container->get(TemplateRendererInterface::class); return new IndexAction($templateRenderer); } } src/Action/IndexFactory.php
  66. 66. Templating <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title><?=$this->e($title);?></title> </head> <body> <?=$this->section('content')?> </body> </html> templates/layout/default.phtml
  67. 67. Caching composer require doctrine/cache ^1.5 mkdir data/doctrine-cache
  68. 68. Caching <?php return [ 'dependencies' => [ 'factories' => [ // ... DoctrineCommonCacheCache::class => AppDoctrineCacheFactory::class, ], ], 'application' => [ 'cache_path' => 'data/doctrine-cache/', ], ]; config/autoload/dependencies.global.php
  69. 69. Caching <?php return [ 'dependencies' => [ 'factories' => [ AppMiddlewareCacheMiddleware::class => AppMiddlewareCacheFactory::class, ] ], 'middleware_pipeline' => [ 'pre_routing' => [ [ 'middleware' => AppMiddlewareCacheMiddleware::class ], ], 'post_routing' => [ ], ], ]; config/autoload/middleware-pipeline.global.php
  70. 70. Caching <?php namespace App; use DoctrineCommonCacheFilesystemCache; use InteropContainerContainerInterface; use ZendServiceManagerExceptionServiceNotCreatedException; class DoctrineCacheFactory { public function __invoke(ContainerInterface $container) { $config = $container->get('config'); if (!isset($config['application']['cache_path'])) { throw new ServiceNotCreatedException('cache_path must be set in application configuration'); } return new FilesystemCache($config['application']['cache_path']); } } src/DoctrineCacheFactory.php
  71. 71. Caching <?php namespace AppMiddleware; use DoctrineCommonCacheCache; use InteropContainerContainerInterface; class CacheFactory { public function __invoke(ContainerInterface $container) { $cache = $container->get(Cache::class); return new CacheMiddleware($cache); } } src/Middleware/CacheFactory.php
  72. 72. Caching <?php namespace AppMiddleware; use DoctrineCommonCacheCache; use PsrHttpMessageResponseInterface; use PsrHttpMessageServerRequestInterface; use ZendStratigilityMiddlewareInterface; class CacheMiddleware implements MiddlewareInterface { private $cache; public function __construct(Cache $cache) { $this->cache = $cache; } src/Middleware/CacheMiddleware.php
  73. 73. Caching public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null) { $cachedResponse = $this->getCachedResponse($request, $response); if (null !== $cachedResponse) { return $cachedResponse; } $response = $next($request, $response); $this->cacheResponse($request, $response); return $response; } src/Middleware/CacheMiddleware.php (cont.)
  74. 74. Caching private function getCacheKey(ServerRequestInterface $request) { return 'http-cache:'.$request->getUri()- >getPath(); } src/Middleware/CacheMiddleware.php (cont.)
  75. 75. Caching private function getCachedResponse(ServerRequestInterface $request, ResponseInterface $response) { if ('GET' !== $request->getMethod()) { return null; } $item = $this->cache->fetch($this->getCacheKey($request)); if (false === $item) { return null; } $response->getBody()->write($item['body']); foreach ($item['headers'] as $name => $value) { $response = $response->withHeader($name, $value); } return $response; } src/Middleware/CacheMiddleware.php (cont.)
  76. 76. Caching private function cacheResponse(ServerRequestInterface $request, ResponseInterface $response) { if ('GET' !== $request->getMethod() || !$response->hasHeader('Cache-Control')) { return; } $cacheControl = $response->getHeader('Cache-Control'); $abortTokens = array('private', 'no-cache', 'no-store'); if (count(array_intersect($abortTokens, $cacheControl)) > 0) { return; } src/Middleware/CacheMiddleware.php (cont.)
  77. 77. Caching foreach ($cacheControl as $value) { $parts = explode('=', $value); if (count($parts) == 2 && 'max-age' === $parts[0]) { $this->cache->save($this->getCacheKey($request), [ 'body' => (string) $response->getBody(), 'headers' => $response->getHeaders(), ], intval($parts[1])); return; } } } } src/Middleware/CacheMiddleware.php (cont.)
  78. 78. Caching rm -rf data/doctrine-cache/* Limpeza de cache
  79. 79. Instalando um provedor de fotos composer require andrewcarteruk/astronomy-picture-of- the-day ^0.1 NASA Astronomy Picture of the Day - API Wrapper
  80. 80. Instalando um provedor de fotos <?php return [ 'dependencies' => [ 'factories' => [ // ... AndrewCarterUKAPODAPIInterface::class => AppAPIFactory::class, ], ], 'application' => [ // ... 'results_per_page' => 24, 'apod_api' => [ 'store_path' => 'public/apod', 'base_url' => '/apod', ], ], ]; config/autoload/dependencies.global.php
  81. 81. Instalando um provedor de fotos <?php return [ 'application' => [ 'apod_api' => [ 'api_key' => 'DEMO_KEY', // DEMO_KEY might be good for a couple of requests // Get your own here: https://api.nasa.gov/index.html#live_example ], ], ]; config/autoload/dependencies.local.php
  82. 82. Instalando um provedor de fotos <?php return [ 'dependencies' => [ // ... 'factories' => [ // ... AppActionPictureListAction::class => AppActionPictureListFactory::class, ], ], 'routes' => [ // ... [ 'name' => 'picture-list', 'path' => '/picture-list[/{page:d+}]', 'middleware' => AppActionPictureListAction::class, 'allowed_methods' => ['GET'], ], ], ]; config/autoload/routes.global.php
  83. 83. Instalando um provedor de fotos mkdir public/apod Diretório de thumbnails
  84. 84. Instalando um provedor de fotos <?php namespace App; use AndrewCarterUKAPODAPI; use GuzzleHttpClient; use InteropContainerContainerInterface; use ZendServiceManagerExceptionServiceNotCreatedException; class APIFactory { public function __invoke(ContainerInterface $container) { $config = $container->get('config'); if (!isset($config['application']['apod_api'])) { throw new ServiceNotCreatedException('apod_api must be set in application configuration'); } return new API(new Client, $config['application']['apod_api']); } } src/APIFactory.php
  85. 85. Instalando um provedor de fotos <?php namespace AppAction; use AndrewCarterUKAPODAPIInterface; use InteropContainerContainerInterface; use ZendServiceManagerExceptionServiceNotCreatedException; class PictureListFactory { public function __invoke(ContainerInterface $container) { $apodApi = $container->get(APIInterface::class); $config = $container->get('config'); if (!isset($config['application']['results_per_page'])) { throw new ServiceNotCreatedException('results_per_page must be set in application configuration'); } return new PictureListAction($apodApi, $config['application']['results_per_page']); } } src/Action/PictureListFactory.php
  86. 86. Instalando um provedor de fotos <?php namespace AppAction; use AndrewCarterUKAPODAPIInterface; use PsrHttpMessageServerRequestInterface; use PsrHttpMessageResponseInterface; use ZendStratigilityMiddlewareInterface; class PictureListAction implements MiddlewareInterface { private $apodApi; private $resultsPerPage; public function __construct(APIInterface $apodApi, $resultsPerPage) { $this->apodApi = $apodApi; $this->resultsPerPage = $resultsPerPage; } src/Action/PictureListAction.php
  87. 87. Instalando um provedor de fotos public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $out = null) { $page = intval($request->getAttribute('page')) ?: 0; $pictures = $this->apodApi->getPage($page, $this->resultsPerPage); $response->getBody()->write(json_encode($pictures)); return $response // ->withHeader('Cache-Control', ['public', 'max-age=3600']) ->withHeader('Content-Type', 'application/json'); } } src/Action/PictureListAction.php (cont.)
  88. 88. Instalando um provedor de fotos <?php chdir(__DIR__.'/..'); include 'vendor/autoload.php'; $container = include 'config/container.php'; // Create a SIGINT handler that sets a shutdown flag $shutdown = false; declare(ticks = 1); pcntl_signal(SIGINT, function () use (&$shutdown) { $shutdown = true; }); bin/update.php
  89. 89. Instalando um provedor de fotos $newPictureHandler = function (array $picture) use (&$shutdown) { echo 'Added: ' . $picture['title'] . PHP_EOL; // If the shutdown flag has been set, die if ($shutdown) { die; } }; $errorHandler = function (Exception $exception) use (&$shutdown) { echo (string) $exception . PHP_EOL; // If the shutdown flag has been set, die if ($shutdown) { die; } }; $container->get(AndrewCarterUKAPODAPIInterface::class)->updateStore(20, $newPictureHandler, $errorHandler); bin/update.php (cont.)
  90. 90. API Key NASA ● https://api.nasa.gov/index.html#live_example php bin/update.php
  91. 91. Onde estará o ZF3?
  92. 92. Referência ● Zimuel, E. Pushing Boundaries: Zend Framework 3. Disponível em <http://zimuel.it/slides/phpday2015> ● Ikhsan, A. M. e O'Phinney, M. W. How to Build a NASA Photo Gallery with Zend Expressive. Disponível em <http://www.sitepoint.com/build- nasa-photo-gallery-zend-expressive/>

×