fare con zend framework 2 ciò che facevo con zf1

Post on 27-Jan-2015

114 Views

Category:

Technology

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

Introduzione a Zend Framework 2 per chi proviene da Zend Framework 1, tenuta allo Zend Framework Day di Milano del 01/02/2013. Introduzione alle nuove caratteristiche e pattern architetturali di ZF2 Zend Framework 2 non è l'evoluzione di ZF, ma un progetto nuovo: il codice è stato riscritto e poche sono le parti in comune con la versione precedente. Lo sviluppatore abituato a ZF1 non ha vita facile, ed è fondato il timore di dover imparare tutto da capo. In questo talk vediamo come cambiare le vecchie abitudini di sviluppatori ZF1, per sfruttare al meglio le potenzialità del nuovo strumento. Attraverso esempi concreti, in cui vedremo all'opera i nuovi pattern e le best practice, mostriamo come - partendo con il piede giusto - il passaggio a ZF2 possa essere meno traumatico del previsto. Il talk è orientato soprattutto a chi già conosce ZF1, ma gli argomenti affrontati possono essere utili anche a chi si avvicina a ZF per la prima volta.

TRANSCRIPT

Zend Framework 2 ciò che facevo con ZF1

Zend Framework Day – Milano – 01/02/2013

Fare con

2

@maraspin

3

http://www.mvassociati.it/

4

http://friuli.grusp.org/

brutto_esempio.php <?php

echo '<html><body>';

$caldaia=$_GET['caldaia'];

$mysqli = new mysqli("localhost", "user", "pwd", "mva");

$query = "SELECT * FROM cespiti WHERE id =".$caldaia;

$result = $mysqli->query($query);

while ($row = $result->fetch_assoc()) {

?><div><?php echo $row["nome, temperatura"]); ?></div>

<?php } ?>

<?php

$result->free();

$mysqli->close();

echo '</html></body>';

?>

IL “FENOMENO”

AGGIORNAMENTO

9

LA SEGRETARIA

UFF. TECNICO

PRODUZIONE

ACCOUNT

14

Com’è strutturata l’azienda?

15

Che in un’applicazione…

16

MVC

17

Flusso MVC

18

Routing

19

Interazione con il modello

20

Il layer di presentazione

21

Risultato all’utente

22

Cosa ci manca?

23

Vorremmo una situazione così

24

Disaccoppiamento

I MODULI

26

Permettono questo

27

Come installare ZF2?

28

THE SKELETON APP

30

Cloning

git clone git://github.com/zendframework/ZendSkeletonApplication.git

31

composer.json {

"name": "zendframework/skeleton-application",

"description": "Skeleton Application for ZF2",

"license": "BSD-3-Clause",

"keywords": [

"framework",

"zf2"

],

"homepage": "http://framework.zend.com/",

"require": {

"php": ">=5.3.3",

"zendframework/zendframework": "2.*"

}

}

composer.json {

"name": "zendframework/skeleton-application",

"description": "Skeleton Application for ZF2",

"license": "BSD-3-Clause",

"keywords": [

"framework",

"zf2"

],

"homepage": "http://framework.zend.com/",

"require": {

"php": ">=5.3.3",

"zendframework/zendframework": "2.*"

}

}

34

Installazione

cd ZendSkeletonApplication

php composer.phar install

35

Installazione

cd ZendSkeletonApplication

php composer.phar install

> Installing zendframework/zendframework (dev-master)

Come impostare il progetto?

36

37

Struttura delle Cartelle

38

Struttura delle Cartelle

Configurazione Applicazione

39

Struttura delle Cartelle

Misc (cache, uploads, …)

40

Struttura delle Cartelle

Moduli

41

Struttura delle Cartelle

Moduli

42

Namespace Module.php Modulo

43

Struttura delle Cartelle

Modulo Application

44

Struttura delle Cartelle

Parte pubblica

DOCUMENT ROOT

