Zend Framework - Guia Rápido

Um PHP Web Framework é uma coleção de classes que ajuda a desenvolver um aplicativo da web. Zend é um dos frameworks PHP mais populares. É umopen-source MVC frameworkpara desenvolvimento rápido de aplicativos da web modernos. Zend Framework tem vários componentes fracamente acoplados, por isso é referido como “Biblioteca de Componentes”. Zend Framework fornece qualquer pilha PHP e servidor Zend para executar aplicativos Zend Framework.

Zend Studio é um IDE que inclui recursos para integração com Zend Framework. Ele fornece visualização MVC e geração de código. O Zend framework 3.0 atual inclui novos componentes como servidor JSON RPC, um conversor XML para JSON, funcionalidade PSR-7 e compatibilidade com PHP 7.

Zend Framework 2 é uma estrutura de código aberto para o desenvolvimento de aplicativos e serviços da web usando PHP 5.3+. Zend Framework 2 usa código 100% orientado a objetos e utiliza a maioria dos novos recursos do PHP 5.3, a saberNamespaces, Lambda Functions e Closures.

O Zend Framework 2 evoluiu do Zend Framework 1, um framework PHP de sucesso com mais de 15 milhões de downloads. Zend Server tem uma versão da comunidade gratuita e uma versão comercial.

Recursos do Zend Framework

Algumas das características salientes do Zend Framework são as seguintes -

  • Framework de aplicativo da web orientado a objeto puro
  • Implementação MVC avançada
  • Suporta vários bancos de dados, incluindo PostgreSQL, SQLite etc.,
  • API de nuvem simples
  • Gerenciamento de sessão
  • Criptografia de dados
  • Roteamento URI Flexível
  • Zend fornece suporte ao desenvolvimento de API RESTful.
  • Código reutilizável e mais fácil de manter.

Por que Zend Framework?

O que torna o Zend Framework um dos principais frameworks usados ​​por desenvolvedores de PHP é que ele fornece código limpo e estável completo com direitos de propriedade intelectual. Também torna a programação mais fácil. É uma estrutura rápida, fácil de aprender e conveniente. Zend oferece suporte a ferramentas de criptografia fortes e técnicas de hashing de senha.

Zend Goals

A seguir estão os objetivos do Zend Framework.

  • Flexibility
  • Simples e produtivo
  • Compatibility
  • Extensibilidade - o programador pode facilmente estender todas as classes do framework.
  • Portabilidade - Suporta vários ambientes

Aplicativos Zend

Os produtos populares a seguir são desenvolvidos usando o Zend Framework.

  • Site da McAfee Company
  • Site da empresa IBM
  • Magento - um dos sites populares de carrinho de compras.

Vantagens do Zend Framework

Algumas das vantagens do Zend Framework estão listadas abaixo.

  • Loosely Coupled - Zend oferece a opção de excluir módulos ou componentes que não precisamos no aplicativo.

  • Performance- Zend Framework é altamente otimizado para desempenho. Zend Framework 3 é 4x mais rápido que sua versão anterior.

  • Security - A estrutura suporta criptografia padrão da indústria.

  • Testing - PHPUnit é integrado com Zend para que você possa testar facilmente o framework.

No próximo capítulo, aprenderemos como instalar o Zend Framework.

Para instalar o Zend Framework, devemos primeiro instalar o Composer e a última versão do PHP conforme mostrado nas etapas a seguir.

  • Install Composer- Zend usa o Composer para gerenciar suas dependências, portanto, certifique-se de ter o Composer instalado em sua máquina. Se o Composer não estiver instalado, visite o site oficial do Composer e instale-o.

  • Install the latest version of PHP- Para obter o máximo benefício do Zend Framework, instale a versão mais recente do PHP. A versão mínima exigida para Zend Framework 3 é PHP 5.6 ou posterior.

Instale Zend Framework

O Zend Framework pode ser instalado de duas maneiras. Eles são os seguintes -

  • Instalação manual
  • Instalação baseada no Composer

Vamos discutir essas duas instalações em detalhes.

Instalação Manual

Baixe a versão mais recente do Zend Framework visitando o seguinte link - https://framework.zend.com/downloads/archives

Extraia o conteúdo do arquivo baixado para a pasta que deseja mantê-lo. Assim que você tiver uma cópia do Zend Framework disponível em sua máquina local, seu aplicativo da web baseado em Zend Framework pode acessar as classes do framework. Embora existam várias maneiras de fazer isso, seu PHPinclude_pathprecisa conter o caminho para as classes Zend Framework no diretório / library na distribuição. Este método se aplica ao Zend Framework versão 2.4 e anteriores apenas.

Instalação baseada no Composer

Para instalar facilmente o Zend Framework, use a ferramenta Composer. Este é o método preferido para instalar a versão mais recente do Zend Framework. Para instalar todos os componentes do Zend Framework, use o seguinte comando Composer -

$ composer require zendframework/zendframework

Cada módulo / componente Zend Framework também pode ser instalado individualmente. Por exemplo, para instalar oMVC component do Zend Framework, use o seguinte composer comando -

$ composer require zendframework/zend-mvc

Vamos criar um esqueleto de aplicação usando a camada Zend Framework MVC e os sistemas de módulo.

Instalação usando Composer

A maneira mais fácil de criar um novo projeto Zend Framework é usar um Composer. É definido como abaixo -

$ cd /path/to/install $ composer create-project -n -sdev zendframework/skeleton-application myapp

Você veria o seguinte resultado em sua tela -

Installing zendframework/skeleton-application (dev-master 
   941da45b407e4f09e264f000fb537928badb96ed)
   - Installing zendframework/skeleton-application (dev-master master)
   Cloning master

Created project in myapp
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
   - Installing zendframework/zend-component-installer (0.3.0)
   Loading from cache
  
   - Installing zendframework/zend-stdlib (3.0.1)
   Loading from cache
   
   - Installing zendframework/zend-config (2.6.0)
   Loading from cache
   
   - Installing zendframework/zend-loader (2.5.1)
   Loading from cache
   
   - Installing zendframework/zend-eventmanager (3.0.1)
   Loading from cache
   
   - Installing zendframework/zend-view (2.8.0)
   Loading from cache
   
   - Installing container-interop/container-interop (1.1.0)
   Loading from cache
   
   - Installing zendframework/zend-servicemanager (3.1.0)
   Loading from cache
   
   - Installing zendframework/zend-validator (2.8.1)
   Loading from cache
   
   - Installing zendframework/zend-escaper (2.5.1)
   Loading from cache
   
   - Installing zendframework/zend-uri (2.5.2)
   Loading from cache
   
   - Installing zendframework/zend-http (2.5.4)
   Loading from cache
   
   - Installing zendframework/zend-router (3.0.2)
   Loading from cache
   
   - Installing zendframework/zend-modulemanager (2.7.2)
   Loading from cache

   - Installing zendframework/zend-mvc (3.0.1)
   Loading from cache
   
   - Installing zendframework/zend-skeleton-installer (0.1.3)
   Loading from cache
   
   - Installing zfcampus/zf-development-mode (3.0.0)
   Loading from cache
zendframework/zend-config suggests installing zendframework/zend-filter
   (Zend\Filter component)
zendframework/zend-config suggests installing zendframework/zend-i18n
   (Zend\I18n component)
zendframework/zend-config suggests installing zendframework/zend-json
   (Zend\Json to use the Json reader or writer classes)
zendframework/zend-view suggests installing zendframework/zend-authentication
   (Zend\Authentication component)
zendframework/zend-view suggests installing zendframework/zend-feed
   (Zend\Feed component)
zendframework/zend-view suggests installing zendframework/zend-filter
   (Zend\Filter component)
zendframework/zend-view suggests installing zendframework/zend-i18n
   (Zend\I18n component)
zendframework/zend-view suggests installing zendframework/zend-json
   (Zend\Json component)
zendframework/zend-view suggests installing zendframework/zend-navigation
   (Zend\Navigation component)
zendframework/zend-view suggests installing zendframework/zend-paginator
   (Zend\Paginator component)
zendframework/zend-view suggests installing zendframework/zend-permissions-acl
   (Zend\Permissions\Acl component)
zendframework/zend-servicemanager suggests installing ocramius/proxy-manager
   (ProxyManager 1.* to handle lazy initialization of services)
zendframework/zend-validator suggests installing zendframework/zend-db
   (Zend\Db component)
zendframework/zend-validator suggests installing zendframework/zend-filter
   (Zend\Filter component, required by the Digits validator)
zendframework/zend-validator suggests installing zendframework/zend-i18n
   (Zend\I18n component to allow translation of validation error messages as well as
   to use the various Date validators)
zendframework/zend-validator suggests installing zendframework/zend-i18nresources
   (Translations of validator messages)
zendframework/zend-validator suggests installing zendframework/zend-math
   (Zend\Math component)
zendframework/zend-validator suggests installing zendframework/zend-session
   (Zend\Session component)
zendframework/zend-router suggests installing zendframework/zend-i18n
   (^2.6, if defining translatable HTTP path segments)

zendframework/zend-modulemanager suggests installing zendframework/zend-console
   (Zend\Console component)
zendframework/zend-mvc suggests installing zendframework/zend-json ((^2.6.1 ||
   ^3.0) To auto-deserialize JSON body content in AbstractRestfulController
   extensions, when json_decode is unavailable)
zendframework/zend-mvc suggests installing zendframework/zend-mvc-console
   (zend-mvc-console provides the ability to expose zend-mvc as a console application)
zendframework/zend-mvc suggests installing zendframework/zend-mvc-i18n
   (zendmvc-i18n provides integration with zend-i18n, including a translation bridge
   and translatable route segments)
zendframework/zend-mvc suggests installing zendframework/zend-mvc-pluginfileprg
   (To provide Post/Redirect/Get functionality around forms that container
   file uploads)
zendframework/zend-mvc suggests installing zendframework/zend-mvc-pluginflashmessenger
   (To provide flash messaging capabilities between requests)
zendframework/zend-mvc suggests installing zendframework/zend-mvc-pluginidentity
   (To access the authenticated identity (per zend-authentication) in controllers)
zendframework/zend-mvc suggests installing zendframework/zend-mvc-plugin-prg
   (To provide Post/Redirect/Get functionality within controllers)
zendframework/zend-mvc suggests installing zendframework/zend-psr7bridge
   ((^0.2) To consume PSR-7 middleware within the MVC workflow)
zendframework/zend-mvc suggests installing zendframework/zend-servicemanager-di
   (zend-servicemanager-di provides utilities for integrating zend-di and
   zendservicemanager in your zend-mvc application)

Generating autoload files
   Removing optional packages from composer.json
   Updating composer.json
Removing zendframework/zend-skeleton-installer...
   - Removing zendframework/zend-skeleton-installer (0.1.3)
   Removed plugin zendframework/zend-skeleton-installer.
   Removing from composer.json
   Complete!
> zf-development-mode enable
You are now in development mode.

Agora que o aplicativo está instalado, você pode testá-lo imediatamente usando o PHP's built-in web server -

$ cd path/to/install/myapp $ composer serve

Então você veria a seguinte resposta -

> php -S 0.0.0.0:8080 -t public/ public/index.php

