SlideShare uma empresa Scribd logo
Existe uma coisa que um programador PHP
não pode ter...




                            MEDO!
Advertência

   Alguns exemplos de código são exemplos de
    como implementar construções com Zend
    Framework 2 e não do Zend Framework 2.
   Alguns exemplos fazem uso de construções
    disponíveis apenas no PHP 5.4.
Advertência

   Esta apresentação não visa saciar sua sede de
    conhecimento, mas deixar você sedento por
    ele.
O que esperar do Zend Framework 2


  Flávio Gomes da
  Silva Lisboa

 www.fgsl.eti.br




                    @fgsl
O que esperar do Zend Framework 2
Inspirador   Inspirado
                                    Desde 2008 capacitando
                                    profissionais em Zend
                                    Framework

           @eminetto
                         @fgsl
ESGOTADO




    ESGOTADO
Uma Breve História do ZF




      Flávio Gomes da Silva Lisboa
A Gênese

   Outubro de 2005: o projeto é anunciado
   Março de 2006: primeiro release público,
    0.1.0
   Final de 2006: Reescrita do MVC
1.0.0, julho de 2007

   Primeiro release estável
   Sistema básico de MVC,
    com plugins, action helpers,
    renderização automatizada,
    etc.
   Muitos consumidores de
    APIs de web services
   Classes servidoras para
    XML-RPC e REST.
1.5.0 – Março de 2008

   Primeiro release menor
   Zend_Form
   Zend_Layout
   Sistema de view helper ciente
    do layout
             Layout content



              View content
1.6.0 – Setembro de 2008

   Integração com Dojo
   Zend_Test: extensão PHPUnit
    para controladores
   Action helper ContextSwitch

         HTML          JSON




         XML
1.7.0 – Novembro de 2008

   Suporte à AMF
   Melhorias de performance
1.8.0 – Abril de 2009

   Zend_Tool
   Zend_Application




                            AMPLAMENTE
                              USADO!




                Matthew O'Phinney, ZF Leader e autor do conteúdo
                no qual esta apresentação se baseia
1.9.0 – Agosto de 2009

   Zend_Feed_Reader
   Suporte/compatibilidade
    com PHP 5.3
   Adições levadas pela
    comunidade
   Início da caça mensal a
    bugs
1.10.0 – Janeiro de 2009

   Integração de
    ControllerTestCase com
    Zend_Application
   Adição de Zend_Feed_Writer
   Mudanças na documentação:
    adoção do PhD para renderizar
    o manual do usuário, introdução
    do sistema de comentário e a
    seção “Learning Zend
    Framework”
1.11.0 – Novembro de 2010

   Suporte mobile via
    Zend_Http_UserAgent
   API SimpleCloud via
    Zend_Cloud
Arquitetura
Arquitetura
Arquitetura
Flexibilidade
Liberdade de Escolha
E daqui vamos para onde?
Revolução
Inevitável
Junte-se ou morra!
Evolução
“A mutação é a chave para a nossa evolução.
Ela nos permitiu evoluir de um organismo
unicelular à espécie dominante do planeta. O
processo é lento, normalmente leva milhares e
milhares de anos. Mas em algumas centenas de
milênios a evolução dá um salto.”
Evolução
O foco do Zend Framework 2.0 é na melhoria da
consistência e performance.
Código Explícito

   Não é isto:
                class SoraniknatuController
                extends Zend_Controller_Action
                {
                public function useTheRingAction()
                {
                $this->view->object = 'imagination';
                }
                }




    Onde isso             Quando
                                              E os
      está                ocorre a
                                            layouts?
    definido?          renderização?
Mágica
   ou
Bruxaria?
Código Explícito

   Código explícito é fácil de entender.
   Código explícito é fácil de analisar.
   Código explícito é fácil de manter.
Melhorias incrementais
Passos de Bebê

   Conversão de código dos prefixos de
    fornecedor (por exemplo “Zend_Phaser”) para
    namespaces do PHP 5.3
   Refatoração das exceções
   Somente autoload
   Melhoria e padronização do sistema de plugins
Reescrever somente onde faz
          sentido
Mudanças na Infraestrutura
Namespaces
O problema

   Nomes de classes muito grandes
       Dificuldade de refatorar
       Dificuldade de reter semântica com nomes mais
        curtos




Zend_Form_Decorator_Marker_File_Interface
A solução

   Cada arquivo de classe declara uma
    namespace
   Um namespace por arquivo
   Qualquer classe usada que não estiver no
    namespace atual (ou em um subnamespace) é
    importada e tipicamente apelidada
   A resolução global é desencorajada, exceto no
    caso de classes referenciadas em strings.
Exemplo de Namespace


namespace ZendEventManager;

use ZendStdlibCallbackHandler;

class EventManager implements EventCollection
{
/* ... */
}
Usando Apelidos

namespace ZendMvc;

use ZendStdlibDispatchable,
ZendDiServiceLocator as Locator;

class FrontController implements Dispatchable
{
public function __construct(Locator $locator)
{
$this->serviceLocator = $locator;
}
}
Recomendação para Migração

Importe classes com o comando
use em vez de fazer chamadas
com require_once em seu
código!
Importando Classes
use Zend_Controller_Action as Controller;

class PowerController extends Controller
{                                           ZF1
}

             Como ficará:
use ZendControllerAction as Controller;

class PowerController extends Controller
{                                           ZF2
}
Nomeação

   Todo código no projeto está no namespace
    “Zend”
   Cada componente define um namespace único
   Classes dentro de um componente residem
    naquele namespace ou em um subnamespace
   Tipicamente, uma classe nomeada de acordo
    com o componente é a classe gateway.
Exemplos de Nomeação




namespace ZendEventManager;

class EventManager implements EventCollection
{

}
Interfaces
Interfaces

   Interfaces são nomeadas de acordo com
    nomes e adjetivos, e descrevem o que elas
    provêem
   Na maioria dos casos, implementações
    concretas interfaces residem em um
    subnamespace nomeado de acordo com a
    interface
   Um paradigma Orientado a Contrato mais
    forte
Exemplo de Interfaces




namespace ZendSession;

use Traversable, ArrayAccess, Serializable, Countable;

interface Storage extends Traversable, ArrayAccess, Serializable,
Countable
{

}
Implementação Concreta


namespace ZendSessionStorage;

use ArrayObject,
ZendSessionStorage,
ZendSessionException;

class ArrayStorage extends ArrayObject implements Storage
{
/* ... */
}
Exceções
O problema

   Todas as exceções derivavam de uma classe
    comum
   Incapacidade de estender os tipos de exceção
    semânticas oferecidas na SPL
   Estratégias de captura limitadas
   Forte dependência para cada e todos os
    componenentes
Abordagem ZF2

   Zend_Exception foi eliminado
   Cada componente define uma interface
    Exception marcadora
   Exceções concretas residem em um
    subnamespace Exception, e estendem
    exceções SPL
O que a solução provê

   Captura tipos de exceções específicas
   Captura tipos de exceções SPL
   Captura exceções no nível do componente
   Captura baseada no tipo de exceção global
Definições de Exceção
                                   namespace ZendEventManager;

                                   interface Exception
                                   {

                                   }

namespace ZendEventManagerException;

use ZendEventManagerException;

class InvalidArgumentException extends InvalidArgumentException
implements Exception
{

}
Capturando Exceções

namespace ZendEventManagerException;

use ZendEventManagerException;

try {
$events->trigger('dom.quixote', $object);
} catch (InvalidArgumentException $e) {
} catch (Exception $e) {
} catch (InvalidArgumentException $e) {
} catch (Exception $e) {
}
Autocarregamento
O problema

   Problemas de performance
       Muitas classes são usadas apenas no momento
        adequado e não devem ser carregadas até que
        seja necessário.
   A falta de chamadas require_once leva a erros.
Abordagem ZF2

   Chega de chamadas require_once!
   Múltiplas abordagens de autocarregamento
       Autocarregador via include_path estilo ZF1
       Autocarregamento pelo namespace / prefixo do
        fornecedor
       Autocarregamento por Mapa de Classes
Autocarregamento estilo ZF1

require_once 'Zend/Loader/StandardAutoloader.php';
$loader = new ZendLoaderStandardAutoloader(array(
'fallback_autoloader' => true,
));
$loader->register();


                  EX
                     EM
                          PL
                            O
Autocarregamento
        Namespace/Prefixo ZF2

require_once 'Zend/Loader/StandardAutoloader.php';
$loader = new ZendLoaderStandardAutoloader();
$loader->registerNamespace('My', __DIR__ . '/../library/My')
->registerPrefix('Fgsl_', __DIR__ . '/../library/Fgsl');
$loader->register();



                       EX
                          EM
                               PL
                                 O
Autocarregamento com Mapas de
           Classes

 return array(
 'GreenLanternHal' => __DIR__ . '/Lantern/Hal.php',
 );


  require_once 'Zend/Loader/ClassMapAutoloader.php';
  $loader = new ZendLoaderClassMapAutoloader();
  $loader->registerAutoloadMap(__DIR__ .
  '/../library/.classmap.php');
  $loader->register();
Mapas de Classes? Mas não dá
         trabalho pra fazer?
   Sim, dá trabalho. Mas nós temos uma
    ferramenta, bin/classmap_generator.php
   E o uso é trivial:
prompt> cd your/library
 
prompt> php /path/to/classmap_generator.php -w



   A execução desse script cria o Mapa de
    Classes em .classmap.php
Por que?

   Mapas de Classes mostram 25% de melhoria
    no carregador do ZF1 quando não é usada
    aceleração.
       E 60-85% quando um cache de opcode está em
        uso.
   O emparelhamento namespaces/prefixos com
    caminhos especificados mostra um ganho de
    10% sem aceleração.
       E 40% de melhoria quando uma cache de opcode é
        usado.
Fábrica de Autocarregadores

   Com múltiplas estratégias vem a necessidade
    por uma fábrica.
   Escolha diversas estratégias:
        Mapa de Classes para pesquisa mais rápida
        Caminhos namespace/prefixo para código comum
        Autocarregador de reserva estilo ZF1/PSR-0 para
         desenvolvimento

        PSR: PHP Specification Request
