Zend Framework - Guida rapida

Un PHP Web Framework è una raccolta di classi che aiuta a sviluppare un'applicazione web. Zend è uno dei framework PHP più popolari. È unopen-source MVC frameworkper applicazioni web moderne e in rapido sviluppo. Zend Framework ha diversi componenti debolmente accoppiati, quindi è indicato come "Libreria dei componenti". Zend Framework fornisce qualsiasi stack PHP e server Zend per eseguire applicazioni framework Zend.

Zend Studio è un IDE che include funzionalità da integrare con Zend Framework. Fornisce la visualizzazione MVC e la generazione di codice. L'attuale Zend Framework 3.0 include nuovi componenti come il server JSON RPC, un convertitore da XML a JSON, funzionalità PSR-7 e compatibilità con PHP 7.

Zend Framework 2 è un framework open source per lo sviluppo di applicazioni e servizi Web utilizzando PHP 5.3+. Zend Framework 2 utilizza codice orientato agli oggetti al 100% e utilizza la maggior parte delle nuove funzionalità di PHP 5.3, vale a direNamespaces, Lambda Functions e Closures.

Zend Framework 2 evolved from Zend Framework 1, a successful PHP framework with over 15 million downloads. Zend Server has a free community version and a commercial version.

Zend Framework Features

Some of the salient features of Zend Framework is as follows −

  • Pure object oriented web application framework
  • Advanced MVC implementation
  • Supports multi databases including PostgreSQL, SQLite etc.,
  • Simple cloud API
  • Session management
  • Data encryption
  • Flexible URI Routing
  • Zend provides RESTful API development support.
  • Code reusable and easier to maintain.

Why Zend Framework?

What makes the Zend Framework one of the premier frameworks used by PHP developers is that – it provides clean and stable code complete with intellectual property rights. It also makes programming easier. It is fast, easy to learn and convenient framework. Zend supports strong cryptography tools and password hashing techniques.

Zend Goals

Following are the goals of the Zend Framework.

  • Flexibility
  • Simple and productive
  • Compatibility
  • Extensibility − Programmer can easily extend all the framework classes.
  • Portability − Supports multiple environments

Zend Applications

The following popular products are developed by using the Zend Framework.

  • McAfee Company website
  • IBM Company website
  • Magento − one of the popular shopping cart website.

Advantages of Zend Framework

Some of the advantages of the Zend Framework are listed below.

  • Loosely Coupled − Zend provides the option to delete modules or components which we don’t need in the application.

  • Performance − Zend Framework is highly optimized for performance. Zend Framework 3 is 4x faster than its previous version.

  • Security − Framework supports industry standard encryption.

  • Testing − PHPUnit is integrated with Zend so you can easily test the framework.

In the next chapter, we will learn how to install the Zend Framework.

To install the Zend Framework, we must first install the Composer and the latest version of PHP as shown in the following steps.

  • Install Composer − Zend uses Composer for managing its dependencies, so make sure you have the Composer installed on your machine. If the Composer is not installed, then visit the official website of Composer and install it.

  • Install the latest version of PHP − To get the maximum benefit of Zend Framework, install the latest version of PHP. The minimum required version for the Zend Framework 3 is PHP 5.6 or later.

Install Zend Framework

Zend Framework can be installed in two ways. They are as follows −

  • Manual installation
  • Composer based installation

Let us discuss both these installations in detail.

Manual Installation

Download the latest version of Zend Framework by visiting the following link – https://framework.zend.com/downloads/archives

Extract the content of the downloaded archive file to the folder you would like to keep it. Once you have a copy of Zend Framework available in your local machine, your Zend Framework based web application can access the framework classes. Though there are several ways to achieve this, your PHP include_path needs to contain the path to the Zend Framework classes under the /library directory in the distribution. This method applies to Zend Framework version 2.4 and earlier only.

Composer Based Installation

To easily install the Zend Framework, use the Composer tool. This is the preferred method to install the latest version of Zend Framework. To install all the components of the Zend Framework, use the following Composer command −

$ composer require zendframework/zendframework

Each Zend Framework module / component can be installed individually as well. For example, to install the MVC component of the Zend Framework, use the following composer command −

$ composer require zendframework/zend-mvc

Let us create a skeleton application using the Zend Framework MVC layer and module systems.

Installation using Composer

The easiest way to create a new Zend Framework project is to use a Composer. It is defined as below −

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

You would see the following result on your screen −

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.

Now that the application is installed, you can test it out immediately using the PHP's built-in web server

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

Then you would see the following response −

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

This will start the PHP built-in CLI server on port 8080. Once the development server is started, you can visit the site at (http://localhost:8080/). The built-in CLI server is for development only.

Unit Tests

To run the skeleton unit tests, type the following command in your terminal.

$ composer require --dev zendframework/zend-test

It will produce the following response −

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

Now the testing support is enabled so you can run the test using the following command.

$ ./vendor/bin/phpunit

Apache Web Server

Hosting the Zend Framework based application in the production environment is very simple and straight-forward. Just create a VirtualHost in the Apache configuration file and point the DocumentRoot to the Public folder of the Zend Framework application.

A sample configuration (myapp) is given below −

<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>

Before proceeding with this chapter, let us have a brief understanding of MVC. A Model View Controller is a software approach that separates the application logic from the presentation. In practice, it permits the webpages to contain minimal PHP scripting since the presentation is separate from it.

The short description of the MVC Components is as follows

  • Model − Model represents the structure of the application data. Typically, model classes contain functions that helps to retrieve, insert and update business data in the back-end database (MySQL, PostgreSQL, etc.).

  • View − View is the presentation layer of the MVC Application. It gets the models data through the Controller and display it as needed. It is loosely coupled to the Controller and the Model and so, it can be changed without affecting either the Model and the Controller.

  • Controller − The Controller is the main component of the MVC architecture. Every request first hits the controller. In other words, the controller processes all the request and serves as an intermediary between the Model, View, and any other resources needed to process the HTTP request and to generate the response.

In the next chapter, we will understand the different concepts of the Zend Framework.

Zend Framework is a collection of 60+ components. They are loosely connected with each other. They can be used as both stand-alone component as well as a group of components working as a single unit.

Zend Framework provides three most important components, which are −

  • zend-servicemanager
  • zend-eventmanager and
  • zend-modulemanager.

They provide Zend components the ability to integrate with other components efficiently.

  • Event Manager − It gives the ability to create event based programming. This helps to create, inject and manage new events.

  • Service Manager − It gives the ability to consume any services (PHP classes) from anywhere with a little effort.

  • Module Manager − Ability to convert a collection of PHP classes with similar functionality into a single unit called as a module. The newly created modules can be used, maintained and configured as a single unit.

We will cover these concepts in detail in the subsequent chapters.

The Zend Framework includes a powerful service locator pattern implementation called zend-servicemanager. Zend framework extensively uses the service manager for all its functionalities. The Service Manager provides a high-level abstraction for the Zend Framework. It also integrates nicely with all the other components of the Zend Framework.

Install Service Manager

The Service Manager component can be installed using the composer tool.

composer require zendframework/zend-servicemanager

Example

First, all the services need to be registered into the service manager. Once the services are registered into the server manager system, it can be accessed at any time with minimal efforts. The service manager provides a lot of options to register the service. A simple example is as follows −

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

The above code registers the stdClass into the system using the Factory option. Now, we can get an instance of the stdClass at any time using the get() method of the service manager as shown below.

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

The get() method shares the retrieved object and so, the object returned by calling the get() method multiple times is one and the same instance. To get a different instance every time, the service manager provides another method, which is the build() method.

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

Service Manager Registration

The service manager provides a set of methods to register a component. Some of the most important methods are as given below −

  • Factory method
  • Abstract factory method
  • Initializer method
  • Delegator factory method

We will discuss each of these in detail in the upcoming chapters.

Factory Method

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.

Tutti i moduli condividono la stessa o simile struttura di quella del modulo Applicazione sopra .

In questo capitolo impareremo come creare un modulo basato su MVC in Zend Framework. Creiamo un modulo chiamato comeTutorial per comprendere il processo di creazione del modulo.

  • Crea una nuova classe PHP denominata Module all'interno della directory –myapp / module / Tutorial / src / e implementare ConfigProviderInterface.

  • Impostato Tutorial come spazio dei nomi per il Module classe.

  • Scrivi una funzione pubblica getConfig nel Module class e restituisce il file di configurazione per Tutorial Modulo.

Il codice completo per Module la classe è la seguente:

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

Configura il Tutorial modulo in composer.json sotto il autoload sezione utilizzando il codice seguente.

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

Aggiorna l'applicazione utilizzando il compositore update comando come mostrato di seguito.

composer update

Il composer Il comando apporterà le modifiche necessarie all'applicazione e mostrerà i log nel prompt dei comandi come mostrato di seguito -

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

Crea il file di configurazione del modulo, "module.config.php" in /config/ con il seguente codice -

<?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',], 
   ], 
];