Isso iniciará o servidor CLI embutido em PHP na porta 8080. Assim que o servidor de desenvolvimento for iniciado, você pode visitar o site em (http://localhost:8080/). O servidor CLI integrado é apenas para desenvolvimento.

Testes Unitários

Para executar os testes de unidade de esqueleto, digite o seguinte comando em seu terminal.

$ composer require --dev zendframework/zend-test

Isso produzirá a seguinte resposta -

Using version ^3.0 for zendframework/zend-test 
   ./composer.json has been updated 
Loading composer repositories with package information 
Updating dependencies (including require-dev) 
   - Installing zendframework/zend-dom (2.6.0) 
   Loading from cache  
   
   - Installing zendframework/zend-console (2.6.0) 
   Loading from cache  
   
   - Installing sebastian/version (2.0.1) 
   Loading from cache 
   
   - Installing symfony/yaml (v3.2.1)
   Downloading: 100%           
   
   - Installing sebastian/resource-operations (1.0.0) 
   Loading from cache  
   
   - Installing sebastian/recursion-context (2.0.0) 
   Loading from cache  
   
   - Installing sebastian/object-enumerator (2.0.0) 
   Loading from cache  
   
   - Installing sebastian/global-state (1.1.1) 
   Loading from cache  
   
   - Installing sebastian/exporter (2.0.0) 
   Loading from cache  
   
   - Installing sebastian/environment (2.0.0) 
   Loading from cache  
   
   - Installing sebastian/diff (1.4.1) 
   Loading from cache  
   
   - Installing sebastian/comparator (1.2.2) 
   Loading from cache  
   
   - Installing phpunit/php-text-template (1.2.1) 
   Loading from cache  
   
   - Installing doctrine/instantiator (1.0.5) 
   Loading from cache  
   
   - Installing phpunit/phpunit-mock-objects (3.4.3) 
   Downloading: 100%          
   
   - Installing phpunit/php-timer (1.0.8)
   Loading from cache  
   
   - Installing phpunit/php-file-iterator (1.4.2) 
   Loading from cache  
   
   - Installing sebastian/code-unit-reverse-lookup (1.0.0) 
   Loading from cache  
   
   - Installing phpunit/php-token-stream (1.4.9) 
   Loading from cache  
   
   - Installing phpunit/php-code-coverage (4.0.4) 
   Downloading: 100%           
   
   - Installing webmozart/assert (1.2.0) 
   Loading from cache  
   
   - Installing phpdocumentor/reflection-common (1.0) 
   Loading from cache  
   
   - Installing phpdocumentor/type-resolver (0.2.1) 
   Loading from cache  
   
   - Installing phpdocumentor/reflection-docblock (3.1.1) 
   Loading from cache  
   
   - Installing phpspec/prophecy (v1.6.2) 
   Loading from cache  
   
   - Installing myclabs/deep-copy (1.5.5) 
   Loading from cache  
   
   - Installing phpunit/phpunit (5.7.4) 
   Downloading: 100%          
   
   - Installing zendframework/zend-test (3.0.2) 
   Loading from cache

zendframework/zend-console suggests installing zendframework/zend-filter 
   (To support DefaultRouteMatcher usage) 
symfony/yaml suggests installing symfony/console (For validating YAML files 
   using the lint command) 
sebastian/global-state suggests installing ext-uopz (*) 
phpunit/phpunit-mock-objects suggests installing ext-soap (*) 
phpunit/php-code-coverage suggests installing ext-xdebug (>=2.4.0) 
phpunit/phpunit suggests installing phpunit/php-invoker (~1.1) 
phpunit/phpunit suggests installing ext-xdebug (*) 
zendframework/zend-test suggests installing zendframework/zend-mvc-console 
   (^1.1.8, to test MVC <-> console integration) 
Writing lock file 
Generating autoload files

Agora o suporte de teste está habilitado para que você possa executar o teste usando o seguinte comando.

$ ./vendor/bin/phpunit

Apache Web Server

Hospedar o aplicativo baseado em Zend Framework no ambiente de produção é muito simples e direto. Basta criar umVirtualHost no arquivo de configuração do Apache e aponte o DocumentRoot ao Public pasta do aplicativo Zend Framework.

Um exemplo de configuração (myapp) é fornecido abaixo -

<VirtualHost *:80> 
   ServerName myapp.localhost 
   DocumentRoot /path/to/install/myapp/public 
   <Directory /path/to/install/myapp/public> 
      DirectoryIndex index.php 
      AllowOverride All 
      Order allow,deny 
      Allow from all 
      <IfModule mod_authz_core.c> 
         Require all granted 
      </IfModule> 
   </Directory> 
</VirtualHost>

Antes de prosseguir com este capítulo, vamos ter uma breve compreensão do MVC. UMAModel View Controlleré uma abordagem de software que separa a lógica do aplicativo da apresentação. Na prática, permite que as páginas da Web contenham um mínimo de scripts PHP, já que a apresentação é separada dele.

A breve descrição dos componentes MVC é a seguinte

  • Model- O modelo representa a estrutura dos dados do aplicativo. Normalmente, as classes de modelo contêm funções que ajudam aretrieve, insert e update business data no banco de dados back-end (MySQL, PostgreSQL, etc.).

  • View- Visualização é a camada de apresentação do aplicativo MVC. Ele obtém os dados dos modelos por meio do Controlador e os exibe conforme necessário. É fracamente acoplado aoController e a Model e, portanto, pode ser alterado sem afetar o Modelo e o Controlador.

  • Controller- O controlador é o principal componente da arquitetura MVC. Cada solicitação atinge primeiro o controlador. Em outras palavras, o controlador processa todas as solicitações e atua como um intermediário entre o modelo, a visualização e quaisquer outros recursos necessários paraprocess the HTTP request e para gerar a resposta.

No próximo capítulo, vamos entender os diferentes conceitos do Zend Framework.

Zend Framework é uma coleção de mais de 60 componentes. Eles estão vagamente conectados um com o outro. Eles podem ser usados ​​como componentes independentes ou como um grupo de componentes trabalhando como uma única unidade.

Zend Framework fornece três componentes mais importantes, que são -

  • zend-servicemanager
  • zend-eventmanager e
  • zend-modulemanager.

Eles fornecem aos componentes Zend a capacidade de integração com outros componentes de forma eficiente.

  • Event Manager- Oferece a capacidade de criar programação baseada em eventos. Isso ajuda a criar, injetar e gerenciar novos eventos.

  • Service Manager - Dá a capacidade de consumir qualquer serviço (classes PHP) de qualquer lugar com um pouco de esforço.

  • Module Manager - Capacidade de converter uma coleção de classes PHP com funcionalidade semelhante em uma única unidade chamada de module. Os módulos recém-criados podem ser usados, mantidos e configurados como uma unidade única.

Abordaremos esses conceitos em detalhes nos capítulos subsequentes.

O Zend Framework inclui uma implementação de padrão de localizador de serviço poderosa chamada zend-servicemanager. O Zend framework usa extensivamente o gerenciador de serviços para todas as suas funcionalidades. O Service Manager fornece uma abstração de alto nível para o Zend Framework. Ele também se integra perfeitamente com todos os outros componentes do Zend Framework.

Instale o Service Manager

O componente Service Manager pode ser instalado usando o composer ferramenta.

composer require zendframework/zend-servicemanager

Exemplo

Primeiro, todos os serviços precisam ser registrados no gerenciador de serviços. Uma vez que os serviços são registrados no sistema gerenciador do servidor, ele pode ser acessado a qualquer momento com o mínimo de esforço. O gerenciador de serviço oferece várias opções para registrar o serviço. Um exemplo simples é o seguinte -

use Zend\ServiceManager\ServiceManager; 
use Zend\ServiceManager\Factory\InvokableFactory; 
use stdClass;  
$serviceManager = new ServiceManager([ 
   'factories' => [stdClass::class => InvokableFactory::class,], 
]);

O código acima registra o stdClass no sistema usando o Factoryopção. Agora, podemos obter uma instância de stdClass a qualquer momento usando oget() método do gerente de serviço conforme mostrado abaixo.

use Zend\ServiceManager\ServiceManager;  
$object = $serviceManager->get(stdClass::class);

O método get () compartilha o objeto recuperado e, portanto, o objeto retornado ao chamar o método get () várias vezes é uma única e mesma instância. Para obter uma instância diferente a cada vez, o gerente de serviço fornece outro método, que é obuild() método.

use Zend\ServiceManager\ServiceManager;  
$a = $serviceManager->build(stdClass::class); $b = $serviceManager->build(stdClass::class);

Registro de gerente de serviço

O gerenciador de serviço fornece um conjunto de métodos para registrar um componente. Alguns dos métodos mais importantes são os indicados abaixo -

  • Método de fábrica
  • Método de fábrica abstrato
  • Método inicializador
  • Método de fábrica de delegador

Discutiremos cada um deles em detalhes nos próximos capítulos.

Método de Fábrica

A factory is basically any callable or any class that implements the FactoryInterface (Zend\ServiceManager\Factory\FactoryInterface).

The FactoryInterface has a single method −

public function __invoke(ContainerInterface $container, $requestedName, array $options = null)

The arguments details of the FactoryInterface is as follows −

  • container (ContainerInterface) − It is the base interface of the ServiceManager. It provides an option to get other services.

  • requestedName − It is the service name.

  • options − It gives additional options needed for the service.

Let us create a simple class implementing the FactoryInterface and see how to register the class.

Class Test - Object to be Retrieved

use stdClass;  
class Test { 
   public function __construct(stdClass $sc) { // use $sc 
   } 
}

The Test class depends on the stdClass.

Class TestFactory - Class to Initialize Test Object

class TestFactory implements FactoryInterface { 
   public function __invoke(ContainerInterface $container, $requestedName, 
      array $options = null) { $dep = $container->get(stdClass::class); return new Test($dep); 
   } 
}

The TestFactory uses a container to retrieve the stdClass, creates the instance of the Test class, and returns it.

Registration and Usage of the Zend Framework

Let us now understand how to register and use the Zend Framework.

serviceManager $sc = new ServiceManager([ 'factories' => [stdClass::class => InvokableFactory::class, Test::class => TestFactory::class] ]); $test = $sc->get(Test::class);

The service manager provides a special factory called InvokableFactory to retrieve any class which has no dependency. For example, the stdClass can be configured using the InvokableFactory since the stdClass does not depend on any other class.

serviceManager $sc = new ServiceManager([ 
   'factories' => [stdClass::class => InvokableFactory::class] 
]);  
$stdC = $sc->get(stdClass::class);

Another way to retrieve an object without implementing the FactoryInterface or using the InvokableFactory is using the inline method as given below.

$serviceManager = new ServiceManager([ 'factories' => [ stdClass::class => InvokableFactory::class, Test::class => function(ContainerInterface $container, $requestedName) { $dep = $container->get(stdClass::class); return new Test($dep); 
      }, 
   ], 
]);

Abstract Factory Method

Sometimes, we may need to create objects, which we come to know only at runtime. This situation can be handled using the AbstractFactoryInterface, which is derived from the FactoryInterface.

The AbstractFactoryInterface defines a method to check whether the object can be created at the requested instance or not. If object creation is possible, it will create the object using the __invokemethod of the FactoryInterface and return it.

The signature of the AbstractFactoryInterface is as follows −

public function canCreate(ContainerInterface $container, $requestedName)

Initializer Method

The Initializer Method is a special option to inject additional dependency for already created services. It implements the InitializerInterface and the signature of the sole method available is as follows −

public function(ContainerInterface $container, $instance)  
function(ContainerInterface $container, $instance) { 
   if (! $instance instanceof EventManagerAwareInterface) { return; } $instance->setEventManager($container->get(EventManager::class)); 
}

In the above example, the method checks whether the instance is of type EventManagerAwareInterface. If it is of type EventManagerAwareInterface, it sets the event manager object, otherwise not. Since, the method may or may not set the dependency, it is not reliable and produces many runtime issues.

Delegator Factory Method

Zend Framework supports delegators pattern through DelegatorFactoryInterface. It can be used to decorate the service.

The signature of this function is as follows −

public function __invoke(ContainerInterface $container, 
   $name, callable $callback, array $options = null 
);

Here, the $callback is responsible for decorating the service instance.

Lazy Services

Lazy service is one of those services which will not be fully initialized at the time of creation. They are just referenced and only initialized when it is really needed. One of the best example is database connection, which may not be needed in all places. It is an expensive resource as well as have time-consuming process to create. Zend framework provides LazyServiceFactory derived from the DelegatorFactoryInterface, which can produce lazy service with the help of the Delegator concept and a 3rd party proxy manager, which is called as the ocramius proxy manager.

Plugin Manager

Plugin Manager extends the service manager and provides additional functionality like instance validation. Zend Framework extensively uses the plugin manager.

For example, all the validation services come under the ValidationPluginManager.

Configuration Option

The service manager provides some options to extend the feature of a service manager. They are shared, shared_by_default and aliases. As we discussed earlier, retrieved objects are shared among requested objects by default and we can use the build() method to get a distinct object. We can also use the shared option to specify which service to be shared. The shared_by_default is same as the shared feature, except that it applies for all services.

$serviceManager = new ServiceManager([ 
   'factories' => [ 
      stdClass::class => InvokableFactory::class 
   ], 
   'shared' => [ 
      stdClass::class => false // will not be shared 
   ], 
   'shared_by_default' => false, // will not be shared and applies to all service 
]);

The aliases option can be used to provide an alternative name to the registered services. This have both advantages and disadvantages. On the positive side, we can provide alternative short names for a service. But, at the same time, the name may become out of context and introduce bugs.

aliases' => ['std' => stdClass::class, 'standard' => 'std']

All modern applications need solid and flexible event components. Zend Framework provides one such component, zend-eventmanager. The zend-eventmanager helps to design high level architecture and supports subject/observer pattern and aspect oriented programming.

Install Event Manager

The event manager can be installed using the Composer as specified below −

composer require zendframework/zend-eventmanager

Concepts of the Event Manager

The core concepts of the event manager are as follows −

  • Event − Event is arbitrarily named action, say greet.

  • Listener − Any PHP callback. They are attached to the events and gets called when the event is triggered. The default signature of Listener is −

function(EventInterface $e)
  • EventInterface Class − Used to specify the event itself. It has methods to set and get event information like name (set/getName), target (get/setTarget) and parameter (get/setParams).

  • EventManager class − The instance of the EventManager tracks all the defined events in an application and its corresponding listeners. The EventManager provides a method, attach to attach listener to an event and it provides a method, trigger to trigger any pre-defined event. Once trigger is called, EventManager calls the listener attached to it.

  • EventManagerAwareInterface − For a class to support event based programming, it needs to implement the EventManagerAwareInterface. It provides two methods, setEventManager and getEventManager to get and set the event manager.

Example

Let us write a simple PHP console application to understand the event manager concept. Follow the steps given below.

  • Create a folder “eventapp”.

  • Install zend-eventmanager using the composer.

  • Create a PHP file Greeter.php inside the “eventapp” folder.

  • Create class Greeter and implement the EventManagerAwareInterface.

require __DIR__ . '/vendor/autoload.php'; 
class Greeter implements EventManagerAwareInterface { 
   // code 
}

Here, require is used to autoload all composer installed components.

Write the setEventManager method in class Greeter as shown below −

public function setEventManager(EventManagerInterface $events) { $events->setIdentifiers([ __CLASS__, get_called_class(),]); 
   $this->events = $events; 
   return $this; 
}

This method sets the current class into the given event manager ($events argument) and then sets the event manager in local variable $events.

The next step is to write the getEventManager method in class Greeter as shown below −

public function getEventManager() { 
   if (null === $this->events) { 
      $this->setEventManager(new EventManager()); } return $this->events; 
}

The method gets the event manager from a local variable. if it is not available, then it creates an instance of event manager and returns it.

Write a method, greet, in class Greeter.

public function greet($message) { printf("\"%s\" from class\n", $message); 
   $this->getEventManager()->trigger(__FUNCTION__, $this, $message ]); 
}

This method gets the event manager and fires / triggers events attached to it.

The next step is to create an instance of the Greeter class and attach a listener to its method, greet.

$greeter = new Greeter();  
$greeter->getEventManager()->attach('greet', function($e) { 
   $event_name = $e->getName(); 
   $target_name = get_class($e->getTarget()); 
   $params_json = json_encode($e->getParams());  
   printf("\"%s\" event of class \"%s\" is called." . 
      " The parameter supplied is %s\n",  
      $event_name, $target_name,  
      $params_json); 
});

The listener callback just prints the name of the event, target and the supplied parameters.

The complete listing of the Greeter.php is as follows −

<?php  
require __DIR__ . '/vendor/autoload.php';  

use Zend\EventManager\EventManagerInterface; 
use Zend\EventManager\EventManager; 
use Zend\EventManager\EventManagerAwareInterface; 

class Greeter implements EventManagerAwareInterface { 
   protected $events;
   public function setEventManager(EventManagerInterface $events) { $events->setIdentifiers([__CLASS__, get_called_class(), ]); 
      $this->events = $events; 
      return $this; } public function getEventManager() { if (null === $this->events) { 
         $this->setEventManager(new EventManager()); } return $this->events; 
   } 
   public function greet($message) { printf("\"%s\" from class\n", $message); 
      $this->getEventManager()->trigger(__FUNCTION__, $this, [$message ]); } } $greeter = new Greeter(); 
$greeter->greet("Hello"); $greeter->getEventManager()->attach('greet', function($e) { $event_name = $e->getName(); $target_name = get_class($e->getTarget()); $params_json = json_encode($e->getParams()); printf("\"%s\" event of class \"%s\" is called." . " The parameter supplied is %s\n", $event_name,
      $target_name, $params_json); 
});  
$greeter->greet("Hello");

Now, run the application in the command prompt php Greeter.php and the result will be as follows −

"Hello" from class 
"Hello" from class 
"greet" event of class "Greeter" is called. The parameter supplied is ["Hello"]

The above sample application explains only the basics of an event manager. The Event manager provides many more advanced options such as Listener Priority, Custom Callback Prototype / Signature, Short Circuiting, etc. The Event manager is used extensively in the Zend MVC framework.

The Zend Framework provides a powerful module system. The module system has three components. They are as follows −

  • Module Autoloader − A Module Autoloader is responsible for locating and loading of modules from variety of sources. It can load modules packaged as Phar archives as well. The implementation of the Module Autoloader is located at myapp/vendor/zendframework/zend-loader/src/ModuleAutoloader.php.

  • Module Manager − Once the Module Autoloader locates the modules, the module manager fires a sequence of events for each module. The implementation of the Module Manager is located at myapp/vendor/zendframework/zendmodulemanager/src/ModuleManager.php.

  • Module Manager Listeners − They can be attached to the events fired by the Module Manager. By attaching to the events of module manager, they can do everything from resolving and loading modules to performing complex work for each modules.

MVC Web Module System

The MVC Web Application in the Zend Framework is usually written as Modules. A single website can contain one or more modules grouped by functionality. The recommended structure for MVC-Oriented module is as follows −

module_root/ 
   Module.php 
   autoload_classmap.php 
   autoload_function.php 
   autoload_register.php 
   config/ 
      module.config.php 
   public/ 
      images/ 
      css/ 
      js/ 
   src/ 
      <module_namespace>/ 
      <code files> 
   test/ 
      phpunit.xml
      bootstrap.php 
      <module_namespace>/ 
         <test code files> 
   view/ 
      <dir-named-after-module-namespace>/ 
         <dir-named-after-a-controller>/ 
            <.phtml files>

The structure is same as discussed in the previous chapter, but here it is generic. The autoload_ files can be used as a default mechanism for autoloading the classes available in the module without using the advanced Module Manager available in the zend-modulemanager.

  • autoload_classmap.php − Returns an array of class name and its corresponding filename.

  • autoload_function.php − Returns a PHP callback. This can utilize classes returned by autoload_classmap.php.

  • autoload_register.php − Registers the PHP callback that is returned by the autoload_function.php.

These autoload files are not required but recommended. In the skeleton application, we have not used the autoload_ files.

Module Class

The Module class should be named Module and the namespace of the module class should be Module name. This will help the Zend Framework to resolve and load the module easily. The Application module code in the skeleton(myapp) application,myapp/module/Application/src/Module.php is as follows −

namespace Application; 
class Module { 
   const VERSION = '3.0.2dev'; 
   public function getConfig() { 
      return include __DIR__ . '/../config/module.config.php'; 
   } 
}

The Zend Framework module manager will call the getConfig() function automatically and will do the necessary steps.

In this chapter, let us understand the structure of the Zend Framework application. The structure of the myapp application is as follows −

├── composer.json 
├── composer.lock 
├── CONDUCT.md 
├── config 
│   ├── application.config.php 
│   ├── autoload 
│   │   ├── development.local.php 
│   │   ├── development.local.php.dist 
│   │   ├── global.php 
│   │   ├── local.php.dist 
│   │   ├── README.md 
│   │   └── zend-developer-tools.local-development.php 
│   ├── development.config.php 
│   ├── development.config.php.dist 
│   └── modules.config.php 
├── CONTRIBUTING.md 
├── data 
│   └── cache 
│       └── module-classmap-cache.application.module.cache.php ├── docker-compose.yml 
├── Dockerfile 
├── LICENSE.md 
├── module 
│   └── Application 
│       ├── config 
│       ├── src 
│       ├── test 
│       └── view 
├── phpcs.xml 
├── phpunit.xml.dist 
├── public
│   ├── css 
│   │   ├── bootstrap.css 
│   │   ├── bootstrap.css.map 
│   │   ├── bootstrap.min.css 
│   │   ├── bootstrap.min.css.map 
│   │   ├── bootstrap-theme.css 
│   │   ├── bootstrap-theme.css.map 
│   │   ├── bootstrap-theme.min.css 
│   │   ├── bootstrap-theme.min.css.map 
│   │   └── style.css 
│   ├── fonts 
│   │   ├── glyphicons-halflings-regular.eot 
│   │   ├── glyphicons-halflings-regular.svg 
│   │   ├── glyphicons-halflings-regular.ttf 
│   │   ├── glyphicons-halflings-regular.woff 
│   │   └── glyphicons-halflings-regular.woff2 
│   ├── img 
│   │   ├── favicon.ico 
│   │   └── zf-logo-mark.svg 
│   ├── index.php 
│   ├── js 
│   │   ├── bootstrap.js 
│   │   ├── bootstrap.min.js 
│   │   └── jquery-3.1.0.min.js 
│   └── web.config 
├── README.md 
├── TODO.md 
├── Vagrantfile 
└── vendor     
├── autoload.php     
├── bin     
│   ├── phpunit -> ../phpunit/phpunit/phpunit     
│   ├── templatemap_generator.php -> ../zendframework/zend-
view/bin/templatemap_generator.php
│   └── zf-development-mode -> ../zfcampus/zf-development-mode/bin/zf-
development-mode 
├── composer     
│   ├── autoload_classmap.php     
│   ├── autoload_namespaces.php     
│   ├── autoload_psr4.php     
│   ├── autoload_real.php     
│   ├── ClassLoader.php     
│   ├── installed.json 
│   └── LICENSE     
├── container-interop 
│   └── container-interop     
├── doctrine 
│   └── instantiator     
├── myclabs 
│   └── deep-copy     
├── phpdocumentor     
│   ├── reflection-common     
│   ├── reflection-docblock 
│   └── type-resolver     
├── phpspec 
│   └── prophecy     
├── phpunit     
│   ├── php-code-coverage     
│   ├── php-file-iterator     
│   ├── php-text-template     
│   ├── php-timer     
│   ├── php-token-stream     
│   ├── phpunit 
│   └── phpunit-mock-objects     
├── sebastian     
│   ├── code-unit-reverse-lookup     
│   ├── comparator     
│   ├── diff     
│   ├── environment     
│   ├── exporter     
│   ├── global-state     
│   ├── object-enumerator
│   ├── recursion-context     
│   ├── resource-operations 
│   └── version     
├── symfony 
│   └── yaml     
├── webmozart 
│   └── assert     
├── zendframework     
│   ├── zend-component-installer     
│   ├── zend-config     
│   ├── zend-console     
│   ├── zend-dom     
│   ├── zend-escaper     
│   ├── zend-eventmanager     
│   ├── zend-http     
│   ├── zend-loader     
│   ├── zend-modulemanager     
│   ├── zend-mvc     
│   ├── zend-router     
│   ├── zend-servicemanager     
│   ├── zend-stdlib     
│   ├── zend-test     
│   ├── zend-uri     
│   ├── zend-validator 
│   └── zend-view 
└── zfcampus 
└── zf-development-mode  

73 directories, 55 files

The Zend Framework application consists of different folders. They are as follows −

  • Application − This directory contains your application. It will house the MVC system, as well as configurations, services used and your bootstrap file.

  • Config − This directory contains the configuration files of an application.

  • Data − This directory provides a place to store application data that is volatile and possibly temporary.

  • Module − Modules allow a developer to group a set of related controllers into a logically organized group.

  • Public − This is the application’s document root. It starts the Zend application. It also contains the assets of the application like JavaScript, CSS, Images, etc.

  • Vendor − This directory contains composer dependencies.

Structure of the Application Modules

This is the main directory of your application. Zend Framework 2 introduces a powerful and flexible module system to organize the application efficiently. The Application module of the skeleton application (myapp) provides bootstrapping, error and routing configuration to the whole application. The structure of the Application module is as shown below −

├── module 
│   └── Application 
│       ├── config 
│       │   └── module.config.php 
│       ├── src 
│       │   ├── Controller 
│       │   │   └── IndexController.php 
│       │   └── Module.php 
│       ├── test 
│       │   └── Controller 
│       │       └── IndexControllerTest.php 
│       └── view 
│           ├── application 
│           │   └── index 
│           │       └── index.phtml 
│           ├── error 
│           │   ├── 404.phtml 
│           │   └── index.phtml 
│           └── layout 
│               └── layout.phtml