Exemplo de Fábrica de
      Autocarregadores
require_once 'Zend/Loader/AutoloaderFactory.php';
use ZendLoaderAutoloaderFactory;
AutoloaderFactory::factory(array(
'ZendLoaderClassMapAutoloader' => array(
__DIR__ . '/../library/.classmap.php',
__DIR__ . '/../application/.classmap.php',
),
'ZendLoaderStandardAutoloader' => array(
'namespaces' => array(
'Zend' => __DIR__ . '/../library/Zend',
),
'fallback_autoloader' => true,
),
));
Quando posso migrar?

   Você pode usar os autocarregadores e as
    facilidades de geração dos mapas de classe do
    ZF2... hoje! Pode começar a migração!
Carregamento de Plugins
Terminologia

   Para nossos propósitos, um “plugin” é qualquer
    classe que é determinada em tempo de
    execução.
       Auxiliares de Controle e Visão
       Adaptadores
       Filtros e Validadores
Plugins
O Problema

   Variar abordagens para descobrir classes
    plugin
       Caminhos relativos para as classes chamadas
       Pilhas prexifo-caminho (mais comum)
       Modificadores para indicar classes
   A abordagem mais comum é terrível
       Má performance
       Difícil de depurar
       Sem caching de plugins descobertos
Abordagem ZF2: o Agente de
             Plugins
   Interface de Localização de Plugins
       Permite variar a implementação de pesquisa de
        plugins
   Interface de Agente de Plugins
       Compõe um Localizador de Plugins
Interface de Localização de
          Plugins


   namespace ZendLoader;
   interface ShortNameLocator
   {
   public function isLoaded($name);
   public function getClassName($name);
   public function load($name);
   }
Interface de Agente de Plugins

namespace ZendLoader;
interface Broker
{
public function load($plugin, array $options = null);
public function getPlugins();
public function isLoaded($name);
public function register($name, $plugin);
public function unregister($name);
public function setClassLoader(ShortNameLocator $loader);
public function getClassLoader();
}
Como usar?

   Crie um carregador de plugins padrão
   Crie um agente de plugins padrão
   Componha um agente dentro de sua classe
   Opcionalmente, defina configuração estática
   Opcionalmente, passe a configuração de
    agente e carregador
   Opcionalmente, registre plugins com o
    localizador ou o agente
Implementação do Localizador de
           Plugins
    namespace ZendView;
    use ZendLoaderPluginClassLoader;
    class HelperLoader extends PluginClassLoader
    {
    /**
      * @var array Pre-aliased view helpers
      */
    protected $plugins = array(
    'action'
    => 'ZendViewHelperAction',
    'base_url' => 'ZendViewHelperBaseUrl',
    /* ... */
    );
    }
Implementação do Agente de
           Plugins
class HelperBroker extends PluginBroker
{
protected $defaultClassLoader = 'ZendViewHelperLoader';
public function load($plugin, array $options = null)
{
$helper = parent::load($plugin, $options);
if (null !== ($view = $this->getView())) {
$helper->setView($view);
}
return $helper;
}
protected function validatePlugin($plugin)
{
if (! $plugin instanceof Helper) {
throw new InvalidHelperException();
}
return true;
}
}
Compondo um Agente
use ZendViewHelperLoader;
class Sinestro
{
protected $broker;
public function broker($spec = null, array $options = array())
{
if ($spec instanceof Broker) {
$this->broker = $spec;
return $spec;
} elseif (null === $this->broker) {
$this->broker = new PluginBroker();
}
if (null === $spec) {
return $this->broker;
} elseif (!is_string($spec)) {
throw new Exception();
}
return $this->broker->load($spec, $options);
}
}
Precedência dos Localizadores

(Do menos para o mais específico)
   Mapa definido no carregador de plugins
    concreto
   Mapas estáticos ( o registro mais recente tem
    precedência)
   Mapeamento passado via instanciação
   Mapeamento explícito provido
    programaticamente
Definindo Mapas Estáticos


use ZendViewHelperLoader;
HelperLoader::addStaticMap(array(
'url'
=> 'KilowogHelperUrl',
'base_url' => 'ProjectHelperBaseUrl',
));
$loader = new HelperLoader();
$class = $loader->load('url'); // "KilowogHelperUrl"
Passando Mapas via
           Configuração


use ZendViewHelperLoader;
$config = array(
'url'
=> 'KilowogHelperUrl',
'base_url' => 'ProjectHelperBaseUrl',
);
$loader = new HelperLoader($config);
$class = $loader->load('url'); // "KilowogHelperUrl"
Passando Mapas para Mapas!

 use ZendViewHelperLoader,
 ZendLoaderPluginClassLoader;
 class HelperMap extends PluginClassLoader
 {
 protected $plugins = array(
 'url'
 => 'KilowogHelperUrl',
 'base_url' => 'ProjectHelperBaseUrl',
 );
 }
 $helpers = new HelperMap();
 $loader = new HelperLoader($helpers);
 $class
 = $loader->load('url'); // "KilowogHelperUrl"
Estendendo Carregadores
use ZendViewHelperLoader;
class HelperMap extends HelperLoader
{
public function __construct($options = null)
{
// Adiciona e/ou sobrescreve o mapa do
HelperLoader
$this->registerPlugins(array(
'url'
=> 'KilowogHelperUrl',
'base_url' => 'ProjectHelperBaseUrl',
));
parent::__construct($options);
}
}
$helpers = new HelperMap();
$class
= $loader->load('url'); // "KilowogHelperUrl"
Passando Mapas via Agente

use ZendViewHelperBroker;
$broker = new HelperBroker(array(
'class_loader' => array(
'class'
=> 'HelperMap',
'options' => array(
'base_url' => 'AppHelperBaseUrl',
),
),
));
$plugin = $broker->load('base_url'); // "AppHelperBaseUrl"
Criando Mapas Manualmente


use ZendViewHelperLoader;
$loader = new HelperLoader();
$loader->registerPlugin('url', 'KilowogHelperUrl')
->registerPlugins(array(
'base_url' => 'ProjectHelperBaseUrl',
));
$class = $loader->load('url'); // "KilowogHelperUrl"
Gerenciando Plugins via Agente

   Por padrão, o carregador é consultado para um
    nome de classe, e instancia a classe com os
    argumentos dados
   Opcionalmente, você pode alimentar o agente,
    registrando objetos plugins manualmente sob
    um dado nome
Registrando um Plugin com o
          Agente

use KilowogHelperUrl;
// Assume:
// - $request == objeto Request
// - $router == objeto Router
// - $broker == HelperBroker

$url = new Url($request, $router);
$broker->registerPlugin('url', $url); // OU:
$broker->registerPlugins(array(
'url' => $url,
));
$url = $broker->load('url'); // === $url acima
E sobre o carregamento tardio?

   Frequentemente você precisa configurar
    plugins
   Mas você quer uma instância só quando ela for
    realmente requisitada
   É aí que entra
    ZendLoaderLazyLoadingBroker
LazyLoadingBroker Interface


namespace ZendLoader;
interface LazyLoadingBroker extends Broker
{
public function registerSpec($name, array $spec = null);
public function registerSpecs($specs);
public function unregisterSpec($name);
public function getRegisteredPlugins();
public function hasPlugin($name);
}
Usando LazyLoadingBroker

   Registra “especificações” com o agente
   Quando o plugin é requisitado, as opções
    fornecidas serão usadas a menos que novas
    opções sejam passadas
   De todas as outras maneiras, ele comporta-se
    como outros agentes, incluindo a permissão do
    registro explícito de plugins
Usando LazyLoadingBroker


$broker->registerSpec('url', array($request, $router));
$broker->registerSpecs(array(
'url' => array($request, $router),
));
if (!$broker->hasPlugin('url')) {
// sem especificação!
}
$plugins = $broker->getRegisteredPlugins(); // array('url')
$url = $broker->load('url'); // Com $request, $router é
injetado
Usando LazyLoadingBroker via
         Configuração

use ZendViewHelperBroker;
$config = array(
'specs' => array(
'url' => array($request, $router),
),
);
$broker = new HelperBroker($config);
$url
= $broker->load('url'); // Com $request, $router é
injetado
E ainda tem mais!
Novos Componentes
E Componentes Poderosos!
Novos Componentes

   ZendEventManager
   ZendDi
EventManager
O Problema

   Como nós introduzimos pontos de log/debug
    no código do framework?
   Como nós permitimos que os usuários
    introduzam caching sem necessidade de
    estender o código do framework?
   Como nós permitimos que os usuários
    introduzam validação, filtragem, verificações de
    controle de acesso, etc., sem necessariamente
    estender o código do framework?
O Problema

   Como permitirmos que os usuários manipulem
    a ordem na qual plugins, filtros de
    interceptação, eventos, etc., são disparados.
   Como nós podemos prover ferramentas para o
    código do usuário trabalhe em prol das
    questões anteriores?
Solução: Programação Orientada
          a Aspectos
   O código define vários “aspectos” que podem
    ser interessantes observar e/ou anexar a partir
    de um consumidor.
   Basicamente, todas as soluções que
    examinaremos podem ser usadas para
    implementar POA em um código base.


                                       www.fgsl.eti.br

                                         Palestras
Requisitos

   Projeto que seja razoavelmente fácil de
    entender.
   Permitir anexar manipuladores de forma
    estática ou por instância, preferencialmente de
    ambas as formas.
   Preferencialmente enquanto reter o estado
    não-global ou permitir sobrescrita.
   Permitir interrupção da execução
   Permitir a priorização de manipuladores
Requisitos

   Projeto que seja razoavelmente fácil de
    entender.
   Permitir anexar manipuladores de forma
    estática ou por instância, preferencialmente de
    ambas as formas.
   Preferencialmente enquanto reter o estado
    não-global ou permitir sobrescrita.
   Permitir interrupção da execução
   Permitir a priorização de manipuladores
Requisitos

   Previsibilidade de argumentos passados para
    manipuladores.
   Habilidade de anexar a muitos componentes
    emissores de eventos de uma vez.