Il file di configurazione ha tre parti e sono le seguenti:

  • Controller configuration - Specificare i controller disponibili all'interno del Modulo.

  • Routing configuration - Specificare come i controller nel modulo devono essere risolti in URL.

  • View configuration - Specificare la configurazione relativa alla visualizzazione del motore come la posizione delle viste, ecc.

Configura il Tutorial module nel file di configurazione a livello di applicazione - myapp / config / modules.config.php.

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

Esegui l'applicazione eseguendo il file composer serve nella radice della cartella dell'applicazione.

Abbiamo aggiunto con successo un nuovo modulo, ma dobbiamo ancora aggiungere il file Controller, Routing e Views per eseguire correttamente il Tutorial modulo.

Come discusso in precedenza, il controllergioca un ruolo importante in Zend MVC Framework. Tutte le pagine web in un'applicazione devono essere gestite da un controller.

In Zend MVC Framework, i controller sono oggetti che implementano - Zend / Stdlib / DispatchableInterface. IlDispatchableInterface ha un unico metodo, dispatch, che ottiene l'estensione Request oggetto come input, esegui un po 'di logica e ritorna Response un oggetto come output.

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

Un semplice esempio di un oggetto Controller per restituire "Hello World" è il seguente:

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!"); 
   } 
}

Il DispatchableInterfaceè basilare e necessita di molte altre interfacce per scrivere controller di alto livello. Alcune di queste interfacce sono le seguenti:

  • InjectApplicationEventInterface - Usato per iniettare eventi (Zend EventManager)

  • ServiceLocatorAwareInterface - Utilizzato per individuare i servizi (Zend ServiceManager)

  • EventManagerAwareInterface - Utilizzato per gestire gli eventi (Zend EventManager)

Tenendo presente queste cose, Zend Framework fornisce molti controller già pronti che implementano queste interfacce. I controller più importanti sono come spiegato di seguito.

AbstractActionController

AbstractActionController (Zend / Mvc / Controller / AbstractActionController) è il controller più utilizzato in Zend MVC Framework. Ha tutte le funzionalità necessarie per scrivere una tipica pagina web. Consente ai percorsi (il routing corrisponde all'URL della richiesta a un controller e uno dei suoi metodi) di abbinare un fileaction. In caso di corrispondenza, un metodo denominato dopo l'azione verrà chiamato dal controller.

Ad esempio, se un percorso test è abbinato e il percorso, test ritorna hello per l'azione, quindi il helloAction metodo verrà invocato.

Scriviamo il nostro TutorialController usando il AbstractActionController.

  • Crea una nuova classe PHP chiamata TutorialController estendendo il AbstractActionController e posizionalo nel file module/Tutorial/src/Controller/ directory.

  • Impostare il Tutorial\Controller come spazio dei nomi.

  • Scrivi un indexAction metodo.

  • Restituisci il file ViewModel oggetto da indexActionmetodo. IlViewModel viene utilizzato per inviare dati dal controller al motore di visualizzazione, che vedremo nei capitoli successivi.

L'elenco completo del codice è il seguente:

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

Abbiamo aggiunto con successo il nuovo TutorialController.

AbstractRestfulController

AbstractRestfulController (Zend \ Mvc \ Controller \ AbstractRestfulController) ispeziona l'HTTP method della richiesta in arrivo e corrisponde all'azione (metodo) considerando i metodi HTTP

Ad esempio, la richiesta con il metodo GET HTTP corrisponde a getList() metodo o il get() metodo, se il id parametro si trova nella richiesta.

AbstractConsoleController

AbstractConsoleController (Zend \ Mvc \ Controller \ AbstractConsoleController) è come AbstractActionController tranne per il fatto che viene eseguito solo nell'ambiente della console anziché in un browser.

Mappe dei percorsi Request URIal metodo di un controller specifico. In questo capitolo vedremo come implementare le rotte in uno Zend Framework.

In generale, qualsiasi URI ha tre parti:

  • Segmento del nome host,
  • Segmento di percorso e
  • Segmento di query.

Ad esempio, in URI / URL - http://www.example.com/index?q=data, www.example.com è il segmento del nome host, index è il segmento di percorso e q=dataè il segmento di query. In genere, il routing controlla il filePage segmentcontro un insieme di vincoli. Se un vincolo corrisponde, restituisce un insieme di valori. Uno dei valori principali è il controller.

Il routing controlla anche il segmento host, il segmento di query, i metodi HTTP di richiesta, le intestazioni HTTP di richiesta, ecc. In una determinata situazione.

Route & RouteStack

Il percorso è l'oggetto principale del percorso. Zend Framework ha un'interfaccia speciale per l'oggetto percorso,RouteInterface. Tutti gli oggetti route devono implementare RouteInterface. L'elenco completo di RouteInterface è il seguente:

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 = []); 
}

Il metodo principale è match. Questo metodo di corrispondenza controlla la richiesta data rispetto al vincolo in esso definito. Se viene trovata una corrispondenza, restituisceRouteMatchoggetto. Questo oggetto RouteMatch fornisce i dettagli della richiesta abbinata come parametri. Questi parametri possono essere estratti daRouteObject usando il getParams metodo.

L'elenco completo di RouteObject è il seguente:

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); 
}

In generale, una tipica applicazione MVC ha molti percorsi. Ciascuno di questo percorso verrà elaborato in ordine LIFO e un singolo percorso verrà abbinato e restituito. Se nessun percorso viene trovato / restituito, l'applicazione restituisce l'errore "Pagina non trovata". Zend Framework fornisce un'interfaccia per elaborare i percorsi,RouteStackInterface. Questa RouteStackInterface ha la possibilità di aggiungere / rimuovere rotte.

L'elenco completo di RouteStackInterface è il seguente:

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); 
}

Il framework Zend fornisce due implementazioni di RouteStack interfaccia e sono i seguenti:

  • SimpleRouteStack
  • TreeRouteStack

Tipo di percorsi

Il framework Zend fornisce molti oggetti di route già pronti per tutte le situazioni nello spazio dei nomi "Zend \ Mvc \ Router \ Http". È sufficiente selezionare e utilizzare l'oggetto di percorso appropriato per la situazione data.

I percorsi disponibili sono i seguenti:

  • Hostname - Usato per abbinare la parte host dell'URI.

  • Literal - Utilizzato per abbinare l'URI esatto.

  • Method - Utilizzato per abbinare il metodo HTTP della richiesta in arrivo.

  • Part - Utilizzato per abbinare la parte del segmento del percorso URI utilizzando la logica personalizzata.

  • Regex - Utilizzato per abbinare il segmento del percorso URI in base al pattern Regex.

  • Schema - Utilizzato per abbinare lo schema URI come http, https, ecc.

  • Segment - Utilizzato per abbinare il percorso dell'URI suddividendolo in più segmenti.

Vediamo come scrivere il letterale e il segmento Route più comunemente usati. Le rotte sono generalmente specificate nel file di configurazione di ogni modulo -module.config.php.

Itinerario letterale

In genere, le route vengono interrogate in un ordine LIFO. Il percorso letterale serve per eseguire la corrispondenza esatta del percorso URI.

È definito come mostrato di seguito:

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

Il percorso sopra corrisponde al /path nell'URL della richiesta e restituisce index come la action e IndexController come controller.

Percorso del segmento

Un percorso segmentato viene utilizzato ogni volta che si suppone che l'URL contenga parametri variabili.

È descritto come indicato di seguito:

$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',), 
));

Qui, i segmenti sono indicati da due punti e seguiti da caratteri alfanumerici. Se si mantiene un segmento facoltativo, viene racchiuso tra parentesi. Ogni segmento può avere vincoli associati ad esso. Ogni vincolo è un'espressione regolare.

Configurazione del percorso nel modulo Tutorial

Aggiungiamo un percorso di segmento nel nostro modulo Tutorial. Aggiorna il file di configurazione del modulo tutorial -module.config.php disponibile a 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',], 
   ], 
];

