+ All Categories
Home > Technology > Il Pattern di Zend Framework 2

Il Pattern di Zend Framework 2

Date post: 08-May-2015
Category:
Upload: zend-technologies
View: 2,095 times
Download: 2 times
Share this document with a friend
Description:
Questo seminario web, originariamente ideato da Matthew Weier O'Phinney, Team Leader del progetto Zend Framework, fornisce una panoramica di questi pattern, li identifica e tratta le interfacce coinvolte e i casi d'uso concreti. Enrico Zimuel, Senior PHP Architect italiano, che recentemente si è unito al team di sviluppo dello Zend Framework, mostrerà come sia possibile creare le proprie implementazioni e come effettuarne lo slip-stream nelle applicazioni. Fra i pattern discussi: eventi, broker e dispatcher.
58
© All rights reserved. Zend Technologies, Inc. Zend Framework 2 presenta Enrico Zimuel ([email protected]) Senior Software Engineer, Zend Technologies Zend Framework Core Team
Transcript
Page 1: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Zend Framework 2

presenta Enrico Zimuel ([email protected])

Senior Software Engineer, Zend TechnologiesZend Framework Core Team

Page 2: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Sommario

● Breve storia del progetto Zend Framework

● Zend Framework 2.0

● I pre-requisiti di ZF 2

● Miglioramento delle performance

● Nuove funzionalità e design patterns

▶ Event Manager▶ Dependency Injection▶ Service Locator

Page 3: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Zend Framework

Page 4: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Breve storia di ZF

● October 2005: Annuncio del progetto

● March 2006: Prima versione (pulic review), 0.1.0

● Fall 2006: Riscrittura dell'MVC

● July 2007: Prima release stabile 1.0

● March 2008: Prima minor release 1.5.0

▶ Zend_Form, Zend_Layout

● September 2008: 1.6.0

▶ Integrazione con Dojo, PHPUnit scaffolding

● November 2008: 1.7.0

▶ Supporto AMF, miglioramento delle performance

Page 5: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Breve storia di ZF (2)● April 2009: 1.8.0

▶ Zend_Tool, Zend_Application● August 2009: 1.9.0

▶ Aggiunta di Zend_Feed_Reader

▶ Supporto di PHP 5.3● January 2010: 1.10.0

▶ Aggiunta di Zend_Feed_Writer, refactoring di Zend_Feed▶ Cambio della documentazione: adozione di PhD per la

generazione del manuale utente, aggiunta dei commenti, nuova sezione “Learning Zend Framework section”

● November 2010: 1.11.0

▶ Supporto dispositivi mobile tramiteZend_Http_UserAgent▶ Simple Cloud API tramite Zend_Cloud

Page 6: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Page 7: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Zend Framework 2.0● Nuova major release

▶ Ci ha permesso di non dover tener conto della retro-compatibilità

▶ Prerequisiti: PHP 5.3 e superiore

● Attenzione posta su:▶ Consistenza▶ Performance▶ Documentazione▶ Produttività utente

Page 8: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Primi passi verso ZF 2.0

● Conversione del codice da prefissi gestiti a mano (es. “Zend_Foo”) ai namespace nativi di PHP 5.3

● Refactoring delle Eccezioni

● Cambio di ZF per essere solo autoload

● Miglioramento e standardizzazione del sistema di plugin

Page 9: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF 2.0 (dev3)

● Il 14 giugno è stata rilasciata la versione dev3 di Zend Framework 2.0

● Tra le funzionalità già implementate:

▶ Refactoring di Zend\Tool e CodeGenerator

▶ Migrazione e refactoring dei servizi LiveDocx ▶ EventManager ▶ Dependency Injection

● Maggiori info: http://bit.ly/lptIpN

Page 10: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

“Riscrivere il codice solo se ha senso”

Page 11: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF2 in una slide

● Miglioramenti:

▶ Namespace (supporto nativo di PHP)▶ Exception▶ Autoloading▶ MVC▶ Plugin▶ Documentazione▶ Performance