Let us cover each of these module directories in detail −

  • Application − This is root directory of the module. The name of the folder will match the name of the module and the name is also used as the PHP namespace of all the class defined inside the module. It will house the MVC system, as well as configurations, services used, and your bootstrap file.

  • Config − Independent configuration of the module.

  • Src − Main business logic of the application.

  • View − Contains design / presentation (HTML) files. For example, index.phtml.

  • src/Module.php − It is the heart of the module. It works as a “front controller” for the module. The Zend process src/Module.php file before processing any PHP Classes in this module.

  • Application/config/module.config.php − It is implemented for the router configuration and auto loading files.

  • Application/view/layout − Layouts represent the common parts of multiple views. For example, page header and footer. By default, layouts should be stored in the views/layoutsfolder.

Todos os módulos compartilham a mesma estrutura ou estrutura semelhante ao módulo do aplicativo acima .

Neste capítulo, aprenderemos como criar um módulo baseado em MVC no Zend Framework. Vamos criar um módulo chamadoTutorial para entender o processo de criação do módulo.

  • Crie uma nova classe PHP chamada Module dentro do diretório –myapp / module / Tutorial / src / e implemente o ConfigProviderInterface.

  • Conjunto Tutorial como o namespace para o Module classe.

  • Escreva uma função pública getConfig no Module classe e retornar o arquivo de configuração para o Tutorial Módulo.

O código completo para o Module a aula é a seguinte -

<?php  
namespace Tutorial; 
use Zend\ModuleManager\Feature\ConfigProviderInterface;
class Module implements ConfigProviderInterface { 
   public function getConfig() {    
      return include __DIR__ . '/../config/module.config.php'; 
   }    
}

Configure o Tutorial módulo no composer.json debaixo de autoload seção usando o código a seguir.

"autoload": { 
   "psr-4": { 
      "Application\\": "module/Application/src/", 
      "Tutorial\\": "module/Tutorial/src/" 
   } 
}

Atualize o aplicativo usando o compositor update comando como mostrado abaixo.

composer update

o composer o comando fará as alterações necessárias no aplicativo e mostrará os logs no prompt de comando, conforme mostrado abaixo -

Loading composer repositories with package information 
Updating dependencies (including require-dev) 
   - Removing zendframework/zend-component-installer (0.3.0) 
   - Installing zendframework/zend-component-installer (0.3.1) 
   Downloading: 100%           
   
   - Removing zendframework/zend-stdlib (3.0.1) 
   - Installing zendframework/zend-stdlib (3.1.0) 
   Loading from cache  
   
   - Removing zendframework/zend-eventmanager (3.0.1) 
   - Installing zendframework/zend-eventmanager (3.1.0) 
   Downloading: 100%           
   
   - Removing zendframework/zend-view (2.8.0) 
   - Installing zendframework/zend-view (2.8.1) 
   Loading from cache  
   
   - Removing zendframework/zend-servicemanager (3.1.0) 
   - Installing zendframework/zend-servicemanager (3.2.0) 
   Downloading: 100%           
   
   - Removing zendframework/zend-escaper (2.5.1) 
   - Installing zendframework/zend-escaper (2.5.2) 
   Loading from cache  
   
   - Removing zendframework/zend-http (2.5.4) 
   - Installing zendframework/zend-http (2.5.5) 
   Loading from cache  
   
   - Removing zendframework/zend-mvc (3.0.1) 
   - Installing zendframework/zend-mvc (3.0.4) 
   Downloading: 100%          
   
   - Removing phpunit/phpunit (5.7.4) 
   - Installing phpunit/phpunit (5.7.5) 
   Downloading: 100%           

Writing lock file 
Generating autoload files

Crie o arquivo de configuração do módulo, “module.config.php” em /config/ com o seguinte código -

<?php  
namespace Tutorial;  
   
use Zend\ServiceManager\Factory\InvokableFactory; 
use Zend\Router\Http\Segment;  
return [ 
   'controllers' => [ 
      'factories' => [Controller\TutorialController::class => InvokableFactory::class,], 
   ],
   'view_manager' => [ 
      'template_path_stack' => ['tutorial' => __DIR__ . '/../view',], 
   ], 
];

O arquivo de configuração tem três partes e são as seguintes -

  • Controller configuration - Especifique os controladores disponíveis dentro do Módulo.

  • Routing configuration - Especifique como os controladores no módulo devem ser resolvidos em URLs.

  • View configuration - Especifique a configuração relacionada à visualização do mecanismo, como a localização das visualizações, etc.

Configure o Tutorial módulo no arquivo de configuração de nível de aplicativo - myapp / config / modules.config.php.

return ['Zend\Router', 'Zend\Validator', 'Application', 'Tutorial'];

Execute o aplicativo executando o composer serve na raiz da pasta do aplicativo.

Adicionamos com sucesso um novo módulo, mas ainda precisamos adicionar o Controller, Routing e Views para executar com sucesso o Tutorial módulo.

Conforme discutido anteriormente, o controllerdesempenha um papel importante no Zend MVC Framework. Todas as páginas da web em um aplicativo precisam ser gerenciadas por um controlador.

No Zend MVC Framework, os controladores são objetos que implementam a - Zend / Stdlib / DispatchableInterface. oDispatchableInterface tem um único método, dispatch, que obtém o Request objeto como entrada, fazer alguma lógica e retornar Response um objeto como saída.

dispatch(Request $request, Response $response = null)

Um exemplo simples de um objeto Controller para retornar “Hello World” é o seguinte -

use Zend\Stdlib\DispatchableInterface; 
use Zend\Stdlib\RequestInterface as Request; 
use Zend\Stdlib\ResponseInterface as Response;  
class HelloWorld implements DispatchableInterface { 
   public function dispatch(Request $request, Response $response = null) { $response->setContent("Hello World!"); 
   } 
}

o DispatchableInterfaceé básico e precisa de muitas outras interfaces para escrever controladores de alto nível. Algumas dessas interfaces são as seguintes -

  • InjectApplicationEventInterface - Usado para injetar eventos (Zend EventManager)

  • ServiceLocatorAwareInterface - Usado para localizar serviços (Zend ServiceManager)

  • EventManagerAwareInterface - Usado para gerenciar eventos (Zend EventManager)

Mantendo essas coisas em mente, o Zend Framework fornece muitos controladores prontos que implementam essas interfaces. Os controladores mais importantes são explicados a seguir.

AbstractActionController

O AbstractActionController (Zend / Mvc / Controller / AbstractActionController) é o controlador mais usado no Zend MVC Framework. Possui todos os recursos necessários para escrever uma página da web típica. Ele permite que as rotas (o roteamento corresponda ao url da solicitação a um controlador e a um de seus métodos) correspondam a umaction. Quando combinado, um método com o nome da ação será chamado pelo controlador.

Por exemplo, se uma rota test é correspondido e a rota, test retorna hello para ação, então o helloAction método será chamado.

Vamos escrever nosso TutorialController usando o AbstractActionController.

  • Crie uma nova classe PHP chamada TutorialController estendendo o AbstractActionController e coloque-o no module/Tutorial/src/Controller/ diretório.

  • Colocou o Tutorial\Controller como o namespace.

  • Escrever um indexAction método.

  • Devolver o ViewModel objeto de indexActionmétodo. oViewModel objeto é usado para enviar dados do controlador para o mecanismo de visualização, que veremos nos capítulos subsequentes.

A lista de códigos completa é a seguinte -

?php  
namespace Tutorial\Controller;  
use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel;  
class TutorialController extends AbstractActionController { 
   public function indexAction() { 
      return new ViewModel(); 
   } 
}

Nós adicionamos com sucesso o novo TutorialController.

AbstractRestfulController

O AbstractRestfulController (Zend \ Mvc \ Controller \ AbstractRestfulController) inspeciona o HTTP method da solicitação recebida e corresponde à ação (método), considerando os métodos HTTP

Por exemplo, a solicitação com o método GET HTTP corresponde ao getList() método ou o get() método, se o id parâmetro é encontrado na solicitação.

AbstractConsoleController

O AbstractConsoleController (Zend \ Mvc \ Controller \ AbstractConsoleController) é como o AbstractActionController, exceto que só roda no ambiente do console em vez de um navegador.

Mapas de rotas Request URIpara um método de controlador específico. Neste capítulo, veremos como implementar as rotas em um Zend Framework.

Em geral, qualquer URI tem três partes -

  • Segmento de nome de host,
  • Segmento de caminho e
  • Segmento de consulta.

Por exemplo, em URI / URL - http://www.example.com/index?q=data, www.example.com é o segmento do nome do host, index é o segmento de caminho e q=dataé o segmento de consulta. Geralmente, o roteamento verifica oPage segmentcontra um conjunto de restrições. Se alguma restrição corresponder, ele retornará um conjunto de valores. Um dos principais valores é o controlador.

O roteamento também verifica o segmento de host, segmento de consulta, métodos de solicitação HTTP, cabeçalhos de solicitação HTTP, etc., em uma determinada situação.

Route & RouteStack

A rota é o principal objeto do roteamento. Zend Framework tem uma interface especial para objetos de rota,RouteInterface. Todos os objetos de rota precisam implementar RouteInterface. A lista completa de RouteInterface é a seguinte -

namespace Zend\Mvc\Router;  
use Zend\Stdlib\RequestInterface as Request;  
interface RouteInterface { 
   public static function factory(array $options = []); public function match(Request $request); 
   public function assemble(array $params = [], array $options = []); 
}

O método principal é match. Este método de correspondência verifica a solicitação fornecida em relação à restrição definida nela. Se qualquer correspondência for encontrada, ele retorna oRouteMatchobjeto. Este objeto RouteMatch fornece os detalhes da solicitação correspondida como parâmetros. Esses parâmetros podem ser extraídos deRouteObject usando o getParams método.

A lista completa do RouteObject é a seguinte -

namespace Zend\Mvc\Router;  
class RouteMatch { 
   public function __construct(array $params); public function setMatchedRouteName($name); 
   public function getMatchedRouteName(); 
   public function setParam($name, $value); 
   public function getParams(); 
   public function getParam($name, $default = null); 
}

Em geral, um aplicativo MVC típico tem muitas rotas. Cada uma dessas rotas será processada em um pedido UEPS e uma única rota será combinada e devolvida. Se nenhuma rota for correspondida / retornada, o aplicativo retornará o erro “Página não encontrada”. Zend Framework fornece uma interface para processar as rotas,RouteStackInterface. Este RouteStackInterface tem a opção de adicionar / remover rotas.

A lista completa de RouteStackInterface é a seguinte -

namespace Zend\Mvc\Router;  
interface RouteStackInterface extends RouteInterface { 
   public function addRoute($name, $route, $priority = null); public function addRoutes(array $routes); 
   public function removeRoute($name); public function setRoutes(array $routes); 
}

O framework Zend fornece duas implementações do RouteStack interface e eles são os seguintes -

  • SimpleRouteStack
  • TreeRouteStack

Tipo de Rotas

O Zend framework oferece muitos objetos de rota prontos para todas as situações no namespace "Zend \ Mvc \ Router \ Http". Basta selecionar e usar o objeto de rota adequado para a situação dada.

As rotas disponíveis são as seguintes -

  • Hostname - Usado para corresponder à parte do host do URI.

  • Literal - Usado para corresponder ao URI exato.

  • Method - Usado para corresponder ao método HTTP da solicitação de entrada.

  • Part - Usado para corresponder à parte do segmento de caminho URI usando lógica personalizada.

  • Regex - Usado para corresponder ao segmento de caminho URI por padrão Regex.

  • Schema - Usado para corresponder ao esquema URI, como http, https, etc.

  • Segment - Usado para corresponder ao caminho URI, dividindo-o em vários segmentos.

Vamos ver como escrever o literal e o segmento Route mais comumente usados. As rotas são geralmente especificadas no arquivo de configuração de cada módulo -module.config.php.

Rota Literal

Normalmente, as rotas são consultadas em uma ordem LIFO. A rota literal é para fazer a correspondência exata do caminho URI.

É definido como mostrado abaixo -

$route = Literal::factory(array( 
   'route' => '/path', 
   'defaults' => array('controller' => 'Application\Controller\IndexController', 
      'action' => 'index',), 
));

A rota acima corresponde ao /path no URL da solicitação e retorna index Enquanto o action e IndexController como controlador.

Rota do Segmento

Uma rota segmentada é usada sempre que seu url deve conter parâmetros variáveis.

É descrito conforme abaixo -

$route = Segment::factory(array( 
   'route' => '/:controller[/:action]', 
   'constraints' => array( 
      'controller' => '[a-zA-Z][a-zA-Z0-9_-]+', 
      'action' => '[a-zA-Z][a-zA-Z0-9_-]+', 
   ), 
   'defaults' => array( 
      'controller' => 'Application\Controller\IndexController', 
      'action' => 'index',), 
));

Aqui, os segmentos são indicados por dois pontos e seguidos por caracteres alfanuméricos. Se você mantiver um segmento opcional, ele será colocado entre colchetes. Cada segmento pode ter restrições associadas a ele. Cada restrição é uma expressão regular.

Configurando a rota no módulo tutorial

Vamos adicionar uma rota de segmento em nosso módulo Tutorial. Atualize o arquivo de configuração do módulo tutorial -module.config.php disponível em myapp/module/Tutorial/config.

<?php  
namespace Tutorial;  
use Zend\ServiceManager\Factory\InvokableFactory; 
use Zend\Router\Http\Segment;  
return [ 
   'controllers' => [ 
      'factories' => [ 
         Controller\TutorialController::class => InvokableFactory::class, 
      ], 
   ], 
   'router' => [ 
      'routes' => [ 
         'tutorial' => [ 
            'type'    => Segment::class, 
               'options' => [ 
                  'route' => '/tutorial[/:action[/:id]]', 
                  'constraints' => [ 
                     'action' => '[a-zA-Z][a-zA-Z0-9_-]*', 
                     'id'     => '[0-9]+', 
                  ], 
                  'defaults' => [
                     'controller' => Controller\TutorialController::class, 
                     'action'     => 'index', 
                  ], 
               ], 
            ], 
      ], 
   ], 
   'view_manager' => [ 
      'template_path_stack' => ['tutorial' => __DIR__ . '/../view',], 
   ], 
];

Adicionamos com sucesso o roteamento para nosso Tutorialmódulo. Estamos apenas um passo atrás na conclusão de nosso módulo Tutorial. Precisamos adicionarView para nosso módulo, que aprenderemos no capítulo subsequente.

Uma camada de visualização é a camada de apresentação do aplicativo MVC. Ele separa a lógica do aplicativo da lógica da apresentação. Em um aplicativo da web PHP típico, toda a lógica de negócios e design são misturados. A mistura permite um desenvolvimento mais rápido em um projeto pequeno. Mas, ele falha miseravelmente em grandes projetos, onde muita arquitetura de alto nível está envolvida. Para mudar o design do aplicativo da web, um desenvolvedor precisa trabalhar na lógica de negócios também. Isso pode ser catastrófico, resultando na quebra da lógica de negócios.

Zend Framework fornece uma camada de visualização bem pensada, limpa, flexível e extensível. A camada de visualização está disponível como um módulo separado,Zend/View e integrar bem com Zend/Mvcmódulo. A camada Zend View é separada em vários componentes que interagem bem uns com os outros.

Seus vários componentes são os seguintes -

  • Variables Containers - Contém os dados da camada de visualização.

  • View Models - Contém recipientes variáveis ​​e modelo de design.

  • Renderers - Processe os dados e o template a partir do View Model e produza uma representação de design, talvez a saída html final.

  • Resolvers - Resolve o template disponível no View Model de tal forma que o Renderer possa consumir.

  • View (Zend\View\View) - Mapeia a solicitação para o renderizador e, em seguida, o renderizador para a resposta.

  • Rendering Strategies - Usado por View para mapear a solicitação para o renderizador.

  • Response Strategies - Usado por View para mapear o renderizador para a resposta.

A camada de visão, View processa o ViewModel, resolve o modelo usando um Resolver, renderize-o usando Rendering Strategy e, finalmente, produz usando o Response Renderer.

Exibir configuração da camada

Como o controlador, uma camada de visualização pode ser configurada em um arquivo de configuração do módulo denominado como - module.config.php. A configuração principal é especificar onde os modelos serão colocados. Isso pode ser feito adicionando a seguinte configuração no “module.config.php”.

'view_manager' => [ 
   'template_path_stack' => ['tutorial' => __DIR__ . '/../view',], 
]

Por padrão, a camada de Visualização tem um comportamento padrão para todos os seus componentes. Por exemplo, umViewModelresolve o nome do modelo da ação de um controlador dentro da raiz do modelo pela regra “nome-do-módulo-minúsculo / nome-do-controlador-minúsculo / nome-da-ação-minúsculo”. No entanto, isso pode ser substituído pelosetTemplate() método do ViewModel.

Controladores e camada de visualização

Por padrão, um controlador não precisa enviar nenhum dado para a camada de visualização. Basta escrever o template no lugar apropriado.

Por exemplo, em nosso exemplo, TutorialController, o modelo deve ser colocado em myapp/module/Tutorial/view/tutorial/tutorial/index.phtml. oindex.phtmlrefere-se ao modelo baseado em PHP e será processado pelo PHPRenderer. Existem outros renderizadores, comoJsonRenderer para json saída e FeedRenderer para rss e atom resultado.

A lista completa é a seguinte -

<?php  
namespace Tutorial\Controller;  
use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel;  
class TutorialController extends AbstractActionController { 
   public function indexAction() { 
   } 
}

Zend Application Template

<div class = "row content"> 
   <h3>This is my first Zend application</h3> 
</div>

Finalmente, concluímos com sucesso o Tutorial módulo e podemos acessá-lo usando url - http://localhost:8080/tutorial.

Passando dados para a camada de visualização

A maneira mais simples de enviar os dados para uma camada de visualização é usar o ViewModelargumentos. O mudouindexAction método é o seguinte -

public function indexAction() { 
   $view = new ViewModel([ 'message' => 'Hello, Tutorial' ]); return $view; 
}

Agora, mude o index.phtml arquivo da seguinte forma -

<div class = "row content"> 
   <h3>This is my first Zend application</h3> 
   <h4><?php echo $this->message?></h4> 
</div>

Ver ajudantes

Um View Helper é usado para escrever pequenas funções atômicas para serem usadas em modelos. Zend framework fornece uma interface, Zend \ View \ Helper \ HelperInterface para escrever helpers de visualização padrão.