Abbiamo aggiunto con successo il routing per il nostro Tutorialmodulo. Siamo solo un passo indietro nel completare il nostro modulo Tutorial. Dobbiamo aggiungereView per il nostro modulo, che impareremo nel capitolo successivo.

Un livello di visualizzazione è il livello di presentazione dell'applicazione MVC. Separa la logica dell'applicazione dalla logica di presentazione. In una tipica applicazione web PHP, tutta la logica aziendale e il design sono mescolati. La miscelazione consente uno sviluppo più rapido in un piccolo progetto. Ma fallisce miseramente in un grande progetto, dove è coinvolta molta architettura di alto livello. Per modificare il design dell'applicazione Web, uno sviluppatore deve lavorare anche sulla logica di business. Questo può essere catastrofico con conseguente rottura della logica aziendale.

Zend Framework fornisce un livello di visualizzazione ben pensato, pulito, flessibile ed estendibile. Il livello di visualizzazione è disponibile come modulo separato,Zend/View e integrali bene con Zend/Mvcmodulo. Lo Zend View Layer è suddiviso in più componenti che interagiscono piacevolmente tra loro.

I suoi vari componenti sono i seguenti:

  • Variables Containers - Contiene i dati del livello di visualizzazione.

  • View Models - Contiene contenitori variabili e modello di progettazione.

  • Renderers - Elabora i dati e il modello da Visualizza modello e genera una rappresentazione del progetto, forse l'output html finale.

  • Resolvers - Risolve il modello disponibile nel modello di visualizzazione in modo tale che il Renderer possa consumare.

  • View (Zend\View\View) - Associa la richiesta al renderer e quindi il renderer alla risposta.

  • Rendering Strategies - Utilizzato da View per mappare la richiesta al renderer.

  • Response Strategies - Utilizzato da View per mappare il renderer alla risposta.

Il livello di visualizzazione, View elabora il file ViewModel, risolve il modello utilizzando un file Resolver, renderlo usando Rendering Strategy e infine lo genera usando il Response Renderer.

Visualizza la configurazione dei livelli

Come il controller, un livello di visualizzazione può essere configurato nel file di configurazione di un modulo chiamato come - module.config.php. La configurazione principale consiste nello specificare dove verranno posizionati i modelli. Ciò può essere ottenuto aggiungendo la seguente configurazione in "module.config.php".

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

Per impostazione predefinita, il livello Visualizza ha un comportamento predefinito per tutti i suoi componenti. Ad esempio, aViewModelrisolve il nome del modello dell'azione di un controller all'interno della radice del modello con la regola "nome-modulo-minuscolo / nome-controllore-minuscolo / nome-azione-minuscolo". Tuttavia, questo può essere sovrascritto dasetTemplate() metodo del ViewModel.

Controller e livello di visualizzazione

Per impostazione predefinita, un controller non ha bisogno di inviare dati al livello di visualizzazione. È sufficiente scrivere il modello nella posizione corretta.

Ad esempio, nel nostro esempio, TutorialController, il modello deve essere posizionato in myapp/module/Tutorial/view/tutorial/tutorial/index.phtml. Ilindex.phtmlfa riferimento al modello basato su PHP e sarà renderizzato dal PHPRenderer. Ci sono altri renderer comeJsonRenderer per json uscita e FeedRenderer per rss e atom produzione.

L'elenco completo è il seguente:

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

Modello di applicazione Zend

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

Infine, abbiamo completato con successo il Tutorial modulo e possiamo accedervi utilizzando l'url - http://localhost:8080/tutorial.

Passaggio dei dati al livello di visualizzazione

Il modo più semplice per inviare i dati a un livello di visualizzazione è utilizzare il file ViewModelargomenti. Il cambiatoindexAction metodo è il seguente:

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

Ora, cambia il file index.phtml file come segue -

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

Visualizza gli aiutanti

Un View Helper viene utilizzato per scrivere piccole funzioni atomiche da utilizzare nei modelli. Il framework Zend fornisce un'interfaccia, Zend \ View \ Helper \ HelperInterface per scrivere helper di visualizzazione standard.

Un'HelperInterface ha solo due metodi,

  • setView() - Questo metodo accetta un'istanza / implementazione Zend \ View \ Renderer \ RendererInterface.

  • getView() - Viene utilizzato per recuperare quell'istanza.

L'elenco completo del codice di HelperInterface è il seguente -

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(); 
}

Per utilizzare un helper nello script di visualizzazione, accedilo utilizzando $this->helperName().

Aiutanti incorporati

Zend Framework fornisce molte funzioni di supporto integrate per vari scopi. Alcuni degli helper di visualizzazione disponibili inzend-mvc sono i seguenti -

URL

L'helper URL viene utilizzato per generare gli URL corrispondenti alle rotte definite nell'applicazione.

La definizione dell'helper URL è:

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

Ad esempio, nel modulo tutorial, la rotta è denominata tutorial e ha due parametri action e id. Possiamo utilizzare l'helper URL per generare due URL diversi come mostrato di seguito:

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

Il risultato sarà il seguente:

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

Segnaposto

L'helper segnaposto viene utilizzato per rendere persistente il contenuto tra gli script di visualizzazione e le istanze di visualizzazione. Fornisce l'opzione per impostare i dati inizialmente e quindi utilizzarli nelle fasi successive.

Ad esempio, possiamo impostare, diciamo company name e poi usalo in tutti gli altri posti.

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

Un segnaposto fornisce alcune delle opzioni avanzate per generare contenuti complessi da array e oggetti PHP. Ha anche la possibilità di catturare alcune sezioni del modello stesso.

Ad esempio, il codice seguente acquisisce il risultato del modello in mezzo e lo memorizza nel file productlist segnaposto.

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

L'helper Doctype viene utilizzato per generare vari doctype html. È l'implementazione concreta delPlaceholderaiutante. Il doctype può essere impostato in un file bootstrap e in un file di configurazione.

L'utilizzo di base è mostrato di seguito:

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

L'helper HeadTitle viene utilizzato per generare l'elemento titolo html. È l'attuazione concreta diPlaceholderaiutante. Zend fornisce un'opzione per impostare il titolo nel file di configurazione del modulo e può essere impostato a qualsiasi livello come sito, modulo, controller, azione, ecc. Un codice parziale per HeadTitle è il seguente:

Module

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

Template

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

Result

action - controller - module - Zend Framework

HeadMeta

L'helper HeadMeta viene utilizzato per generare meta tag html. È un'implementazione concreta dell'helper Placeholder.

Template -

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

Result

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

HeadLink

L'helper HeadLink viene utilizzato per generare collegamenti html per includere risorse esterne. È un'implementazione concreta dell'helper Placeholder.

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

L'helper HeadStyle viene utilizzato per generare stili CSS in linea. È un'implementazione concreta dell'helper Placeholder.

Template

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

HeadScript

HeadScript viene utilizzato per generare script in linea o per includere script esterni. È un'implementazione concreta dell'helper Placeholder.

Template

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

InlineScript

InlineScript viene utilizzato per generare uno script sia nella sezione head che in quella del corpo del modello html. È derivato da HeadScript.

HTMLList

HTMLList viene utilizzato per generare un elenco ordinato e non ordinato. La definizione di HTMLList è la seguente:

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

Un ciclo viene utilizzato per generare alternative in un ambiente loop. Ha funzione di assegnazione, successiva e precedente.

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>

Alcuni altri importanti helper integrati sono i seguenti:

  • BasePath - Il BasePath viene utilizzato per generare il percorso della cartella pubblica della radice dell'applicazione.

  • Partial - Partial viene utilizzato per eseguire il rendering di un modello specifico nel proprio ambito variabile.

  • PartialLoop - PartialLoop è come Partial, ma utilizzato nell'ambiente di loop.

  • Identity - L'identità viene utilizzata per recuperare l'identità dell'utente connesso dal servizio di autenticazione.

  • JSON- JSON viene utilizzato in un ambiente riposante, in cui l'output è in formato JSON. Emette un'intestazione HTTP corretta e disabilita il concetto di layout.

Ci sono ancora molti helper disponibili in Zend Framework come il i18n helper, form helpers, pagination helpers, navigation helpers, eccetera.

Creazione di view helper

Zend Framework fornisce un built-in AbstractHelper implementazione HelperInterface per scrivere view helper.

I passaggi necessari per scrivere un nuovo aiutante sono i seguenti:

  • Step 1 - Estendi la classe Zend \ View \ Helper \ AbstractHelper.

  • Step 2 - Ignora il file __invoke() funzione.

  • Step 3 - Impostare la configurazione nel file module.config.php file.

  • Step 4 - Usa l'helper di visualizzazione negli script di visualizzazione.