DOCUMENT ROOT

Come funziona il bootstrap?

48

index.php <?php

/**

* This makes our life easier when dealing with paths. Everything is

* relative to the application root now.

*/

chdir(dirname(__DIR__));

// Setup autoloading

require 'init_autoloader.php';

// Run the application!

Zend\Mvc\Application::init(require 'config/application.config.php')->run();

Configurazione

50

config/application.config.php

config/application.config.php <?php

return array(

'modules' => array(

'Application',

),

[...]

);

Elenco dei moduli attivati

Configurazione

52

Module.config.php <?php [...]

return array(

'router' => array('routes' => array([…]),

),

'service_manager' => array(

'factories' => array(

'translator' => Zend\I18n\Translator\TranslatorServiceFactory',

),),

[...]

'controllers' => array(

'invokables' => array(

'Application\Controller\Index‘=>'Application\Controller\IndexController'

),),

'view_manager' => array(

[...]

),

);

Configurazione

54

Module.php <?php [...]

class Module implements

AutoloaderProviderInterface,

ConfigProviderInterface,

ServiceProviderInterface {

public function getAutoloaderConfig() {[...]}

public function getConfig($env = null) {

return include __DIR__ . '/config/module.config.php';

}

public function getControllerPluginConfig() {[...]}

public function getViewHelperConfig() {[...]}

public function getServiceConfig() {[...]}

}

Configurazione

56

Configurazione

57

BOOTSTRAP

ROUTING

Dall’url al codice return array( […]

'routes'=> array(

[…]

'route' => '/sostituiscilampadina',

'defaults' => array(

'controller' => 'Application\Controller\Elettricista',

'action' => ‘sostlampadina',

)

[…]

),

'controllers' => array(

'invokables' => array(

'App\Controller\Elettricista' => 'App\Controller\ElettricistaController',

),

),

)

Dall’url al codice return array( […]

'routes'=> array(

[…]

'route' => '/sostituiscilampadina',

'defaults' => array(

'controller' => 'Application\Controller\Elettricista',

'action' => ‘sostlampadina',

)

[…]

),

'controllers' => array(

'invokables' => array(

'App\Controller\Elettricista' => 'App\Controller\ElettricistaController',

),

),

)

Dall’url al codice return array( […]

'routes'=> array(

[…]

'route' => '/sostituiscilampadina',

'defaults' => array(

'controller' => 'Application\Controller\Elettricista',

'action' => ‘sostlampadina',

)

[…]

),

'controllers' => array(

'invokables' => array(

'App\Controller\Elettricista' => 'App\Controller\ElettricistaController',

),

),

)

CONVENTION

VS

CONFIGURATION

Come sono fatti i controller?

64

Controller Semplice in ZF2 <?php

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController

{

public function indexAction()

{

$timestamp = time();

return new ViewModel(array(

'timestamp' => $timestamp

));

}

}

Action <?php

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController

{

public function indexAction()

{

$timestamp = time();

return new ViewModel(array(

'timestamp' => $timestamp

));

}

}

Come interagisco con il model?

67

Controller ZF1 […]