Um HelperInterface tem apenas dois métodos,

  • setView() - Este método aceita uma instância / implementação Zend \ View \ Renderer \ RendererInterface.

  • getView() - É usado para recuperar essa instância.

A lista completa de códigos de HelperInterface é o seguinte -

namespace Zend\View\Helper;  
use Zend\View\Renderer\RendererInterface as Renderer;  
interface HelperInterface { 
   /** 
      * Set the View object 
      * 
      * @param  Renderer $view 
      * @return HelperInterface 
   */ 
   public function setView(Renderer $view);  
   /** 
      * Get the View object 
      * 
      * @return Renderer 
   */ 
   public function getView(); 
}

Para usar um auxiliar em seu script de visualização, acesse-o usando $this->helperName().

Ajudantes integrados

O Zend Framework fornece várias funções auxiliares integradas para diversos fins. Alguns dos View Helpers disponíveis nozend-mvc são os seguintes -

URL

O auxiliar de URL é usado para gerar os URLs correspondentes às rotas definidas no aplicativo.

A definição do auxiliar de URL é -

$this->url($name, $params, $options, $reuseMatchedParameters)

Por exemplo, no módulo tutorial, a rota é nomeada como tutorial e tem dois parâmetros action e id. Podemos usar o auxiliar de URL para gerar dois URLs diferentes, conforme mostrado abaixo -

<a href = "<? = $this->url('tutorial'); ?>">Tutorial Index</a>  
<a href = "<? = $this->url('tutorial', ['action' => 'show', 'id' =>10]); ?>"> 
   Details of Tutorial #10 
</a>

O resultado será o seguinte -

<a href = "/tutorial">Tutorial Index</a>  
<a href = "/tutorial/show/10"> Details of Tutorial #10</a>

Placeholder

O auxiliar de espaço reservado é usado para persistir o conteúdo entre scripts de exibição e instâncias de exibição. Ele oferece a opção de definir os dados inicialmente e depois usá-los em estágios posteriores.

Por exemplo, podemos definir, digamos company name e usá-lo em todos os outros lugares.

<?php $this->placeholder('companyname')->set("TutorialsPoint") ?>  
<?= $this->placeholder('companyname'); ?>

Um espaço reservado fornece algumas das opções avançadas para gerar conteúdo complexo a partir de uma matriz e objetos PHP. Ele também tem a opção de capturar determinada seção do próprio modelo.

Por exemplo, o código a seguir captura o resultado do modelo no meio e o armazena no productlist placeholder.

Class – Product

class Product { 
   public $name; 
   public $description; 
}

Controller

$p1 = new Product(); 
$p1->name = 'Car'; $p1->description = 'Car';  
$p2 = new Product(); $p2->name = 'Cycle'; 
$p2->description = 'Cycle'; $view = new ViewModel(['products' => $products]);

Template

<!-- start capture --> 
<?php $this->placeholder('productlist')->captureStart(); 
   foreach ($this->products as $product): ?> 
<div> 
   <h2><?= $product->name ?></h2> <p><?= $product->description ?></p> 
</div> 
<?php endforeach; ?> 
<?php $this->placeholder('productlist')->captureEnd() ?> <!-- end capture --> <?= $this->placeholder('productlist') ?>

Result

<div class = "foo"> 
   <h2>Car</h2> 
   <p>Car</p> 
</div>
<div class = "foo"> 
   <h2>Cycle</h2> 
   <p>Cycle</p> 
</div>

Doctype

O auxiliar Doctype é usado para gerar vários doctypes html. É a implementação concreta doPlaceholderajudante. O doctype pode ser definido em um arquivo de inicialização e um arquivo de configuração.

O uso básico é mostrado abaixo -

Application Bootstrap file

use Zend\View\Helper\Doctype;  
$doctypeHelper = new Doctype(); $doctypeHelper->doctype('XHTML5');

Module Configuration

// module/Application/config/module.config.php: 
return [ 
   /* ... */ 
   'view_manager' => [ 
      'doctype' => 'html5', 
      /* ... */ 
   ], 
];

Template

<?php echo $this->doctype() ?>

HeadTitle

O auxiliar HeadTitle é usado para gerar o elemento de título html. É a implementação concreta dePlaceholderajudante. Zend oferece uma opção para definir o título no arquivo de configuração do módulo e pode ser definido em qualquer nível, como site, módulo, controlador, ação, etc. Um código parcial para HeadTitle é o seguinte -

Module

headTitleHelper->append($action); 
$headTitleHelper->append($controller); 
$headTitleHelper->append($module); 
$headTitleHelper->append($siteName);

Template

<?= $this->headTitle() ?>

Result

action - controller - module - Zend Framework

HeadMeta

O auxiliar HeadMeta é usado para gerar metatags html. É uma implementação concreta do auxiliar de Espaço reservado.

Template -

<?php 
   $this->headMeta()->appendName('keywords', 'turorialspoint, zend framework, php');  
   echo $this->headMeta() 
?>

Result

<meta name = "keywords" content = "tutorialspoint, zend framework, php" />

HeadLink

O auxiliar HeadLink é usado para gerar links html para incluir recursos externos. É uma implementação concreta do auxiliar de Espaço reservado.

Template

<?php 
   // setting links in a view script: 
   $this->headLink(['rel' => 'icon', 'href' => '/img/favicon.ico'], 'PREPEND') 
      ->appendStylesheet('/styles/site.css') 
      ->prependStylesheet('/styles/mystyle.css', 'screen', true, ['id' => 'mystyle']);  
   
   // rendering the links from the layout: 
   echo $this->headLink(); 
?>

Result

<link href = "/styles/mystyle.css" media = "screen" rel = "stylesheet" 
   type = "text/css" id = "mystyle"> 
<link href = "/img/favicon.ico" rel = "icon"> 
<link href = "/styles/site.css" media = "screen" rel = "stylesheet" type = "text/css">

HeadStyle

O auxiliar HeadStyle é usado para gerar estilos CSS embutidos. É uma implementação concreta do auxiliar de Espaço reservado.

Template

<?php $this->headStyle()->appendStyle($styles); ?> <?php echo $this->headStyle() ?>

HeadScript

O HeadScript é usado para gerar script embutido ou incluir scripts externos. É uma implementação concreta do auxiliar de Espaço reservado.

Template

<? $this->headScript()->appendFile(‘/js/sample.js’);?> <?php echo $this->headScript() ?>

InlineScript

O InlineScript é usado para gerar um script nas seções head e body do template html. É derivado do HeadScript.

HTMLList

O HTMLList é usado para gerar listas ordenadas e não ordenadas. A definição de HTMLList é a seguinte -

Definition

htmlList($items, $ordered, $attribs, $escape)

Template

$items = [ '2015', ['March', 'November'], '2016', ]; echo $this->htmlList($items);

Result

<ul> 
   <li>2015 
      <ul> 
         <li>March</li> 
         <li>November</li> 
      </ul> 
   </li> 
   <li>2016</li> 
</ul>

Ciclo

Um Cycle é usado para gerar alternativas em um ambiente de loop. Tem funções de atribuição, seguinte e anterior.

Controller

$view = new ViewModel(['message' => 'Hello, Tutorial', 'data' => array('One', 'Two')]);

Template

<?php $this->cycle()->assign(['#F0F0F0', '#FFF'], 'colors'); ?> <table> <?php foreach ($this->data as $datum): ?> <tr style = "background-color: <?= $this->cycle()->setName('colors')>next() ?>">
      <td><?= $this->escapeHtml($datum) ?></td>
   </tr>
   <?php endforeach ?>
</table>

Result

<table> 
   <tr style = "background-color: #F0F0F0"> 
      <td>One</td> 
   </tr> 
   <tr style = "background-color: #FFF"> 
      <td>Two</td> 
   </tr> 
</table>

Alguns outros ajudantes integrados importantes são os seguintes -

  • BasePath - O BasePath é usado para gerar o caminho da pasta pública da raiz do aplicativo.

  • Partial - Parcial é usado para renderizar um modelo específico em seu próprio escopo de variável.

  • PartialLoop - PartialLoop é como Partial, mas usado no ambiente de loop.

  • Identity - A identidade é usada para recuperar a identidade do usuário conectado no serviço de autenticação.

  • JSON- JSON é usado em um ambiente tranquilo, onde a saída está no formato JSON. Ele emite o cabeçalho HTTP adequado e desativa o conceito de layout.

Ainda há muitos helpers disponíveis no Zend Framework, como o i18n helper, form helpers, pagination helpers, navigation helpersetc.

Criação de auxiliares de visualização

O Zend Framework fornece um recurso integrado AbstractHelper implementando HelperInterface para escrever ajudantes de visualização.

As etapas envolvidas na escrita de um novo ajudante são as seguintes -

  • Step 1 - Estenda a classe Zend \ View \ Helper \ AbstractHelper.

  • Step 2 - Substitua o __invoke() função.

  • Step 3 - Defina a configuração no module.config.php file.

  • Step 4 - Use view helper em view scripts.

Vamos agora criar um TestHelper

Crie a pasta Helper em myapp/module/Tutorial/src/View directory. EscrevaTestHelper dentro do diretório Helper, TestHelper.php.

A lista completa é a seguinte -

<?php  
namespace Tutorial\View\Helper; 
use Zend\View\Helper\AbstractHelper; 
class TestHelper extends AbstractHelper { 
   public function __invoke() { 
      $output = "I am from test helper"; return htmlspecialchars($output, ENT_QUOTES, 'UTF-8'); 
   } 
}

Definir configuração em module.config.php.

'view_helpers' => [ 
   'aliases' => [ 
      'testHelper' => View\Helper\TestHelper::class, 
   ], 
   'factories' => [ 
      View\Helper\TestHelper::class => InvokableFactory::class, 
   ],
],

Use o recém-criado TestHelper no about ver o script.

<?= $this->testHelper() ?>

Um Layout representa as partes comuns de múltiplas visualizações, por exemplo, cabeçalho e rodapé da página. Por padrão, os layouts devem ser armazenados noview/layout pasta.

Uma configuração de layout é definida no view_manager seção no module.config.php.

A configuração padrão do aplicativo esqueleto é a seguinte -

