ݺߣ

ݺߣShare a Scribd company logo
Zend Framework 2
               Fare con



                                           ciò che facevo con ZF1




Zend Framework Day – Milano – 01/02/2013
@maraspin



2
http://www.mvassociati.it/




3
http://friuli.grusp.org/




4
Fare con Zend Framework 2 ciò che facevo con ZF1
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
Com’è strutturata l’azienda?




14
Che in un’applicazione…




15
MVC




16
Flusso MVC




17
Routing




18
Interazione con il modello




19
Il layer di presentazione




20
Risultato all’utente




21
Cosa ci manca?




22
Vorremmo una situazione così




23
Disaccoppiamento




24
I MODULI
Permettono questo




26
27
Come installare ZF2?




28
THE SKELETON APP
Cloning


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




30
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.*"
    }
}
Installazione


 cd ZendSkeletonApplication
 php composer.phar install




34
Installazione


 cd ZendSkeletonApplication
 php composer.phar install
 > Installing zendframework/zendframework (dev-master)




35
Come impostare il progetto?




36
Struttura delle Cartelle




37
Struttura delle Cartelle

                          Configurazione Applicazione




38
Struttura delle Cartelle

                          Misc (cache, uploads, …)




39
Struttura delle Cartelle


                            Moduli




40
Struttura delle Cartelle


                            Moduli




41
Namespace   Module.php   Modulo




42
Struttura delle Cartelle


                          Modulo Application




43
Struttura delle Cartelle


                         Parte pubblica




44
DOCUMENT ROOT
DOCUMENT ROOT
Fare con Zend Framework 2 ciò che facevo con ZF1
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!
ZendMvcApplication::init(require 'config/application.config.php')->run();
Configurazione


             config/
     application.config.php




50
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' => ZendI18nTranslatorTranslatorServiceFactory',
           ),),
      [...]
      'controllers' => array(
           'invokables' => array(
     'ApplicationControllerIndex‘=>'ApplicationControllerIndexController'
           ),),
      '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' => 'ApplicationControllerElettricista',
                        'action'    => ‘sostlampadina',
                    )
              […]
    ),
    'controllers' => array(
         'invokables' => array(
    'AppControllerElettricista' => 'AppControllerElettricistaController',
         ),
     ),
)
Dall’url al codice
return array( […]
    'routes'=> array(
              […]
                    'route' => '/sostituiscilampadina',
                    'defaults' => array(
                        'controller' => 'ApplicationControllerElettricista',
                        'action'    => ‘sostlampadina',
                    )
              […]
    ),
    'controllers' => array(
         'invokables' => array(
    'AppControllerElettricista' => 'AppControllerElettricistaController',
         ),
     ),
)
Dall’url al codice
return array( […]
    'routes'=> array(
              […]
                    'route' => '/sostituiscilampadina',
                    'defaults' => array(
                        'controller' => 'ApplicationControllerElettricista',
                        'action'    => ‘sostlampadina',
                    )
              […]
    ),
    'controllers' => array(
         'invokables' => array(
    'AppControllerElettricista' => 'AppControllerElettricistaController',
         ),
     ),
)
CONVENTION


VS

CONFIGURATION
Come sono fatti i controller?




64
Controller Semplice in ZF2
<?php


namespace ApplicationController;


use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;


class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $timestamp = time();


        return new ViewModel(array(
              'timestamp' => $timestamp
        ));
    }
}
Action
<?php


namespace ApplicationController;