class IdraulicoController extends Zend_Controller_Action {

public function installaCaldaia () {

$operatore = new Operatore();

$esito = $operatore->installaCaldaia();

$this->view->esito =$esito;

}

Scendiamo nel dettaglio […]

class IdraulicoController extends Zend_Controller_Action {

public function installaCaldaia () {

$operatore = new Operatore();

$esito = $operatore->installaCaldaia();

$this->view->esito =$esito;

}

Com’è fatto questo oggetto? […]

Class Operatore {

public function __constructor () {

$this->caldaia = new Caldaia();

}

public function getCaldaia() {

return $this->caldaia;

}

public function installaCaldaia() {

// Fai qualcosa con $this->caldaia

}

}

Dipendenza. Siamo vincolati! […]

Class Operatore {

public function __constructor () {

$this->caldaia = new Caldaia();

}

public function getCaldaia() {

return $this->caldaia;

}

public function installaCaldaia() {

// Fai qualcosa con $this->caldaia

}

}

“IL PRINCIPIO DEL GARZONE”

Siamo vincolati […]

Class Operatore {

public function __constructor (Caldaia $caldaia) {

$this->caldaia = $caldaia;

}

public function getCaldaia() {

return $this->caldaia;

}

public function installaCaldaia() {

// Fai qualcosa con $this->caldaia

}

}

Siamo vincolati […]

Class Operatore {

public function __constructor (Caldaia $caldaia) {

$this->caldaia = $caldaia;

}

public function getCaldaia() {

return $this->caldaia;

}

public function installaCaldaia() {

// Fai qualcosa con $this->caldaia

}

}

Test operatore […]

class OperatoreTest extends TestCase {

function testInstallaCaldaia() {

$caldaia = mockCaldaia();

$operatore = new Operatore($caldaia);

$esito = $operatore->installaCaldaia();

$this->assertTrue($esito);

}

}

Da…

76

A…

77

INVERSIONE DI CONTROLLO

Factory operatore […]

class OperatoreFactory {

public static function create ($nome) {

$caldaia = new Caldaia();

$operatore = new Operatore($caldaia);

return $operatore;

}

}

Controller ZF1 […]

class IdraulicoController extends Zend_Controller_Action {

public function installaCaldaia () {

$I_operatore = OperatoreFactory::create();

$esito = $I_operatore->installaCaldaia();

$this->view->esito =$esito;

}

ZF2 - Il Service Manager […]

class IdraulicoController extends AbstractActionController {

public function installaCaldaia () {

$operatore = $this->serviceLocator->get(‘operatore’);

$esito = $I_operatore->installaCaldaia();

return new ViewModel(‘operatore’ => $operatore,

‘esito’ => $esito);

}

Riconsideriamo la configurazione return array(

...

'controllers' => array(

‘factories' => array(

'App\Controller\Idraulico' =>

'App\Controller\IdraulicoControllerFactory',

),),

‘service_manager’ =>

‘factories' => array(

‘operatore' => ‘MVA\Services\OperatoreFactory',

),

‘invokables' => array(

‘caldaia' => ‘MVA\Services\Caldaia',

),

‘aliases' => array(

‘attrezzi.martelloPneumatico' => ‘attrezzi.martello',

),

)

Factories return array(

...

'controllers' => array(

‘factories' => array(

'App\Controller\Idraulico' =>

'App\Controller\IdraulicoControllerFactory',

),),

‘service_manager’ =>

‘factories' => array(

‘operatore' => ‘MVA\Services\OperatoreFactory',

),

‘invokables' => array(

‘caldaia' => ‘MVA\Services\Caldaia',

),

‘aliases' => array(

‘attrezzi.martelloPneumatico' => ‘attrezzi.martello',

),

)

Invokables return array(

...

'controllers' => array(

‘factories' => array(

'App\Controller\Idraulico' =>

'App\Controller\IdraulicoControllerFactory',

),),

‘service_manager’ =>

‘factories' => array(

‘operatore' => ‘MVA\Services\OperatoreFactory',

),

‘invokables' => array(

‘caldaia' => ‘MVA\Services\Caldaia',

),

‘aliases' => array(

‘attrezzi.martelloPneumatico' => ‘attrezzi.martello',

),

)

LAZY REGISTRY, ON STEROIDS

Service Locator

SE FATTO CON REGISTRY

Service Locator

Service Locator

Uso di Alias return array(

...

'controllers' => array(

‘factories' => array(

'App\Controller\Idraulico' =>

'App\Controller\IdraulicoControllerFactory',

),

),

‘service_manager’ =>

‘invokables' => array(

‘attrezzi.martello' => 'App\Services\Martello',