Creiamo ora un file TestHelper

Crea cartella Helper in myapp/module/Tutorial/src/View directory. ScriviTestHelper all'interno della directory Helper, TestHelper.php.

L'elenco completo è il seguente:

<?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'); 
   } 
}

Imposta la configurazione in module.config.php.

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

Usa il file appena creato TestHelper nel about visualizza lo script.

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

Un layout rappresenta le parti comuni di più visualizzazioni, ad esempio l'intestazione e il piè di pagina della pagina. Per impostazione predefinita, i layout dovrebbero essere archiviati nel fileview/layout cartella.

Una configurazione del layout è definita sotto view_manager sezione nel module.config.php.

La configurazione predefinita dell'applicazione scheletro è la seguente:

'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', 
),

Qui, il template_mapviene utilizzato per specificare il layout. Se il layout non viene trovato, restituirà un errore. Diamo uno sguardo al layout principale dell'applicazione scheletro.

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>

Mentre analizzi il layout, utilizza principalmente gli helper di visualizzazione, di cui abbiamo discusso nel capitolo precedente. Mentre guardiamo più da vicino, il layout utilizza una variabile speciale,$this->content. Questa variabile è importante in quanto verrà sostituita dallo script di visualizzazione (modello) della pagina richiesta effettiva.

Creazione di un nuovo layout

Creiamo un nuovo layout per il nostro modulo Tutorial.

Per cominciare, creiamo un file tutorial.css file nella directory "public / css".

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

Crea un nuovo file di layout newlayout.phtmlin / myapp / module / Tutorial / view / layout / e copia il contenuto dal layout esistente. Quindi, aggiungi il filetutorial.css foglio di stile utilizzando il HeadLink classe helper all'interno della sezione head del layout.

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

Aggiungi un nuovo about link nella sezione di navigazione utilizzando il URL aiutante.

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

Questa pagina di layout è comune per l'applicazione del modulo tutorial. Aggiorna il fileview_manager sezione del file di configurazione del modulo tutorial.

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

Aggiungi il aboutAction funzione in TutorialController.

public function aboutAction() { 
}

Aggiungi il about.phtml su myapp / module / Tutorial / view / tutorial / tutorial / con il seguente contenuto.

<h2>About page</h2>

Ora sei pronto per eseguire finalmente l'applicazione - http://localhost:8080/tutorial/about.

In questo capitolo, discuteremo dei vari modelli e del database di Zend Framework.

Modelli in Zend Framework

Un modello definisce la rappresentazione logica dei dati dell'applicazione. Ad esempio, in un'applicazione di carrello degli acquisti - Prodotto, Cliente, Carrello e Ordini sono modelli. Definiscono le proprietà dell'entità che detiene. Alcuni dei concetti di modelli sono i seguenti:

  • I controllori comunicano con i modelli e chiedono loro di recuperare le informazioni di cui hanno bisogno. Queste informazioni recuperate vengono quindi passate dal controller alla visualizzazione. Infine, View renderà il modello come dati di presentazione utilizzabili dall'utente.

  • È molto raro che un modello interagisca direttamente con una vista, ma a volte può accadere.

  • I modelli possono parlare tra loro e non sono autonomi. Hanno rapporti tra loro. Queste relazioni rendono più facile e veloce per un controllore ottenere informazioni, poiché non deve interagire con modelli diversi; i modelli possono farlo da soli.

Diamo un'occhiata a un semplice modello: MyModel

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

Database in Zend Framework

Il framework Zend fornisce una classe semplice e ricca di funzionalità, Zend \ Db \ TableGateway \ TableGateway per trovare, inserire, aggiornare ed eliminare i dati da una tabella di database.

Vediamo come collegare il file MySqlservice tramite il driver PDO di PHP nel framework Zend attraverso i seguenti passaggi.

Passaggio 1: crea il database in MySQL

Crea database tutorialsnel server MySQL locale. Possiamo usarephpmyadmino qualsiasi altro strumento GUI MySQL per questo scopo. Usiamo ilMySQL clientnel prompt dei comandi. Connettiti al server mysql ed esegui il seguente comando per creare il filetutorial Banca dati.

create database tutorials

Passaggio 2: creare una tabella nei tutorial db

Creiamo ora un database book nel tutorials db utilizzando il seguente 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) 
);

Passaggio 3: popolare i dati nella tabella del libro

Popolare il booktabella con dati di esempio. Usa il seguente 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');

Passaggio 4: aggiorna la connessione al database

Aggiorna il file di configurazione globale, che è - myapp / config / autoload / global.php con le informazioni necessarie sull'unità del database.

<?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', 
      ), 
   ), 
);

Passaggio 5: aggiorna le credenziali del database

Aggiorna le credenziali del database nel file di configurazione locale, che è - myapp / config / autoload / local.php. In questo modo, possiamo separare le credenziali di connessione del database locale e live.

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

Passaggio 6: creare un modello per il libro

Creiamo un modello, Book nel nostro modulo srcdirectory. Generalmente, i modelli sono raggruppati nella cartella Model - /myapp/module/Tutorial/src/Model/Book.php.

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

Passaggio 7: implementare exchangeArray nel modello di libro

Il TableGateway interagisce con un modello attraverso il exchangeArrayfunzione. L'argomento standard della funzione exchangeArray è il set di risultati del database archiviato come array PHP. Usando ilexchangeArrayfunction, la proprietà di un modello può essere facilmente sincronizzata con la tabella del database corrispondente.

Aggiorna il modello, Book come mostrato di seguito -

<?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; 
   } 
}

Passaggio 8: utilizzare TableGateway per recuperare il libro

Crea una classe, BookTableper recuperare le informazioni sul libro dal database. Crea la classe, BookTable inModel cartella stessa.

<?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; 
   } 
}

Abbiamo usato select()metodo della classe TableGateway per recuperare le informazioni sul libro dal database. Ma non abbiamo usato alcun riferimento alla tabella -booknel codice. Il TableGateway è di natura generica e può recuperare i dati da qualsiasi tabella utilizzando determinate configurazioni. Di solito, queste configurazioni vengono eseguite inmodule.config.php file, di cui parleremo nei passaggi successivi.

Passaggio 9: configurare la classe BookTable

Aggiorna il modulo tutorial, Module.php con il getServiceConfig() metodo.

<?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);
            },
         ],
      ];
   }
}

Qui abbiamo registrato il file BookTableclasse utilizzando il gestore del servizio. La classe BookTable viene utilizzata per recuperare le informazioni sul libro e, registrandole, possiamo accedervi ovunque sia necessario. Poiché i servizi registrati sono condivisi, aumentano le prestazioni, riducono il consumo di memoria, ecc.

Un altro elemento, Model \ BookTableGateway :: class è l'oggetto TableGateway specializzato per Book modello ed è una dipendenza del BookTable.

Passaggio 10: aggiorna la configurazione di TutorialController

Abbiamo bisogno di BookTableservizio nel controller del tutorial per recuperare le informazioni sul libro. Per ottenere il servizio BookTable, registralo come dipendenza del costruttore nel TutorialController.

Questa dipendenza dal costruttore aiuta a ottenere il servizio BookTable mentre il controller stesso è nella fase di inizializzazione. Aggiorna la sezione controller della configurazione del modulo tutorial,module.config.php come mostrato di seguito.

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

Passaggio 11: aggiorna il controller del tutorial

Questo viene fatto aderendo ai seguenti tre passaggi.

  • Aggiungi il costruttore con BookTable come argomento.
private $table;
public function __construct(BookTable $table) { $this->table = $table; 
}
  • Recupera le informazioni sul libro utilizzando il BookTable's fetchAll() metodo e registrarlo nella vista.

public function indexAction() { 
   $view = new ViewModel([ 
      'data' => $this->table->fetchAll(), ]); return $view; 
}
  • Visualizza le informazioni sul libro nello script di visualizzazione.

<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>

Passaggio 12: eseguire l'applicazione

Controlla l'applicazione eseguendo - http://localhost:8080/tutorial.

Come discusso nell'ultimo capitolo, il framework Zend fornisce un modo generico per accedere al database utilizzando il Database Driverconcetto. Lavorare con un database dipende esclusivamente dalle informazioni sul conducente e quindi la connessione con un database diverso implica solo la modifica delle informazioni sul conducente.