● Nuove funzionalità:

▶ Event Manager▶ Dependency Injection / Service Locator▶ Supporto di nuovi servizi cloud▶ Molto altro ancora...

Page 12: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Namespace

Page 13: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

L'approccio di ZF2 ai namespace

● Formalizzare i prefissi utilizzati in ZF1

▶ Separatore di namespace correllato con il separatore di directory

● Aiutare ad identificare le dipendenze (imports)

▶ Abilitare il refactoring utilizzazando diverse implementazioni

▶ Facilitare il sistema di packaging

Page 14: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Namespace

namespace Zend\EventManager;

use Zend\Stdlib\CallbackHandler;

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

namespace Zend\EventManager;

use Zend\Stdlib\CallbackHandler;

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

Page 15: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Namespace● Interfacce come namespace

▶ I nomi d'interfaccia sono aggettivi o sostantivi

▶ Implementazione concreta in sub-namespace denominati dopo l'interfaccia

▶ Paradigma Contract-Oriented

Page 16: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Interfacce come Namespace

Zend/Session|-- Storage.php`-- Storage |-- ArrayStorage.php `-- SessionStorage.php

namespace Zend\Session;interface Storage { /* ... */}

namespace Zend\Session;interface Storage { /* ... */}

namespace Zend\Session\Storage;use ArrayObject, Zend\Session\Storage, Zend\Session\Exception;class ArrayStorage extends ArrayObject implements Storage{ /* ... */ }

namespace Zend\Session\Storage;use ArrayObject, Zend\Session\Storage, Zend\Session\Exception;class ArrayStorage extends ArrayObject implements Storage{ /* ... */ }

Page 17: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF2 approccio ai namespace

● Ogni file di classe dichiara un namespace

● Un namespace per file

● Ogniclasse utilizzata che non fa parte del namespace attuale è importata (tipicamante tramite un alias)

● L'uso di riferimenti globali di classe è scoraggiato, eccetto nel caso di classi referenziate tramite stringhe

Page 18: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Autoloading

Page 19: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF2 Autoloading● Non più chiamate require_once!● Differenti approcci:

▶ Stile ZF1 con include_path autoloader▶ Per-namespace/prefix autoloading▶ Class-map autoloading

Page 20: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Stile ZF1 di autoloading

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

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

Page 21: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF2 NS/Prefix Autoloading

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

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

Page 22: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF2 Class-Map Autoloading

return array( 'My\Foo\Bar' => __DIR__ . '/Foo/Bar.php',);

return array( 'My\Foo\Bar' => __DIR__ . '/Foo/Bar.php',);

require_once 'Zend/Loader/ClassMapAutoloader.php';$loader = new Zend\Loader\ClassMapAutoloader();$loader->registerAutoloadMap( __DIR__ . '/../library/.classmap.php');$loader->register();

require_once 'Zend/Loader/ClassMapAutoloader.php';$loader = new Zend\Loader\ClassMapAutoloader();$loader->registerAutoloadMap( __DIR__ . '/../library/.classmap.php');$loader->register();

● .classmap.php:

Page 23: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Class-Maps richiede più lavoro?

● Si, ma abbiamo già rilasciato un tool a linea di comando: bin/classmap_generator.php

● L'utilizzo è immediato:

$ cd your/library$ php /path/to/classmap_generator.php -w

$ cd your/library$ php /path/to/classmap_generator.php -w

● Class-Map verrà creato in .classmap.php

Page 24: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Perchè?

● Class-Maps evidenzia un miglioramento di performance del 25% rispetto all'autoloader del ZF1 (senza acceleratore di opcode)

▶ e un miglioramento del 60-85% con un acceleratore di bytecode PHP

● L'utilizzo di prefissi e namespace con percorsi specifici evidenzia un miglioramento del 10% sulle performance (senza acceleratore di opcode)

▶ e un miglioramento del 40% con un acceleratore di bytecode PHP