'view_manager' => array( 
   'display_not_found_reason' => true, 
   'display_exceptions' => true, 
   'doctype' => 'HTML5', 
   'not_found_template' => 'error/404', 
   'exception_template' => 'error/index', 
   'template_map' => array( 
      'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 
      'application/index/index' => __DIR__ . '/../view/application/index/index.phtml', 
      'error/404' => __DIR__ . '/../view/error/404.phtml', 
      'error/index' => __DIR__ . '/../view/error/index.phtml', 
   ), 
   'template_path_stack' => array( 
   __DIR__ . '/../view', 
),

Aqui o template_mapé usado para especificar o layout. Se o layout não for encontrado, ele retornará um erro. Vamos dar uma olhada no layout principal do aplicativo esqueleto.

Layout.phtml

<?= $this->doctype() ?>  
<html lang = "en"> 
   <head> 
      <meta charset = "utf-8"> 
      <?= $this->headTitle('ZF Skeleton Application')->setSeparator(' - ')> setAutoEscape(false) ?> <?= $this->headMeta() 
         ->appendName('viewport', 'width = device-width, initial-scale = 1.0') 
         ->appendHttpEquiv('X-UA-Compatible', 'IE = edge') 
      ?>  
      
      <!-- Le styles --> 
      <?= $this->headLink(['rel' => 'shortcut icon', 'type' => 'image/vnd.microsoft.icon', 'href' => $this->basePath() . '/img/favicon.ico']) 
         ->prependStylesheet($this->basePath('css/style.css')) ->prependStylesheet($this->basePath('css/bootstraptheme.min.css')) 
         ->prependStylesheet($this->basePath('css/bootstrap.min.css')) ?> <!-- Scripts --> <?= $this->headScript() 
         ->prependFile($this->basePath('js/bootstrap.min.js')) ->prependFile($this->basePath('js/jquery-3.1.0.min.js')) 
      ?> 
   </head> 
   
   <body> 
      <nav class = "navbar navbar-inverse navbar-fixed-top" role = "navigation"> 
         <div class = "container"> 
            <div class = "navbar-header"> 
               <button type = "button" class = "navbar-toggle" data-
                  toggle = "collapse" data-target = ".navbar-collapse"> 
                  <span class = "icon-bar"></span> 
                  <span class = "icon-bar"></span> 
                  <span class = "icon-bar"></span> 
               </button> 
            
               <a class = "navbar-brand" href = "<?= $this->url('home') ?>"> <img src = "<?= $this->basePath('img/zf-logo-mark.svg') ?>
                     " height = "28" alt = "Zend Framework <?= \Application\Module::
                     VERSION ?>"/> Skeleton Application 
               </a> 
            </div>
         
            <div class = "collapse navbar-collapse"> 
               <ul class = "nav navbar-nav"> 
                  <li class = "active"><a href = "<?= 
                     $this->url('home') ?>">Home</a></li> </ul> </div> </div> </nav> <div class = "container"> <?= $this->content ?> 
         <hr> 
         <footer> 
            <p>© 2005 - <?= date('Y') ?> by Zend Technologies Ltd. 
               All rights reserved.</p> 
         </footer> 
      </div> 
      <?= $this->inlineScript() ?> 
   </body> 
</html>

Conforme você analisa o layout, ele usa principalmente os auxiliares de visualização, que discutimos no capítulo anterior. Ao olharmos mais de perto, o layout usa uma variável especial,$this->content. Esta variável é importante porque será substituída pelo script de visualização (modelo) da página solicitada real.

Criação de um novo layout

Vamos criar um novo layout para nosso módulo Tutorial.

Para começar, vamos criar um tutorial.css file sob o diretório “public / css”.

body { 
   background-color: lightblue; 
} 
h1 { 
   color: white; 
   text-align: center; 
}

Crie um novo arquivo de layout newlayout.phtmlem / myapp / module / Tutorial / view / layout / e copie o conteúdo do layout existente. Em seguida, adicione otutorial.css folha de estilo usando o HeadLink classe auxiliar dentro da seção do cabeçalho do layout.

<?php echo $this->headLink()->appendStylesheet('/css/tutorial.css');?>

Adicionar um novo about link na seção de navegação usando o URL ajudante.

<li><a href = "<?= $this->url('tutorial', ['action' => 'about']) ?>">About</a></li>

Esta página de layout é comum para o aplicativo do módulo tutorial. Atualize oview_manager seção do arquivo de configuração do módulo tutorial.

'view_manager' => array( 
   'template_map' => array( 
      'layout/layout' => __DIR__ . '/../view/layout/newlayout.phtml'), 
   'template_path_stack' => array('tutorial' => __DIR__ . '/../view',), 
)

Adicione o aboutAction função no TutorialController.

public function aboutAction() { 
}

Adicione o about.phtml em myapp / module / Tutorial / view / tutorial / tutorial / com o seguinte conteúdo.

<h2>About page</h2>

Agora, você está pronto para finalmente executar o aplicativo - http://localhost:8080/tutorial/about.

Neste capítulo, discutiremos sobre os vários modelos e o banco de dados do Zend Framework.

Modelos no Zend Framework

Um modelo define a representação lógica dos dados do aplicativo. Por exemplo, em um aplicativo de carrinho de compras - Produto, Cliente, Carrinho e Pedidos são modelos. Eles definem as propriedades da entidade que detém. Alguns dos conceitos de modelos são os seguintes -

  • Os controladores se comunicam com os modelos e pedem que eles recuperem as informações de que precisam. Esta informação recuperada é então passada pelo controlador para a Visualização. Finalmente, o View renderizará o modelo como dados de apresentação consumíveis do usuário.

  • É muito raro que um modelo interaja diretamente com uma visualização, mas às vezes pode acontecer.

  • Os modelos podem conversar uns com os outros e não são independentes. Eles têm relacionamentos um com o outro. Esses relacionamentos tornam mais fácil e rápido para um controlador obter informações, uma vez que ele não precisa interagir com diferentes modelos; os modelos podem fazer isso sozinhos.

Vamos dar uma olhada em um modelo simples - MyModel

<?php  
namespace Tutorial\Model;  
class Book { 
   public $id; public $author; 
   public $title; 
}

Banco de dados no Zend Framework

Zend framework fornece uma classe simples e rica em recursos, Zend \ Db \ TableGateway \ TableGateway, para localizar, inserir, atualizar e excluir dados de uma tabela de banco de dados.

Vamos ver como conectar o MySqlservice via driver PDO do PHP no framework Zend por meio das seguintes etapas.

Etapa 1: Criar banco de dados em MySQL

Criar banco de dados tutorialsno servidor MySQL local. Podemos usarphpmyadminou qualquer outra ferramenta MySQL GUI para este propósito. Vamos usar oMySQL clientno prompt de comando. Conecte-se ao servidor mysql e execute o seguinte comando para criar otutorial base de dados.

create database tutorials

Etapa 2: Criar tabela no banco de dados de tutoriais

Vamos agora criar um banco de dados book no tutorials db usando o seguinte comando SQL.

use tutorials;  
CREATE TABLE book ( 
   id int(11) NOT NULL auto_increment, 
   author varchar(100) NOT NULL, 
   title varchar(100) NOT NULL, 
   PRIMARY KEY (id) 
);

Etapa 3: preencher os dados na tabela do livro

Preencher o booktabela com dados de amostra. Use o seguinte comando SQL.

INSERT INTO book (author, title) VALUES ('Dennis Ritchie', 'C Programming'); 
INSERT INTO book (author, title) VALUES ('James gosling', 'Java Programming'); 
INSERT INTO book (author, title) VALUES ('Rasmus Lerdorf', 'Programming PHP');

Etapa 4: Atualizar conexão de banco de dados

Atualize o arquivo de configuração global, que é - myapp / config / autoload / global.php com as informações necessárias da unidade de banco de dados.

<?php 
return array( 
   'db' => array( 
      'driver' => 'Pdo', 
      'dsn' => 'mysql:dbname = tutorials;host = localhost', 
      'driver_options' => array( 
         PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'' 
      ), 
   ), 
   'service_manager' => array( 
      'factories' => array(  
         'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory', 
      ), 
   ), 
);

Etapa 5: atualizar as credenciais do banco de dados

Atualize as credenciais do banco de dados no arquivo de configuração local, que é - myapp / config / autoload / local.php. Dessa forma, podemos separar as credenciais de conexão do banco de dados local e ao vivo.

<?php 
return array( 
   'db' => array( 
      'username' => '<user_name>', 
      'password' => '<password>', 
   ), 
);

Etapa 6: Criar modelo para livro

Vamos criar um modelo, Book em nosso módulo srcdiretório. Geralmente, os modelos são agrupados na pasta Modelo - /myapp/module/Tutorial/src/Model/Book.php.

<?php  
namespace Tutorial\Model;  
class Book { 
   public $id; 
   public $author; public $title; 
}

Etapa 7: Implementar exchangeArray no modelo de livro

o TableGateway interage com um modelo por meio do exchangeArrayfunção. O argumento padrão da função exchangeArray é o conjunto de resultados do banco de dados armazenado como array PHP. Usando oexchangeArrayfunction, a propriedade de um modelo pode ser facilmente sincronizada com a tabela de banco de dados correspondente.

Atualize o modelo, Book como mostrado abaixo -

<?php  
namespace Tutorial\Model;  
class Book { 
   public $id; public $author; 
   public $title; public function exchangeArray($data) { 
      $this->id = (!empty($data['id'])) ? $data['id'] : null; $this->Author = (!empty($data['author'])) ? $data['author'] : null; 
      $this->Title = (!empty($data['title'])) ? $data['title'] : null; 
   } 
}

Etapa 8: use o TableGateway para buscar o livro

Crie uma classe, BookTablepara buscar informações do livro no banco de dados. Crie a classe BookTable noModel própria pasta.

<?php  
namespace Tutorial\Model;  
use Zend\Db\TableGateway\TableGatewayInterface;  
class BookTable {
   protected $tableGateway; 
   public function __construct(TableGatewayInterface $tableGateway) { $this->tableGateway = $tableGateway; } public function fetchAll() { $resultSet = $this->tableGateway->select(); return $resultSet; 
   } 
}

Nós usamos select()método da classe TableGateway para buscar as informações do livro no banco de dados. Mas, não usamos nenhuma referência à tabela -bookno código. O TableGateway é de natureza genérica e pode buscar dados de qualquer tabela usando certa configuração. Normalmente, essas configurações são feitas nomodule.config.php arquivo, que discutiremos nas etapas subsequentes.

Etapa 9: configurar a classe BookTable

Atualize o módulo do tutorial, Module.php com o getServiceConfig() método.

<?php
namespace Tutorial;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\ModuleManager\Feature\ConfigProviderInterface;

class Module implements ConfigProviderInterface {
   
   public function getConfig() {
      return include __DIR__ . '/../config/module.config.php';
   }
   public function getServiceConfig() {
      return [
         'factories' => [
            Model\BookTable::class => function ($container) { $tableGateway = $container->get(Model\BookTableGateway::class); $table = new Model\BookTable($tableGateway); return $table;
            },
            Model\BookTableGateway::class => function ($container) { $dbAdapter = $container->get(AdapterInterface::class); $resultSetPrototype = new ResultSet();
               $resultSetPrototype->setArrayObjectPrototype(new Model\Book()); return new TableGateway('book', $dbAdapter, null, $resultSetPrototype);
            },
         ],
      ];
   }
}

Aqui, registramos o BookTableclasse usando o gerenciador de serviços. A classe BookTable é usada para buscar as informações do livro e, ao registrá-lo, podemos acessá-lo sempre que necessário. Visto que os serviços registrados são compartilhados, eles aumentam o desempenho, reduzem o consumo de memória, etc.

Outro item, Model \ BookTableGateway :: class é o objeto TableGateway especializado para o Book modelo e é uma dependência do BookTable.

Etapa 10: Atualizar a configuração do TutorialController

Nós precisamos do BookTableserviço no controlador de tutorial para buscar as informações do livro. Para obter o serviço BookTable, registre-o como dependência do construtor no TutorialController.

Essa dependência do Construtor ajuda a obter o serviço BookTable enquanto o próprio controlador está no estágio de inicialização. Atualize a seção do controlador da configuração do módulo tutorial,module.config.php como mostrado abaixo.

'controllers' => [ 
   'factories' => [ 
      Controller\TutorialController::class => function($container) { 
         return new Controller\TutorialController( 
            $container->get(Model\BookTable::class) 
         ); 
      }, 
   ], 
],

Etapa 11: Atualizar controlador de tutorial

Isso é feito seguindo as três etapas a seguir.

  • Adicione o construtor com BookTable como argumento.
private $table;
public function __construct(BookTable $table) { $this->table = $table; 
}
  • Busque as informações do livro usando o BookTable's fetchAll() método e registrá-lo na visualização.

public function indexAction() { 
   $view = new ViewModel([ 
      'data' => $this->table->fetchAll(), ]); return $view; 
}
  • Exibe as informações do livro no script de visualização.

<table class = "table"> 
   <tr> 
      <th>Author</th> 
      <th>Title</th> 
      <th> </th> 
   </tr> 
   <?php foreach ($data as $sampledata) : ?> 
   <tr> 
      <td><?php echo $this->escapeHtml($data->author);?></td>  
      <td><?php echo $this->escapeHtml($data->title);?></td> 
   </tr> 
   <?php endforeach ?> 
</table>

Etapa 12: execute o aplicativo

Verifique o aplicativo executando - http://localhost:8080/tutorial.

Conforme discutido no último capítulo, o framework Zend fornece uma maneira genérica de acessar o banco de dados usando o Database Driverconceito. Trabalhar com um banco de dados depende apenas das informações do driver e, portanto, conectar-se a um banco de dados diferente envolve apenas alterar as informações do driver.

Vamos agora mudar o book exemplo para se conectar ao postgresql banco de dados com as seguintes etapas.

Step 1 - Crie um banco de dados, tutoriais no banco de dados postgresql local usando o seguinte comando -

CREATE DATABASE tutorials

Step 2 - Adicionar bookmesa. Mova para o novo banco de dados e execute o script de criação da tabela.

\c tutorials 
CREATE TABLE book ( 
   id SERIAL NOT NULL, 
   author varchar(100) NOT NULL, 
   title varchar(100) NOT NULL, 
   PRIMARY KEY (id) 
);

Step 3 - Adicione informações do livro de amostra usando o seguinte script -

INSERT INTO book (author, title) VALUES ('Dennis Ritchie', 'C Programming'); 
INSERT INTO book (author, title) VALUES ('James gosling', 'Java Programming'); 
INSERT INTO book (author, title) VALUES ('Rasmus Lerdorf', 'Programming PHP');

Step 4 - Alterar as informações do motorista no global.config file.

<?php 
return array ( 
   'db' => array ( 
      'driver' => 'Pdo', 
      'dsn' => 'pgsql:dbname = tutorials;host = localhost', 
      'driver_options' => array ( 
      ), 
   ), 
);

Step 5 - Altere as credenciais do banco de dados no local.config Arquivo.

return array ( 
   'db' => array( 
      'username' => '<username>', 
      'password' => '<password>', 
   ), 
);

Step 6 - Por fim, execute o aplicativo http://localhost:8080/tutorial. O resultado é o mesmo do aplicativo MySQL.

Zend Framework fornece um componente separado, zend-formpara acelerar o processo de criação e validação de formulários. Ele conecta o modelo e a camada de visualização. Ele fornece um conjunto de elementos de formulário para criar um formulário html completo a partir de modelos predefinidos, umInputFilter classe para validar o modelo em relação ao formulário e opções para vincular os dados do formulário ao modelo e vice-versa.

Instalar o componente do formulário

O componente de formulário Zend pode ser instalado usando o Composer comando conforme especificado abaixo -

composer require zendframework/zend-form

Um framework de formulário Zend tem três subcomponentes para gerenciar os formulários. Eles são explicados abaixo em detalhes -

  • Elements - Usado para definir um único controle de entrada html mapeado para uma propriedade no modelo.

  • Fieldset - Usado para agrupar elementos e outros fieldset de uma maneira aninhada.

  • Form - Usado para criar um formulário html e consiste em elementos e conjuntos de campos.

Zend Forms são geralmente criados sob o module//src/Form diretório.

Exemplo

Vamos agora criar um formulário simples para adicionar bookno banco de dados. Para fazer isso, devemos seguir as seguintes etapas -

Etapa 1: Criar BookForm

Crie o “BookForm.php” no diretório * myapp / module / Tutorial / src / Form ”. Adicione as seguintes alterações no arquivo -

<?php  
namespace Tutorial\Form;  
use Zend\Form\Form;  

class BookForm extends Form {
   
   public function __construct($name = null) { parent::__construct('book'); $this->add(array( 
         'name' => 'id', 
         'type' => 'Hidden', 
      ));  
      $this->add(array( 'name' => 'author', 'type' => 'Text', 'options' => array( 'label' => 'Author', ), )); $this->add(array( 
         'name' => 'title', 
         'type' => 'Text', 
         'options' => array( 
            'label' => 'Title', 
         ), 
      ));  
      $this->add(array( 
         'name' => 'submit', 
         'type' => 'Submit', 
         'attributes' => array( 
            'value' => 'Go', 
            'id' => 'submitbutton', 
         ), 
      )); 
   } 
}

o Form classe fornece um add methodpara mapear o modelo e seus detalhes de formulário correspondentes. nós criamos oBookForm estendendo o Form classe e adicionou os detalhes do formulário para Book modelo.

Etapa 2: atualize o modelo do livro, Book.php

Atualize o modelo, ‘Book’ com filtro e validação conforme especificado abaixo -

<?php 
namespace Tutorial\Model;  
use Zend\InputFilter\InputFilterInterface; 
use Zend\InputFilter\InputFilterAwareInterface; 
use Zend\InputFilter\InputFilter;  

class Book implements InputFilterAwareInterface { 
   public $id; 
   public $author; public $title;  
   protected $inputFilter; public function setInputFilter(InputFilterInterface $inputFilter) { 
      throw new \Exception("Not used"); 
   }  
   public function getInputFilter() { 
      if (!$this->inputFilter) { $inputFilter = new InputFilter(); 
         $inputFilter->add(array( 'name' => 'id', 'required' => true, 'filters' => array( array('name' => 'Int'), ), )); $inputFilter->add(array( 
            'name' => 'author', 
            'required' => true, 
            'filters' => array( 
               array('name' => 'StripTags'), 
               array('name' => 'StringTrim'), 
            ), 
            'validators' => array( 
               array( 
                  'name' => 'StringLength', 
                  'options' => array( 
                     'encoding' => 'UTF-8', 
                     'min' => 1, 
                     'max' => 100, 
                  ), 
               ), 
            ), 
         )); 
         $inputFilter->add(array( 'name' => 'title', 'required' => true, 'filters' => array( array('name' => 'StripTags'), array('name' => 'StringTrim'), ), 'validators' => array( array( 'name' => 'StringLength', 'options' => array( 'encoding' => 'UTF-8', 'min' => 1, 'max' => 100, ), ), ), )); $this->inputFilter = $inputFilter; } return $this->inputFilter; 
   }  
   public function exchangeArray($data) { $this->id = (!empty($data['id'])) ? $data['id'] : null; 
      $this->author = (!empty($data['author'])) ? $data['author'] : null; $this->title = (!empty($data['title'])) ? $data['title'] : null; 
   } 
}

Cada modelo deve implementar o InputFilterAwareInterface. O InputFilterAwareInterface fornece dois métodos,setInputFilter() e getInputFilter().

O getInputFilter é usado para obter os detalhes de validação do modelo. Zend framework fornece um rico conjunto de filtros e validadores para validar o formulário. Alguns dos filtros e validadores usados ​​no modelo de livro são os seguintes -

  • StripTags - Remova HTML indesejado.

  • StringTrim - Remova os espaços em branco desnecessários.

  • StringLength validator - Certifique-se de que o usuário não insira mais caracteres do que o limite especificado.

Etapa 3: atualize a classe BookTable

Inclui o saveBook método para adicionar livro ao banco de dados.

BookTable.php

<?php  
namespace Tutorial\Model;  
use Zend\Db\TableGateway\TableGatewayInterface;  

class BookTable {
   protected $tableGateway; public function __construct(TableGatewayInterface $tableGateway) { 
      $this->tableGateway = $tableGateway; 
   }  
   public function fetchAll() { 
      $resultSet = $this->tableGateway->select(); 
      return $resultSet; } public function getBook($id) { 
      $id = (int) $id; 
      $rowset = $this->tableGateway->select(array('id' => $id)); $row = $rowset->current(); if (!$row) { 
         throw new \Exception("Could not find row $id"); } return $row; 
   }  
   public function saveBook(Book $book) { $data = array ( 
         'author' => $book->author, 'title' => $book->title, 
      );  
      $id = (int) $book->id; 
      if ($id == 0) { $this->tableGateway->insert($data); } else { if ($this->getBook($id)) { $this->tableGateway->update($data, array('id' => $id));  
         } else { 
            throw new \Exception('Book id does not exist'); 
         } 
      } 
   } 
}

Etapa 4: atualize a classe TutorialController

Adicione uma nova ação addAction no controlador do tutorial - myapp / module / Tutorial / src / Controller / TutorialController.php.

public function addAction() { 
   $form = new BookForm(); $form->get('submit')->setValue('Add');  
   $request = $this->getRequest(); 
   if ($request->isPost()) { $book = new Book(); 
      $form->setInputFilter($book->getInputFilter()); 
      $form->setData($request->getPost());  
      if ($form->isValid()) { $book->exchangeArray($form->getData()); $this->bookTable->saveBook($book); // Redirect to list of Tutorial return $this->redirect()->toRoute('tutorial'); 
      } 
   }  
   return array('form' => $form); 
}

o addAction método faz os seguintes processos -

  • Obtém o objeto da solicitação.

  • Verifica se o método http da solicitação é um post método.

  • Se o método http do pedido não for post, ele apenas renderiza o modelo, add.phtml

  • Se o método http da solicitação não for post, então ele define o inputfilter, obtém os dados da solicitação e os define no inputfiler.

  • Verifica se o formulário é válido usando o isValid() método da classe Form.

  • Se o formulário não for válido, ele renderiza novamente o modelo, add.phtml

  • Se o formulário for válido, ele salva o livro no banco de dados e o redireciona para a página inicial.

Etapa 5: adicione o modelo add.phtml

Crie um modelo - add.phtml em myapp / module / Tutorial / view / tutorial / tutorial / add.phtml

Add.phtml

<?php  
$title = 'Add new Book'; 
$this->headTitle($title);  
?>  
<h1><?php echo $this->escapeHtml($title); ?></h1>  
<?php  
if(!empty($form)) { $form->setAttribute('action', $this->url('tutorial', array('action' => 'add'))); $form->prepare();  
   echo $this->form()->openTag($form); 
   echo $this->formHidden($form->get('id')); 
   echo $this->formRow($form->get('author'))."<br>"; 
   echo $this->formRow($form->get('title'))."<br>"; 
   echo $this->formSubmit($form->get('submit')); 
   echo $this->form()->closeTag(); 
}

Aqui, estamos renderizando a forma do livro usando o Form instância, $form.

Etapa 6: execute o aplicativo

Agora, podemos executar o aplicativo - http://localhost:8080/tutorial/add.

Form Page

Validate Error Page

O upload de arquivos é um dos principais conceitos na programação de formulários. Zend framework fornece todos os itens necessários para fazer upload de arquivos através dozend-form e a zend-inputfilter componente.

Classe FileInput

O componente zend-inputfilter fornece a classe Zend \ InputFilter \ FileInput para lidar com o elemento de entrada do arquivo html - <input type = 'file' />. oFileInputé como os outros filtros de entrada, com algumas exceções. Eles são os seguintes -

  • Uma vez que o PHP salva os detalhes do arquivo enviado em $_FILES array global, o FileInput reúne as informações do arquivo carregado apenas por meio de $ _FILES.

  • A validação precisa ser feita antes que a classe FileInput processe os dados. É o comportamento oposto dos outros filtros de entrada.

  • O Zend \ Validator \ File \ UploadFile é o validador padrão a ser usado. oUploadFile valida os detalhes de entrada do arquivo.

Para adicionar um tipo de upload de arquivo em um formulário, precisamos usar o tipo de entrada File. O código parcial é o seguinte -

$form->add(array( 
   'name' => 'imagepath', 
   'type' => 'File', 
   'options' => array('label' => 'Picture',), 
));

Outra classe usada no upload de arquivos é Zend \ Filter \ File \ RenameUpload. oRenameUploadé usado para mover o arquivo carregado para o local desejado. A classe parcial para usar o filtro de arquivo é a seguinte -

$file = new FileInput('imagepath'); 
$file->getValidatorChain()->attach(new UploadFile()); $file->getFilterChain()->attach( 
   new RenameUpload([ 
      'target'    => './public/tmpuploads/file', 
      'randomize' => true, 
      'use_upload_extension' => true 
   ]));
$inputFilter->add($file);

Aqui, as opções de RenameUpload são os seguintes -

  • target - O caminho de destino do arquivo carregado.

  • randomize - Adicione uma string aleatória para evitar a duplicação do arquivo carregado.

  • use_upload_extension - Anexe a extensão do arquivo ao arquivo enviado ao destino.

Upload de arquivo - Exemplo de trabalho

Vamos modificar o módulo do tutorial e incluir um recurso de upload de imagem.

Modifique a tabela do banco de dados

Vamos adicionar o imagepath coluna para a tabela do livro executando o seguinte comando SQL -

ALTER TABLE `book` ADD `imagepath` VARCHAR(255) NOT NULL AFTER 'imagepath';

Atualizar BookForm.php

Adicione o elemento de entrada de arquivo para enviar uma imagem no formato de livro - myapp / module / Tutorial / src / Model / BookForm.php.

Inclua o seguinte código no __constructmethod da classe BookForm.

$this->add(array( 
   'name' => 'imagepath', 
   'type' => 'File', 
   'options' => array ('label' => 'Picture',), 
));

Atualizar Book.php

Faça as seguintes alterações na classe Book - myapp / module / Tutorial / src / Model / Book.php.

  • Adicionar uma nova propriedade imagepath para a foto.

public $imagepath;
  • Atualize o getInputFilter método como mostrado abaixo -

    • Adicione o FileInput filtro para elemento de entrada de arquivo.

    • Colocou o UploadFile validação para validar o elemento de entrada do arquivo.

    • Configure o RenameUpload para mover o arquivo carregado para o destino adequado.

A listagem parcial do código é a seguinte -

$file = new FileInput('imagepath'); $file->getValidatorChain()->attach(new UploadFile()); 
$file->getFilterChain()->attach( new RenameUpload([ 'target' => './public/tmpuploads/file', 'randomize' => true, 'use_upload_extension' => true ])); $inputFilter->add($file);
  • Atualize o exchangeArray método para incluir o imagepathpropriedade. O imagepath pode vir de um formulário ou banco de dados. Se o imagepath vier de um formulário, o formato será uma matriz com a seguinte especificação -

array(1) { 
   ["imagepath"] => array(5) { 
      ["name"]     => string "myimage.png" 
      ["type"]     => string "image/png"           
      ["tmp_name"] => string 
         "public/tmpuploads/file_<random_string>.<image_ext>" 
      ["error"]    => int <error_number> 
      ["size"]     => int <size> 
   } 
}
  • Se o imagepath vier de um banco de dados, será uma string simples. A listagem de código parcial para analisar um caminho de imagem é a seguinte -

if(!empty($data['imagepath'])) { 
   if(is_array($data['imagepath'])) { $this->imagepath = str_replace("./public", "", $data['imagepath']['tmp_name']); } else { $this->imagepath = $data['imagepath']; } } else { $data['imagepath'] = null; 
}

A lista completa do Book modelo é o seguinte -

<?php  
namespace Tutorial\Model;  
use Zend\InputFilter\InputFilterInterface; 
use Zend\InputFilter\InputFilterAwareInterface;  
use Zend\Filter\File\RenameUpload; 
use Zend\Validator\File\UploadFile; 
use Zend\InputFilter\FileInput; 
use Zend\InputFilter\InputFilter;  

class Book implements InputFilterAwareInterface { 
   public $id; public $author; 
   public $title; public $imagepath;  
   protected $inputFilter; public function setInputFilter(InputFilterInterface $inputFilter) { 
      throw new \Exception("Not used");
   }  
   public function getInputFilter() { 
      if (!$this->inputFilter) { $inputFilter = new InputFilter(); 
         $inputFilter->add(array( 'name' => 'id', 'required' => true, 'filters' => array( array('name' => 'Int'), ), )); $inputFilter->add(array( 
            'name' => 'author', 
            'required' => true, 
            'filters' => array( 
               array('name' => 'StripTags'), 
               array('name' => 'StringTrim'), 
            ), 
            'validators' => array( 
               array( 
                  'name' => 'StringLength', 
                  'options' => array( 
                     'encoding' => 'UTF-8', 
                     'min' => 1, 
                     'max' => 100, 
                  ), 
               ), 
            ), 
         )); 
         $inputFilter->add(array( 'name' => 'title', 'required' => true, 'filters' => array( array('name' => 'StripTags'), array('name' => 'StringTrim'), ), 'validators' => array( array( 'name' => 'StringLength', 'options' => array( 'encoding' => 'UTF-8', 'min' => 1, 'max' => 100, ), ), ), )); $file = new FileInput('imagepath'); 
         $file->getValidatorChain()->attach(new UploadFile()); $file->getFilterChain()->attach( 
            new RenameUpload([ 
               'target'    => './public/tmpuploads/file', 
               'randomize' => true, 
               'use_upload_extension' => true 
            ])); 
            $inputFilter->add($file);  
            $this->inputFilter = $inputFilter; 
      } 
      return $this->inputFilter; } public function exchangeArray($data) { 
      $this->id = (!empty($data['id'])) ? $data['id'] : null; $this->author = (!empty($data['author'])) ? $data['author'] : null; 
      $this->title = (!empty($data['title'])) ? $data['title'] : null; if(!empty($data['imagepath'])) { 
         if(is_array($data['imagepath'])) { $this->imagepath = str_replace("./public", "", 
               $data['imagepath']['tmp_name']); } else { $this->imagepath = $data['imagepath']; } } else { $data['imagepath'] = null; 
      } 
   } 
}

Atualizar BookTable.php

Nós atualizamos BookForm e a Book model. Agora, atualizamos oBookTable e modificar o saveBookmétodo. Isso é o suficiente para incluir a entrada imagepath na matriz de dados,$data.

A listagem parcial do código é a seguinte -

$data = array('author' => $book->author, 'title' => $book->title, 
   'imagepath' => $book->imagepath 
);

A lista completa de códigos do BookTable a aula é a seguinte -

<?php  
namespace Tutorial\Model;  
use Zend\Db\TableGateway\TableGatewayInterface;  

class BookTable {  
   protected $tableGateway; 
   public function __construct(TableGatewayInterface $tableGateway) { $this->tableGateway = $tableGateway; } public function fetchAll() { $resultSet = $this->tableGateway->select(); return $resultSet; 
   }  
   public function getBook($id) { $id  = (int) $id; $rowset = $this->tableGateway->select(array('id' => $id)); 
      $row = $rowset->current(); 
      if (!$row) { throw new \Exception("Could not find row $id"); 
      } 
      return $row; } public function saveBook(Book $book) { 
      $data = array ( 'author' => $book->author,
         'title'  => $book->title, 'imagepath' => $book->imagepath 
      );  
      $id = (int) $book->id; 
      if ($id == 0) { $this->tableGateway->insert($data); } else { if ($this->getBook($id)) { $this->tableGateway->update($data, array('id' => $id)); 
         } else { 
            throw new \Exception('Book id does not exist'); 
         } 
      } 
   } 
}

Update addAction in the TutorialController.php: As informações de upload do arquivo estarão disponíveis no $_FILES array global e pode ser acessado usando o Request's getFiles()método. Portanto, mescle os dados postados e as informações de upload de arquivo conforme mostrado abaixo.

$post = array_merge_recursive( 
   $request->getPost()->toArray(), $request->getFiles()->toArray() 
);

A lista completa do addAction() método é o seguinte -

public function addAction() { 
   $form = new BookForm(); $form->get('submit')->setValue('Add');  
   $request = $this->getRequest(); 
   if ($request->isPost()) { $book = new Book(); 
      $form->setInputFilter($book->getInputFilter()); 
      $post = array_merge_recursive( $request->getPost()->toArray(), 
         $request->getFiles()->toArray() ); $form->setData($post); if ($form->isValid()) { 
         $book->exchangeArray($form->getData());  
         $this->bookTable->saveBook($book);  
         
         // Redirect to list of Tutorial 
         return $this->redirect()->toRoute('tutorial'); } } return array('form' => $form); 
}

Atualizar visualização do add.phtml

Finalmente, altere o “add.phtml” e inclua o elemento de entrada do arquivo imagepath como mostrado abaixo -

echo $this->formRow($form->get('imagepath'))."<br>";

A lista completa é a seguinte -

<?php 
$title = 'Add new Book'; $this->headTitle($title); ?> <h1><?php echo $this->escapeHtml($title); ?></h1> <?php if(!empty($form)) {  
   $form->setAttribute('action', $this->url('tutorial', array('action' => 'add'))); 
   $form->prepare(); echo $this->form()->openTag($form); echo $this->formHidden($form->get('id')); echo $this->formRow($form->get('author'))."<br>"; echo $this->formRow($form->get('title'))."<br>"; echo $this->formRow($form->get('imagepath'))."<br>"; echo $this->formSubmit($form->get('submit')); echo $this->form()->closeTag(); 
}

Execute o aplicativo

Por fim, execute o aplicativo em http://localhost:8080/tutorial/add e adicione os novos registros.

O resultado será como mostrado nas seguintes imagens -

Form Page

Index Page

AJAX é uma tecnologia moderna em programação web. Ele fornece opções para enviar e receber dados em uma página da Web de forma assíncrona, sem atualizar a página. Zend framework oferece uma opção de trabalhar com ojson modelo através zend-view e zend-jsoncomponente. Vamos aprender a programação Zend AJAX neste capítulo.

Instale o componente json

O componente Zend json pode ser instalado usando o Composer comando conforme especificado abaixo -

composer require zendframework/zend-json

Conceito

A estrutura Zend fornece dois métodos para escrever facilmente um aplicativo da Web habilitado para AJAX. Eles são os seguintes -

  • o isXmlHttpRequest() método no Requestobject - Se uma solicitação AJAX for feita, o método isXmlHttpRequest () do objeto de solicitação retornará verdadeiro, caso contrário, será falso. Este método é usado para lidar com uma solicitação AJAX corretamente no lado do servidor.

if ($request->isXmlHttpRequest()) { 
   // Ajax request 
} else { 
   // Normal request 
}
  • O Zend / View / Model / JsonModel - O JsonModel é uma alternativa para ViewModelpara ser usado exclusivamente para AJAX e os cenários de API REST. O JsonModel junto comJsonStrategy (a ser configurado no bloco do gerenciador de visualização do módulo) codifica os dados do modelo em Json e retorna como uma resposta em vez de visualizações (phtml).

AJAX - Exemplo de Trabalho

Vamos adicionar uma nova página ajax, ajaxno módulo tutorial e busque as informações do livro de forma assíncrona. Para fazer isso, devemos seguir as etapas a seguir.

Etapa 1: Adicionar JsonStrategy na configuração do módulo

Atualize o bloco do gerenciador de visualização no arquivo de configuração do módulo do tutorial - myapp / module / Tutorial / config / module.config.php. Então,JsonStrategy vai trabalhar com JsonModel para codificar e enviar os dados json.

'view_manager' => [ 
   'template_map' => array
      ('layout/layout' => __DIR__ . '/../view/layout/newlayout.phtml'), 
   'template_path_stack' => [ 
      'tutorial' => __DIR__ . '/../view', 
   ], 
   'strategies' => array('ViewJsonStrategy',), 
],

Etapa 2: adicione o método ajaxAction no TutorialController.php

Adicione o método ajaxAction no TutorialController.php com o seguinte código -

public function ajaxAction() { 
   $data = $this->bookTable->fetchAll(); $request = $this->getRequest(); $query = $request->getQuery(); if ($request->isXmlHttpRequest() || $query->get('showJson') == 1) { $jsonData = array(); 
      $idx = 0; foreach($data as $sampledata) { $temp = array( 
            'author' => $sampledata->author, 'title' => $sampledata->title, 
            'imagepath' => $sampledata->imagepath ); $jsonData[$idx++] = $temp; 
      } 
      $view = new JsonModel($jsonData); 
      $view->setTerminal(true); } else { $view = new ViewModel(); 
   }  
   return $view; 
}

Aqui, ajaxAction verificará se a solicitação de entrada é AJAX ou não. Se a solicitação de entrada for AJAX, então oJsonModelSerá criado. Caso contrário, um normalViewModel Será criado.

Em ambos os casos, as informações do livro serão obtidas do banco de dados e preenchidas no modelo. Se o modelo for um JsonModel, entãoJsonStrategy será chamado e codificará os dados como json e retornará como resposta.

o $query->get('showJson') == 1é usado para fins de depuração. Basta adicionarshowJson=1 no url e a página exibirá os dados json.

Etapa 3: adicione ajax.phtml

Agora, adicione o script de visualização ajax.phtmlpara o método ajaxAction. Esta página terá um link com o rótulo -Load book information.

Clicar nesse link fará uma solicitação AJAX, que buscará as informações do livro como dados Json e mostrará as informações do livro como uma tabela formatada. O processamento AJAX é feito usando oJQuery.

A lista de códigos completa é a seguinte -

<a id = "loadbook" href = "#">Load book information</a> 
</br> </br> 

<table class = "table"> 
   <tbody id = "book"> 
   </tbody> 
</table>  

<script language = "javascript"> 
$(document).ready(function(){ $("#loadbook").on("click", function(event){ 
      $.ajax({ url: '/tutorial/ajax', type: 'POST', dataType: 'json', async: true, success: function(data, status) { var e = $('<tr><th>Author</th><th>Title</th><th>Picture</th></tr>'); 
            $('#book').html(''); $('#book').append(e); 
            
            for(i = 0; i < data.length; i++) { 
               book = data[i]; 
               var e = $('<tr><td id = "author"></td><td id = "title"></td> <td id="imagepath"><img src = ""/></td></tr>'); $('#author', e).html(book['author']); 
               $('#title', e).html(book['title']); $('#imagepath img', e).attr('src', book['imagepath']); 
               $('#book').append(e); 
            } 
         }, 
         error : function(xhr, textStatus, errorThrown) { 
            alert('Ajax request failed.'); 
         } 
      }); 
   }); 
}); 
</script>

Etapa 4: execute o aplicativo

Finalmente, execute o aplicativo - http://localhost:8080/tutorial/ajax e clique no link Carregar informações do livro.

O resultado será como mostrado abaixo -

Ajax Page -

Ajax Page with Book Information

Ajax page with debugging information

O Cookie é um conceito muito importante em uma aplicação web. Ele oferece a opção de persistir os dados do usuário, geralmente um pequeno pedaço de informação no próprio navegador por um período limitado.

Um Cookie é usado para manter o estado do aplicativo da web. Zend framework fornece um módulo de cookie dentro dozend-httpcomponente. Este zend-http fornece a abstração HTTP e sua implementação.

Instalando o Componente HTTP

O componente HTTP pode ser facilmente instalado usando o Composer conforme especificado no código abaixo.

composer require zendframework/zend-http

Conceito

O zend-http fornece o Zend\Http\Cookiesclasse para gerenciar cookies. É usado junto com oZend\Http\Clientclasse, que é usada para enviar uma solicitação a um servidor web. Os cookies podem ser inicializados conforme mostrado no código abaixo -

use Zend\Http\Cookies  
$c = new Cookies();

Quando o cliente HTTP (Zend \ Http \ Client) envia pela primeira vez uma solicitação de URI ao servidor web, ele não possui nenhum cookie. Assim que a solicitação é recebida pelo servidor da web, ele inclui o cookie em seu objeto de resposta como oHTTP Header, Set-Cookiee envia para o cliente HTTP. O cliente HTTP extrairá o cookie da resposta http e o reenviará como o mesmo cabeçalho HTTP na solicitação subsequente. Geralmente, cada cookie será mapeado para um domínio e um caminho do domínio.

Os métodos disponíveis em Cookies classe são as seguintes -

  • addCookie(uri) - É usado para adicionar um cookie ao objeto de solicitação do URI fornecido.

  • getCookie(cookieName, $cookieForm) - É usado para obter o cookie $ cookieName disponível no URI fornecido, $uri. O terceiro argumento é como o cookie será retornado, seja string ou array.

  • fromResponse(uri) - É usado para extrair cookies do objeto de resposta do URI fornecido.

  • addCookiesFromResponse - É o mesmo que fromResponse, mas o extrai e adiciona novamente ao objeto de solicitação do URI fornecido.

  • isEmpty() - É usado para descobrir se o dado Cookie objeto tem qualquer cookie ou não.

  • reset() - É usado para limpar todos os cookies no URI fornecido.

No próximo capítulo, discutiremos com relação ao gerenciamento de sessão no Zend Framework.

Uma sessão é um conceito muito importante em uma aplicação web. Ele oferece a opção de persistir os dados do usuário no servidor da web por um período limitado de tempo. Zend framework fornece um componente separado,zend-session para lidar com as informações da sessão.

Instale um componente de sessão

O componente da sessão pode ser instalado usando o Composer conforme especificado abaixo -

composer require zendframework/zend-session

Componentes da Sessão

O Zend framework fornece seis componentes para lidar com o gerenciamento de sessão. Todos esses componentes foram explicados abaixo -

  • Zend\Session\Container - A API principal para ler e escrever as informações da sessão.

  • Zend\Session\SessionManager - É usado para gerenciar todo o ciclo de vida de uma sessão.

  • Zend\Session\Storage - Isso é usado para especificar como os dados da sessão serão armazenados na memória.

  • Zend\Session\SaveHandler - É usado para armazenar e recuperar os dados da sessão em um local físico como RDBMS, Redis, MangoDB, etc.

  • Zend\Session\Validator - Isso é usado para proteger a sessão de sequestro, verificando o endereço remoto da solicitação inicial e subsequente e o agente do usuário.

  • Zend\Session\Config\SessionConfig - É usado para configurar como a sessão deve se comportar.

A configuração padrão é suficiente para trabalhar com uma sessão. Usando os componentes acima, todos os aspectos de uma sessão podem ser tratados facilmente.

Exemplo de componente de sessão

Vamos seguir os seguintes pontos para criar uma nova página para entender uma sessão no framework Zend. Por padrão, é suficiente criar uma instância de umContainer classe para gerenciar as sessões.

  • Crie uma nova ação, sessionAction dentro TutorialController.

  • Inicialize um Container objeto.

$c = new Container();
  • Verifique se uma chave arbitrária countexiste. Se a chave não estiver disponível, inicialize ocount com valor 1. Se estiver disponível, incremente o valor conforme mostrado no código a seguir.

if (!isset($c->count)) { $c->count = 0; 
} else { 
   $c->count++; 
}
  • Registre a contagem no ViewModel.

  • Crie um arquivo de modelo para - sessionAction, session.phtml em myapp / module / Tutorial / view / tutorial / tutorial / session.phtml e então renderize o count valor.

  • Atualizar a página aumentará o valor de countna sessão. A lista completa é a seguinte -

TutorialController.php

public function sessionAction() { 
   $c = new Container();  
   if (!isset($c->count)) { $c->count = 0; 
   } else { 
      $c->count++; } $view = new ViewModel([ 
      'count' => $c->count, ]); return $view; 
}

session.pthml

Session data, COUNT = <?= $this->count ?>

Sample Result

Session data, Count = 5

A autenticação é um dos recursos mais significativos e obrigatórios em qualquer aplicativo da web. Zend Framework fornece um componente separado para lidar com a autenticação, que é chamado dezend-authentication.

Instale um componente de autenticação

O componente de autenticação pode ser instalado usando o seguinte Composer comando.

composer require zendframework/zend-authentication

Conceito

Normalmente, um desenvolvedor escreve uma função php para autenticar os detalhes do usuário em uma fonte de dados. Uma vez que a autenticação é feita, os detalhes de autenticação são mantidos para solicitações subsequentes. Zend Framework generaliza este conceito e fornece duas classes, que são explicadas abaixo -

Classe 1 Zend \ Authentication \ Adapter \ AdaptorInterface

Esta classe fornece um único método, authenticatepara escrever a lógica de autenticação. O método de autenticação retorna uma instância deZend\Authentication\Result classe.

este Resultobjeto mantém o status de autenticação; identidade se a autenticação for bem-sucedida e uma mensagem de erro se a autenticação falhar. A assinatura da interface de autenticação e classe de resultado é a seguinte -

AdaptorInterface

namespace Zend\Authentication\Adaptor; 
public function authenticate() { 
   // code 
}

Result class

namespace Zend\Authentication; 
class Result { 
   public function __construct($code, $identity, array $messages = []); 
}

O Zend Framework fornece uma implementação padrão para autenticação no banco de dados, ldap, http básico e credenciais digest. AAdaptor autentica, mas não mantém os detalhes para quaisquer solicitações futuras.

Classe 2 Zend \ Authentication \ AuthenticationService

O AuthenticationService é o componente principal, que usa o adaptador já configurado para fins de autenticação. Depois que a autenticação é feita, ele persiste os detalhes de autenticação e fornece métodos,hasIdentity() para verificar se uma identidade está disponível, getIdentity() para obter os detalhes de autenticação e clearIdentity() para limpar os detalhes de autenticação.

A listagem parcial do código para usar este AuthenticationService é a seguinte -

$adap = new Adapter($username, $password); $auth = new AuthenticationService(); 
$result = $auth->authenticate($adap); if($result->isValid) { 
   $identity = $auth->getIdentity(); 
} else { 
   // process $result->getMessages() } // clear $auth->clearIdentity();

O material relacionado à autorização é empacotado como dois módulos separados, que são - zend-permissions-acl e zend-permissions-rbac. O zend-permissions-acl é baseado na lista de controle de acesso e o zend-permissions-rbac é baseado na lista de controle de acesso baseada na função. Eles fornecem abstração de alto nível do conceito ACL e RBAC e auxiliam na escrita do aplicativo de nível empresarial.

O Zend Framework fornece um componente separado chamado zend-mailpara enviar mensagens de e-mail. O componente zend-mail também oferece uma opção de ler e escrever mensagens de e-mail com anexos em formato de texto e html. Enviar um e-mail no Zend é muito mais fácil e simples de configurar.

Vamos examinar os conceitos de e-mail, configurações básicas, configurações avançadas, como transporte SMTP, etc., neste capítulo.

Instalar o Componente Mail

O componente de correio pode ser instalado usando o seguinte comando Composer.

composer require zendframework/zend-mail

Configuração Básica de Email

Um e-mail básico consiste em um ou mais destinatários, um assunto, um corpo e um remetente. Zend forneceZend\Mail\Messageclasse para criar uma nova mensagem de e-mail. Para enviar um e-mail usando ozend-mail, você deve especificar pelo menos um destinatário, bem como o corpo da mensagem.

O código parcial para criar uma nova mensagem de e-mail é o seguinte -

use Zend\Mail;
$mail = new Mail\Message(); $mail->setSubject('Zend email sample'); 
$mail->setBody('This is content of the mail message'); $mail->setFrom('[email protected]', "sender-name"); 
$mail->addTo('[email protected]', "recipient-name");

Zend fornece a classe Zend \ Mail \ Sendmail para enviar a mensagem de correio. Sendmail usa a função de correio nativo php, mail para enviar a mensagem de e-mail e podemos configurar a camada de transporte usando o arquivo de configuração php.

A codificação parcial usando Sendmail é a seguinte -

$transport = new Mail\Transport\Sendmail(); 
$transport->send($mail);

o zend-mail fornece muitas camadas de transporte e cada uma pode exigir muitos parâmetros adicionais, como nome de usuário, senha, etc.

Métodos de gerenciamento de e-mail

Alguns dos métodos notáveis ​​de gerenciamento de e-mail são os seguintes -

  • isValid - Mensagens sem endereço 'De' são inválidas.

isValid() : bool
  • setEncoding - Defina a codificação da mensagem.

setEncoding(string $encoding) : void
  • getEncoding - Obtenha a codificação da mensagem.

getEncoding() : string
  • setHeaders - Compor cabeçalhos.

setHeaders(Zend\Mail\Headers $headers) : void
  • getHeaders - Acesse a coleção de cabeçalhos.

getHeaders() : Zend\Mail\Headers
  • setFrom- Definir (substituir) endereços de. Ele contém pares de chave / valor em que a chave é o nome legível por humanos e o valor é o endereço de e-mail.

setFrom( 
   string|AddressInterface|array|AddressList|Traversable $emailOrAddressList, string|null $name 
) : void
  • addFrom - Adicione um endereço 'De'.

addFrom( 
   string|AddressInterface|array|AddressList|Traversable $emailOrAddressOrList, string|null $name 
) : void
  • getFrom - Recuperar lista de remetentes 'De'.

getFrom() : AddressList 
setTo - Overwrite the address list in the To recipients. 
setTo( 
   string|AddressInterface|array|AddressList|Traversable $emailOrAddressList, null|string $name 
) : void
  • setSubject - Defina o valor do cabeçalho do assunto da mensagem.

setSubject(string $subject) :void
  • setBody - Defina o corpo da mensagem.

setBody(null|string|Zend\Mime\Message|object $body) : void

Camada de Transporte SMTP

o zend-mail fornece opções para enviar um e-mail usando o servidor SMTP através do Zend\Mail\Transport\Smtpclass. É comoSendmail exceto que tem algumas opções adicionais para configurar o host SMTP, porta, nome de usuário, senha, etc.

O código parcial é o seguinte -

use Zend\Mail\Transport\Smtp as SmtpTransport; 
use Zend\Mail\Transport\SmtpOptions;  
$transport = new SmtpTransport(); $options = new SmtpOptions([ 
   'name' => 'localhost', 
   'host' =>'smtp.gmail.com', 
   'port' => 465, 
]); 
$transport->setOptions($options);

Aqui,

  • name - Nome do host SMTP.

  • host - Nome de host remoto ou endereço IP.

  • port - Porta na qual o host remoto está escutando.

Conceito de Correio - Exemplo

Vamos seguir os seguintes pontos para escrever um aplicativo simples de console php para entender o conceito de e-mail.

  • Crie uma pasta “mailapp”.

  • Instalar zend-mail usando a ferramenta de composição.

  • Crie um arquivo php Mail.php dentro da pasta “mailapp”.

  • Crie a mensagem usando o Zend\Mail\Message.

$message = new Message(); $message->addTo('[email protected]'); 
$message->addFrom('[email protected]'); $message->setSubject('Hello!'); 
$message->setBody("My first Zend-mail application!");
  • Crie a camada de transporte SMTP e adicione a configuração necessária.

// Setup SMTP transport using LOGIN authentication 
$transport = new SmtpTransport(); 
$options = new SmtpOptions([ 'name' => 'localhost', 'host' => 'smtp.gmail.com', // or any SMTP server 'port' => 465, // port on which the SMTP server is listening 'connection_class' => 'login', 'connection_config' => [ username' => '<your username>', 'password' => '<your password>', 'ssl' => 'ssl'], ]); $transport->setOptions($options);
  • Envie o e-mail usando o send método.

$transport->send($message);

A lista completa, Mail.php , é a seguinte -

<?php  
require __DIR__ . '/vendor/autoload.php';  

use Zend\Mail\Message; 
use Zend\Mail\Transport\Smtp as SmtpTransport; 
use Zend\Mail\Transport\SmtpOptions;  
  
$message = new Message(); 
$message->addTo('[email protected]'); $message->addFrom('[email protected]'); 
$message->setSubject('Hello!'); $message->setBody("My first Zend-mail application!");  
  
// Setup SMTP transport using LOGIN authentication 
$transport = new SmtpTransport(); $options = new SmtpOptions([ 
   'name' => 'localhost', 
   'host' => 'smtp.gmail.com', // or any SMTP server 
   'port' => 465, // port on which the SMTP server is listening 
   'connection_class' => 'login', 
   'connection_config' => [ 
      'username' => '<your username>', 'password' => '<your password>', 
      'ssl' => 'ssl'], 
]); 
$transport->setOptions($options); 
$transport->send($message);

Agora, execute o aplicativo no prompt de comando php Mail.php. Isso enviará o e-mail conforme configurado no aplicativo.

Em geral, podemos depurar um aplicativo PHP usando o advanced debugger tool ou usando comandos simples como echo e die. Em um cenário da web, precisamos testar a lógica de negócios, bem como a camada de apresentação. Os formulários em um aplicativo da web podem ser testados inserindo dados de teste relevantes para garantir que os formulários estejam funcionando conforme o esperado.

O design de um site pode ser testado manualmente usando um navegador. Esse tipo de processo de teste pode ser automatizado usando teste de unidade. Um teste de unidade é essencial em grandes projetos. Esses testes de unidade ajudarão a automatizar o processo de teste e alertar o desenvolvedor quando algo der errado.

Configurando o PHPUnit

O framework Zend se integra com o framework de teste de unidade PHPUnit. Para escrever um teste de unidade para o framework Zend, precisamos configurar o PHPUnit, o que pode ser feito facilmente usando o seguinte comando Composer.

$ composer require --dev phpunit/phpunit

Depois de executar o comando acima, você obterá uma resposta conforme mostrado no seguinte bloco de código.

Using version ^5.7 for phpunit/phpunit 
./composer.json has been updated 
Loading composer repositories with package information 
Updating dependencies (including require-dev) 
Nothing to install or update 
Writing lock file 
Generating autoload files

Agora, ao abrir o arquivo “composer.json”, você verá as seguintes alterações -

"require-dev": { 
   "phpunit/phpunit": "^5.7" 
}

TestCase e Assertions

O framework Zend fornece classes auxiliares para testar a unidade do controlador. oTestCase é o principal componente em um PHPUnit framework para escrever os casos de teste e o Zend Framework fornece uma implementação abstrata do TestCase que é chamado de AbstractHttpControllerTestCase.

Este AbstractHttpControllerTestCase fornece vários Assertmétodos e podem ser agrupados por funcionalidade. Eles são os seguintes -

  • Request Assertions- Usado para declarar a solicitação http. Por exemplo, assertControllerName.

  • CSS Select Assertions - Usado para verificar o HTML de resposta usando o modelo HTML DOM.

  • XPath Assertions - Uma alternativa para as asserções de seleção de CSS com base no XPath.

  • Redirect Assertions - Usado para verificar o redirecionamento da página.

  • Response Header Assertions - Usado para verificar o cabeçalho de resposta como código de status (assertResponseStatusCode)

Criar diretório de testes

Um teste de unidade pode ser escrito separadamente para cada módulo. Toda a codificação relacionada ao teste precisa ser criada dentro dotest pasta no diretório raiz do módulo.

Por exemplo, para escrever um teste para o TutorialController disponível no módulo Tutorial, a classe de teste precisa ser colocada no diretório myapp / module / Tutorial / test / Controller /.

Exemplo

Vamos escrever uma classe de teste para testar a unidade TutorialController.

Para começar, devemos escrever uma classe chamada TutorialControllerTest e estendê-la para AbstractHttpControllerTestCase.

A próxima etapa é escrever um Setupmétodo para configurar o ambiente de teste. Isso pode ser feito chamando osetApplicationConfig método e passando nosso arquivo de configuração do aplicativo principal myapp / config / application.config.php

public function setUp() { 
   $configOverrides = [];  
   $this->setApplicationConfig(ArrayUtils::merge( include __DIR__ . '/../../../../config/application.config.php', $configOverrides 
   )); 
   parent::setUp(); 
}

Escreva um ou mais métodos e chame vários métodos de declaração, dependendo do requisito.

$this->assertMatchedRouteName('tutorial');

Escrevemos a classe de teste e a lista completa é a seguinte -

<?php  
namespace TutorialTest\Controller;  
use Tutorial\Controller\TutorialController; 
use Zend\Stdlib\ArrayUtils; 
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;  

class TutorialControllerTest extends AbstractHttpControllerTestCase { 
   public function setUp() { 
      $configOverrides = [];  
      $this->setApplicationConfig(ArrayUtils::merge( include __DIR__ . '/../../../../config/application.config.php', $configOverrides 
      ));  
      parent::setUp(); 
   }  
   public function testIndexActionCanBeAccessed() { 
      $this->dispatch('/tutorial', 'GET'); $this->assertResponseStatusCode(200); 
      $this->assertModuleName('tutorial'); $this->assertControllerName(TutorialController::class); 
      $this->assertControllerClass('TutorialController'); $this->assertMatchedRouteName('tutorial'); 
   } 
}

Agora, abra um prompt de comando, vá para o diretório raiz do aplicativo e execute o phpunit executável disponível dentro do vendor pasta.

cd /path/to/app  
./vendor/bin/phpunit ./vendor/bin/phpunit module/
   Tutorial/test/Controller/TutorialControllerTest.php

O resultado será como mostrado no seguinte bloco de código -

PHPUnit 5.7.5 by Sebastian Bergmann and contributors.  
.1 / 1 (100%)  
Time: 96 ms, Memory: 8.00MB  
OK (1 test, 5 assertions)

A falha do sistema precisa ser tratada de forma eficaz para o bom funcionamento do sistema. Zend Framework vem com umdefault error trappingque imprime e registra o erro conforme eles ocorrem. Este mesmo manipulador de erros é usado para capturarExceptions.

O Error Handler exibe erros quando a depuração é verdadeira e registra o erro quando a depuração é falsa. Zend Framework tem várias classes de exceção e o tratamento de exceção embutido irá capturar qualquer exceção não capturada e renderizar uma página útil.

Tratamento de erros padrão

Podemos definir as configurações de erro padrão no arquivo de configuração do aplicativo, myapp / module / Application / config / module.config.php.

O exemplo de código parcial é o seguinte -

'view_manager' => [ 
   'display_not_found_reason' => true, 
   'display_exceptions'       => true, 
   'doctype'                  => 'HTML5', 
   'not_found_template'       => 'error/404', 
   'exception_template'       => 'error/index', 
   'template_map' => [ 
      'layout/layout'           => __DIR__ . '/../view/layout/layout.phtml', 
      'application/index/index' => __DIR__ . '/../view/application/index/index.phtml', 
      'error/404'               => __DIR__ . '/../view/error/404.phtml', 
      'error/index'             => __DIR__ . '/../view/error/index.phtml', 
   ], 
   'template_path_stack' => [ 
      __DIR__ . '/../view', 
   ], 
],

Aqui, display_exception, not_found_template, exception_template, error / 404 e o erro / índice são itens de configuração relacionados a erros e são autoexplicativos.

O item mais importante entre estes é o error/index. Este é o modelo mostrado quando ocorre uma exceção no sistema. Podemos modificar este modelo, myapp / module / Application / view / error / index.phtml para controlar a quantidade de erro a ser mostrado.

Neste capítulo, aprenderemos como criar um aplicativo de funcionário completo baseado em MVC no Zend Framework. Siga as etapas fornecidas abaixo.

Etapa 1: Module.php

Primeiro, devemos criar um módulo Employee dentro do diretório - myapp / module / Employee / src / e então implementar a interface ConfigProviderInterface.

O código completo para a classe Módulo é o seguinte -

<?php  
namespace Employee;  
use Zend\ModuleManager\Feature\ConfigProviderInterface;  
class Module implements ConfigProviderInterface { 
   public function getConfig() {    
      return include __DIR__ . '/../config/module.config.php'; 
   }    
}

Etapa 2: composer.json

Configure o Tutorial módulo em composer.json na seção autoload usando o código a seguir.

"autoload": { 
   "psr-4": { 
      "Application\\": "module/Application/src/", 
      "Tutorial\\": "module/Tutorial/src/", 
      "Employee\\": "module/Employee/src/" 
   } 
}

Agora, atualize o aplicativo usando um comando de atualização do composer.

composer update

O comando Composer fará as alterações necessárias no aplicativo e mostrará os logs conforme mostrado no prompt de comando abaixo.

Loading composer repositories with package information 
Updating dependencies (including require-dev) 
   - Removing zendframework/zend-component-installer (0.3.0) 
   - Installing zendframework/zend-component-installer (0.3.1) 
   Downloading: 100%           
    
   - Removing zendframework/zend-stdlib (3.0.1) 
   - Installing zendframework/zend-stdlib (3.1.0) 
   Loading from cache  
    
   - Removing zendframework/zend-eventmanager (3.0.1) 
   - Installing zendframework/zend-eventmanager (3.1.0) 
   Downloading: 100%           
    
   - Removing zendframework/zend-view (2.8.0) 
   - Installing zendframework/zend-view (2.8.1) 
   Loading from cache  
    
   - Removing zendframework/zend-servicemanager (3.1.0) 
   - Installing zendframework/zend-servicemanager (3.2.0) 
   Downloading: 100%           
    
   - Removing zendframework/zend-escaper (2.5.1) 
   - Installing zendframework/zend-escaper (2.5.2) 
   Loading from cache  
   
   - Removing zendframework/zend-http (2.5.4) 
   - Installing zendframework/zend-http (2.5.5) 
   Loading from cache  
    
   - Removing zendframework/zend-mvc (3.0.1)
   - Installing zendframework/zend-mvc (3.0.4)  
   Downloading: 100%           
   
   - Removing phpunit/phpunit (5.7.4) 
   - Installing phpunit/phpunit (5.7.5) 
   Downloading: 100%           
  
Writing lock file 
Generating autoload files

Etapa 3: module.config.php para o módulo Employee

Crie o arquivo de configuração do módulo, “module.config.php” em myapp / module / Employee / config com o código a seguir.

<?php  
namespace Employee;  
use Zend\ServiceManager\Factory\InvokableFactory; 
use Zend\Router\Http\Segment;  
return [ 
   'controllers' => [ 
      'factories' => [ 
         Controller\EmployeeController::class => InvokableFactory::class, 
      ], 
   ], 
   'view_manager' => [ 
      'template_path_stack' => ['employee' => __DIR__ . '/../view',], 
   ], 
];

Agora, configure o módulo Employee no arquivo de configuração de nível de aplicativo - myapp / config / modules.config.php.

return ['Zend\Router', 'Zend\Validator', 'Application', 'Tutorial', 'Employee'];

Etapa 4: EmployeeController

Crie uma nova classe PHP, EmployeeController, estendendo o AbstractActionController e coloque-o no diretório myapp / module / Employee / src / Controller.

A lista de códigos completa é a seguinte -

<?php  
namespace Employee\Controller;  
use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel;  
class EmployeeController extends AbstractActionController { 
   public function indexAction() { 
      return new ViewModel(); 
   } 
}

Etapa 5: configuração do roteador

Vamos adicionar uma rota de segmento em nosso módulo Employee. Atualize o arquivo de configuração do módulo do funcionário, module.config.php disponível em myapp / module / Employee / config.

<?php  
namespace Employee;
use Zend\ServiceManager\Factory\InvokableFactory; 
use Zend\Router\Http\Segment;  
return [ 
   'controllers' => [ 
      'factories' => [ 
         Controller\EmployeeController::class => InvokableFactory::class, 
      ], 
   ], 
   'router' => [ 
      'routes' => [ 
         'employee' => [ 
            'type' => Segment::class,
            'options' => [ 
               'route' => '/employee[/:action[/:id]]',
               'constraints' => [
                  'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                  'id' => '[0-9]+', 
               ], 
               'defaults' => [ 
                  'controller' => Controller\EmployeeController::class,
                  'action' => 'index', 
               ], 
            ], 
         ], 
      ], 
   ], 
   'view_manager' => [ 
      'template_path_stack' => [ 
         'employee' => __DIR__ . '/../view', 
      ], 
   ], 
];

Adicionamos com sucesso o roteamento para nosso módulo Funcionário. A próxima etapa é criar um script de visualização para o aplicativo Employee.

Etapa 6: Criar ViewModel

Crie um arquivo chamado “index.phtml” no diretório myapp / module / Employee / view / employee / employee.

Adicione as seguintes alterações no arquivo -

<div class = "row content"> 
   <h3>This is my first Zend application</h3> 
</div> 
Move to “EmployeeController.php” file and edit the following changes, 

<?php 
namespace Employee\Controller;  
use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel;  
class EmployeeController extends AbstractActionController { 
   public function indexAction() { 
      return new ViewModel();  
   } 
}

Finalmente, concluímos com sucesso o módulo Funcionário. podemos acessá-lo usando o seguinte url -http://localhost:8080/employee.

Resultado

Na próxima etapa, vamos realizar add, edit e deleteoperações de dados no aplicativo do funcionário. Para realizar essas operações, devemos primeiro criar um modelo de banco de dados. Isso é descrito na próxima etapa.

Etapa 7: Crie um modelo

Vamos criar um modelo, Funcionário em nosso módulo src directory. Geralmente, os modelos são agrupados na pasta Modelo (myapp / module / Employee / src / Model / Employee.php)

<?php  
namespace Employee\Model;  
class Employee { 
   public $id; public $emp_name; 
   public $emp_job; 
}

Etapa 8: Tabela MySQL

Crie um banco de dados chamado tutorials no servidor MYSQL local usando o seguinte comando -

create database tutorials;

Vamos criar uma tabela chamada employee no banco de dados usando o seguinte comando SQL -

use tutorials;  
CREATE TABLE employee ( 
   id int(11) NOT NULL auto_increment, 
   emp_name varchar(100) NOT NULL, 
   emp_job varchar(100) NOT NULL, 
   PRIMARY KEY (id) 
);

Insira dados no employee tabela usando a seguinte consulta -

INSERT INTO employee (emp_name, emp_job) VALUES ('Adam',  'Tutor'); 
INSERT INTO employee (emp_name, emp_job) VALUES ('Bruce',  'Programmer'); 
INSERT INTO employee (emp_name, emp_job) VALUES ('David',  'Designer');

Etapa 9: Atualizar a configuração do banco de dados

Atualize o arquivo de configuração global, myapp / config / autoload / global.php com as informações de unidade de banco de dados necessárias.

return [
   'db' => [
      'driver' => 'Pdo',
      'dsn' => 'mysql:dbname = tutorials;host=localhost',
      'driver_options' => [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''],
   ],
];

Agora, atualize as credenciais do banco de dados no arquivo de configuração local - myapp / config / autoload / local.php. Dessa forma, podemos separar as credenciais de conexão do banco de dados local e ao vivo.

<?php 
return array( 
   'db' => array('username' => '<user_name>', 'password' => '<password>',), 
);

Etapa 10: Implementar exchangeArray

Implemente a função exchangeArray no modelo Employee.

<?php 
namespace Employee\Model; 
class Employee { 
   public $id; 
   public $emp_name; public $emp_job;  
   public function exchangeArray($data) { $this->id = (!empty($data['id'])) ? $data['id'] : null; 
      $this->emp_name = (!empty($data['emp_name'])) ? $data['emp_name'] : null; $this->emp_job = (!empty($data['emp_job'])) ? $data['emp_job'] : null; 
   } 
}

Etapa 11: use o TableGateway para buscar os dados do funcionário

Crie a classe, EmployeeTable na própria pasta Model. É definido no seguinte bloco de código.

<?php  
namespace Employee\Model;  
use Zend\Db\TableGateway\TableGatewayInterface;  
class EmployeeTable { 
   protected $tableGateway; public function __construct(TableGatewayInterface $tableGateway) { 
      $this->tableGateway = $tableGateway; 
   }
   public function fetchAll() { 
      $resultSet = $this->tableGateway->select();  
      return $resultSet; 
   } 
}

Etapa 12: configurar a classe EmployeeTable

Atualize o serviço do funcionário em Module.php usando o método getServiceConfig ()

<?php
namespace Employee;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\ModuleManager\Feature\ConfigProviderInterface;

class Module implements ConfigProviderInterface {
   public function getConfig() {
      return include __DIR__ . '/../config/module.config.php';
   }
   public function getServiceConfig() {
      return [
         'factories' => [
            Model\EmployeeTable::class => function (    $container) {
               $tableGateway = $container>get( Model\EmployeeTableGateway::class);
               $table = new Model\EmployeeTable($tableGateway);
               return $table; }, Model\EmployeeTableGateway::class => function ($container) {
               $dbAdapter = $container->get(AdapterInterface::class);
               $resultSetPrototype = new ResultSet(); $resultSetPrototype->setArrayObjectPrototype(new Model\Employee());
               return new TableGateway('employee', $dbAdapter, null, $resultSetPrototype);
            },
         ],
      ];
   }
}

Etapa 13: Adicionar Serviço de Funcionário no Controlador

Atualize a seção do controlador da Configuração do Módulo de Funcionário em - myapp / module / config / module.config.php conforme mostrado abaixo.

'controllers' => [
   'factories' => [
      Controller\EmployeeController::class => function($container) { return new Controller\EmployeeController( $container->get(Model\EmployeeTable::class)
         ); 
      }, 
   ], 
]

Etapa 14: Adicionar Construtor para EmployeeController

Adicione o construtor com EmployeeTable como o argumento e edite as seguintes alterações.

<?php  
namespace Employee\Controller; 
use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel;
use Employee\Model\Employee; 
use Employee\Model\EmployeeTable;  

class EmployeeController extends AbstractActionController { 
   private $table; public function __construct(EmployeeTable $table) { 
      $this->table = $table; 
   }  
   public function indexAction() { 
      $view = new ViewModel([ 'data' => $this->table->fetchAll(), 
      ]);  
      return $view; 
   } 
}

Etapa 15: Exibir informações do funcionário no script de exibição “index.phtml”

Mover para o arquivo - index.phtml e faça as seguintes alterações -

<?php 
$title = 'Employee application'; 
$this->headTitle($title); 
?>  

<table class="table"> 
   <tr> 
      <th>Employee Name</th> 
      <th>Employee Job</th> 
      <th>Edit/Delete operations</th>
   </tr> 
   <?php foreach ($data as $empdata) : ?> 
   <tr>  
      <td><?php echo $this->escapeHtml($empdata->emp_name);?></td> 
      <td><?php echo $this->escapeHtml($empdata->emp_job);?></td> 
      <td> 
         <a href="<?php echo $this->url('employee', array('action'=>'edit', 'id' =>$empdata->id));?>">Edit</a> 
         <a href="<?php echo $this->url('employee', array('action'=>'delete', 'id' => $empdata->id));?>">Delete</a> 
      </td> 
   </tr> 
   <?php endforeach; ?> 
</table>

Agora, criamos com sucesso um modelo de banco de dados e podemos buscar os registros dentro do aplicativo.

Solicite o aplicativo usando o url - http://localhost:8080/employee.

Resultado

A próxima etapa explica sobre o insert, edit e delete operações de dados no módulo de funcionários.

Etapa 16: Criar um formulário de funcionário

Crie um arquivo chamado EmployeeForm.phpno diretório myapp / module / Employee / src / Form. Ele é descrito no bloco de código abaixo.

<?php  
namespace Employee\Form; 
use Zend\Form\Form;  

class EmployeeForm extends Form { 
   public function __construct($name = null) { / / we want to ignore the name passed parent::__construct('employee'); $this->add(array( 
         'name' => 'id', 
         'type' => 'Hidden', 
      )); 
      $this->add(array( 'name' => 'emp_name', 'type' => 'Text', 'options' => array( 'label' => 'Name', ), )); $this->add(array( 
         'name' => 'emp_job', 
         'type' => 'Text', 
         'options' => array( 
            'label' => 'Job', 
         ), 
      )); 
      $this->add(array( 
         'name' => 'submit', 
         'type' => 'Submit', 
         'attributes' => array(
            'value' => 'Go', 
            'id' => 'submitbutton', 
         ), 
      )); 
   } 
}

Etapa 17: Atualizar o modelo do funcionário

Atualize o modelo do funcionário e implemente o InputFilterAwareInterface. Mova para o diretório myapp / module / Employee / src / Employee / Model e adicione as seguintes alterações noEmployee.phpfile.

<?php  
namespace Employee\Model;  

// Add these import statements 
use Zend\InputFilter\InputFilter; 
use Zend\InputFilter\InputFilterAwareInterface; 
use Zend\InputFilter\InputFilterInterface;  

class Employee implements InputFilterAwareInterface { 
   public $id; 
   public $emp_name; public $emp_job; 
   protected $inputFilter; public function exchangeArray($data) { 
      $this->id = (isset($data['id'])) ? $data['id'] : null; $this->emp_name = (isset($data['emp_name'])) ? $data['emp_name'] : null;         
      $this->emp_job = (isset($data['emp_job']))  ? $data['emp_job'] : null; } // Add content to these methods: public function setInputFilter(InputFilterInterface $inputFilter) { 
      throw new \Exception("Not used"); 
   }  
   public function getInputFilter() { 
      if (!$this->inputFilter) { $inputFilter = new InputFilter();  
         $inputFilter->add(array( 'name' => 'id', 'required' => true, 'filters' => array( array('name' => 'Int'), ), )); $inputFilter->add(array( 
            'name' => 'emp_name', 
            'required' => true, 
            'filters' => array( 
               array('name' => 'StripTags'), 
               array('name' => 'StringTrim'), 
            ), 
            'validators' => array( 
               array('name' => 'StringLength', 
                        'options' => array( 
                           'encoding' => 'UTF-8', 
                           'min' => 1, 
                           'max' => 50, 
                        ), 
                    ), 
                ), 
            ));
         $inputFilter->add(array( 'name' => 'emp_job', 'required' => true, 'filters' => array( array('name' => 'StripTags'), array('name' => 'StringTrim'), ), 'validators' => array( array('name' => 'StringLength', 'options' => array( 'encoding' => 'UTF-8', 'min' => 1, 'max' => 50, ), ), ), )); $this->inputFilter = $inputFilter; } return $this->inputFilter; 
   } 
}

Etapa 18: Adicionar addAction no controlador de funcionário

Adicione as seguintes alterações no EmployeeController classe.

<?php  
use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel; 
use Employee\Model\Employee;       
use Employee\Model\EmployeeTable;    
use Employee\Form\EmployeeForm;

public function addAction() { 
   $form = new EmployeeForm(); $form->get('submit')->setValue('Add');  
   $request = $this->getRequest(); 
   
   if ($request->isPost()) { $employee = new Employee(); 
      $form->setInputFilter($employee->getInputFilter()); 
      $form->setData($request->getPost());  
      
      if ($form->isValid()) { $employee->exchangeArray($form->getData()); $this->table->saveEmployee($employee); // Redirect to list of employees return $this->redirect()->toRoute('employee'); 
      } 
   } 
   return array('form' => $form); 
}

Etapa 19: adicione a funcionalidade de salvamento na classe EmployeeTable

Adicione as duas funções a seguir na classe EmployeeTable - myapp / module / Employee / src / Model / EmployeeTable.php

public function getEmployee($id) { 
   $id = (int) $id; 
   $rowset = $this->tableGateway->select(array('id' => $id)); $row = $rowset->current(); if (!$row) { 
      throw new \Exception("Could not find row $id"); } return $row; 
}  
public function saveEmployee(Employee $employee) { $data = array (  
      'emp_name' => $employee->emp_name, 'emp_job' => $employee->emp_job, 
   );  
   $id = (int) $employee->id; 
   if ($id == 0) { $this->tableGateway->insert($data); } else { if ($this->getEmployee($id)) { $this->tableGateway->update($data, array('id' => $id)); 
      } else { 
         throw new \Exception('Employee id does not exist'); 
      } 
   } 
}

Etapa 20: Criar script de visualização para o método AddAction, Add.phtml

Adicione as seguintes alterações no arquivo “Add.phtml” em - myapp / module / view / employee / employee.

<?php 
   $title = 'Add new employee'; $this->headTitle($title); ?> <h1><?php echo $this->escapeHtml($title); ?></h1> <?php $form->setAttribute('action', $this->url('employee', array('action' => 'add'))); $form->prepare(); 
   echo $this->form()->openTag($form); 
   echo $this->formHidden($form->get('id')); 
   echo $this->formRow($form->get('emp_name'))."<br>"; 
   echo $this->formRow($form->get('emp_job'))."<br>";   
   echo $this->formSubmit($form->get('submit')); 
   echo $this->form()->closeTag(); 
Request the application using the url, http://localhost:8080/employee/add

Resultado

Assim que os dados forem adicionados, eles serão redirecionados para a página inicial.

Etapa 21: Editar registros de funcionários

Vamos realizar as operações de edição de dados no módulo Employee. Atualize as seguintes mudanças noEmployeecontroller.php.

public function editAction() { 
   $id = (int) $this->params()->fromRoute('id', 0); if (!$id) { 
      return $this->redirect()->toRoute('employee', array( 'action' => 'add' )); } try { $employee = $this->table->getEmployee($id); 
   } catch (\Exception $ex) { return $this->redirect()->toRoute('employee', array( 
         'action' => 'index' 
      )); 
   }  
   $form = new EmployeeForm(); $form->bind($employee); $form->get('submit')->setAttribute('value', 'Edit');  
   $request = $this->getRequest(); 
   
   if ($request->isPost()) { $form->setInputFilter($employee->getInputFilter()); $form->setData($request->getPost()); if ($form->isValid()) { 
         $this->table->saveEmployee($employee);  
         
         // Redirect to list of employees 
         return $this->redirect()->toRoute('employee'); } } return array('id' => $id, 'form' => $form,); 
}

Aqui, procuramos o id, que está no roteiro combinado e carrega os detalhes do funcionário para a operação de edição.

Etapa 22: Employee.php

Agora adicione as seguintes alterações no arquivo “Employee.php”, que reside no diretório - myapp / module / Employee / src / Employee / Model /.

public function getArrayCopy() { 
   return get_object_vars($this); 
}

Aqui, o Zend \ Stdlib \ Hydrator \ ArraySerializable espera encontrar dois métodos no modelo: getArrayCopy() e exchangeArray().

No qual, o exchangeArray () é usado para iteração. Esta função é usada para vincular os dados da tabela de funcionários.

Agora, precisamos criar um script de visualização para editAction().

Etapa 23: Crie Edit.phtml

Crie um arquivo de script de visualização no módulo / Employee / view / employee / employee / edit.phtml

<?php 
   $title = 'Edit employee records'; $this->headTitle($title); ?> <h1><?php echo $this->escapeHtml($title); ?></h1> <?php $form = $this->form; $form->setAttribute('action', $this->url( 'employee', array('action' => 'edit', 'id' => $this->id,) 
)); 
$form->prepare(); echo $this->form()->openTag($form); echo $this->formHidden($form->get('id')); echo $this->formRow($form->get('emp_name'))."<br>"; echo $this->formRow($form->get('emp_job'))."<br>"; echo $this->formSubmit($form->get('submit')); echo $this->form()->closeTag();

A edição dos detalhes do funcionário é mostrada na captura de tela a seguir.

Depois que os dados forem editados, eles serão redirecionados para a página inicial.

Etapa 24: adicione o método deleteEmployee

Adicione o método deleteEmployee na classe EmployeeTable - myapp / module / Employee / src / Model / EmployeeTable.php

public function deleteEmployee($id) { $this->tableGateway->delete(['id' => (int) $id]); 
}

Etapa 25: Excluir os registros de funcionários

Vamos agora realizar as operações de exclusão de dados no módulo Employee. Adicione o seguinte método,deleteAction na classe EmployeeController.

public function deleteAction() { 
   $id = (int) $this->params()->fromRoute('id', 0); if (!$id) { 
      return $this->redirect()->toRoute('employee'); } $request = $this->getRequest(); if ($request->isPost()) { 
      $del = $request->getPost('del', 'No');  
      if ($del == 'Yes') { $id = (int) $request->getPost('id'); $this->table->deleteEmployee($id); } return $this->redirect()->toRoute('employee'); 
   }  
   return array( 
      'id' => $id, 'employee' => $this->table->getEmployee($id) 
   ); 
}

Aqui, o método deleteEmployee () exclui o funcionário por seu id e redireciona para a página da lista de funcionários (home page).

Vamos agora criar scripts de visualização correspondentes para o método deleteAction ().

Etapa 26: Criar um script de visualização

Crie um arquivo chamado delete.phtml em - myapp / module / Employee / view / employee / employee / delete.phtml e adicione o seguinte código nele.

<?php 
   $title = 'Delete an employee record'; 
   $this->headTitle($title);  
?> 
<h1><?php echo $this->escapeHtml($title); ?></h1>  

'<?php echo $this->escapeHtml($employee->emp_name); ?>' by 
'<?php echo $this->escapeHtml($employee->emp_job); ?&'?  
<?php 
   $url = $this->url('employee', array('action' => 'delete', 'id' => $this->id,)); ?> <form action ="<?php echo $url; ?>" method = "post">
   <div> 
      <input type = "hidden" name = "id" value = "<?php echo (int) $employee->id; ?>" /> 
      <input type = "submit" name = "del" value = "Yes" /> 
      <input type = "submit" name = "del" value = "No" /> 
   </div> 
</form>

Agora, exclua qualquer funcionário usando o edit na página inicial e o resultado será como mostrado na imagem a seguir.

Resultado

Concluímos com sucesso o módulo Funcionário, implementando todos os recursos necessários.

Conclusão

No ambiente competitivo atual, o framework Zend é colocado no primeiro lugar pelo desenvolvedor. Ele fornece abstrações para qualquer programa ou qualquer tipo de aplicativo na linguagem PHP. É uma estrutura desenvolvida e oferece suporte a recursos modernos da linguagem PHP. É divertido, profissional, em evolução e em sintonia com a tecnologia atual.