Cambiamo ora il file book esempio per connettersi a postgresql database con i seguenti passaggi.

Step 1 - Crea un database, tutorial nel database postgresql locale utilizzando il seguente comando -

CREATE DATABASE tutorials

Step 2 - Aggiungi booktavolo. Passa al nuovo database ed esegui lo script di creazione della tabella.

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

Step 3 - Aggiungi informazioni sul libro di esempio utilizzando il seguente 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 - Modificare le informazioni sul conducente nel file global.config file.

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

Step 5 - Modificare le credenziali del database nel file local.config file.

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

Step 6 - Infine, esegui l'applicazione http://localhost:8080/tutorial. Il risultato è lo stesso dell'applicazione MySQL.

Zend Framework fornisce un componente separato, zend-formper accelerare il processo di creazione e convalida dei moduli. Collega il modello e il livello di visualizzazione. Fornisce una serie di elementi del modulo per creare moduli html a tutti gli effetti da modelli predefiniti, un fileInputFilter class per convalidare il modello rispetto al modulo e opzioni per associare i dati dal modulo al modello e viceversa.

Installa componente modulo

Il componente del modulo Zend può essere installato utilizzando il Composer comando come specificato di seguito -

composer require zendframework/zend-form

Un framework di moduli Zend ha tre sottocomponenti per gestire i moduli. Sono come spiegato di seguito in dettaglio:

  • Elements - Utilizzato per definire un singolo controllo di input HTML mappato a una proprietà nel modello.

  • Fieldset - Utilizzato per raggruppare elementi e altro fieldset in modo annidato.

  • Form - Utilizzato per creare un modulo html e consiste di elementi e set di campi.

I moduli Zend vengono solitamente creati con l'estensione module//src/Form directory.

Esempio

Creiamo ora un semplice modulo da aggiungere booknel database. Per fare ciò, dovremmo attenerci ai seguenti passaggi:

Passaggio 1: crea BookForm

Crea il "BookForm.php" nella directory * myapp / module / Tutorial / src / Form ". Aggiungi le seguenti modifiche nel file:

<?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', 
         ), 
      )); 
   } 
}

Il Form class fornisce un file add methodper mappare il modello e i dettagli del modulo corrispondente. abbiamo creato il fileBookForm estendendo il Form class e ha aggiunto i dettagli del modulo per Book modello.

Passaggio 2: aggiorna il modello del libro, Book.php

Aggiorna il modello, ‘Book’ con filtro e convalida come specificato di seguito -

<?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; 
   } 
}

Ogni modello dovrebbe implementare il InputFilterAwareInterface. InputFilterAwareInterface fornisce due metodi,setInputFilter() e getInputFilter().

GetInputFilter viene utilizzato per ottenere i dettagli di convalida del modello. Il framework Zend fornisce un ricco set di filtri e validatori per convalidare il modulo. Alcuni dei filtri e dei validatori utilizzati nel modello di libro sono i seguenti:

  • StripTags - Rimuovi l'HTML indesiderato.

  • StringTrim - Rimuovere lo spazio bianco non necessario.

  • StringLength validator - Assicurati che l'utente non inserisca più caratteri del limite specificato.

Passaggio 3: aggiorna la classe BookTable

Includere il file saveBook metodo per aggiungere il libro al database.

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'); 
         } 
      } 
   } 
}

Passaggio 4: aggiorna la classe TutorialController

Aggiungi una nuova azione addAction nel controller del 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); 
}

Il addAction metodo esegue i seguenti processi:

  • Ottiene l'oggetto richiesta.

  • Controlla se il metodo http della richiesta è un file post metodo.

  • Se il metodo http della richiesta non lo è post, esegue solo il rendering del modello, add.phtml

  • Se il metodo http della richiesta non lo è post, quindi imposta il inputfilter, ottiene i dati della richiesta e li imposta nel file input.

  • Verifica se il modulo è valido utilizzando il isValid() metodo della classe Form.

  • Se il modulo non è valido, esegue nuovamente il rendering del modello, add.phtml

  • Se il modulo è valido, salva il libro nel database e reindirizza alla home page.

Passaggio 5: aggiungi il modello add.phtml

Crea un modello - add.phtml sotto 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(); 
}

Qui, stiamo renderizzando il modulo del libro usando il Form esempio, $form.

Passaggio 6: eseguire l'applicazione

Ora possiamo eseguire l'applicazione - http://localhost:8080/tutorial/add.

Form Page

Validate Error Page

Il caricamento dei file è uno dei concetti principali nella programmazione dei moduli. Il framework Zend fornisce tutti gli elementi necessari per caricare i file tramitezend-form e il zend-inputfilter componente.

Classe FileInput

Il componente zend-inputfilter fornisce la classe Zend \ InputFilter \ FileInput per gestire l'elemento di input del file html - <input type = 'file' />. IlFileInputè come gli altri filtri di input con poche eccezioni. Sono i seguenti:

  • Poiché PHP salva i dettagli del file caricato in formato $_FILES array globale, FileInput raccoglie le informazioni sul file caricato solo tramite $ _FILES.

  • La convalida deve essere eseguita prima che la classe FileInput elabori i dati. È il comportamento opposto degli altri filtri di input.

  • Zend \ Validator \ File \ UploadFile è il validatore predefinito da utilizzare. IlUploadFile convalida i dettagli di input del file.

Per aggiungere un tipo di caricamento file in un modulo, è necessario utilizzare il tipo di input File. Il codice parziale è il seguente:

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

Un'altra classe utilizzata nel caricamento dei file è Zend \ Filter \ File \ RenameUpload. IlRenameUploadviene utilizzato per spostare il file caricato nella posizione desiderata. La classe parziale per utilizzare il filtro file è la seguente:

$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);

Qui, le opzioni di RenameUpload sono i seguenti -

  • target - Il percorso di destinazione del file caricato.

  • randomize - Aggiungi una stringa casuale per evitare la duplicazione del file caricato.

  • use_upload_extension - Aggiungi l'estensione del file al file caricato alla destinazione.

Caricamento di file - Esempio di lavoro

Modifichiamo il modulo del tutorial e includiamo una funzione di caricamento delle immagini.

Modifica la tabella del database

Aggiungiamo il file imagepath colonna alla tabella del libro eseguendo il seguente comando SQL:

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

Aggiorna BookForm.php

Aggiungi l'elemento di input del file per caricare un'immagine nel formato del libro: myapp / module / Tutorial / src / Model / BookForm.php.

Includere il codice seguente nel file __constructmethod della classe BookForm.

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

Aggiorna Book.php

Esegui le seguenti modifiche nella classe Book: myapp / module / Tutorial / src / Model / Book.php.

  • Aggiungi una nuova proprietà imagepath per l'immagine.

public $imagepath;
  • Aggiorna il file getInputFilter metodo come mostrato di seguito -

    • Aggiungi il FileInput filtro per elemento di input del file.

    • Impostare il UploadFile convalida per convalidare l'elemento di input del file.

    • Configura il RenameUpload per spostare il file caricato nella destinazione corretta.

L'elenco dei codici parziale è il seguente:

$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);
  • Aggiorna il file exchangeArray metodo per includere il imagepathproprietà. Il percorso dell'immagine può provenire da un modulo o da un database. Se il percorso dell'immagine proviene da un modulo, il formato sarà un array con la seguente specifica:

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 il percorso dell'immagine proviene da un database, sarà una semplice stringa. L'elenco di codice parziale per analizzare un percorso immagine è il seguente:

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; 
}

L'elenco completo di Book il modello è il seguente:

<?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; 
      } 
   } 
}

Aggiorna BookTable.php

Abbiamo aggiornato BookForm e il Book model. Ora aggiorniamo il fileBookTable e modificare il file saveBookmetodo. Questo è sufficiente per includere la voce del percorso immagine nell'array di dati,$data.

L'elenco dei codici parziale è il seguente:

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

L'elenco completo del codice di BookTable la classe è la seguente:

<?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: Le informazioni sul caricamento dei file saranno disponibili nel file $_FILES array globale ed è possibile accedervi utilizzando il Request's getFiles()metodo. Quindi, unisci i dati pubblicati e le informazioni di caricamento dei file come mostrato di seguito.

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

L'elenco completo di addAction() metodo è il seguente:

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); 
}

Aggiorna la vista del file add.phtml

Infine, cambia "add.phtml" e includi l'elemento di input del file imagepath come mostrato di seguito -

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

L'elenco completo è il seguente:

<?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(); 
}

Esegui l'applicazione