Page 25: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Strategie di autoloading

● Con strategie di autoloading differenti c'è la necessità di un factory

● Scegliere tra differenti strategie:

▶ Class-Map per performance migliori▶ Prefissi/Namespace per esigenze standard▶ Autoloader “classico” (in stile ZF1) per

ambienti di sviluppo

Page 26: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Migrare a ZF2

● Potete utilizzare il nuovo autoloader ZF2 da subito, anche per progetti ZF1

● Iniziare a migrare ora!

● “Backported ZF2 Autoloaders”by Matthew Weier O'Phinney http://bit.ly/mq4UAh

Page 27: Il Pattern di Zend Framework 2

27 © All rights reserved. Zend Technologies, Inc.

Exception

Page 28: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Problema● Tutte le eccezioni derivano da una classe

comune● Nessuna possibilità di espandere la

semantica delle eccezioni tramite SPL

Page 29: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

L'approccio di ZF2● Eliminare Zend_Exception● Ogni componente definisce una propria

interfaccia di eccezioni● Eccezioni addizionali vengono create in

un subnamespace specifico▶ Queste eccezioni estendono le funzionalità

SPL ed implementato le interfacce specifiche dei componenti

Page 30: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Vantaggi● Intercetttare specifiche eccezioni● Intercettare eccezioni di tipo SPL● Intercettare eccezioni a livello di

componenti● Intercettare basandosi su un tipo di

eccezione globale

Page 31: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Esempio di ExceptionZend/EventManager|-- Exception.php`-- Exception `-- InvalidArgument- Exception.php

Zend/EventManager|-- Exception.php`-- Exception `-- InvalidArgument- Exception.php

namespace Zend\EventManager;

interface Exception {}

namespace Zend\EventManager;

interface Exception {}

namespace Zend\EventManager\Exception;

use Zend\EventManager\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements Exception{}

namespace Zend\EventManager\Exception;

use Zend\EventManager\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements Exception{}

Page 32: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Esempio di Exception (2)

namespace Zend\EventManager\Exception;use Zend\EventManager\Exception;try { $events->trigger('foo.bar', $object);} catch (InvalidArgumentException $e) {} catch (Exception $e) {} catch (\InvalidArgumentException $e) {} catch (\Exception $e) {}

namespace Zend\EventManager\Exception;use Zend\EventManager\Exception;try { $events->trigger('foo.bar', $object);} catch (InvalidArgumentException $e) {} catch (Exception $e) {} catch (\InvalidArgumentException $e) {} catch (\Exception $e) {}

Page 33: Il Pattern di Zend Framework 2

33 © All rights reserved. Zend Technologies, Inc.

Nuove funzionalità

Page 34: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Nuove funzionalità● Zend\EventManager

● Zend\Di

● Nuovi servizi cloud:▶ Zend\Rackspace

▶ Zend\Service\GoGrid

▶ Zend\Cloud\Infrastructure

● Amazon S3● Rackspace● GoGrid

● E molto altro...

Page 35: Il Pattern di Zend Framework 2

35 © All rights reserved. Zend Technologies, Inc.

Event manager

Page 36: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Il problema● Come inserire sistemi di logging/debug in un progetto Zend

Framework?

● Come offrire la possibilità di utilizzare un sistema di caching senza estendere il codice del framework?

● Come offrire la possibilità di validare, filtrare, gestire un ACL, etc, senza estendere il codice del framework?

● Come offrire la possibilità di decidere l'ordine di un plugin, di intercettare un filtro, un evento, un trigger, etc?

● Come offrire uno strumento in grado di soddisfare queste esigenze?

Page 37: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

ZF2 Event Manager● Summa di diversi design patterns: PubSub,

SignalSlot, ed Intercepting Filters

● Non risolvono completamente il problema di composizione/statici

▶ Possiamo risolverlo in PHP 5.4 via Traits▶ Ci sono alcuni modi eleganti per gestire

componenti statici

Page 38: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Interfaccia EventCollection