‘attrezzi.martelloPneumatico‘ => 'App\Services\MartelloPneumatico',

),

)

Uso di Alias return array(

...

'controllers' => array(

‘factories' => array(

'App\Controller\Idraulico' =>

'App\Controller\IdraulicoControllerFactory',

),

),

‘service_manager’ =>

[…]

‘invokables' => array(

‘attrezzi.martello' => 'App\Services\Martello',

‘attrezzi.supermartello' => 'App\Services\Martello',

),

‘aliases' => array(

‘attrezzi.martelloPneumatico' => ‘attrezzi.supermartello',

),

)

I diversi service managers

Diagramma service managers

Peering

Uso del Service Locator? […]

class Termostato implements ServiceLocatorAwareInterface {

[…]

public function getTemperatura() {

$sm = $this->getServiceLocator();

$sensore = $sm->get(‘Azienda\Model\TermoSensore');

return $sensore->getTemperatura();

}

public function setServiceLocator(ServiceLocatorInterface

$serviceLocator) {

$this->serviceLocator = $serviceLocator; }

public function getServiceLocator() {

return $this->serviceLocator; }

}

Abuso del Service Locator […]

class Termostato implements ServiceLocatorAwareInterface {

[…]

public function getTemperatura() {

$sm = $this->getServiceLocator();

$sensore = $sm->get(‘Azienda\Model\TermoSensore');

return $sensore->getTemperatura();

}

public function setServiceLocator(ServiceLocatorInterface

$serviceLocator) {

$this->serviceLocator = $serviceLocator; }

public function getServiceLocator() {

return $this->serviceLocator; }

}

ATTENZIONE!

Abuso del Service Locator […]

class Termostato implements ServiceLocatorAwareInterface {

[…]

public function getTemperatura() {

$sm = $this->getServiceLocator();

$sensore = $sm->get(‘Azienda\Model\TermoSensore');

return $sensore->getTemperatura();

}

public function setServiceLocator(ServiceLocatorInterface

$serviceLocator) {

$this->serviceLocator = $serviceLocator; }

public function getServiceLocator() {

return $this->serviceLocator; }

}

Factory per il Controller […]

Class IdraulicoControllerFactory implements

FactoryInterface {

public static function

createService(ServiceLocatorInterface $services) {

$sm = $services->getServiceLocator();

$operatore = $sm->get(‘Operatore');

return new IdraulicoController($operatore);

}

[…]

}

?>

DEPENDENCY INJECTION

http://ocramius.github.com/blog/zend-framework-2-controllers-and-dependency-injection-with-zend-di/

E per le funzioni di supporto?

101

Scambio di messaggi class IdraulicoController {

public function installaCaldaiaAction() {

$operatore = $this->serviceLocator->get(‘operatore’);

$esito = $I_operatore->installaCaldaia();

$I_logger = new Logger();

$I_logger->log(‘Installazione Caldaia’);

return new ViewModel(‘operatore’ => $operatore,

‘esito’ => $esito);

}

}

Mi trovo nel posto giusto? class IdraulicoController {

public function installaCaldaiaAction() {

$operatore = $this->serviceLocator->get(‘operatore’);

$esito = $I_operatore->installaCaldaia();

$I_logger = new Logger();

$I_logger->log(‘Installazione Caldaia’);

return new ViewModel(‘operatore’ => $operatore,

‘esito’ => $esito);

}

}

Messaggio Diretto

CROSS CUTTING CONCERNS

Problema di estendibilità

$s_msg = ‘Installazione Caldaia’;

$I_logger = new Logger();

$I_logger->log($s_msg);

$I_mailer = new Mailer();

$I_mailer->mail($s_msg);

[…]

Event Manager

Class Segretaria {

public function onFinitoIntervento() {

/* Occupati della Fatturazione */

}

}

Event Manager Class IdraulicoFactory {

createService(ServiceLocatorInterface $serviceLocator) {

$idraulico = new Idraulico ();

$idraulico ->setEventManager(

$serviceLocator->get('eventManager')

);

$segretaria = $serviceLocator->get(‘segretaria');

$idraulico->getEventManager()->attach(

‘finitointervento',

array($segretaria, ‘onFinitoIntervento')

);

return $idraulico;

}

}

Event Manager //nella classe che scatena l’evento...

class Idraulico {

public function installaCaldaia () {

/* Codice Installazione Caldaia */

$this->eventManager

->trigger(‘finitointervento‘,

$this,

array(‘azione’ => ‘Tutto OK!’)

);

}

}

Event Manager

OBSERVER

Event Manager

Come interagisco con il DB?

113

ZEND\DB

115

Come uso controller plugin?

116

Esempio con controller plugin <?php

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController

{

public function redirectAction()

{

$this->redirect()->toUrl(‘http://www.zfday.it’);

}

}

Come recupero parametri?

118

Factory per il Controller […]

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController

{

public function scriviNomeAction()

{

$nome = $this->getEvent()

->getRouteMatch()->getParam('slug');

return (‘nome’ => $nome);

}

}

E se ho funzionalità ripetute?

120

init() <?php

class IdraulicoController extends Zend_Controller_Action {

public function init () {

$this->view->azienda = $this->getParam(‘azienda’);

}

}

Ma non ho ancora l’EM! […]

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController

{

public function __construct()

{

$this->azienda = $this->getEvent()

->getRouteMatch()->getParam(‘azienda');

}

}

Sulla Dependency Injection… […]

// Sul costruttore

public function __construct($dipendenza) {

$this->dipendenza = $dipendenza;

}

// Con setters

Public function __construct() {

}

Public function setDipendenza() {

$this->dipendenza = $dipendenza;

}

Agisco sul setter […]

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IdraulicoController extends AbstractActionController

{

public function setEventManager(EventManagerInterface $events) {

parent::setEventManager($events);

$controller = $this;

$events->attach('dispatch', function ($e) use ($controller) {

$this->name = $controller->params()->fromRoute(‘azienda',

‘Sconosciuta');

}

}}

Vedasi anche il post di M. W. O’Phinney: http://www.mwop.net/blog/2012-07-30-the-new-init.html

Come funzionano le viste?

125

Il layer di presentazione

View //view index/index.phtml <div class="row">

<!-- Including header partial -->

<?php echo $this->partial('partials/header.phtml', array()); ?>

<!-- Stampiamo la data -->

<h1>Actual time is: <?php echo $this->timestamp;?></h1>

</div>

View con helper //usando il view helper printData //view index/index.phtml

<div class="row">

<!-- Including header partial -->

<?php echo $this->partial('partials/header.phtml', array()); ?>

<!-- Stampiamo la data -->

<h1>Actual time is:

<?php echo $this->printData($this->timestamp);?>

</h1>

</div>

Helper //Creando un viewHelper per formattare la data // Va registrato tra gli invokables del SM dei ViewHelpers

<?php

namespace Application\View\Helper;

class PrintData extends \Zend\View\Helper\AbstractHelper {

public function __invoke($timestamp) {

$date = new \DateTime();

$date->setTimestamp($timestamp);

$result = $date->format('d-m-Y H:i');

return $result;

}

}

Come funzionano le form?

130

Creando una form //Creiamo il file ContactForm dentro nostro modulo Application/src/Form

<?php

namespace Application\Form;

use Zend\Form\Element;

use Zend\Form\Form;

class ContactForm extends Form

{

public function __construct()

{

parent::__construct();

// …

}

//...

}

Form: aggiungiamo i campi public function init() {

$this->setName('contact');

$this->add(array(

'name' => ‘emailMittente',

'type' => 'Zend\Form\Element\Text',

'options' => array(

'label' => 'From:',

),

)

$this->add(array(

'name' => 'Send',

'type' => 'Zend\Form\Element\Submit',

'attributes' => array(

'value' => 'Send',

),); //...

}

}

La Form

Form

Gli InputFilter

Validation: inputFilter //creiamo l'imput filter contactFilter.php dentro Application/src/Form

<?php

namespace Application\Form;

use Zend\InputFilter\InputFilter;

use Zend\Validator\Hostname as HostnameValidator;

class ContactFilter extends InputFilter

{

public function __construct()

{

//aggiungiamo i filtri

}

}

InputFilter: filter & validation //Esempio filtering(trim) + email validation with custom message

$this->add(array(

'name' => ‘emailMittente',

'required' => true,

'filters' => array(

array('name' => 'StringTrim'),

),

'validators' => array(

array(

'name' => 'EmailAddress',

'options' => array(

'messages' => array(

\Zend\Validator\EmailAddress::INVALID =>

'L\'indirizzo email inserito non è valido.'),

)

)

)

));

Controller: Usando la form namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Application\Form\Contact;

use Application\Form\ContactFilter;

class IndexController extends AbstractActionController

{

public function contactAction()

{

$form = new Contact();

$filter = new ContactFilter();

$form->setInputFilter($filter);

return new ViewModel(array(

'form' => $form

);

}

}

View: Usando la form <?php

$form = $this->form;

$form->setAttribute('action', $this->url('contact'));

$form->prepare();

echo $this->form()->openTag($form); ?>

<dl class="contact_form">

<dt><?php echo $this->formLabel($form->get('from')); ?></dt>

<dd><?php

echo $this->formInput($form->get('from'));

echo $this->formElementErrors($form->get('from'));

?></dd>

<!-- ... -->

</dl>

<?php echo $this->form()->closeTag($form) ?>;

Una form più filtri

Come posso proseguire?

140

Per Approfondire

141

Per Approfondire

142

Sporcati le mani: https://packages.zendframework.com/docs/latest/manual/en/user-guide/overview.html

143

Segui i migliori eventi

144

http://www.phpday.it

In sintesi 1. Maggior enfasi sul riuso. Tenere a mente

che ci sono i Moduli 2. Su ZF2 si segue maggiormente un

approccio orientato alla configurazione piuttosto che convenzione

3. Lo strumento cerca di favorire il disaccoppiamento (EventManager) e l’inversione di controllo (ServiceManager, DI)

145

Grazie per l’attenzione

Stefano Maraspin @maraspin s.maraspin@mvassociati.it

DOMANDE?

Photo Credits • http://www.flickr.com/photos/cclark395/7671665642/ • http://www.flickr.com/photos/thompsonrivers/8072087088/ • http://www.flickr.com/photos/ter-burg/5807937726/ • http://www.flickr.com/photos/cimmyt/7798631622/ • http://www.flickr.com/photos/reckless_sniper/6568298617/ • http://www.flickr.com/photos/fil/144232588/ • http://www.flickr.com/photos/ponchopenguin/3262049873/ • http://www.flickr.com/photos/hugosimmelink/1791812548/ • http://www.flickr.com/photos/calsidyrose/4925267732/ • http://www.flickr.com/photos/29233640@N07/8412347937/ • http://www.flickr.com/photos/stungeye/2774997317/ • http://www.flickr.com/photos/urbanwoodswalker/4375401057/ • http://www.flickr.com/photos/adelaide_archivist/3262863212/ • http://www.flickr.com/photos/syslfrog/172945973/ • http://www.flickr.com/photos/tognum/6279595321/ • http://www.flickr.com/photos/dominichargreaves/2825624738/ • http://www.flickr.com/photos/lstcaress/502606063/ • http://www.flickr.com/photos/a-g/2128462119/ • http://www.flickr.com/photos/see-through-the-eye-of-g/4087838437/

148

Stefano Maraspin @maraspin s.maraspin@mvassociati.it

top related