Infine, esegui l'applicazione su http://localhost:8080/tutorial/add e aggiungi i nuovi record.

Il risultato sarà come mostrato negli screenshot seguenti:

Form Page

Index Page

AJAX è una moderna tecnologia nella programmazione web. Fornisce opzioni per inviare e ricevere dati in una pagina Web in modo asincrono, senza aggiornare la pagina. Il framework Zend offre un'opzione per lavorare conjson modello attraverso zend-view e zend-jsoncomponente. Impariamo la programmazione Zend AJAX in questo capitolo.

Installa il componente JSON

Il componente Zend json può essere installato utilizzando il Composer comando come specificato di seguito -

composer require zendframework/zend-json

Concetto

Il framework Zend fornisce due metodi per scrivere facilmente un'applicazione web abilitata per AJAX. Sono i seguenti:

  • Il isXmlHttpRequest() metodo in Requestoggetto - Se viene effettuata una richiesta AJAX, il metodo isXmlHttpRequest () dell'oggetto richiesta restituisce true, altrimenti false. Questo metodo viene utilizzato per gestire correttamente una richiesta AJAX sul lato server.

if ($request->isXmlHttpRequest()) { 
   // Ajax request 
} else { 
   // Normal request 
}
  • Zend / View / Model / JsonModel - The JsonModel è un'alternativa per ViewModelda utilizzare esclusivamente per gli scenari AJAX e API REST. Il JsonModel insieme aJsonStrategy (da configurare nel blocco view manager del modulo) codifica i dati del modello in Json e lo restituisce come risposta invece di visualizzazioni (phtml).

AJAX - Esempio di lavoro

Aggiungiamo una nuova pagina ajax, ajaxnel modulo tutorial e recupera le informazioni sul libro in modo asincrono. Per fare ciò, dobbiamo attenerci ai seguenti passaggi.

Passaggio 1: aggiungere JsonStrategy nella configurazione del modulo

Aggiorna il blocco del gestore di visualizzazione nel file di configurazione del modulo tutorial - myapp / module / Tutorial / config / module.config.php. Poi,JsonStrategy lavorerà con JsonModel per codificare e inviare i dati json.

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

Passaggio 2: aggiungi il metodo ajaxAction in TutorialController.php

Aggiungi il metodo ajaxAction in TutorialController.php con il codice seguente:

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; 
}

Qui, ajaxAction controllerà se la richiesta in arrivo è AJAX o meno. Se la richiesta in arrivo è AJAX, il fileJsonModelsarà creato. Altrimenti, normaleViewModel sarà creato.

In entrambi i casi, le informazioni sul libro verranno recuperate dal database e popolate nel modello. Se il modello è un JsonModel, alloraJsonStrategy verrà richiamato e codificherà i dati come json e restituirà come risposta.

Il $query->get('showJson') == 1viene utilizzato per scopi di debug. Basta aggiungereshowJson=1 nell'URL e la pagina mostrerà i dati json.

Passaggio 3: aggiungi ajax.phtml

Ora aggiungi lo script di visualizzazione ajax.phtmlper il metodo ajaxAction. Questa pagina avrà un collegamento con l'etichetta -Load book information.

Facendo clic su quel collegamento verrà eseguita una richiesta AJAX, che recupererà le informazioni sul libro come dati Json e mostrerà le informazioni sul libro come una tabella formattata. L'elaborazione AJAX viene eseguita utilizzando ilJQuery.

L'elenco completo del codice è il seguente:

<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>

Passaggio 4: eseguire l'applicazione

Infine, esegui l'applicazione - http://localhost:8080/tutorial/ajax e fare clic sul collegamento Carica informazioni sul libro.

Il risultato sarà come mostrato di seguito -

Ajax Page -

Ajax Page with Book Information

Ajax page with debugging information

Il Cookie è un concetto molto importante in un'applicazione web. Fornisce la possibilità di conservare i dati dell'utente, di solito una piccola parte di informazioni nel browser stesso per un periodo limitato.

Un cookie viene utilizzato per mantenere lo stato dell'applicazione web. Il framework Zend fornisce un modulo cookie all'interno dizend-httpcomponente. Questo zend-http fornisce l'astrazione HTTP e la sua implementazione.

Installazione del componente HTTP

Il componente HTTP può essere facilmente installato utilizzando il Composer come specificato nel codice sottostante.

composer require zendframework/zend-http

Concetto

Zend-http fornisce l'estensione Zend\Http\Cookiesclasse per gestire i cookie. Viene utilizzato insieme aZend\Http\Clientclass, che viene utilizzata per inviare una richiesta a un server web. I cookie possono essere inizializzati come mostrato nel codice sottostante -

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

Quando il client HTTP (Zend \ Http \ Client) invia per la prima volta una richiesta URI al server web, non ha alcun cookie. Una volta ricevuta la richiesta dal server web, include il cookie nel suo oggetto di risposta come fileHTTP Header, Set-Cookiee lo invia al client HTTP. Il client HTTP estrarrà il cookie dalla risposta http e lo rinvierà come stessa intestazione HTTP nella richiesta successiva. In genere, ogni cookie verrà mappato a un dominio e a un percorso del dominio.

I metodi disponibili in Cookies le classi sono le seguenti:

  • addCookie(uri) - Viene utilizzato per aggiungere un cookie all'oggetto richiesta dell'URI specificato.

  • getCookie(cookieName, $cookieForm) - Viene utilizzato per ottenere il cookie, $ cookieName disponibile nell'URI specificato, $uri. Il terzo argomento è come verrà restituito il cookie, stringa o array.

  • fromResponse(uri) - Viene utilizzato per estrarre i cookie dall'oggetto di risposta dell'URI specificato.

  • addCookiesFromResponse - È uguale a fromResponse, ma lo estrae e lo aggiunge di nuovo nell'oggetto richiesta dell'URI specificato.

  • isEmpty() - Viene utilizzato per verificare se il dato Cookie oggetto ha un cookie o meno.

  • reset() - Viene utilizzato per cancellare tutti i cookie nell'URI specificato.

Nel prossimo capitolo, discuteremo della gestione delle sessioni in Zend Framework.

Una sessione è un concetto molto importante in un'applicazione web. Offre la possibilità di mantenere i dati dell'utente nel server web per un periodo di tempo limitato. Il framework Zend fornisce un componente separato,zend-session per gestire le informazioni sulla sessione.

Installa un componente di sessione

Il componente di sessione può essere installato utilizzando il Composer come di seguito specificato -

composer require zendframework/zend-session

Componenti della sessione

Il framework Zend fornisce sei componenti per gestire la gestione delle sessioni. Tutti questi componenti sono stati spiegati di seguito:

  • Zend\Session\Container - L'API principale per leggere e scrivere le informazioni sulla sessione.

  • Zend\Session\SessionManager - Viene utilizzato per gestire l'intero ciclo di vita di una sessione.

  • Zend\Session\Storage - Viene utilizzato per specificare come i dati della sessione verranno archiviati nella memoria.

  • Zend\Session\SaveHandler - Viene utilizzato per archiviare e recuperare i dati della sessione in una posizione fisica come RDBMS, Redis, MangoDB, ecc.

  • Zend\Session\Validator - Viene utilizzato per proteggere la sessione dal dirottamento tramite il controllo incrociato dell'indirizzo remoto e dell'agente utente della richiesta iniziale e successiva.

  • Zend\Session\Config\SessionConfig - Viene utilizzato per configurare il comportamento della sessione.

La configurazione predefinita è sufficiente per lavorare con una sessione. Utilizzando i componenti di cui sopra, tutti gli aspetti di una sessione possono essere gestiti facilmente.

Esempio di componente di sessione

Atteniamoci ai seguenti punti per creare una nuova pagina per comprendere una sessione nel framework Zend. Per impostazione predefinita, è sufficiente creare un'istanza di un fileContainer classe per gestire le sessioni.

  • Crea una nuova azione, sessionAction in TutorialController.

  • Inizializza un file Container oggetto.

$c = new Container();
  • Controlla se una chiave arbitraria countesiste. Se la chiave non è disponibile, inizializza il filecount con valore 1. Se disponibile, incrementare il valore come mostrato nel codice seguente.

if (!isset($c->count)) { $c->count = 0; 
} else { 
   $c->count++; 
}
  • Registra il conteggio nel ViewModel.

  • Creare un file modello per - sessionAction, session.phtml in myapp / module / Tutorial / view / tutorial / tutorial / session.phtml e quindi eseguire il rendering del count valore.

  • L'aggiornamento della pagina aumenterà il valore di countnella sessione. L'elenco completo è il seguente:

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