Solução: Observador de Sujeitos

   Prós
       Simples de entender
       Interfaces SPL são bem conhecidas (mas
        limitadas)
   Contras
       Tipicamente, não pode interromper a execução de
        observadores remanescentes
       Requer um sistema para cada componente e/ou
        classe
       Tipicamente, sem habilidade para priorizar
        manipuladores
Solução: Publicador/Sobrescritor
          de Eventos
   Prós
       Sobrescrita de notificações arbitrárias
       Tipicamente por componente + uso global; em
        muitas linguagens, um único agregador global
       Paradigma bem-conhecido na programação de
        interfaces com o usuário (pense em Javascript)
       Tende a ser um Turing completo
Solução: Publicador/Sobrescritor
     de Eventos (PubSub)
   Contras
       Frequentemente, precisa testar o evento fornecido
        para garantir que você pode manipulá-lo.
       Uso global implica em agregação estática e/ou
        dependências estáticas.
       … mas o uso por componente implica em um
        boilerplate para compor em cada classe se ele for
        usado.
       Tipicamente, sem habilidade para priorizar
        manipuladores.
   Falaremos mais sobre isso mais tarde...
Pausa para esclarecimento

   boilerplate é o termo usado para descrever
    seções de código que foram incluídas em
    muitos lugares com pouca ou nenhuma
    alteração.
Solução: SignalSlots

   Prós
       Conceito bem conhecido nos círculos de Ciência da
        Computação
       O código emite sinais, que são interceptados por
        slots (vulgos manipuladores)
       Tipicamente, compõe um gerenciador de sinais em
        uma classe, mas pode ser integrado com um
        gerenciador global também
       Geralmente tem algumas habilidades para priorizar
        manipuladores
Solução: SignalSlots

   Contras
       Esse palavreado não é bem conhecido entre
        programadores PHP.
       Argumentos irão variar entre sinais.
       Os mesmos problemas com composição por classe
        e uso estático como vemos em sistemas de
        eventos.
Filtros de Interceptação

   Prós
       Similar às soluções anteriores, exceto que cada
        manipulador recebe a cadeia de filtros como um
        argumento, e é responsável por chamar o próximo
        na cadeia.
       Frequentemente, o “trabalho” inteiro de um método
        é simplesmente um executar um filtro.
       Dependendo do projeto, pode permitir acesso
        global/estático.
Filtros de Interceptação

   Contras
       Algumas vezes é difícil acompanhar fluxos de
        trabalho complexos.
       Os mesmos problemas com composição por classe
        e uso estático como vemos em sistemas de evento.
       É fácil esquecer de invocar o próximo filtro na
        cadeia.
       Tipicamente, sem habilidade de priorizar filtros.
Mas
 qual a
solução
 afinal?
Nenhuma!
Todas!
Combinação




                               de Poderes
                                            Linka
Wheeler




 Gi                    Ma-Ti                    Kwame
ZF2: EventManager Component

   A cereja do bolo de cada solução, PubSub,
    SignalSlot, e Filtros de Interceptação, para
    prover uma solução compreensiva.
   Não pode resolver completamente os
    problemas de composição/uso estático.
   Nós podemos resolver o problema da
    composição no PHP 5.4 com Traits.
   Há formas elegantes de manipular o uso
    estático.
Interface EventCollection

namespace ZendEventManager;
use ZendStdlibCallbackHandler;
interface EventCollection
{
public function trigger($event, $context, $argv = array());
public function triggerUntil($event, $context, $argv, $callback);
public function attach($event, $callback, $priority = 1);
public function detach(CallbackHandler $handle);
public function getEvents();
public function getHandlers($event);
public function clearHandlers($event);
}
Disparando Eventos

use ZendEventManagerEventManager;
$events = new EventManager();
$events->trigger($eventName, $object, $params);
/* Onde:
  * - $eventName é o nome do evento; geralmente o nome do evento
atual
*
* - $object é o objeto que está disparando o evento
* - $params são os parâmetros que o manipulador pode precisar
para ter acesso,
geralmente os argumentos do método
*
*/
CallbackHandler


$handler = $events->attach('algum-evento', function($e) use
($log) {
$event
= $e->getName();
$context = get_class($e->getTarget());
$params = json_encode($e->getParams());
$log->info(sprintf("%s: %s: %s", $event, $context, $params));
});
Callback Handler com Prioridade



$handler = $events->attach('algum-evento', function($e) use
($log) {
/* o mesmo que o anterior */
}, 100); // Priorize! (números altos ganham)
Interrompendo a Execução:
        Testando Resultados


$results = $events->triggerUntil('algum-evento', $o,
$argv,
function($result) {
return ($result instanceof SomeType);
});
if ($results->stopped()) {
return $results->last();
}
Interrompendo a Execução: via
          Manipuladores

$events->attach('algum-evento', function($e) {
$result = new Result;
$e->stopPropagation(true);
return $result;
});
$results = $events->trigger('algum-evento', $object,
$params);
if ($results->stopped()) {
return $results->last();
}
Compondo um EventManager
use ZendEventManagerEventCollection as Events,
ZendEventManagerEventManager;
class Arisia
{
protected $events;
public function events(Events $events = null)
{
if (null !== $events) {
$this->events = $events;
} elseif (null === $this->events) {
$this->events = new EventManager(__CLASS__);
}
return $this->events;
}
public function doSomething($param1, $param2)
{
$params = compact('param1', 'param2');
$this->events()->trigger(__FUNCTION__, $this, $params);
}
}
Usando um Trait!
use ZendEventManagerEventCollection as Events,
ZendEventManagerEventManager;
trait Eventful
{
public function events(Events $events = null)
{
if (null !== $events) {
$this->events = $events;
} elseif (null === $this->events) {
$this->events = new EventManager(__CLASS__);
}
return $this->events;
}
}
class Arisia
{
use Eventful;
protected $events;
}
Conectando Manipuladores
       Estaticamente


use ZendEventManagerStaticEventManager;
$events = StaticEventManager::getInstance();
$events->connect('Arisia', 'algum-evento', function
($e) {
/* ... */
});
Recomendações

   Nomeie seus eventos usando __FUNCTION__
       Se disparar múltiplos eventos no mesmo método,
        sufixe com um “.(pre|pos|etc.)”
   Forneça para o construtor do EventManager
    tanto o nome da classe quanto um ou mais
    nomes de “serviços”, para fazer anexações
    estáticas mais semânticas.
       Isso permite que um único callback ouça muitos
        componentes!
Injeção de Dependência (DI)
O Que é Injeção de Dependência?

   Muito simples: definir modos de passar
    dependências para dentro de um objeto.

       namespace TomarreHelper;
       class Url
       {
       public function __construct(Request $request)
       {
       $this->request = $request;
       }
       public function setRouter(Router $router)
       {
       $this->router = $router;
       }
       }
Então porque as pessoas tem
            medo disso?
   Porque elas não fazem isso.
   Elas temem os Conteineres de Injeção de
    Dependência.
O Que é um Conteiner de Injeção
        de Dependência

  Colocando de forma
       simples:
Um grafo de objetos para
  mapear relações de
  dependência entre
        objetos.
Grafos
Novamente, por que as pessoas
     tem medo disso?

   Porque parece mágica!
Objeto com Dependências

namespace TomarreHelper;
class Url
{
public function __construct(Request $request)
{
$this->request = $request;
}
public function setRouter(Router $router)
{
$this->router = $router;
}
}
Outro Objeto com Dependências


     namespace mwopMvc;
     class Router
     {
     public function addRoute(Route $route)
     {
     $this->routes->push($route);
     }
     }
Agarrando um Objeto e Usando-o



$urlHelper = $di->get('url-helper');
echo $url->generate('/css/site.css');
echo $url->generate(array('id' => $id), array('name' =>
'blog'));
As Questões

   Como eu posso estar certo se eu tenho minhas
    dependências?
       Você as define explicitamente.
       Você recupera o objeto via conteiner, o que garante
        que as definições são usadas.
   Onde eu defino essas coisas?
       Programaticamente, via configuração, ou usando
        uma ferramenta.
As Questões

   Se eu chamar $object = new Salaak(), como eu
    forço o uso de diferentes dependências?
       Chamar new não usa o conteiner. Na verdade,
        nada força você a usá-lo!
Por que usar um?

   Se a instanciação de seus objetos não está
    debaixo de seu controle direto (por exemplo,
    controladores), como você retém controle
    sobre suas dependências?
       Acesso a dados diferente baseado no ambiente da
        aplicação.
       Substituição de implementações mock/stub durante
        o teste.
Abordagem ZF2

   Padronizar em uma interface de localizador de
    serviços.
   Prover uma solução DI performática, e integrá-
    la dentro de um localizador de serviços.
   Prover ferramentas para auxiliar na criação de
    definições de DI durante o desenvolvimento.
Interface para Localizador de
           Serviços


namespace ZendDi;
interface ServiceLocation
{
public function set($name, $service);
public function get($name, array $params = null);
}
Interface para Injetor de
            Dependências

namespace ZendDi;
interface DependencyInjection
{
public function get($name, array $params = null);
public function newInstance($name, array $params = null);
public function setDefinitions($definitions);
public function setDefinition(
DependencyDefinition $definition, $serviceName = null);
public function setAlias($alias, $serviceName);
public function getDefinitions();
public function getAliases();
}
Definições
namespace ZendDi;
interface DependencyDefinition
{
public function __construct($className);
public function getClass();
public function setConstructorCallback($callback);
public function getConstructorCallback();
public function hasConstructorCallback();
public function setParam($name, $value);
public function setParams(array $params);
public function setParamMap(array $map);
public function getParams();
public function setShared($flag = true);
public function isShared();
public function addTag($tag);
public function addTags(array $tags);
public function getTags();
public function hasTag($tag);
public function addMethodCall($name, array $args);
public function getMethodCalls();
}
Referências



namespace ZendDi;
interface DependencyReference
{
public function __construct($serviceName);
public function getServiceName();
}
Definição de Classe
use ZendDiDefinition,
ZendDiReference;
$mongo = new Definition('Mongo');
$mongoDB = new Definition('MongoDB');
$mongoDB->setParam('conn', new Reference('mongo'))
->setParam('name', 'test');
$coll = new Definition('MongoCollection');
$coll->setParam('db', new Reference('mongodb'))
->setParam('name', 'resource');
$di->setDefinitions(array(
'mongo'=> $mongo,
'mongodb' => $mongoDB,
'resource' => $coll,
));
$resource = $di->get('resource');
Injeção por Modificador


