O que esperar do Zend Framework 3
Flávio Gomes da Silva Lisboa
www.fgsl.eti.br
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.
Autor de
20132012201020092008
http://www.novatec.com.br/autores/flaviogomes/
Saindo do forno...
E em breve...
Zend Framework Componentes Poderosos para PHP 3ª edição
Criando Aplicações PHP com Zend e ExtJS
Autor também de
http://www.perse.com.br
Escreve no blog
http://romocavaleirodoespaco.blogspot.com.br/
Sumário
● Componentes
● HTTP, PSR-7 e Middleware
● PHP 7 e PHP 5.5
ZF3
● Ênfase em componentes
ZF3
● Ênfase em componentes
● Foco em HTTP, via PSR-7 e middleware
ZF3
● Ênfase em componentes
● Foco em HTTP, via PSR-7 e middleware
● Otimizado para PHP 7, mas suporta PHP 5.5+
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...
Componentes
ZF1: o passado
● Componentes eram desenvolvidos dentro do
repositório do framework, e
ZF1: o passado
● Componentes eram desenvolvidos dentro do
repositório do framework, e
● Eram instaláveis somente com o framework
inteiro.
ZF2: o presente
● Componentes são desenvolvidos dentro do
repositório do framework, e
● Podem ser instalados individualmente
(Composer, GIT).
ZF 2.5: o presente
● Não há mais pacotes de instalação.
● O repositório ZF depende dos componentes.
Instale só o que vai usar
{
"require": {
"zendframework/zend-authentication": "^2.5",
"zendframework/zend-cache": "^2.5",
"zendframework/zend-captcha": "^2.5",
"etc": "*"
}
}
Por que?
Fácil manutenção
● Permite mais times com direitos de alterar
código de componentes
● Permite um destino determinístico de
repositórios
Esqueletos específicos para casos
de uso
● Entrega somente serviços?
● Precisa de desempenho?
● Precisa de tudo?
Haverá um esqueleto para isso!
HTTP, PSR-7 e Middleware
HTTP é o fundamento da Web
● Um cliente envia uma requisição
● Um servidor devolve uma resposta
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
Frameworks modelam mensagens
Mas cada framework faz isso diferente
$method = $request->getMethod();
$method = $request->getRequestMethod();
$method = $request->method;
Requisição
$method = $request->getMethod();
$accept = $request->getHeader('Accept');
$path = $request->getUri()->getPath();
$controller = $request->getAttribute('controller');
Resposta
$response->getBody()->write('Hello world!');
$response = $response
->withStatus(200, 'OK')
->withHeader('Content-Type', 'text/plain');
Middleware
Entre a requisição e a resposta
function (Request $request, Response $response)
{
// do some work
return $response; // same, or a new instance.
}
Uma arquitetura de terceirização
Isso parece...
Tipos de Middleware
Pilhas ou Condutores
$pipeline->pipe($middleware1); // always evaluate
$pipeline->pipe('/path', $middleware2); // only if path matches
$pipeline->pipe('/different/path', $middleware3);
$response = $pipeline->run();
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);
Estilo Lambda
function (Request $request)
{
// do some work
return $response;
}
$response = $middleware($request);
Consumindo Middleware
ZF permitirá despachar o seguinte middleware:
… e controladores ZF serão middleware.
/**
* @return Response
*/
public function (Request $request, Response $response);
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);
}
}
Middleware como alternativa para
tempo de execução
● Desempenho
● Experiência do desenvolvedor
● Reusabilidade entre frameworks
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);
PSR-7 e Middleware provêem...
● Caminhos para otimização de desempenho
● Interfaces para web mais simples
● Maior interoperabilidade e potencial reuso
PHP 7 e PHP 5.5
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!
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
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);
Bench.php
Wordpress
Frameworks
ZF3: Otimizado para PHP 7
Atualizar PHP provê melhor segurança, melhora
o desempenho e permite melhorar o framework
Certo, mas e onde está esse ZF3?
Não existe Zend Framework 3
Mas não tema!
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.
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
Instalação com Composer via
composer.json
{
"require": {
"zendframework/zend-expressive" : "*",
"zendframework/zend-servicemanager" : "*",
"zendframework/zend-expressive-
fastroute" : "*"
}
}
Se a rota não casar...
Cannot GET http://[URL DO PROJETO]]
Instalação com Composer via
terminal
composer require zendframework/zend-
expressive aura/router zendframework/zend-
servicemanager
Anatomia
Comparação com ZF2
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).
Criando uma galeria de fotos com
ZendExpressive
Criando um novo projeto
composer create-project -s rc
zendframework/zend-expressive-skeleton
<project-directory>
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/*
Configuração do Container
<?php
return [
'dependencies' => [
'factories' => [
ZendExpressiveApplication::class =>
ZendExpressiveContainerApplicationFactory::class,
],
],
];
config/autoload/dependencies.global.php
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
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
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
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
Caching
composer require doctrine/cache ^1.5
mkdir data/doctrine-cache
Caching
<?php
return [
'dependencies' => [
'factories' => [
// ...
DoctrineCommonCacheCache::class => AppDoctrineCacheFactory::class,
],
],
'application' => [
'cache_path' => 'data/doctrine-cache/',
],
];
config/autoload/dependencies.global.php
Caching
<?php
return [
'dependencies' => [
'factories' => [
AppMiddlewareCacheMiddleware::class => AppMiddlewareCacheFactory::class,
]
],
'middleware_pipeline' => [
'pre_routing' => [
[ 'middleware' => AppMiddlewareCacheMiddleware::class ],
],
'post_routing' => [
],
],
];
config/autoload/middleware-pipeline.global.php
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
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
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
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.)
Caching
private function
getCacheKey(ServerRequestInterface $request)
{
return 'http-cache:'.$request->getUri()-
>getPath();
}
src/Middleware/CacheMiddleware.php (cont.)
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.)
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.)
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.)
Caching
rm -rf data/doctrine-cache/*
Limpeza de cache
Instalando um provedor de fotos
composer require
andrewcarteruk/astronomy-picture-of-
the-day ^0.1
NASA Astronomy Picture of the Day - API Wrapper
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
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
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
Instalando um provedor de fotos
mkdir public/apod
Diretório de thumbnails
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
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
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
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.)
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
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.)
API Key NASA
● https://api.nasa.gov/index.html#live_example
php bin/update.php
Onde estará o ZF3?
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/>

O que esperar do Zend Framework 3

  • 1.
    O que esperardo Zend Framework 3 Flávio Gomes da Silva Lisboa www.fgsl.eti.br
  • 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.
  • 4.
  • 5.
    E em breve... ZendFramework Componentes Poderosos para PHP 3ª edição Criando Aplicações PHP com Zend e ExtJS
  • 6.
  • 7.
  • 8.
    Sumário ● Componentes ● HTTP,PSR-7 e Middleware ● PHP 7 e PHP 5.5
  • 9.
    ZF3 ● Ênfase emcomponentes
  • 10.
    ZF3 ● Ênfase emcomponentes ● Foco em HTTP, via PSR-7 e middleware
  • 11.
    ZF3 ● Ênfase emcomponentes ● Foco em HTTP, via PSR-7 e middleware ● Otimizado para PHP 7, mas suporta PHP 5.5+
  • 12.
    ZF3 ● Ênfase emcomponentes ● Foco em HTTP, via PSR-7 e middleware ● Otimizado para PHP 7, mas suporta PHP 5.5+ ● Lançamento previsto para...
  • 13.
  • 14.
    ZF1: o passado ●Componentes eram desenvolvidos dentro do repositório do framework, e
  • 15.
    ZF1: o passado ●Componentes eram desenvolvidos dentro do repositório do framework, e ● Eram instaláveis somente com o framework inteiro.
  • 16.
    ZF2: o presente ●Componentes são desenvolvidos dentro do repositório do framework, e ● Podem ser instalados individualmente (Composer, GIT).
  • 17.
    ZF 2.5: opresente ● Não há mais pacotes de instalação. ● O repositório ZF depende dos componentes.
  • 18.
    Instale só oque vai usar { "require": { "zendframework/zend-authentication": "^2.5", "zendframework/zend-cache": "^2.5", "zendframework/zend-captcha": "^2.5", "etc": "*" } }
  • 19.
  • 20.
    Fácil manutenção ● Permitemais times com direitos de alterar código de componentes ● Permite um destino determinístico de repositórios
  • 21.
    Esqueletos específicos paracasos de uso ● Entrega somente serviços? ● Precisa de desempenho? ● Precisa de tudo? Haverá um esqueleto para isso!
  • 22.
    HTTP, PSR-7 eMiddleware
  • 23.
    HTTP é ofundamento da Web ● Um cliente envia uma requisição ● Um servidor devolve uma resposta
  • 24.
    Mensagens HTTP GET /pathHTTP/1.1 Host: example.com Accept: application/json HTTP/1.1 200 OK Content-Type: application/json {"foo":"bar"} Requisição Resposta
  • 25.
    Frameworks modelam mensagens Mascada framework faz isso diferente $method = $request->getMethod(); $method = $request->getRequestMethod(); $method = $request->method;
  • 27.
    Requisição $method = $request->getMethod(); $accept= $request->getHeader('Accept'); $path = $request->getUri()->getPath(); $controller = $request->getAttribute('controller');
  • 28.
    Resposta $response->getBody()->write('Hello world!'); $response =$response ->withStatus(200, 'OK') ->withHeader('Content-Type', 'text/plain');
  • 29.
    Middleware Entre a requisiçãoe a resposta function (Request $request, Response $response) { // do some work return $response; // same, or a new instance. }
  • 30.
    Uma arquitetura deterceirização
  • 31.
  • 32.
  • 33.
    Pilhas ou Condutores $pipeline->pipe($middleware1);// always evaluate $pipeline->pipe('/path', $middleware2); // only if path matches $pipeline->pipe('/different/path', $middleware3); $response = $pipeline->run();
  • 34.
    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);
  • 35.
    Estilo Lambda function (Request$request) { // do some work return $response; } $response = $middleware($request);
  • 36.
    Consumindo Middleware ZF permitirádespachar o seguinte middleware: … e controladores ZF serão middleware. /** * @return Response */ public function (Request $request, Response $response);
  • 37.
    Encapsulador de Middlewarepara 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); } }
  • 38.
    Middleware como alternativapara tempo de execução ● Desempenho ● Experiência do desenvolvedor ● Reusabilidade entre frameworks
  • 39.
    Exemplo $app = newMiddleware(); $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);
  • 40.
    PSR-7 e Middlewareprovêem... ● Caminhos para otimização de desempenho ● Interfaces para web mais simples ● Maior interoperabilidade e potencial reuso
  • 41.
    PHP 7 ePHP 5.5
  • 42.
    Atualização para oPHP 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!
  • 43.
    PHP 7 Impressionante melhoriade desempenho! Novo gerenciamento de estruturas de dados no motor do PHP Novas funcionalidades como declarações de tipo para argumento e retorno
  • 44.
    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);
  • 45.
  • 46.
  • 47.
  • 48.
    ZF3: Otimizado paraPHP 7 Atualizar PHP provê melhor segurança, melhora o desempenho e permite melhorar o framework
  • 49.
    Certo, mas eonde está esse ZF3?
  • 51.
    Não existe ZendFramework 3
  • 52.
  • 54.
    Zend Expressive Expressive permiteque 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.
  • 55.
    Hello World (para index.phpno 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
  • 56.
    Instalação com Composervia composer.json { "require": { "zendframework/zend-expressive" : "*", "zendframework/zend-servicemanager" : "*", "zendframework/zend-expressive- fastroute" : "*" } }
  • 57.
    Se a rotanão casar... Cannot GET http://[URL DO PROJETO]]
  • 58.
    Instalação com Composervia terminal composer require zendframework/zend- expressive aura/router zendframework/zend- servicemanager
  • 59.
  • 60.
  • 61.
    Próximas funcionalidades Um esqueletode 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).
  • 62.
    Criando uma galeriade fotos com ZendExpressive
  • 63.
    Criando um novoprojeto composer create-project -s rc zendframework/zend-expressive-skeleton <project-directory>
  • 64.
    Removendo o códigodesnecessário rm public/favicon.ico rm public/zf-logo.png rm src/Action/* rm test/Action/* rm templates/app/* rm templates/layout/*
  • 65.
    Configuração do Container <?php return[ 'dependencies' => [ 'factories' => [ ZendExpressiveApplication::class => ZendExpressiveContainerApplicationFactory::class, ], ], ]; config/autoload/dependencies.global.php
  • 66.
    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
  • 67.
    Controlador ● <?php ● ● namespace AppAction; ● ● use PsrHttpMessageServerRequestInterface; ● usePsrHttpMessageResponseInterface; ● 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
  • 68.
    Fábrica <?php namespace AppAction; use InteropContainerContainerInterface; useZendExpressiveTemplateTemplateRendererInterface; class IndexFactory { public function __invoke(ContainerInterface $container) { $templateRenderer = $container->get(TemplateRendererInterface::class); return new IndexAction($templateRenderer); } } src/Action/IndexFactory.php
  • 69.
    Templating <!DOCTYPE html> <html lang="en"> <head> <metacharset="utf-8" /> <title><?=$this->e($title);?></title> </head> <body> <?=$this->section('content')?> </body> </html> templates/layout/default.phtml
  • 70.
    Caching composer require doctrine/cache^1.5 mkdir data/doctrine-cache
  • 71.
    Caching <?php return [ 'dependencies' =>[ 'factories' => [ // ... DoctrineCommonCacheCache::class => AppDoctrineCacheFactory::class, ], ], 'application' => [ 'cache_path' => 'data/doctrine-cache/', ], ]; config/autoload/dependencies.global.php
  • 72.
    Caching <?php return [ 'dependencies' =>[ 'factories' => [ AppMiddlewareCacheMiddleware::class => AppMiddlewareCacheFactory::class, ] ], 'middleware_pipeline' => [ 'pre_routing' => [ [ 'middleware' => AppMiddlewareCacheMiddleware::class ], ], 'post_routing' => [ ], ], ]; config/autoload/middleware-pipeline.global.php
  • 73.
    Caching <?php namespace App; use DoctrineCommonCacheFilesystemCache; useInteropContainerContainerInterface; 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
  • 74.
    Caching <?php namespace AppMiddleware; use DoctrineCommonCacheCache; useInteropContainerContainerInterface; class CacheFactory { public function __invoke(ContainerInterface $container) { $cache = $container->get(Cache::class); return new CacheMiddleware($cache); } } src/Middleware/CacheFactory.php
  • 75.
    Caching <?php namespace AppMiddleware; use DoctrineCommonCacheCache; usePsrHttpMessageResponseInterface; use PsrHttpMessageServerRequestInterface; use ZendStratigilityMiddlewareInterface; class CacheMiddleware implements MiddlewareInterface { private $cache; public function __construct(Cache $cache) { $this->cache = $cache; } src/Middleware/CacheMiddleware.php
  • 76.
    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.)
  • 77.
    Caching private function getCacheKey(ServerRequestInterface $request) { return'http-cache:'.$request->getUri()- >getPath(); } src/Middleware/CacheMiddleware.php (cont.)
  • 78.
    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.)
  • 79.
    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.)
  • 80.
    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.)
  • 81.
  • 82.
    Instalando um provedorde fotos composer require andrewcarteruk/astronomy-picture-of- the-day ^0.1 NASA Astronomy Picture of the Day - API Wrapper
  • 83.
    Instalando um provedorde 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
  • 84.
    Instalando um provedorde 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
  • 85.
    Instalando um provedorde 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
  • 86.
    Instalando um provedorde fotos mkdir public/apod Diretório de thumbnails
  • 87.
    Instalando um provedorde 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
  • 88.
    Instalando um provedorde 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
  • 89.
    Instalando um provedorde 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
  • 90.
    Instalando um provedorde 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.)
  • 91.
    Instalando um provedorde 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
  • 92.
    Instalando um provedorde 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.)
  • 93.
    API Key NASA ●https://api.nasa.gov/index.html#live_example php bin/update.php
  • 94.
  • 95.
    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/>