L'autenticazione è una delle funzionalità più significative e indispensabili in qualsiasi applicazione web. Zend Framework fornisce un componente separato per gestire l'autenticazione, chiamatozend-authentication.

Installa un componente di autenticazione

Il componente di autenticazione può essere installato utilizzando quanto segue Composer comando.

composer require zendframework/zend-authentication

Concetto

Di solito, uno sviluppatore scrive una funzione php per autenticare i dettagli dell'utente rispetto a un'origine dati. Una volta eseguita l'autenticazione, i dettagli di autenticazione vengono mantenuti per le richieste successive. Zend Framework generalizza questo concetto e fornisce due classi, che vengono spiegate di seguito:

Classe 1 Zend \ Authentication \ Adapter \ AdaptorInterface

Questa classe fornisce un unico metodo, authenticateper scrivere la logica di autenticazione. Il metodo di autenticazione restituisce un'istanza diZend\Authentication\Result classe.

Questo Resultl'oggetto detiene lo stato di autenticazione; identità se l'autenticazione riesce e un messaggio di errore, se l'autenticazione fallisce. La firma dell'interfaccia di autenticazione e della classe dei risultati è la seguente:

AdaptorInterface

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

Result class

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

Zend Framework fornisce un'implementazione predefinita per l'autenticazione rispetto alle credenziali di database, ldap, http di base e digest. UnAdaptor autentica ma non conserva i dettagli per eventuali richieste future.

Classe 2 Zend \ Authentication \ AuthenticationService

AuthenticationService è il componente principale, che utilizza l'adattatore già configurato per scopi di autenticazione. Una volta eseguita l'autenticazione, mantiene i dettagli di autenticazione e fornisce metodi,hasIdentity() per verificare se un'identità è disponibile, getIdentity() per ottenere i dettagli di autenticazione e clearIdentity() per cancellare i dettagli di autenticazione.

L'elenco di codice parziale per utilizzare questo AuthenticationService è il seguente:

$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();

Le cose relative all'autorizzazione sono confezionate come due moduli separati, che sono: zend-permissions-acl e zend-permissions-rbac. Zend-permissions-acl si basa sull'elenco di controllo degli accessi e zend-permissions-rbac si basa sull'elenco di controllo degli accessi basato sui ruoli. Forniscono un'astrazione di alto livello del concetto ACL e RBAC e aiutano nella scrittura dell'applicazione di livello aziendale.

Zend Framework fornisce un componente separato chiamato come zend-mailper inviare messaggi di posta elettronica. Il componente zend-mail fornisce anche un'opzione per leggere e scrivere messaggi di posta elettronica con allegati sia in formato testo che html. L'invio di un'e-mail in Zend è molto più facile e semplice da configurare.

Esaminiamo i concetti di posta elettronica, le impostazioni di base, le impostazioni avanzate come il trasporto SMTP, ecc. In questo capitolo.

Installa il componente di posta

Il componente di posta può essere installato utilizzando il seguente comando Composer.

composer require zendframework/zend-mail

Configurazione email di base

Un'email di base è composta da uno o più destinatari, un oggetto, un corpo e un mittente. Zend fornisceZend\Mail\Messageclass per creare un nuovo messaggio di posta elettronica. Per inviare un'e-mail utilizzando il filezend-mail, è necessario specificare almeno un destinatario e il corpo del messaggio.

Il codice parziale per creare un nuovo messaggio di posta è il seguente:

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 fornisce la classe Zend \ Mail \ Sendmail per inviare il messaggio di posta. Sendmail utilizza la funzione di posta nativa di php, mail per inviare il messaggio di posta e possiamo configurare il livello di trasporto utilizzando il file di configurazione php.

La codifica parziale utilizzando Sendmail è la seguente:

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

Il zend-mail fornisce molti livelli di trasporto e ognuno può richiedere molti parametri aggiuntivi come nome utente, password, ecc

Metodi di gestione della posta elettronica

Alcuni dei metodi di gestione della posta elettronica più importanti sono i seguenti:

  • isValid - I messaggi senza un indirizzo "Da" non sono validi.

isValid() : bool
  • setEncoding - Imposta la codifica del messaggio.

setEncoding(string $encoding) : void
  • getEncoding - Ottieni la codifica del messaggio.

getEncoding() : string
  • setHeaders - Componi intestazioni.

setHeaders(Zend\Mail\Headers $headers) : void
  • getHeaders - Accedere alla raccolta delle intestazioni.

getHeaders() : Zend\Mail\Headers
  • setFrom- Imposta (sovrascrivi) indirizzi da. Contiene una coppia chiave / valore in cui la chiave è il nome leggibile dall'uomo e il valore è l'indirizzo e-mail.

setFrom( 
   string|AddressInterface|array|AddressList|Traversable $emailOrAddressList, string|null $name 
) : void
  • addFrom - Aggiungi un indirizzo "Da".

addFrom( 
   string|AddressInterface|array|AddressList|Traversable $emailOrAddressOrList, string|null $name 
) : void
  • getFrom - Recupera l'elenco dei mittenti "Da".

getFrom() : AddressList 
setTo - Overwrite the address list in the To recipients. 
setTo( 
   string|AddressInterface|array|AddressList|Traversable $emailOrAddressList, null|string $name 
) : void
  • setSubject - Imposta il valore dell'intestazione dell'oggetto del messaggio.

setSubject(string $subject) :void
  • setBody - Imposta il corpo del messaggio.

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

Livello di trasporto SMTP

Il zend-mail fornisce opzioni per inviare un'e-mail utilizzando il server SMTP tramite Zend\Mail\Transport\Smtpclass. È comeSendmail tranne per il fatto che ha alcune opzioni aggiuntive per configurare l'host SMTP, la porta, il nome utente, la password, ecc.

Il codice parziale è il seguente:

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);

Qui,

  • name - Nome dell'host SMTP.

  • host - Nome host remoto o indirizzo IP.

  • port - Porta su cui è in ascolto l'host remoto.

Concetto di posta - Esempio

Seguiamo i seguenti punti per scrivere una semplice applicazione per console php per comprendere il concetto di posta.

  • Crea una cartella "mailapp".

  • Installare zend-mail utilizzando lo strumento di composizione.

  • Crea un file php Mail.php all'interno della cartella "mailapp".

  • Crea il messaggio usando il Zend\Mail\Message.

$message = new Message(); $message->addTo('[email protected]'); 
$message->addFrom('[email protected]'); $message->setSubject('Hello!'); 
$message->setBody("My first Zend-mail application!");
  • Crea il livello di trasporto SMTP e aggiungi la configurazione necessaria.

// 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);
  • Invia l'e-mail utilizzando il send metodo.

$transport->send($message);

L'elenco completo, Mail.php è il seguente:

<?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);

Ora, esegui l'applicazione nel prompt dei comandi php Mail.php. Questo invierà la posta come configurato nell'applicazione.

In generale, possiamo eseguire il debug di un'applicazione PHP utilizzando il advanced debugger tool o usando semplici comandi come echo e die. In uno scenario web, dobbiamo testare le logiche di business e il livello di presentazione. I moduli in un'applicazione Web possono essere testati immettendo dati di test pertinenti per garantire che i moduli funzionino come previsto.

Il design di un sito web può essere testato manualmente utilizzando un browser. Questo tipo di processi di test possono essere automatizzati utilizzando i test unitari. Uno unit test è essenziale nei grandi progetti. Questi test unitari aiuteranno ad automatizzare il processo di test e avviseranno lo sviluppatore quando qualcosa va storto.

Configurazione di PHPUnit

Il framework Zend si integra con il framework di test di unità PHPUnit. Per scrivere uno unit test per il framework Zend, dobbiamo impostare PHPUnit, che può essere facilmente eseguito utilizzando il seguente comando Composer.

$ composer require --dev phpunit/phpunit

Dopo aver eseguito il comando precedente, riceverai una risposta come mostrato nel seguente blocco di codice.

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

Ora, quando apri il file "composer.json", vedrai le seguenti modifiche:

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

TestCase e asserzioni

Il framework Zend fornisce classi helper per testare l'unità del controller. IlTestCase è il componente principale in un file PHPUnit framework per scrivere i casi di test e Zend Framework fornisce un'implementazione astratta del TestCase che viene chiamato come AbstractHttpControllerTestCase.