use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;


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 Ҵܰ”
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(
           'AppControllerIdraulico' =>
                         'AppControllerIdraulicoControllerFactory',
       ),),
    ‘service_manager’ =>
       ‘factories' => array(
           ‘operatore' => ‘MVAServicesOperatoreFactory',
       ),
     ‘invokables' => array(
           ‘caldaia' => ‘MVAServicesCaldaia',
       ),
     ‘aliases' => array(
           ‘attrezzi.martelloPneumatico' => ‘attrezzi.martello',
       ),
)
Factories
return array(
     ...
     'controllers' => array(
       ‘factories' => array(
           'AppControllerIdraulico' =>
                         'AppControllerIdraulicoControllerFactory',
       ),),
    ‘service_manager’ =>
       ‘factories' => array(
           ‘operatore' => ‘MVAServicesOperatoreFactory',
       ),
     ‘invokables' => array(
           ‘caldaia' => ‘MVAServicesCaldaia',
       ),
     ‘aliases' => array(
           ‘attrezzi.martelloPneumatico' => ‘attrezzi.martello',
       ),
)
Invokables
return array(
     ...
     'controllers' => array(
       ‘factories' => array(
           'AppControllerIdraulico' =>
                         'AppControllerIdraulicoControllerFactory',
       ),),
    ‘service_manager’ =>
       ‘factories' => array(
           ‘operatore' => ‘MVAServicesOperatoreFactory',
       ),
     ‘invokables' => array(
           ‘caldaia' => ‘MVAServicesCaldaia',
       ),
     ‘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(
           'AppControllerIdraulico' =>
                         'AppControllerIdraulicoControllerFactory',
       ),
),
    ‘service_manager’ =>
       ‘invokables' => array(
       ‘attrezzi.martello' => 'AppServicesMartello',
       ‘attrezzi.martelloPneumatico‘ => 'AppServicesMartelloPneumatico',
       ),
)
Uso di Alias
return array(
     ...
     'controllers' => array(
       ‘factories' => array(
           'AppControllerIdraulico' =>
                         'AppControllerIdraulicoControllerFactory',
       ),
),
    ‘service_manager’ =>
     […]
    ‘invokables' => array(
           ‘attrezzi.martello' => 'AppServicesMartello',
       ‘attrezzi.supermartello' => 'AppServicesMartello',
       ),
     ‘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(‘AziendaModelTermoSensore');
        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(‘AziendaModelTermoSensore');
        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(‘AziendaModelTermoSensore');
        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
ZENDDB
115
Come uso controller plugin?




116
Esempio con controller plugin
<?php


namespace ApplicationController;


use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;


class IndexController extends AbstractActionController
{
    public function redirectAction()
    {
        $this->redirect()->toUrl(‘http://www.zfday.it’);
    }
}
Come recupero parametri?




118
Factory per il Controller
[…]
use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;


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 ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;


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 ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;


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


class PrintData extends ZendViewHelperAbstractHelper   {


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


use ZendFormElement;
use ZendFormForm;


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' => 'ZendFormElementText',
            'options' => array(
                 'label' => 'From:',
            ),
        )
        $this->add(array(
                 'name' => 'Send',
                 'type' => 'ZendFormElementSubmit',
                 'attributes' => array(
                        'value' => 'Send',
                 ),); //...
    }
}
La Form




      Form
Gli InputFilter
Validation: inputFilter
//creiamo l'imput filter contactFilter.php dentro Application/src/Form
<?php
namespace ApplicationForm;


use ZendInputFilterInputFilter;
use ZendValidatorHostname 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(
                                ZendValidatorEmailAddress::INVALID =>
                                'L'indirizzo email inserito non è valido.'),
                       )
                   )
              )
        ));
Controller: Usando la form
namespace ApplicationController;
use ZendMvcControllerAbstractActionController;
use ApplicationFormContact;
use ApplicationFormContactFilter;
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




                   http://www.phpday.it




144
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

More Related Content