use ZendDiDefinition,
ZendDiReference;
$service = new Definition('mwopServiceResources');
$service->addMethod('setResource', array(
new Reference('resource')
));
$di->setDefinition('resources', $service);
$resources = $di->get('resources');
Fazendo mais Rápido

   Especificar mapas de parâmetros de construtor
    em definições.
   Gerar localizadores de serviço a partir de um
    conteiner DI.
Mapas de Parâmetros


$mongoDB->setParam('conn', new Reference('mongo'))
->setParam('name', 'test')
->setParamMap(array(
'conn' => 0,
'name' => 1,
));
// Garante que os parâmetros estão em ordem, sem precisar
// recorrer à API de reflexão
Gerando um Localizador de
       Serviços a partir de DI


use ZendDiContainerBuilder as DiBuilder;
$builder = new DiBuilder($injector);
$builder->setContainerClass('AppContext');
$container = $builder->getCodeGenerator(
__DIR__ . '/../application/AppContext.php'
); // Retorna uma instância de ZendCodeGeneratorPhpPhpFile
$container->write(); // Grava no disco
Exemplo de um localizador
           gerado
use ZendDiDependencyInjectionContainer;
class AppContext extends DependencyInjectionContainer
{
public function get($name, array $params = array())
{
switch ($name) {
case 'request':
case 'ZendHttpRequest':
return $this->getZendHttpRequest();
default:
return parent::get($name, $params);
}
}
public function getZendHttpRequest()
{
if (isset($this->services['ZendHttpRequest'])) {
return $this->services['ZendHttpRequest'];
}
$object = new ZendHttpRequest();
$this->services['ZendHttpRequest'] = $object;
return $object;
}
}
Usando um localizador gerado



$context = new AppContext();
$request = $context->get('request');
// O mesmo que usar um localizador de serviços ou
um conteiner DI!
Fazendo mais simples ainda

   Use arquivos de configuração
   Você pode usar qualquer formato suportado
    por ZendConfig:
       INI
       JSON
       XML
       YAML
Exemplo de configuração com
           JSON
{
"production": { "definitions": [
{ "class": "Mongo" },
{ "class": "MongoDB",
"params": {
"conn": {"__reference": "mongocxn"},
"name": "mwoptest"
},
"param_map": { "conn": 0, "name": 1 }
},
{ "class": "MongoCollection",
"params": {
"db": {"__reference": "MongoDB"},
"name": "entries"
},
"param_map": { "db": 0, "name": 1 }
}
], "aliases": {
"mongocxn": "Mongo",
"mongo-collection-entries": "MongoCollection"
}
}
}
Quais são os casos de uso no
                ZF2?
   Um grandão.

Tirar os controladores
  MVC do conteiner
Um Controlador de Ação
namespace BlogController;
class Entry implements Dispatchable
{
public function setResource(Resource $resource)
{
$this->resource = $resource;
}
public function dispatch(Request $request, Response $response =
null)
{
/* ... */
$entry = $this->resource->get($id);
/* ... */
}
}
O Controlador Frontal
class FrontController implements Dispatchable
{
public function __construct(DependencyInjection $di)
{
$this->di = $di;
}
public function dispatch(Request $request, Response $response =
null)
{
/* ... */
$controller = $this->di->get($controllerName);
$result = $controller->dispatch($request, $response);
/* ... */
}
}
Benefícios de usar DI deste modo

   Performance
   Desacoplamento de código
   Simplificação do código do controlador
E vem mais por aí

   Compilação na primeira execução.
   Ferramentas para vasculhar classes ou
    namespaces para construir definições.
   Injeção de interface.
   … e mais coisas legais.
Padrões MVC
Padrões MVC
Os Problemas

   Como os controladores obtém dependências?
   Como nós acomodamos diferentes padrões de
    controladores?
       E se se nós quisermos uma seleção de ações mais
        apurada, baseada em outros dados no ambiente de
        requisição?
       E se quisermos passar argumentos para nomes de
        ações, ou argumentos pré-validados?
       E se nós não gostarmos do sufixo “Action” nos
        métodos acionadores?
       E se...
Os Problemas

   Como nós podemos melhorar o uso de
    componentes do servidor dentro do MVC?
   Como nós podemos fazer o MVC mais
    performático?
A estrutura básica de uma
aplicação web é a de um
       ciclo de vida
  Requisição/Resposta
A interface Dispatchable


namespace ZendStdlib;
interface Dispatchable
{
public function dispatch(
Request $request, Response $response = null
);
}
Requisição e Resposta

   Tanto a Requisição quanto a Resposta
    simplesmente agregam metadados e conteúdo.
   A Resposta também tem a habilidade de enviar
    a si mesma.
   Variantes específicas de HTTP serão o núcleo
    do MVC.
       Para prover conveniência em torno de variáveis
        superglobais, cookies e tarefas comuns tais como
        determinar os cabeçalhos Accept e Content-Type.
Qualquer Dispatchable pode
           anexar ao MVC

Dispatchable é simplesmente
uma formalização do padrão de
projeto Command.
   Controladores
   Servidores
   Qualquer coisa que você sonhar! Apenas
    implemente Dispatchable!
Um protótipo simples de um
            Controlador Frontal
public function dispatch(Request $request, Response $response = null)
{
$params = compact('request', 'response');
$this->events()->trigger(__FUNCTION__ . '.route.pre', $this,
$params);
$result = $this->getRouter()->route($request);
if (!$result) {
$result = array('controller' => 'page', 'page' => 404);
}
$params['routing'] = (object) $result;
$this->events()->trigger(__FUNCTION__ . '.route.post', $params);
$controller = $this->di->get($params['routing']->controller);
if (!$controller instanceof Dispatchable) {
$controller = new NotFoundController();
}
$result = $controller->dispatch($request, $response);
$params['__RESULT__'] = $result;
$this->events()->trigger(__FUNCTION__ . '.dispatch.post',
$params);
return $response;
}
Contexto Temporal

   Quando esta apresentação foi finalizada, o
    último release do Zend Framework 1 era o
    1.11.11 e o Zend Framework 2 estava na
    versão 2.0.0beta1.
Mais informações

   http://framework.zend.com
   https://github.com/zendframework/zf2
   www.fgsl.eti.br
       Aguarde... treinamentos de arquitetura, migração,
        e desenvolvimento.
       Pra quem quer sair na frente, Mão na Massa MVC
        Zend Framework 2!
       Coming soon 2012!

Mais conteúdo relacionado

PDF
Zend Framework 2 - Desenvolvimento Ágil Competente
PDF
CDI -Contextos e Dependências
PDF
Seu framework é melhor pra quê?
PDF
PHP Experience 2016 - [Palestra] Vagrant, LXC, Docker, etc: Entenda as difere...
PPTX
Conhecendo o Zend Framework
PDF
Começando com Zend Framework 2
PDF
Cdi conceitos
PDF
PHP Experience 2016 - [Palestra] Rumo à Certificação PHP
Zend Framework 2 - Desenvolvimento Ágil Competente
CDI -Contextos e Dependências
Seu framework é melhor pra quê?
PHP Experience 2016 - [Palestra] Vagrant, LXC, Docker, etc: Entenda as difere...
Conhecendo o Zend Framework
Começando com Zend Framework 2
Cdi conceitos
PHP Experience 2016 - [Palestra] Rumo à Certificação PHP

Mais procurados (20)

ODP
Introdução a CDI e como utilizá-la em aplicações reais
PDF
ZF2 básico : Desenvolvendo um Blog com o Zend Framework 2
PDF
Zephir
PDF
Sistemas Distribuídos - Comunicação Distribuída - EJB
PDF
Demoiselle Behave - Parte 2
PDF
Como construir aplicações gráficas e applets
PDF
Demoiselle Behave - Parte 3
PDF
Introdução à Programação em Java - Aula 1 (PT-PT)
PDF
Zend Framework 1.11
PDF
Introdução a Linguagem Java
PDF
Demoiselle Behave - Parte 4
PPTX
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
PDF
Artigo Automação de testes funcionais com Demoiselle Behave
PPTX
Programação Orientada a Objetos com Java
ODP
Selenium Workshop
PPT
Apostila de Fundamentos Java
ODP
servlet-introducao
PDF
Webservices e Computação em Nuvem com PHP
PDF
A arquitetura modular do Java 9
ODP
Apresentação Java, SOA, MICROSERVICE, HTTP, HTTPS, VERSIONAMENTO DE CONTRATO,
Introdução a CDI e como utilizá-la em aplicações reais
ZF2 básico : Desenvolvendo um Blog com o Zend Framework 2
Zephir
Sistemas Distribuídos - Comunicação Distribuída - EJB
Demoiselle Behave - Parte 2
Como construir aplicações gráficas e applets
Demoiselle Behave - Parte 3
Introdução à Programação em Java - Aula 1 (PT-PT)
Zend Framework 1.11
Introdução a Linguagem Java
Demoiselle Behave - Parte 4
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
Artigo Automação de testes funcionais com Demoiselle Behave
Programação Orientada a Objetos com Java
Selenium Workshop
Apostila de Fundamentos Java
servlet-introducao
Webservices e Computação em Nuvem com PHP
A arquitetura modular do Java 9
Apresentação Java, SOA, MICROSERVICE, HTTP, HTTPS, VERSIONAMENTO DE CONTRATO,
Anúncio

Destaque (10)

PPT
SQL Devlopment for 10 ppt
PPT
PHP- Introduction to Object Oriented PHP
PDF
Desenvolvimento Web com CakePHP
PPS
Workshop: WebSockets com HTML 5 & PHP - Gustavo Ciello
PDF
PHP 5.3 - Estruturas de Controle
PPT
Css Ppt
PDF
HTML5 for PHP Developers - IPC
PPSX
Classroom Objects: PowerPoint Activities
PPT
PPTX
PHP Powerpoint -- Teach PHP with this
SQL Devlopment for 10 ppt
PHP- Introduction to Object Oriented PHP
Desenvolvimento Web com CakePHP
Workshop: WebSockets com HTML 5 & PHP - Gustavo Ciello
PHP 5.3 - Estruturas de Controle
Css Ppt
HTML5 for PHP Developers - IPC
Classroom Objects: PowerPoint Activities
PHP Powerpoint -- Teach PHP with this
Anúncio