Questo AbstractHttpControllerTestCase fornisce vari Assertmetodi e possono essere raggruppati per funzionalità. Sono i seguenti:

  • Request Assertions- Usato per affermare la richiesta http. Ad esempio, assertControllerName.

  • CSS Select Assertions - Utilizzato per controllare la risposta HTML utilizzando il modello HTML DOM.

  • XPath Assertions - Un'alternativa alle asserzioni di selezione CSS basate su XPath.

  • Redirect Assertions - Usato per controllare il reindirizzamento della pagina.

  • Response Header Assertions - Utilizzato per controllare l'intestazione della risposta come il codice di stato (assertResponseStatusCode)

Crea directory dei test

Un test unitario può essere scritto separatamente per ogni modulo. Tutta la codifica relativa ai test deve essere creata all'interno del filetest cartella nella directory principale del modulo.

Ad esempio, per scrivere un test per il TutorialController disponibile nel modulo Tutorial, la classe di test deve essere collocata nella directory myapp / module / Tutorial / test / Controller /.

Esempio

Scriviamo una classe di test per testare l'unità TutorialController.

Per cominciare, dovremmo scrivere una classe chiamata TutorialControllerTest ed estenderla a AbstractHttpControllerTestCase.

Il prossimo passo è scrivere un file Setupmetodo per configurare l'ambiente di test. Questo può essere fatto chiamando ilsetApplicationConfig e passando il nostro file di configurazione dell'applicazione principale myapp / config / application.config.php

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

Scrivi uno o più metodi e chiama diversi metodi di asserzione a seconda del requisito.

$this->assertMatchedRouteName('tutorial');

We have written the test class and the complete listing is as follows −

<?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'); 
   } 
}

Now, open a command prompt, move on to application root directory and execute the phpunit executable available inside the vendor folder.

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

The result will be as shown in the following code block −

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

Failure of system needs to be handled effectively for the smooth running of the system. Zend Framework comes with a default error trapping that prints and logs the error as they occur. This same error handler is used to catch Exceptions.

The Error Handler displays errors when the debug is true and logs the error when the debug is false. Zend Framework has several exception classes and the built-in exception handling will capture any uncaught exception and render a useful page.

Default Error Handling

We can configure the default error settings in the application configuration file, myapp/module/Application/config/module.config.php.

The partial code sample is as follows −

'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', 
   ], 
],

Here, the display_exception, not_found_template, exception_template, error/404 and the error/index are error related configuration items and are self-explanatory.

The most important item among these is the error/index. This is the template shown when an exception occurs in the system. We can modify this template, myapp/module/Application/view/error/index.phtml to control the amount of error to be shown.

In this chapter, we will learn how to create a complete MVC based Employee Application in Zend Framework. Follow the steps given below.

Step 1: Module.php

First, we should create an Employee module inside the – myapp/module/Employee/src/ directory and then implement the ConfigProviderInterface interface.

The complete code for the Module class is as follows −

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

Step 2: composer.json

Configure the Tutorial module in composer.json under the autoload section by using the following code.

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

Now, update the application using a composer update command.

composer update

The Composer command will do the necessary changes to the application and show the logs as shown in the command prompt below.

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

Step 3: module.config.php for the Employee Module

Create the module configuration file, “module.config.php” under the myapp/module/Employee/config with the following code.

<?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',], 
   ], 
];

Now, configure the Employee module in the application level configuration file – myapp/config/modules.config.php.

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

Step 4: EmployeeController

Create a new PHP class, EmployeeController by extending the AbstractActionController and place it at the myapp/module/Employee/src/Controller directory.

The complete code listing is as follows −

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

Step 5: Router Configuration

Let us add a segment route in our Employee module. Update the employee module configuration file, module.config.php available at 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', 
      ], 
   ], 
];

We have successfully added the routing for our Employee module. The next step is to create a view script for the Employee application.

Step 6: Create ViewModel

Create a file called as “index.phtml” under the myapp/module/Employee/view/employee/employee directory.

Add the following changes in the file −

<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();  
   } 
}

Finally, we have successfully completed the Employee module. we can access it using the following url − http://localhost:8080/employee.

Result

In the next step, we will perform add, edit and delete data operations in the employee application. To perform these operations, we should first create a database model. It is described in the next step.

Step 7: Create a Model

Let us create a model, Employee in our module src directory. Generally, models are grouped under the Model folder (myapp/module/Employee/src/Model/Employee.php)

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

Step 8: MySQL Table

Create a database named as tutorials in the local MYSQL server using the following command −

create database tutorials;

Let us create a table named as employee in the database using following SQL command −

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) 
);

Insert data into the employee table using the following query −

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');

Step 9: Update the Database Configuration

Update the Global Configuration file, myapp/config/autoload/global.php with the necessary database drive information.

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

Now, Update the database credentials in the local configuration file – myapp/config/autoload/local.php. In this way, we can separate local and live database connection credentials.

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

Step 10: Implement exchangeArray

Implement exchangeArray function in Employee model.

<?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; 
   } 
}

Step 11: Use TableGateway to fetch the Employee Data

Create the class, EmployeeTable in the Model folder itself. It is defined in the following code block.

<?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; 
   } 
}

Step 12: Configure EmployeeTable Class

Update employee service in Module.php using getServiceConfig() method

<?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);
            },
         ],
      ];
   }
}

Step 13: Add Employee Service in Controller

Update the controller section of the Employee Module Configuration in − myapp/module/config/module.config.php as shown below.

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

Step 14: Add Constructor for EmployeeController

Add the constructor with EmployeeTable as the argument and edit the following changes.

<?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; 
   } 
}

Step 15: Display Employee Information in the view script “index.phtml”

Move to the file − index.phtml and make the following changes −

<?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>

Now we have successfully created a database model and can fetch the records within the application.

Request the application using the url − http://localhost:8080/employee.

Result

The next step explains about the insert, edit and delete data operations in the employee module.

Step 16: Create an Employee Form

Create a file called EmployeeForm.php in myapp/module/Employee/src/Form directory. It is described in the code block below.

<?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', 
         ), 
      )); 
   } 
}

Step 17: Update the Employee Model

Update the employee model and implement the InputFilterAwareInterface. Move to the directory myapp/module/Employee/src/Employee/Model and add the following changes in the Employee.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; 
   } 
}

Step 18: Add addAction in the Employee Controller

Add the following changes in the EmployeeController class.

<?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); 
}

Step 19: Add save functionality in the EmployeeTable class

Add the following two functions in the EmployeeTable class – 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'); 
      } 
   } 
}

Step 20: Create View script for AddAction method, Add.phtml

Add the following changes in the “Add.phtml” file in the − 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

Result

Once the data has been added, it will redirect to the home page.

Step 21: Edit Employee Records

Let us perform the editing data operations in the Employee module. Update the following changes in the Employeecontroller.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,); 
}

Here, we look for the id, which is in the matched route and then load the employee details for the editing operation.

Step 22: Employee.php

Now add the following changes in the “Employee.php” file, which resides in the − myapp/module/Employee/src/Employee/Model/ directory.

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

Here, the Zend\Stdlib\Hydrator\ArraySerializable expects to find two methods in the model: getArrayCopy() and exchangeArray().

In which, the exchangeArray() is used for iteration. This function is used for binding the data from the employee table.

Now, we need to create a view script for editAction().

Step 23: Create Edit.phtml

Create a view script file in the module/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();

Editing the employee details is shown in the following screenshot.

Once the data has been edited, it will redirect to the home page.

Step 24: Add deleteEmployee method

Add the deleteEmployee method in the EmployeeTable class – myapp/module/Employee/src/Model/EmployeeTable.php

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

Step 25: Delete the Employee Records

Let us now perform the deleting data operations in the Employee module. Add the following method, deleteAction in the EmployeeController class.

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) 
   ); 
}

Here, the deleteEmployee() method deletes the employee by his id and redirects to the employees list page (home page).

Let us now create a corresponding view scripts for the deleteAction() method.

Step 26: Create a View Script

Create a file named delete.phtml in the − myapp/module/Employee/view/employee/employee/delete.phtml and add the following code in it.

<?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>

Now, delete any employee using the edit link in the home page and the result will be as shown in the following screenshot.

Result

We have successfully completed the Employee module by implementing all necessary features.

Conclusion

In the current competitive environment, Zend framework is placed at the top spot by the developer. It provides abstractions to any program or any type of an application in the PHP language. It is a matured framework and supports modern PHP language features. It is fun, professional, evolving and keeping pace with the current technology.