Fare con Zend Framework 2 ciò che facevo con ZF1

  • 1. Zend Framework 2 Fare con ciò che facevo con ZF1 Zend Framework Day – Milano – 01/02/2013
  • 6. 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>'; ?>
  • 9. 9
  • 19. Interazione con il modello 19
  • 20. Il layer di presentazione 20
  • 27. 27
  • 30. Cloning git clone git://github.com/zendframework/ZendSkeletonApplication.git 30
  • 31. 31
  • 32. 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.*" } }
  • 33. 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 34
  • 35. Installazione cd ZendSkeletonApplication php composer.phar install > Installing zendframework/zendframework (dev-master) 35
  • 36. Come impostare il progetto? 36
  • 38. Struttura delle Cartelle Configurazione Applicazione 38
  • 39. Struttura delle Cartelle Misc (cache, uploads, …) 39
  • 42. Namespace Module.php Modulo 42
  • 43. Struttura delle Cartelle Modulo Application 43
  • 44. Struttura delle Cartelle Parte pubblica 44
  • 48. Come funziona il bootstrap? 48
  • 49. 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! ZendMvcApplication::init(require 'config/application.config.php')->run();
  • 50. Configurazione config/ application.config.php 50
  • 51. config/application.config.php <?php return array( 'modules' => array( 'Application', ), [...] ); Elenco dei moduli attivati
  • 53. Module.config.php <?php [...] return array( 'router' => array('routes' => array([…]), ), 'service_manager' => array( 'factories' => array( 'translator' => ZendI18nTranslatorTranslatorServiceFactory', ),), [...] 'controllers' => array( 'invokables' => array( 'ApplicationControllerIndex‘=>'ApplicationControllerIndexController' ),), 'view_manager' => array( [...] ), );
  • 55. 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() {[...]} }
  • 60. Dall’url al codice return array( […] 'routes'=> array( […] 'route' => '/sostituiscilampadina', 'defaults' => array( 'controller' => 'ApplicationControllerElettricista', 'action' => ‘sostlampadina', ) […] ), 'controllers' => array( 'invokables' => array( 'AppControllerElettricista' => 'AppControllerElettricistaController', ), ), )
  • 61. Dall’url al codice return array( […] 'routes'=> array( […] 'route' => '/sostituiscilampadina', 'defaults' => array( 'controller' => 'ApplicationControllerElettricista', 'action' => ‘sostlampadina', ) […] ), 'controllers' => array( 'invokables' => array( 'AppControllerElettricista' => 'AppControllerElettricistaController', ), ), )
  • 62. Dall’url al codice return array( […] 'routes'=> array( […] 'route' => '/sostituiscilampadina', 'defaults' => array( 'controller' => 'ApplicationControllerElettricista', 'action' => ‘sostlampadina', ) […] ), 'controllers' => array( 'invokables' => array( 'AppControllerElettricista' => 'AppControllerElettricistaController', ), ), )
  • 64. Come sono fatti i controller? 64
  • 65. Controller Semplice in ZF2 <?php namespace ApplicationController; use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class IndexController extends AbstractActionController { public function indexAction() { $timestamp = time(); return new ViewModel(array( 'timestamp' => $timestamp )); } }
  • 66. Action <?php namespace ApplicationController; use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class IndexController extends AbstractActionController { public function indexAction() { $timestamp = time(); return new ViewModel(array( 'timestamp' => $timestamp )); } }
  • 67. Come interagisco con il model? 67
  • 68. Controller ZF1 […] class IdraulicoController extends Zend_Controller_Action { public function installaCaldaia () { $operatore = new Operatore(); $esito = $operatore->installaCaldaia(); $this->view->esito =$esito; }
  • 69. Scendiamo nel dettaglio […] class IdraulicoController extends Zend_Controller_Action { public function installaCaldaia () { $operatore = new Operatore(); $esito = $operatore->installaCaldaia(); $this->view->esito =$esito; }
  • 70. 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 } }
  • 71. 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 } }
  • 73. 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 } }
  • 74. 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 } }
  • 75. Test operatore […] class OperatoreTest extends TestCase { function testInstallaCaldaia() { $caldaia = mockCaldaia(); $operatore = new Operatore($caldaia); $esito = $operatore->installaCaldaia(); $this->assertTrue($esito); } }
  • 79. Factory operatore […] class OperatoreFactory { public static function create ($nome) { $caldaia = new Caldaia(); $operatore = new Operatore($caldaia); return $operatore; } }
  • 80. Controller ZF1 […] class IdraulicoController extends Zend_Controller_Action { public function installaCaldaia () { $I_operatore = OperatoreFactory::create(); $esito = $I_operatore->installaCaldaia(); $this->view->esito =$esito; }
  • 81. 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); }
  • 82. Riconsideriamo la configurazione return array( ... 'controllers' => array( ‘factories' => array( 'AppControllerIdraulico' => 'AppControllerIdraulicoControllerFactory', ),), ‘service_manager’ => ‘factories' => array( ‘operatore' => ‘MVAServicesOperatoreFactory', ), ‘invokables' => array( ‘caldaia' => ‘MVAServicesCaldaia', ), ‘aliases' => array( ‘attrezzi.martelloPneumatico' => ‘attrezzi.martello', ), )
  • 83. Factories return array( ... 'controllers' => array( ‘factories' => array( 'AppControllerIdraulico' => 'AppControllerIdraulicoControllerFactory', ),), ‘service_manager’ => ‘factories' => array( ‘operatore' => ‘MVAServicesOperatoreFactory', ), ‘invokables' => array( ‘caldaia' => ‘MVAServicesCaldaia', ), ‘aliases' => array( ‘attrezzi.martelloPneumatico' => ‘attrezzi.martello', ), )
  • 84. Invokables return array( ... 'controllers' => array( ‘factories' => array( 'AppControllerIdraulico' => 'AppControllerIdraulicoControllerFactory', ),), ‘service_manager’ => ‘factories' => array( ‘operatore' => ‘MVAServicesOperatoreFactory', ), ‘invokables' => array( ‘caldaia' => ‘MVAServicesCaldaia', ), ‘aliases' => array( ‘attrezzi.martelloPneumatico' => ‘attrezzi.martello', ), )
  • 85. LAZY REGISTRY, ON STEROIDS
  • 87. SE FATTO CON REGISTRY
  • 90. Uso di Alias return array( ... 'controllers' => array( ‘factories' => array( 'AppControllerIdraulico' => 'AppControllerIdraulicoControllerFactory', ), ), ‘service_manager’ => ‘invokables' => array( ‘attrezzi.martello' => 'AppServicesMartello', ‘attrezzi.martelloPneumatico‘ => 'AppServicesMartelloPneumatico', ), )
  • 91. Uso di Alias return array( ... 'controllers' => array( ‘factories' => array( 'AppControllerIdraulico' => 'AppControllerIdraulicoControllerFactory', ), ), ‘service_manager’ => […] ‘invokables' => array( ‘attrezzi.martello' => 'AppServicesMartello', ‘attrezzi.supermartello' => 'AppServicesMartello', ), ‘aliases' => array( ‘attrezzi.martelloPneumatico' => ‘attrezzi.supermartello', ), )
  • 92. I diversi service managers
  • 95. Uso del Service Locator? […] class Termostato implements ServiceLocatorAwareInterface { […] public function getTemperatura() { $sm = $this->getServiceLocator(); $sensore = $sm->get(‘AziendaModelTermoSensore'); return $sensore->getTemperatura(); } public function setServiceLocator(ServiceLocatorInterface $serviceLocator) { $this->serviceLocator = $serviceLocator; } public function getServiceLocator() { return $this->serviceLocator; } }
  • 96. Abuso del Service Locator […] class Termostato implements ServiceLocatorAwareInterface { […] public function getTemperatura() { $sm = $this->getServiceLocator(); $sensore = $sm->get(‘AziendaModelTermoSensore'); return $sensore->getTemperatura(); } public function setServiceLocator(ServiceLocatorInterface $serviceLocator) { $this->serviceLocator = $serviceLocator; } public function getServiceLocator() { return $this->serviceLocator; } }
  • 98. Abuso del Service Locator […] class Termostato implements ServiceLocatorAwareInterface { […] public function getTemperatura() { $sm = $this->getServiceLocator(); $sensore = $sm->get(‘AziendaModelTermoSensore'); return $sensore->getTemperatura(); } public function setServiceLocator(ServiceLocatorInterface $serviceLocator) { $this->serviceLocator = $serviceLocator; } public function getServiceLocator() { return $this->serviceLocator; } }
  • 99. 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); } […] } ?>
  • 101. E per le funzioni di supporto? 101
  • 102. 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); } }
  • 103. 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); } }
  • 106. 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); […]
  • 107. Event Manager Class Segretaria { public function onFinitoIntervento() { /* Occupati della Fatturazione */ } }
  • 108. 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; } }
  • 109. 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!’) ); } }
  • 113. Come interagisco con il DB? 113
  • 114. ZENDDB
  • 115. 115
  • 116. Come uso controller plugin? 116
  • 117. Esempio con controller plugin <?php namespace ApplicationController; use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class IndexController extends AbstractActionController { public function redirectAction() { $this->redirect()->toUrl(‘http://www.zfday.it’); } }
  • 119. Factory per il Controller […] use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class IndexController extends AbstractActionController { public function scriviNomeAction() { $nome = $this->getEvent() ->getRouteMatch()->getParam('slug'); return (‘nome’ => $nome); } }
  • 120. E se ho funzionalità ripetute? 120
  • 121. init() <?php class IdraulicoController extends Zend_Controller_Action { public function init () { $this->view->azienda = $this->getParam(‘azienda’); } }
  • 122. Ma non ho ancora l’EM! […] use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class IndexController extends AbstractActionController { public function __construct() { $this->azienda = $this->getEvent() ->getRouteMatch()->getParam(‘azienda'); } }
  • 123. Sulla Dependency Injection… […] // Sul costruttore public function __construct($dipendenza) { $this->dipendenza = $dipendenza; } // Con setters Public function __construct() { } Public function setDipendenza() { $this->dipendenza = $dipendenza; }
  • 124. Agisco sul setter […] use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; 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
  • 125. Come funzionano le viste? 125
  • 126. Il layer di presentazione
  • 127. 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>
  • 128. 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>
  • 129. Helper //Creando un viewHelper per formattare la data // Va registrato tra gli invokables del SM dei ViewHelpers <?php namespace ApplicationViewHelper; class PrintData extends ZendViewHelperAbstractHelper { public function __invoke($timestamp) { $date = new DateTime(); $date->setTimestamp($timestamp); $result = $date->format('d-m-Y H:i'); return $result; } }
  • 130. Come funzionano le form? 130
  • 131. Creando una form //Creiamo il file ContactForm dentro nostro modulo Application/src/Form <?php namespace ApplicationForm; use ZendFormElement; use ZendFormForm; class ContactForm extends Form { public function __construct() { parent::__construct(); // … } //... }
  • 132. Form: aggiungiamo i campi public function init() { $this->setName('contact'); $this->add(array( 'name' => ‘emailMittente', 'type' => 'ZendFormElementText', 'options' => array( 'label' => 'From:', ), ) $this->add(array( 'name' => 'Send', 'type' => 'ZendFormElementSubmit', 'attributes' => array( 'value' => 'Send', ),); //... } }
  • 133. La Form Form
  • 135. Validation: inputFilter //creiamo l'imput filter contactFilter.php dentro Application/src/Form <?php namespace ApplicationForm; use ZendInputFilterInputFilter; use ZendValidatorHostname as HostnameValidator; class ContactFilter extends InputFilter { public function __construct() { //aggiungiamo i filtri } }
  • 136. 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( ZendValidatorEmailAddress::INVALID => 'L'indirizzo email inserito non è valido.'), ) ) ) ));
  • 137. Controller: Usando la form namespace ApplicationController; use ZendMvcControllerAbstractActionController; use ApplicationFormContact; use ApplicationFormContactFilter; class IndexController extends AbstractActionController { public function contactAction() { $form = new Contact(); $filter = new ContactFilter(); $form->setInputFilter($filter); return new ViewModel(array( 'form' => $form ); } }
  • 138. 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) ?>;
  • 139. Una form più filtri
  • 143. Sporcati le mani: https://packages.zendframework.com/docs/latest/manual/en/user-guide/overview.html 143
  • 144. Segui i migliori eventi http://www.phpday.it 144
  • 145. 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
  • 146. Grazie per l’attenzione Stefano Maraspin @maraspin s.maraspin@mvassociati.it
  • 148. 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