Semelhante a O que esperar do Zend Framework 2 (20)

PDF
Introdução ao Zend Framework 2
PDF
Desmistificando o Framework da Zend
PDF
Desfrutando os Componentes do Zend Framework
PDF
Apostila Zend Framework
PDF
O que esperar do Zend Framework 3
PPT
ZF Básico - 1. Introdução
PDF
Framework PHP Zend e MVC
PPSX
Cakephp 2.0 - O que mudou
PDF
Introdução ao zend framework
PPTX
Certificação Zend Framework
ODP
Zend Framework - PHPSP - 2009
PDF
Phpjedi 090307090434-phpapp01 2
PDF
PHP like a super hero
PPT
Aop Aspect J 1.5.4
PPT
Java Seminar
PDF
Gerenciando aspectos e eventos com Zend Framework 2
PPT
Curso de Introdução - PHP Zend Framework
PDF
Desenvolvendo em Zend Framework: Ênfase no Zend_Db
PDF
Palestra Zend Framework no Governo Federal
PDF
Palestra Zend Framework CISL 2012 - ZF no Governo Federal
Introdução ao Zend Framework 2
Desmistificando o Framework da Zend
Desfrutando os Componentes do Zend Framework
Apostila Zend Framework
O que esperar do Zend Framework 3
ZF Básico - 1. Introdução
Framework PHP Zend e MVC
Cakephp 2.0 - O que mudou
Introdução ao zend framework
Certificação Zend Framework
Zend Framework - PHPSP - 2009
Phpjedi 090307090434-phpapp01 2
PHP like a super hero
Aop Aspect J 1.5.4
Java Seminar
Gerenciando aspectos e eventos com Zend Framework 2
Curso de Introdução - PHP Zend Framework
Desenvolvendo em Zend Framework: Ênfase no Zend_Db
Palestra Zend Framework no Governo Federal
Palestra Zend Framework CISL 2012 - ZF no Governo Federal

Mais de Flávio Lisboa (20)

PDF
Evolução em código: algoritmos genéticos com PHP
PDF
Dos requisitos ao código: como criar código rastreável em PHP
PDF
D de SOLID: Reduzindo o vendor lock-in em aplicações PHP
PDF
Use and Production of FLOSS in Brazilian States: an Wider Survey
PDF
Um primeiro olhar sobre o uso de software livre nos estados brasileiros
PDF
Criando testes integrados de APIs com PHP
PDF
Cooperativas de Software Livre: Uma comparação entre Brasil e Argentina
PDF
Aprenda a afiar suas garras com Laminas
PDF
Ciência e software livre: desenvolvendo com método
PDF
Turbinando microsserviços em PHP
PDF
O que esperar do framework Laminas
PDF
PHP Conference Brazil - What can we expect about framework Laminas?
PDF
Algoritmos Genéticos em PHP - PHP Conference Brasil 2019
PDF
Criando microsserviços em PHP
PDF
Como se tornar o pior programador PHP do mundo
PDF
A demanda da santa entrega Batman: bugs e gargalos em aplicações PHP
PDF
Comunicação e padrões em código aberto: quando convergente e divergente cooperam
PDF
Criação de robôs em PHP para raspagem de dados
PDF
Amanhecer esmeralda
PDF
Estudo de Caso: Utilização de PHP no Serviço Federal de Processamento de Dados
Evolução em código: algoritmos genéticos com PHP
Dos requisitos ao código: como criar código rastreável em PHP
D de SOLID: Reduzindo o vendor lock-in em aplicações PHP
Use and Production of FLOSS in Brazilian States: an Wider Survey
Um primeiro olhar sobre o uso de software livre nos estados brasileiros
Criando testes integrados de APIs com PHP
Cooperativas de Software Livre: Uma comparação entre Brasil e Argentina
Aprenda a afiar suas garras com Laminas
Ciência e software livre: desenvolvendo com método
Turbinando microsserviços em PHP
O que esperar do framework Laminas
PHP Conference Brazil - What can we expect about framework Laminas?
Algoritmos Genéticos em PHP - PHP Conference Brasil 2019
Criando microsserviços em PHP
Como se tornar o pior programador PHP do mundo
A demanda da santa entrega Batman: bugs e gargalos em aplicações PHP
Comunicação e padrões em código aberto: quando convergente e divergente cooperam
Criação de robôs em PHP para raspagem de dados
Amanhecer esmeralda
Estudo de Caso: Utilização de PHP no Serviço Federal de Processamento de Dados

Último (19)

PDF
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
PDF
Processos na gestão de transportes, TM100 Col18
PDF
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
PDF
Apple Pippin Uma breve introdução. - David Glotz
PPTX
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
PDF
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
PDF
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
PDF
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
PPTX
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
PDF
Custos e liquidação no SAP Transportation Management, TM130 Col18
PDF
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
PPTX
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
PPTX
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
PDF
COBITxITIL-Entenda as diferença em uso governança TI
PDF
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
PPTX
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
PPTX
Aula 18 - Manipulacao De Arquivos python
PDF
Aula04-Academia Heri- Tecnologia Geral 2025
PPTX
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
Processos na gestão de transportes, TM100 Col18
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
Apple Pippin Uma breve introdução. - David Glotz
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
Custos e liquidação no SAP Transportation Management, TM130 Col18
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
COBITxITIL-Entenda as diferença em uso governança TI
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
Aula 18 - Manipulacao De Arquivos python
Aula04-Academia Heri- Tecnologia Geral 2025
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss

O que esperar do Zend Framework 2

  • 1. Existe uma coisa que um programador PHP não pode ter... MEDO!
  • 2. Advertência  Alguns exemplos de código são exemplos de como implementar construções com Zend Framework 2 e não do Zend Framework 2.  Alguns exemplos fazem uso de construções disponíveis apenas no PHP 5.4.
  • 3. Advertência  Esta apresentação não visa saciar sua sede de conhecimento, mas deixar você sedento por ele.
  • 4. O que esperar do Zend Framework 2 Flávio Gomes da Silva Lisboa www.fgsl.eti.br @fgsl
  • 6. Inspirador Inspirado Desde 2008 capacitando profissionais em Zend Framework @eminetto @fgsl ESGOTADO ESGOTADO
  • 7. Uma Breve História do ZF Flávio Gomes da Silva Lisboa
  • 8. A Gênese  Outubro de 2005: o projeto é anunciado  Março de 2006: primeiro release público, 0.1.0  Final de 2006: Reescrita do MVC
  • 9. 1.0.0, julho de 2007  Primeiro release estável  Sistema básico de MVC, com plugins, action helpers, renderização automatizada, etc.  Muitos consumidores de APIs de web services  Classes servidoras para XML-RPC e REST.
  • 10. 1.5.0 – Março de 2008  Primeiro release menor  Zend_Form  Zend_Layout  Sistema de view helper ciente do layout Layout content View content
  • 11. 1.6.0 – Setembro de 2008  Integração com Dojo  Zend_Test: extensão PHPUnit para controladores  Action helper ContextSwitch HTML JSON XML
  • 12. 1.7.0 – Novembro de 2008  Suporte à AMF  Melhorias de performance
  • 13. 1.8.0 – Abril de 2009  Zend_Tool  Zend_Application AMPLAMENTE USADO! Matthew O'Phinney, ZF Leader e autor do conteúdo no qual esta apresentação se baseia
  • 14. 1.9.0 – Agosto de 2009  Zend_Feed_Reader  Suporte/compatibilidade com PHP 5.3  Adições levadas pela comunidade  Início da caça mensal a bugs
  • 15. 1.10.0 – Janeiro de 2009  Integração de ControllerTestCase com Zend_Application  Adição de Zend_Feed_Writer  Mudanças na documentação: adoção do PhD para renderizar o manual do usuário, introdução do sistema de comentário e a seção “Learning Zend Framework”
  • 16. 1.11.0 – Novembro de 2010  Suporte mobile via Zend_Http_UserAgent  API SimpleCloud via Zend_Cloud
  • 22. E daqui vamos para onde?
  • 26. Evolução “A mutação é a chave para a nossa evolução. Ela nos permitiu evoluir de um organismo unicelular à espécie dominante do planeta. O processo é lento, normalmente leva milhares e milhares de anos. Mas em algumas centenas de milênios a evolução dá um salto.”
  • 28. O foco do Zend Framework 2.0 é na melhoria da consistência e performance.
  • 29. Código Explícito  Não é isto: class SoraniknatuController extends Zend_Controller_Action { public function useTheRingAction() { $this->view->object = 'imagination'; } } Onde isso Quando E os está ocorre a layouts? definido? renderização?
  • 30. Mágica ou Bruxaria?
  • 31. Código Explícito  Código explícito é fácil de entender.  Código explícito é fácil de analisar.  Código explícito é fácil de manter.
  • 33. Passos de Bebê  Conversão de código dos prefixos de fornecedor (por exemplo “Zend_Phaser”) para namespaces do PHP 5.3  Refatoração das exceções  Somente autoload  Melhoria e padronização do sistema de plugins
  • 34. Reescrever somente onde faz sentido
  • 37. O problema  Nomes de classes muito grandes  Dificuldade de refatorar  Dificuldade de reter semântica com nomes mais curtos Zend_Form_Decorator_Marker_File_Interface
  • 38. A solução  Cada arquivo de classe declara uma namespace  Um namespace por arquivo  Qualquer classe usada que não estiver no namespace atual (ou em um subnamespace) é importada e tipicamente apelidada  A resolução global é desencorajada, exceto no caso de classes referenciadas em strings.
  • 39. Exemplo de Namespace namespace ZendEventManager; use ZendStdlibCallbackHandler; class EventManager implements EventCollection { /* ... */ }
  • 40. Usando Apelidos namespace ZendMvc; use ZendStdlibDispatchable, ZendDiServiceLocator as Locator; class FrontController implements Dispatchable { public function __construct(Locator $locator) { $this->serviceLocator = $locator; } }
  • 41. Recomendação para Migração Importe classes com o comando use em vez de fazer chamadas com require_once em seu código!
  • 42. Importando Classes use Zend_Controller_Action as Controller; class PowerController extends Controller { ZF1 } Como ficará: use ZendControllerAction as Controller; class PowerController extends Controller { ZF2 }
  • 43. Nomeação  Todo código no projeto está no namespace “Zend”  Cada componente define um namespace único  Classes dentro de um componente residem naquele namespace ou em um subnamespace  Tipicamente, uma classe nomeada de acordo com o componente é a classe gateway.
  • 44. Exemplos de Nomeação namespace ZendEventManager; class EventManager implements EventCollection { }
  • 46. Interfaces  Interfaces são nomeadas de acordo com nomes e adjetivos, e descrevem o que elas provêem  Na maioria dos casos, implementações concretas interfaces residem em um subnamespace nomeado de acordo com a interface  Um paradigma Orientado a Contrato mais forte
  • 47. Exemplo de Interfaces namespace ZendSession; use Traversable, ArrayAccess, Serializable, Countable; interface Storage extends Traversable, ArrayAccess, Serializable, Countable { }
  • 48. Implementação Concreta namespace ZendSessionStorage; use ArrayObject, ZendSessionStorage, ZendSessionException; class ArrayStorage extends ArrayObject implements Storage { /* ... */ }
  • 50. O problema  Todas as exceções derivavam de uma classe comum  Incapacidade de estender os tipos de exceção semânticas oferecidas na SPL  Estratégias de captura limitadas  Forte dependência para cada e todos os componenentes
  • 51. Abordagem ZF2  Zend_Exception foi eliminado  Cada componente define uma interface Exception marcadora  Exceções concretas residem em um subnamespace Exception, e estendem exceções SPL
  • 52. O que a solução provê  Captura tipos de exceções específicas  Captura tipos de exceções SPL  Captura exceções no nível do componente  Captura baseada no tipo de exceção global
  • 53. Definições de Exceção namespace ZendEventManager; interface Exception { } namespace ZendEventManagerException; use ZendEventManagerException; class InvalidArgumentException extends InvalidArgumentException implements Exception { }
  • 54. Capturando Exceções namespace ZendEventManagerException; use ZendEventManagerException; try { $events->trigger('dom.quixote', $object); } catch (InvalidArgumentException $e) { } catch (Exception $e) { } catch (InvalidArgumentException $e) { } catch (Exception $e) { }
  • 56. O problema  Problemas de performance  Muitas classes são usadas apenas no momento adequado e não devem ser carregadas até que seja necessário.  A falta de chamadas require_once leva a erros.
  • 57. Abordagem ZF2  Chega de chamadas require_once!  Múltiplas abordagens de autocarregamento  Autocarregador via include_path estilo ZF1  Autocarregamento pelo namespace / prefixo do fornecedor  Autocarregamento por Mapa de Classes
  • 58. Autocarregamento estilo ZF1 require_once 'Zend/Loader/StandardAutoloader.php'; $loader = new ZendLoaderStandardAutoloader(array( 'fallback_autoloader' => true, )); $loader->register(); EX EM PL O
  • 59. Autocarregamento Namespace/Prefixo ZF2 require_once 'Zend/Loader/StandardAutoloader.php'; $loader = new ZendLoaderStandardAutoloader(); $loader->registerNamespace('My', __DIR__ . '/../library/My') ->registerPrefix('Fgsl_', __DIR__ . '/../library/Fgsl'); $loader->register(); EX EM PL O
  • 60. Autocarregamento com Mapas de Classes return array( 'GreenLanternHal' => __DIR__ . '/Lantern/Hal.php', ); require_once 'Zend/Loader/ClassMapAutoloader.php'; $loader = new ZendLoaderClassMapAutoloader(); $loader->registerAutoloadMap(__DIR__ . '/../library/.classmap.php'); $loader->register();
  • 61. Mapas de Classes? Mas não dá trabalho pra fazer?  Sim, dá trabalho. Mas nós temos uma ferramenta, bin/classmap_generator.php  E o uso é trivial: prompt> cd your/library  prompt> php /path/to/classmap_generator.php -w   A execução desse script cria o Mapa de Classes em .classmap.php
  • 62. Por que?  Mapas de Classes mostram 25% de melhoria no carregador do ZF1 quando não é usada aceleração.  E 60-85% quando um cache de opcode está em uso.  O emparelhamento namespaces/prefixos com caminhos especificados mostra um ganho de 10% sem aceleração.  E 40% de melhoria quando uma cache de opcode é usado.
  • 63. Fábrica de Autocarregadores  Com múltiplas estratégias vem a necessidade por uma fábrica.  Escolha diversas estratégias:  Mapa de Classes para pesquisa mais rápida  Caminhos namespace/prefixo para código comum  Autocarregador de reserva estilo ZF1/PSR-0 para desenvolvimento PSR: PHP Specification Request
  • 64. Exemplo de Fábrica de Autocarregadores require_once 'Zend/Loader/AutoloaderFactory.php'; use ZendLoaderAutoloaderFactory; AutoloaderFactory::factory(array( 'ZendLoaderClassMapAutoloader' => array( __DIR__ . '/../library/.classmap.php', __DIR__ . '/../application/.classmap.php', ), 'ZendLoaderStandardAutoloader' => array( 'namespaces' => array( 'Zend' => __DIR__ . '/../library/Zend', ), 'fallback_autoloader' => true, ), ));
  • 65. Quando posso migrar?  Você pode usar os autocarregadores e as facilidades de geração dos mapas de classe do ZF2... hoje! Pode começar a migração!
  • 67. Terminologia  Para nossos propósitos, um “plugin” é qualquer classe que é determinada em tempo de execução.  Auxiliares de Controle e Visão  Adaptadores  Filtros e Validadores
  • 69. O Problema  Variar abordagens para descobrir classes plugin  Caminhos relativos para as classes chamadas  Pilhas prexifo-caminho (mais comum)  Modificadores para indicar classes  A abordagem mais comum é terrível  Má performance  Difícil de depurar  Sem caching de plugins descobertos
  • 70. Abordagem ZF2: o Agente de Plugins  Interface de Localização de Plugins  Permite variar a implementação de pesquisa de plugins  Interface de Agente de Plugins  Compõe um Localizador de Plugins
  • 71. Interface de Localização de Plugins namespace ZendLoader; interface ShortNameLocator { public function isLoaded($name); public function getClassName($name); public function load($name); }
  • 72. Interface de Agente de Plugins namespace ZendLoader; interface Broker { public function load($plugin, array $options = null); public function getPlugins(); public function isLoaded($name); public function register($name, $plugin); public function unregister($name); public function setClassLoader(ShortNameLocator $loader); public function getClassLoader(); }
  • 73. Como usar?  Crie um carregador de plugins padrão  Crie um agente de plugins padrão  Componha um agente dentro de sua classe  Opcionalmente, defina configuração estática  Opcionalmente, passe a configuração de agente e carregador  Opcionalmente, registre plugins com o localizador ou o agente
  • 74. Implementação do Localizador de Plugins namespace ZendView; use ZendLoaderPluginClassLoader; class HelperLoader extends PluginClassLoader { /** * @var array Pre-aliased view helpers */ protected $plugins = array( 'action' => 'ZendViewHelperAction', 'base_url' => 'ZendViewHelperBaseUrl', /* ... */ ); }
  • 75. Implementação do Agente de Plugins class HelperBroker extends PluginBroker { protected $defaultClassLoader = 'ZendViewHelperLoader'; public function load($plugin, array $options = null) { $helper = parent::load($plugin, $options); if (null !== ($view = $this->getView())) { $helper->setView($view); } return $helper; } protected function validatePlugin($plugin) { if (! $plugin instanceof Helper) { throw new InvalidHelperException(); } return true; } }
  • 76. Compondo um Agente use ZendViewHelperLoader; class Sinestro { protected $broker; public function broker($spec = null, array $options = array()) { if ($spec instanceof Broker) { $this->broker = $spec; return $spec; } elseif (null === $this->broker) { $this->broker = new PluginBroker(); } if (null === $spec) { return $this->broker; } elseif (!is_string($spec)) { throw new Exception(); } return $this->broker->load($spec, $options); } }
  • 77. Precedência dos Localizadores (Do menos para o mais específico)  Mapa definido no carregador de plugins concreto  Mapas estáticos ( o registro mais recente tem precedência)  Mapeamento passado via instanciação  Mapeamento explícito provido programaticamente
  • 78. Definindo Mapas Estáticos use ZendViewHelperLoader; HelperLoader::addStaticMap(array( 'url' => 'KilowogHelperUrl', 'base_url' => 'ProjectHelperBaseUrl', )); $loader = new HelperLoader(); $class = $loader->load('url'); // "KilowogHelperUrl"
  • 79. Passando Mapas via Configuração use ZendViewHelperLoader; $config = array( 'url' => 'KilowogHelperUrl', 'base_url' => 'ProjectHelperBaseUrl', ); $loader = new HelperLoader($config); $class = $loader->load('url'); // "KilowogHelperUrl"
  • 80. Passando Mapas para Mapas! use ZendViewHelperLoader, ZendLoaderPluginClassLoader; class HelperMap extends PluginClassLoader { protected $plugins = array( 'url' => 'KilowogHelperUrl', 'base_url' => 'ProjectHelperBaseUrl', ); } $helpers = new HelperMap(); $loader = new HelperLoader($helpers); $class = $loader->load('url'); // "KilowogHelperUrl"
  • 81. Estendendo Carregadores use ZendViewHelperLoader; class HelperMap extends HelperLoader { public function __construct($options = null) { // Adiciona e/ou sobrescreve o mapa do HelperLoader $this->registerPlugins(array( 'url' => 'KilowogHelperUrl', 'base_url' => 'ProjectHelperBaseUrl', )); parent::__construct($options); } } $helpers = new HelperMap(); $class = $loader->load('url'); // "KilowogHelperUrl"
  • 82. Passando Mapas via Agente use ZendViewHelperBroker; $broker = new HelperBroker(array( 'class_loader' => array( 'class' => 'HelperMap', 'options' => array( 'base_url' => 'AppHelperBaseUrl', ), ), )); $plugin = $broker->load('base_url'); // "AppHelperBaseUrl"
  • 83. Criando Mapas Manualmente use ZendViewHelperLoader; $loader = new HelperLoader(); $loader->registerPlugin('url', 'KilowogHelperUrl') ->registerPlugins(array( 'base_url' => 'ProjectHelperBaseUrl', )); $class = $loader->load('url'); // "KilowogHelperUrl"
  • 84. Gerenciando Plugins via Agente  Por padrão, o carregador é consultado para um nome de classe, e instancia a classe com os argumentos dados  Opcionalmente, você pode alimentar o agente, registrando objetos plugins manualmente sob um dado nome
  • 85. Registrando um Plugin com o Agente use KilowogHelperUrl; // Assume: // - $request == objeto Request // - $router == objeto Router // - $broker == HelperBroker $url = new Url($request, $router); $broker->registerPlugin('url', $url); // OU: $broker->registerPlugins(array( 'url' => $url, )); $url = $broker->load('url'); // === $url acima
  • 86. E sobre o carregamento tardio?  Frequentemente você precisa configurar plugins  Mas você quer uma instância só quando ela for realmente requisitada  É aí que entra ZendLoaderLazyLoadingBroker
  • 87. LazyLoadingBroker Interface namespace ZendLoader; interface LazyLoadingBroker extends Broker { public function registerSpec($name, array $spec = null); public function registerSpecs($specs); public function unregisterSpec($name); public function getRegisteredPlugins(); public function hasPlugin($name); }
  • 88. Usando LazyLoadingBroker  Registra “especificações” com o agente  Quando o plugin é requisitado, as opções fornecidas serão usadas a menos que novas opções sejam passadas  De todas as outras maneiras, ele comporta-se como outros agentes, incluindo a permissão do registro explícito de plugins
  • 89. Usando LazyLoadingBroker $broker->registerSpec('url', array($request, $router)); $broker->registerSpecs(array( 'url' => array($request, $router), )); if (!$broker->hasPlugin('url')) { // sem especificação! } $plugins = $broker->getRegisteredPlugins(); // array('url') $url = $broker->load('url'); // Com $request, $router é injetado
  • 90. Usando LazyLoadingBroker via Configuração use ZendViewHelperBroker; $config = array( 'specs' => array( 'url' => array($request, $router), ), ); $broker = new HelperBroker($config); $url = $broker->load('url'); // Com $request, $router é injetado
  • 91. E ainda tem mais!
  • 94. Novos Componentes  ZendEventManager  ZendDi
  • 96. O Problema  Como nós introduzimos pontos de log/debug no código do framework?  Como nós permitimos que os usuários introduzam caching sem necessidade de estender o código do framework?  Como nós permitimos que os usuários introduzam validação, filtragem, verificações de controle de acesso, etc., sem necessariamente estender o código do framework?
  • 97. O Problema  Como permitirmos que os usuários manipulem a ordem na qual plugins, filtros de interceptação, eventos, etc., são disparados.  Como nós podemos prover ferramentas para o código do usuário trabalhe em prol das questões anteriores?
  • 98. Solução: Programação Orientada a Aspectos  O código define vários “aspectos” que podem ser interessantes observar e/ou anexar a partir de um consumidor.  Basicamente, todas as soluções que examinaremos podem ser usadas para implementar POA em um código base. www.fgsl.eti.br Palestras
  • 99. Requisitos  Projeto que seja razoavelmente fácil de entender.  Permitir anexar manipuladores de forma estática ou por instância, preferencialmente de ambas as formas.  Preferencialmente enquanto reter o estado não-global ou permitir sobrescrita.  Permitir interrupção da execução  Permitir a priorização de manipuladores
  • 100. Requisitos  Projeto que seja razoavelmente fácil de entender.  Permitir anexar manipuladores de forma estática ou por instância, preferencialmente de ambas as formas.  Preferencialmente enquanto reter o estado não-global ou permitir sobrescrita.  Permitir interrupção da execução  Permitir a priorização de manipuladores
  • 101. Requisitos  Previsibilidade de argumentos passados para manipuladores.  Habilidade de anexar a muitos componentes emissores de eventos de uma vez.
  • 102. Solução: Observador de Sujeitos  Prós  Simples de entender  Interfaces SPL são bem conhecidas (mas limitadas)  Contras  Tipicamente, não pode interromper a execução de observadores remanescentes  Requer um sistema para cada componente e/ou classe  Tipicamente, sem habilidade para priorizar manipuladores
  • 103. Solução: Publicador/Sobrescritor de Eventos  Prós  Sobrescrita de notificações arbitrárias  Tipicamente por componente + uso global; em muitas linguagens, um único agregador global  Paradigma bem-conhecido na programação de interfaces com o usuário (pense em Javascript)  Tende a ser um Turing completo
  • 104. Solução: Publicador/Sobrescritor de Eventos (PubSub)  Contras  Frequentemente, precisa testar o evento fornecido para garantir que você pode manipulá-lo.  Uso global implica em agregação estática e/ou dependências estáticas.  … mas o uso por componente implica em um boilerplate para compor em cada classe se ele for usado.  Tipicamente, sem habilidade para priorizar manipuladores.  Falaremos mais sobre isso mais tarde...
  • 105. Pausa para esclarecimento  boilerplate é o termo usado para descrever seções de código que foram incluídas em muitos lugares com pouca ou nenhuma alteração.
  • 106. Solução: SignalSlots  Prós  Conceito bem conhecido nos círculos de Ciência da Computação  O código emite sinais, que são interceptados por slots (vulgos manipuladores)  Tipicamente, compõe um gerenciador de sinais em uma classe, mas pode ser integrado com um gerenciador global também  Geralmente tem algumas habilidades para priorizar manipuladores
  • 107. Solução: SignalSlots  Contras  Esse palavreado não é bem conhecido entre programadores PHP.  Argumentos irão variar entre sinais.  Os mesmos problemas com composição por classe e uso estático como vemos em sistemas de eventos.
  • 108. Filtros de Interceptação  Prós  Similar às soluções anteriores, exceto que cada manipulador recebe a cadeia de filtros como um argumento, e é responsável por chamar o próximo na cadeia.  Frequentemente, o “trabalho” inteiro de um método é simplesmente um executar um filtro.  Dependendo do projeto, pode permitir acesso global/estático.
  • 109. Filtros de Interceptação  Contras  Algumas vezes é difícil acompanhar fluxos de trabalho complexos.  Os mesmos problemas com composição por classe e uso estático como vemos em sistemas de evento.  É fácil esquecer de invocar o próximo filtro na cadeia.  Tipicamente, sem habilidade de priorizar filtros.
  • 112. Todas!
  • 113. Combinação de Poderes Linka Wheeler Gi Ma-Ti Kwame
  • 114. ZF2: EventManager Component  A cereja do bolo de cada solução, PubSub, SignalSlot, e Filtros de Interceptação, para prover uma solução compreensiva.  Não pode resolver completamente os problemas de composição/uso estático.  Nós podemos resolver o problema da composição no PHP 5.4 com Traits.  Há formas elegantes de manipular o uso estático.
  • 115. Interface EventCollection namespace ZendEventManager; use ZendStdlibCallbackHandler; interface EventCollection { public function trigger($event, $context, $argv = array()); public function triggerUntil($event, $context, $argv, $callback); public function attach($event, $callback, $priority = 1); public function detach(CallbackHandler $handle); public function getEvents(); public function getHandlers($event); public function clearHandlers($event); }
  • 116. Disparando Eventos use ZendEventManagerEventManager; $events = new EventManager(); $events->trigger($eventName, $object, $params); /* Onde: * - $eventName é o nome do evento; geralmente o nome do evento atual * * - $object é o objeto que está disparando o evento * - $params são os parâmetros que o manipulador pode precisar para ter acesso, geralmente os argumentos do método * */
  • 117. CallbackHandler $handler = $events->attach('algum-evento', function($e) use ($log) { $event = $e->getName(); $context = get_class($e->getTarget()); $params = json_encode($e->getParams()); $log->info(sprintf("%s: %s: %s", $event, $context, $params)); });
  • 118. Callback Handler com Prioridade $handler = $events->attach('algum-evento', function($e) use ($log) { /* o mesmo que o anterior */ }, 100); // Priorize! (números altos ganham)
  • 119. Interrompendo a Execução: Testando Resultados $results = $events->triggerUntil('algum-evento', $o, $argv, function($result) { return ($result instanceof SomeType); }); if ($results->stopped()) { return $results->last(); }
  • 120. Interrompendo a Execução: via Manipuladores $events->attach('algum-evento', function($e) { $result = new Result; $e->stopPropagation(true); return $result; }); $results = $events->trigger('algum-evento', $object, $params); if ($results->stopped()) { return $results->last(); }
  • 121. Compondo um EventManager use ZendEventManagerEventCollection as Events, ZendEventManagerEventManager; class Arisia { protected $events; public function events(Events $events = null) { if (null !== $events) { $this->events = $events; } elseif (null === $this->events) { $this->events = new EventManager(__CLASS__); } return $this->events; } public function doSomething($param1, $param2) { $params = compact('param1', 'param2'); $this->events()->trigger(__FUNCTION__, $this, $params); } }
  • 122. Usando um Trait! use ZendEventManagerEventCollection as Events, ZendEventManagerEventManager; trait Eventful { public function events(Events $events = null) { if (null !== $events) { $this->events = $events; } elseif (null === $this->events) { $this->events = new EventManager(__CLASS__); } return $this->events; } } class Arisia { use Eventful; protected $events; }
  • 123. Conectando Manipuladores Estaticamente use ZendEventManagerStaticEventManager; $events = StaticEventManager::getInstance(); $events->connect('Arisia', 'algum-evento', function ($e) { /* ... */ });
  • 124. Recomendações  Nomeie seus eventos usando __FUNCTION__  Se disparar múltiplos eventos no mesmo método, sufixe com um “.(pre|pos|etc.)”  Forneça para o construtor do EventManager tanto o nome da classe quanto um ou mais nomes de “serviços”, para fazer anexações estáticas mais semânticas.  Isso permite que um único callback ouça muitos componentes!
  • 126. O Que é Injeção de Dependência?  Muito simples: definir modos de passar dependências para dentro de um objeto. namespace TomarreHelper; class Url { public function __construct(Request $request) { $this->request = $request; } public function setRouter(Router $router) { $this->router = $router; } }
  • 127. Então porque as pessoas tem medo disso?  Porque elas não fazem isso.  Elas temem os Conteineres de Injeção de Dependência.
  • 128. O Que é um Conteiner de Injeção de Dependência Colocando de forma simples: Um grafo de objetos para mapear relações de dependência entre objetos.
  • 129. Grafos
  • 130. Novamente, por que as pessoas tem medo disso? Porque parece mágica!
  • 131. Objeto com Dependências namespace TomarreHelper; class Url { public function __construct(Request $request) { $this->request = $request; } public function setRouter(Router $router) { $this->router = $router; } }
  • 132. Outro Objeto com Dependências namespace mwopMvc; class Router { public function addRoute(Route $route) { $this->routes->push($route); } }
  • 133. Agarrando um Objeto e Usando-o $urlHelper = $di->get('url-helper'); echo $url->generate('/css/site.css'); echo $url->generate(array('id' => $id), array('name' => 'blog'));
  • 134. As Questões  Como eu posso estar certo se eu tenho minhas dependências?  Você as define explicitamente.  Você recupera o objeto via conteiner, o que garante que as definições são usadas.  Onde eu defino essas coisas?  Programaticamente, via configuração, ou usando uma ferramenta.
  • 135. As Questões  Se eu chamar $object = new Salaak(), como eu forço o uso de diferentes dependências?  Chamar new não usa o conteiner. Na verdade, nada força você a usá-lo!
  • 136. Por que usar um?  Se a instanciação de seus objetos não está debaixo de seu controle direto (por exemplo, controladores), como você retém controle sobre suas dependências?  Acesso a dados diferente baseado no ambiente da aplicação.  Substituição de implementações mock/stub durante o teste.
  • 137. Abordagem ZF2  Padronizar em uma interface de localizador de serviços.  Prover uma solução DI performática, e integrá- la dentro de um localizador de serviços.  Prover ferramentas para auxiliar na criação de definições de DI durante o desenvolvimento.
  • 138. Interface para Localizador de Serviços namespace ZendDi; interface ServiceLocation { public function set($name, $service); public function get($name, array $params = null); }
  • 139. Interface para Injetor de Dependências namespace ZendDi; interface DependencyInjection { public function get($name, array $params = null); public function newInstance($name, array $params = null); public function setDefinitions($definitions); public function setDefinition( DependencyDefinition $definition, $serviceName = null); public function setAlias($alias, $serviceName); public function getDefinitions(); public function getAliases(); }
  • 140. Definições namespace ZendDi; interface DependencyDefinition { public function __construct($className); public function getClass(); public function setConstructorCallback($callback); public function getConstructorCallback(); public function hasConstructorCallback(); public function setParam($name, $value); public function setParams(array $params); public function setParamMap(array $map); public function getParams(); public function setShared($flag = true); public function isShared(); public function addTag($tag); public function addTags(array $tags); public function getTags(); public function hasTag($tag); public function addMethodCall($name, array $args); public function getMethodCalls(); }
  • 141. Referências namespace ZendDi; interface DependencyReference { public function __construct($serviceName); public function getServiceName(); }
  • 142. Definição de Classe use ZendDiDefinition, ZendDiReference; $mongo = new Definition('Mongo'); $mongoDB = new Definition('MongoDB'); $mongoDB->setParam('conn', new Reference('mongo')) ->setParam('name', 'test'); $coll = new Definition('MongoCollection'); $coll->setParam('db', new Reference('mongodb')) ->setParam('name', 'resource'); $di->setDefinitions(array( 'mongo'=> $mongo, 'mongodb' => $mongoDB, 'resource' => $coll, )); $resource = $di->get('resource');
  • 143. Injeção por Modificador use ZendDiDefinition, ZendDiReference; $service = new Definition('mwopServiceResources'); $service->addMethod('setResource', array( new Reference('resource') )); $di->setDefinition('resources', $service); $resources = $di->get('resources');
  • 144. Fazendo mais Rápido  Especificar mapas de parâmetros de construtor em definições.  Gerar localizadores de serviço a partir de um conteiner DI.
  • 145. Mapas de Parâmetros $mongoDB->setParam('conn', new Reference('mongo')) ->setParam('name', 'test') ->setParamMap(array( 'conn' => 0, 'name' => 1, )); // Garante que os parâmetros estão em ordem, sem precisar // recorrer à API de reflexão
  • 146. Gerando um Localizador de Serviços a partir de DI use ZendDiContainerBuilder as DiBuilder; $builder = new DiBuilder($injector); $builder->setContainerClass('AppContext'); $container = $builder->getCodeGenerator( __DIR__ . '/../application/AppContext.php' ); // Retorna uma instância de ZendCodeGeneratorPhpPhpFile $container->write(); // Grava no disco
  • 147. Exemplo de um localizador gerado use ZendDiDependencyInjectionContainer; class AppContext extends DependencyInjectionContainer { public function get($name, array $params = array()) { switch ($name) { case 'request': case 'ZendHttpRequest': return $this->getZendHttpRequest(); default: return parent::get($name, $params); } } public function getZendHttpRequest() { if (isset($this->services['ZendHttpRequest'])) { return $this->services['ZendHttpRequest']; } $object = new ZendHttpRequest(); $this->services['ZendHttpRequest'] = $object; return $object; } }
  • 148. Usando um localizador gerado $context = new AppContext(); $request = $context->get('request'); // O mesmo que usar um localizador de serviços ou um conteiner DI!
  • 149. Fazendo mais simples ainda  Use arquivos de configuração  Você pode usar qualquer formato suportado por ZendConfig:  INI  JSON  XML  YAML
  • 150. Exemplo de configuração com JSON { "production": { "definitions": [ { "class": "Mongo" }, { "class": "MongoDB", "params": { "conn": {"__reference": "mongocxn"}, "name": "mwoptest" }, "param_map": { "conn": 0, "name": 1 } }, { "class": "MongoCollection", "params": { "db": {"__reference": "MongoDB"}, "name": "entries" }, "param_map": { "db": 0, "name": 1 } } ], "aliases": { "mongocxn": "Mongo", "mongo-collection-entries": "MongoCollection" } } }
  • 151. Quais são os casos de uso no ZF2?  Um grandão. Tirar os controladores MVC do conteiner
  • 152. Um Controlador de Ação namespace BlogController; class Entry implements Dispatchable { public function setResource(Resource $resource) { $this->resource = $resource; } public function dispatch(Request $request, Response $response = null) { /* ... */ $entry = $this->resource->get($id); /* ... */ } }
  • 153. O Controlador Frontal class FrontController implements Dispatchable { public function __construct(DependencyInjection $di) { $this->di = $di; } public function dispatch(Request $request, Response $response = null) { /* ... */ $controller = $this->di->get($controllerName); $result = $controller->dispatch($request, $response); /* ... */ } }
  • 154. Benefícios de usar DI deste modo  Performance  Desacoplamento de código  Simplificação do código do controlador
  • 155. E vem mais por aí  Compilação na primeira execução.  Ferramentas para vasculhar classes ou namespaces para construir definições.  Injeção de interface.  … e mais coisas legais.
  • 158. Os Problemas  Como os controladores obtém dependências?  Como nós acomodamos diferentes padrões de controladores?  E se se nós quisermos uma seleção de ações mais apurada, baseada em outros dados no ambiente de requisição?  E se quisermos passar argumentos para nomes de ações, ou argumentos pré-validados?  E se nós não gostarmos do sufixo “Action” nos métodos acionadores?  E se...
  • 159. Os Problemas  Como nós podemos melhorar o uso de componentes do servidor dentro do MVC?  Como nós podemos fazer o MVC mais performático?
  • 160. A estrutura básica de uma aplicação web é a de um ciclo de vida Requisição/Resposta
  • 161. A interface Dispatchable namespace ZendStdlib; interface Dispatchable { public function dispatch( Request $request, Response $response = null ); }
  • 162. Requisição e Resposta  Tanto a Requisição quanto a Resposta simplesmente agregam metadados e conteúdo.  A Resposta também tem a habilidade de enviar a si mesma.  Variantes específicas de HTTP serão o núcleo do MVC.  Para prover conveniência em torno de variáveis superglobais, cookies e tarefas comuns tais como determinar os cabeçalhos Accept e Content-Type.
  • 163. Qualquer Dispatchable pode anexar ao MVC Dispatchable é simplesmente uma formalização do padrão de projeto Command.  Controladores  Servidores  Qualquer coisa que você sonhar! Apenas implemente Dispatchable!
  • 164. Um protótipo simples de um Controlador Frontal public function dispatch(Request $request, Response $response = null) { $params = compact('request', 'response'); $this->events()->trigger(__FUNCTION__ . '.route.pre', $this, $params); $result = $this->getRouter()->route($request); if (!$result) { $result = array('controller' => 'page', 'page' => 404); } $params['routing'] = (object) $result; $this->events()->trigger(__FUNCTION__ . '.route.post', $params); $controller = $this->di->get($params['routing']->controller); if (!$controller instanceof Dispatchable) { $controller = new NotFoundController(); } $result = $controller->dispatch($request, $response); $params['__RESULT__'] = $result; $this->events()->trigger(__FUNCTION__ . '.dispatch.post', $params); return $response; }
  • 165. Contexto Temporal  Quando esta apresentação foi finalizada, o último release do Zend Framework 1 era o 1.11.11 e o Zend Framework 2 estava na versão 2.0.0beta1.
  • 166. Mais informações  http://framework.zend.com  https://github.com/zendframework/zf2  www.fgsl.eti.br  Aguarde... treinamentos de arquitetura, migração, e desenvolvimento.  Pra quem quer sair na frente, Mão na Massa MVC Zend Framework 2!  Coming soon 2012!