namespace Zend\EventManager;use Zend\Stdlib\CallbackHandler;interface EventCollection{public function trigger($event, $context, $argv = array());public function triggerUntil($event, $context, $argv, $callback);public function attach($event, $callback, $priority = 1);public function detach(CallbackHandler $handle);public function getEvents();public function getHandlers($event);public function clearHandlers($event);}

namespace Zend\EventManager;use Zend\Stdlib\CallbackHandler;interface EventCollection{public function trigger($event, $context, $argv = array());public function triggerUntil($event, $context, $argv, $callback);public function attach($event, $callback, $priority = 1);public function detach(CallbackHandler $handle);public function getEvents();public function getHandlers($event);public function clearHandlers($event);}

Page 39: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Triggering di eventi

use Zend\EventManager\EventManager;$events = new EventManager();$events->trigger($eventName, $object, $params);

use Zend\EventManager\EventManager;$events = new EventManager();$events->trigger($eventName, $object, $params);

● Dove:▶ $eventName è il nome dell'evento, di solito il nome

del metod

▶ $object è l'oggetto triggering dell'evento

▶ $params sono i parametri di cui l'handler necessita, di solito gli argomenti del metodo

Page 40: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

CallbackHandler

$handler = $events->attach(’some-event’, function($e) use ($log) {

$event = $e->getName();$context = get_class($e->getTarget());$params = json_encode($e->getParams());$log->info(sprintf("%s: %s: %s", $event,

$context, $params));});

$handler = $events->attach(’some-event’, function($e) use ($log) {

$event = $e->getName();$context = get_class($e->getTarget());$params = json_encode($e->getParams());$log->info(sprintf("%s: %s: %s", $event,

$context, $params));});

Page 41: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Comporre un Event Manager

use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;

class Foo{

protected $events;public function events(Events $events = null) {

if (null !== $events) {$this->events = $events;

} elseif (null === $this->events) {$this->events = new EventManager(__CLASS__);

}return $this->events;

}public function doSomething($param1, $param2) {

$params = compact('param1', 'param2');$this->events()->trigger(__FUNCTION__, $this, $params);

}}

use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;

class Foo{

protected $events;public function events(Events $events = null) {

if (null !== $events) {$this->events = $events;

} elseif (null === $this->events) {$this->events = new EventManager(__CLASS__);

}return $this->events;

}public function doSomething($param1, $param2) {

$params = compact('param1', 'param2');$this->events()->trigger(__FUNCTION__, $this, $params);

}}

Page 42: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Utilizzo dei Trait!

use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;

trait Eventful{

public function events(Events $events = null) {if (null !== $events) {

$this->events = $events;} elseif (null === $this->events) {

$this->events = new EventManager(__CLASS__);}return $this->events;

}}class Foo{

use Eventful;protected $events;

}

use Zend\EventManager\EventCollection as Events, Zend\EventManager\EventManager;

trait Eventful{

public function events(Events $events = null) {if (null !== $events) {

$this->events = $events;} elseif (null === $this->events) {

$this->events = new EventManager(__CLASS__);}return $this->events;

}}class Foo{

use Eventful;protected $events;

}

Page 43: Il Pattern di Zend Framework 2

43 © All rights reserved. Zend Technologies, Inc.

Dependency Injection

Page 44: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Il problema

● Come gestire le dipendeze tra oggetti?▶ In particolare, come gestire le dipendenze

tra Controller?

Page 45: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

L'approccio di ZF2 ● Service Locator

▶ Schema di base: ● set($name, $service)● get($name)

▶ Formalizzazione dell'application service(mailer, logger, profiler, etc.)

▶ Buone interfacce con il typehinting

Page 46: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Service Locator

use Zend\Di\ServiceLocator, Zend\EventManager\EventManager;

class MyLocator extends ServiceLocator{ protected $events; protected $map = array('events' => 'getEvents');

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

use Zend\Di\ServiceLocator, Zend\EventManager\EventManager;

class MyLocator extends ServiceLocator{ protected $events; protected $map = array('events' => 'getEvents');

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

Page 47: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

L'approccio di ZF2 ● Dependency Injection Container

▶ Injection in costruzione (construct) e setters

▶ Via codice o tramite configurazione▶ Tipicamente utilizzato per iniettare un

service locator

Page 48: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Dependency Injection

$db = new Definition('My\Db\Adapter\Sqlite');$db->setParam('name', __DIR__ . '/../data/db/users.db');

$mapper = new Definition('My\Mapper\Db');$mapper->addMethodCall( 'setAdapter', array(new Reference('db')));

$service = new Definition('My\Resource\Users');$service->setParam('mapper', new Reference('mapper'));

$di = new DependencyInjector;$di->setDefinitions(array( 'db' => $db, 'mapper' => $mapper, 'users' => $service,));

$users = $di->get('users'); // My\Resource\Users

$db = new Definition('My\Db\Adapter\Sqlite');$db->setParam('name', __DIR__ . '/../data/db/users.db');

$mapper = new Definition('My\Mapper\Db');$mapper->addMethodCall( 'setAdapter', array(new Reference('db')));

$service = new Definition('My\Resource\Users');$service->setParam('mapper', new Reference('mapper'));

$di = new DependencyInjector;$di->setDefinitions(array( 'db' => $db, 'mapper' => $mapper, 'users' => $service,));

$users = $di->get('users'); // My\Resource\Users

Page 49: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Controller come servizi● Risolve il problema della dipendenza dei

controller● Ogni richiesta istanzia soltanto lo stretto

necessario● Migliore testabilità dei controller

Page 50: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Controller come servizi: esempio

$userController = new Definition('Site\Controller\User');$userController->setParam('service',

new Reference('users'));$di->setDefinition($userController, 'controller-user');

// Inside dispatcher:$controller = $di->get($controllerName);$result = $controller->dispatch($request, $response);

$userController = new Definition('Site\Controller\User');$userController->setParam('service',

new Reference('users'));$di->setDefinition($userController, 'controller-user');

// Inside dispatcher:$controller = $di->get($controllerName);$result = $controller->dispatch($request, $response);

Page 51: Il Pattern di Zend Framework 2

51 © All rights reserved. Zend Technologies, Inc.

Nuovi servizi cloud

Page 52: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Zend\Cloud● Supporto di nuovi servizi cloud:

▶ Rackspace ▶ GoGrid

● Supporto di Rackspace in Zend\Cloud\StorageService

▶ Rackspace

● Zend\Cloud\Infrastructure per la gestione delle infrastrutture di cloud computing:

▶ Amazon EC2▶ Rackspace Cloud Servers▶ GoGrid▶ Windows Azure

Page 53: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Zend\Cloud\Infrastructure● Zend\Cloud\Infrastructure (alpha version):

▶ Attualmente supporta soltanto Amazon EC2▶ A breve disponibili adapter per Rackspace

Servers e GoGrid▶ Download: http://bit.ly/imQLzB

● Zend\Service\Rackspace\Files (beta version):

▶ Download: http://bit.ly/muC6AT

Page 54: Il Pattern di Zend Framework 2

54 © All rights reserved. Zend Technologies, Inc.

Partecipare al progetto

Page 55: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Contribuire a ZF2

● ZF2 wiki:

▶ http://bit.ly/zf2wiki● zf-contributors mailing list:

[email protected]● IRC:

▶ #zftalk.dev su Freenode

Page 56: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Risorse● Git guide:

▶ http://bit.ly/zf2gitguide● GitHub:

▶ http://github.com/zendframework/zf2● Official repo:

▶ git://git.zendframework.com/zf.git▶ http://git.zendframework.com/

Page 57: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Domande?

Page 58: Il Pattern di Zend Framework 2

© All rights reserved. Zend Technologies, Inc.

Grazie!

Maggiori informazioni:http://www.zend.comhttp://framework.zend.com/


Recommended