SlideShare uma empresa Scribd logo
1 de 73
Symfony2, creare bundle e valore
         per il cliente

          Leonardo Proietti
              @_leopro_




             Symfony day
        Torino, 5 ottobre 2012
valore per il cliente = benefici / costi
collaborazione
collaborazione
responsabilità
collaborazione
     responsabilità
reciproca soddisfazione
Il processo di sviluppo basato sulla
collaborazione, sulla reciproca soddisfazione e
sul senso di responsabilità permette di ottenere
           un alto valore per il cliente.
bundle = è una cartella con una struttura ben
definita, che può ospitare qualsiasi cosa, dalle
     classi ai controllori e alle risorse web

http://symfony.com/it/doc/current/cookbook/bundles/best_practices.html
bundle = uno spazio dei nomi di PHP ovvero un
   namespace, con con una classe Bundle

 http://symfony.com/it/doc/current/cookbook/bundles/best_practices.html
bundle = una libreria sufficientemente astratta
da essere utilizzata in contesti diversi tra loro
la realizzazione di un bundle non è valore
               per il cliente
Richiesta
un sito web con contenuti aggiornabili
      disponibili in diverse lingue
Analisi
gli strumenti esistenti sono valutati come non
                     adatti
Idea
relazione uno-a-molti, DIC, eventi
Sarà una libreria riutilizzabile?
Sarà una libreria riutilizzabile?
Non è importante perchè l'obiettivo principale è
         produrre valore per il cliente
Ma non vogliamo spaghetti code
Test Driven Development
ovvero sviluppare guidati dai test
Test Driven Development
ovvero sviluppi meglio, vivi meglio
$article->getTitle();

     /it/{article}
  “Il mio articolo”
   /en/{article}
    “My article”
Acme
  CoreBundle
  Listener
  LocaleListener.php
  EntityListener.php
  AnotherListener.php
  Locale
  Locale.php
  LocaleInterface.php
  Model
  Translatable.php
  TranslatableInterface.php
  TranslatingInterface.php
  AnotherModelUtil.php
  Tests
  ...
Acme
  CoreBundle
  Listener
  LocaleListener.php
  EntityListener.php
  AnotherListener.php
  Locale
  Locale.php
  LocaleInterface.php
  Model
  Translatable.php
  TranslatableInterface.php
  TranslatingInterface.php
  AnotherModelUtil.php
  Tests
  ...
interface LocaleInterface
{
   function setLocale($locale);

    function getLocale();

    function getDefaultLocale();
}
use AcmeCoreBundleModelTranslatingInterface;
use AcmeCoreBundleLocaleLocaleInterface;

interface TranslatableInterface
{
   function addTranslation(TranslatingInterface $translation);

    function getTranslations();

    function setLocale(LocaleInterface $locale);
}
use AcmeCoreBundleModelTranslatableInterface;

interface TranslatingInterface
{
    function setTranslatable(TranslatableInterface $translatable);

    function getLocale();

    function setLocale($string);
}
class Article
{
   /**
   * @ORMOneToMany
   * (targetEntity="ArticleI18n", mappedBy="translatable")
   */
   protected $translations;

    public function getTitle()
    {
       return $this->getTranslation()->getTitle();
    }
}
class Article
{
   /**
   * @ORMOneToMany
   * (targetEntity="ArticleI18n", mappedBy="translatable")
   */
   protected $translations;

    public function getTitle()
    {
       return $this->getTranslation()->getTitle();
    }
}
class ArticleI18n
{
   /**
   * @ORMManyToOne(targetEntity="Article", inversedBy="translations"
   * @ORMJoinColumn(name="article_id", referencedColumnName="id")
   */
    protected $translatable;

    /**
     * @ORMColumn(type="string", length=128)
     */
     private $title;

    public function getTitle()
    {
      return $this->title;
    }
}
Symfony2
kernel.request
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
public function testOnKernelRequest()
{
  //SymfonyComponentHttpKernelEventGetResponseEvent
  $this->event->expects($this->once()
  ->method('getRequest')
          ->will($this->returnValue($this->request));


    //SymfonyComponentHttpFoundationRequest
    $this->request->expects($this->once())
           ->method('getLocale')
           ->will($this->returnValue('en'));


    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale->expects($this->once())
       ->method('setLocale')
        ->with('en');

    //AcmeCoreBundleListenerLocaleListener
    $this->listener = new LocaleListener($this->locale);
    $this->listener->onKernelRequest($this->event);
}
Doctrine2
postLoad
public function testPostLoad()
{
    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale;


    //DoctrineORMEventLifecycleEventArgs
    $this->args->expects($this->once())
           ->method('getEntity')
           ->will($this->returnValue($this->entity));


    //AcmeCoreBundleModelTranslatableInterface
    $this->entity->expects($this->once())
            ->method('setLocale')
            ->with($this->locale);

    //AcmeCoreBundleListenerEntityListener
    $this->listener = new TranslatableListener($this->locale);
    $this->listener->postLoad($this->event);
}
public function testPostLoad()
{
    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale;


    //DoctrineORMEventLifecycleEventArgs
    $this->args->expects($this->once())
           ->method('getEntity')
           ->will($this->returnValue($this->entity));


    //AcmeCoreBundleModelTranslatableInterface
    $this->entity->expects($this->once())
            ->method('setLocale')
            ->with($this->locale);

    //AcmeCoreBundleListenerEntityListener
    $this->listener = new TranslatableListener($this->locale);
    $this->listener->postLoad($this->event);
}
public function testPostLoad()
{
    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale;


    //DoctrineORMEventLifecycleEventArgs
    $this->args->expects($this->once())
           ->method('getEntity')
           ->will($this->returnValue($this->entity));


    //AcmeCoreBundleModelTranslatableInterface
    $this->entity->expects($this->once())
            ->method('setLocale')
            ->with($this->locale);

    //AcmeCoreBundleListenerEntityListener
    $this->listener = new TranslatableListener($this->locale);
    $this->listener->postLoad($this->event);
}
public function testPostLoad()
{
    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale;


    //DoctrineORMEventLifecycleEventArgs
    $this->args->expects($this->once())
           ->method('getEntity')
           ->will($this->returnValue($this->entity));


    //AcmeCoreBundleModelTranslatableInterface
    $this->entity->expects($this->once())
            ->method('setLocale')
            ->with($this->locale);

    //AcmeCoreBundleListenerEntityListener
    $this->listener = new TranslatableListener($this->locale);
    $this->listener->postLoad($this->event);
}
public function testPostLoad()
{
    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale;


    //DoctrineORMEventLifecycleEventArgs
    $this->args->expects($this->once())
           ->method('getEntity')
           ->will($this->returnValue($this->entity));


    //AcmeCoreBundleModelTranslatableInterface
    $this->entity->expects($this->once())
            ->method('setLocale')
            ->with($this->locale);

    //AcmeCoreBundleListenerEntityListener
    $this->listener = new TranslatableListener($this->locale);
    $this->listener->postLoad($this->event);
}
public function testPostLoad()
{
    //AcmeCoreBundleLocaleLocaleInterface
    $this->locale;


    //DoctrineORMEventLifecycleEventArgs
    $this->args->expects($this->once())
           ->method('getEntity')
           ->will($this->returnValue($this->entity));


    //AcmeCoreBundleModelTranslatableInterface
    $this->entity->expects($this->once())
            ->method('setLocale')
            ->with($this->locale);

    //AcmeCoreBundleListenerEntityListener
    $this->listener = new TranslatableListener($this->locale);
    $this->listener->postLoad($this->event);
}
//tranlsations, defaultLocale, locale, tranlsationExpected
public function getTranslationProvider()
{
     return array(
     array(
     array('it' => 'translationIt', 'en' => 'translationEn'),
     'en',
     'en',
     'translationEn'),
     array(
     array('en' => 'translationEn', 'it' => 'translationIt'),
     'en',
     'it',
     'translationIt'),
     array(
     array('en' => 'translationEn'),
     'en',
     'it',
     'translationEn'),
     )
}
//tranlsations, defaultLocale, locale, tranlsationExpected
public function getTranslationProvider()
{
     return array(
     array(
     array('it' => 'translationIt', 'en' => 'translationEn'),
     'en',
     'en',
     'translationEn'),
     array(
     array('en' => 'translationEn', 'it' => 'translationIt'),
     'en',
     'it',
     'translationIt'),
     array(
     array('en' => 'translationEn'),
     'en',
     'it',
     'translationEn'),
     )
}
//tranlsations, defaultLocale, locale, tranlsationExpected
public function getTranslationProvider()
{
     return array(
     array(
     array('it' => 'translationIt', 'en' => 'translationEn'),
     'en',
     'en',
     'translationEn'),
     array(
     array('en' => 'translationEn', 'it' => 'translationIt'),
     'en',
     'it',
     'translationIt'),
     array(
     array('en' => 'translationEn'),
     'en',
     'it',
     'translationEn'),
     )
}
//tranlsations, defaultLocale, locale, tranlsationExpected
public function getTranslationProvider()
{
     return array(
     array(
     array('it' => 'translationIt', 'en' => 'translationEn'),
     'en',
     'en',
     'translationEn'),
     array(
     array('en' => 'translationEn', 'it' => 'translationIt'),
     'en',
     'it',
     'translationIt'),
     array(
     array('en' => 'translationEn'),
     'en',
     'it',
     'translationEn'),
     )
}
public function testGetTranslation($translations, $defaultLocale, $locale,
$translationExpected)
{
     $this->translatable = new Translatable();
     $this->translatable->setLocale($this->locale);

     foreach ($translations as $language => $translation) {
          $this->$translation->expects($this->exactly(2))->method('getLocale')
               ->will($this->returnValue($language));
          $this->translatable->addTranslation($this->$translation);
     }

     $this->locale->expects($this->exactly(1))
           ->method('getDefaultLocale')
           ->will($this->returnValue($defaultLocale));

     $this->locale->expects($this->exactly(1))
           ->method('getLocale')
           ->will($this->returnValue($locale));



     $result = $this->translatable->getTranslation();
     $this->assertEquals($this->$translationExpected, $result);
}
public function testGetTranslation($translations, $defaultLocale, $locale,
$translationExpected)
{
     $this->translatable = new Translatable();
     $this->translatable->setLocale($this->locale);

     foreach ($translations as $language => $translation) {
          $this->$translation->expects($this->exactly(2))->method('getLocale')
               ->will($this->returnValue($language));
          $this->translatable->addTranslation($this->$translation);
     }

     $this->locale->expects($this->exactly(1))
           ->method('getDefaultLocale')
           ->will($this->returnValue($defaultLocale));

     $this->locale->expects($this->exactly(1))
           ->method('getLocale')
           ->will($this->returnValue($locale));



     $result = $this->translatable->getTranslation();
     $this->assertEquals($this->$translationExpected, $result);
}
Non resta che soddisfare i test scrivendo del
           codice funzionante :-)
configuriamo i servizi
//src/Acme/CoreBundle/Resources/config/services.yml

services:
 acme_core.locale:
     class:   AcmeCoreBundleServiceLocale
     arguments: [%locale%]
 acme_core.listener.locale:
     class:   AcmeCoreBundleServiceLocaleListener
     arguments: ["@acme.core.locale"]
     tags:
       - { name: kernel.event_listener, event: kernel.request }
 acme_core.listener.entity:
     class:   AcmeCoreBundleServiceEntityListener
     arguments: ["@acme.core.locale"]
     tags:
       - { name: doctrine.event_listener, event: postLoad }
configuriamo i servizi
//src/Acme/CoreBundle/Resources/config/services.yml

services:
 acme_core.locale:
     class:   AcmeCoreBundleServiceLocale
     arguments: [%locale%]
 acme_core.listener.locale:
     class:   AcmeCoreBundleServiceLocaleListener
     arguments: ["@acme.core.locale"]
     tags:
       - { name: kernel.event_listener, event: kernel.request }
 acme_core.listener.entity:
     class:   AcmeCoreBundleServiceEntityListener
     arguments: ["@acme.core.locale"]
     tags:
       - { name: doctrine.event_listener, event: postLoad }
class Article extends Translatable
{
   /**
   * @ORMOneToMany
   * (targetEntity="ArticleI18n", mappedBy="translatable")
   */
   protected $translations;

    public function getTitle()
    {
       return $this->getTranslation()->getTitle();
    }
}
Una volta testata anche l'integrazione e
  verificato che la richiesta del cliente è stata
soddisfatta, abbiamo prodotto il valore richiesto
             e ci possiamo fermare.
Nuovo cliente, stessa richiesta
Prendiamo il codice e lo isoliamo
       PUGX/I18nBundle
AcmePlus
PUGX
  I18nBundle
  Listener
  LocaleListener.php
  EntityListener.php
  Locale
  Locale.php
  LocaleInterface.php
  Model
  Translatable.php
  TranslatableInterface.php
  TranslatingInterface.php
  Tests
Il grosso è fatto, ora dovremo:

- esporre una configurazione semantica

- gestire le dipendenze (composer) e la configurazione dei test

- aggiungere la documentazione, la licenza ecc.
AcmePlus
PUGX
  I18nBundle
  DependencyInjection
  Configuration.php
  PUGXI18nExtension.php
  […]
  Tests
  bootstrap.php
  PUGXI18nBundle.php
  composer.json
  phpunit.xml.dist
namespace PUGXI18nBundle;

use SymfonyComponentHttpKernelBundleBundle;
use PUGXI18nBundleDependencyInjectionPUGXI18nExtension;

class PUGXI18nBundle extends Bundle
{
    public function getContainerExtension()
    {
      return new PUGXI18nExtension();
    }
}
namespace PUGXI18nBundleDependencyInjection;

use SymfonyComponentConfigDefinitionBuilderTreeBuilder;
use SymfonyComponentConfigDefinitionConfigurationInterface;

class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
      $treeBuilder = new TreeBuilder();
      $rootNode = $treeBuilder->root('pugx_i18n');

        return $treeBuilder;
    }
}
namespace PUGXI18nBundleDependencyInjection;

use SymfonyComponentDependencyInjectionContainerBuilder;
use SymfonyComponentConfigFileLocator;
use SymfonyComponentHttpKernelDependencyInjectionExtension;
use SymfonyComponentDependencyInjectionLoaderYamlFileLoader;

class PUGXI18nExtension implements Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
      $configuration = new Configuration();
      $config = $this->processConfiguration($configuration, $configs);
      $path = __DIR__.'/../Resources/config'
      $loader = new YamlFileLoader($container, new FileLocator($path));
      $loader->load('services.yml');
    }

    public function getAlias()
    {
      return 'pugx_i18n';
    }
}
Composer
gestisce le dipendenze
//src/PUGX/I18nBundle/composer.json

{
    "name": "pugx/i18n-bundle",
    "type": "symfony-bundle",
    "description": "Manage i18n",
    "keywords": ["symfony2, i18n, translation"],
    "license": "MIT",
    "authors": [
    {
    "name":"Leonardo Proietti",
    "email":"leonardo.proietti@gmail.com"
    }
    ],
    "minimum-stability": "dev",
    "require": {
    "php": ">=5.3.2",
    "symfony/framework-bundle": "2.1.*",
    "doctrine/orm": ">=2.2.3,<2.4-dev",
    "symfony/yaml": "2.1.*"
    },
    "autoload": {
    "psr-0": { "PUGXI18nBundle": "" }
     },
     "target-dir": "PUGX/I18nBundle"
//src/PUGX/I18nBundle/Tests/bootstrap.php

if (!is_file($autoloadFile = __DIR__.'/../vendor/autoload.php')) {
      throw new LogicException('Could not find autoload.php');
}

require $autoloadFile;
//src/PUGX/I18nBundle/phpunit.xml.dist

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./Tests/bootstrap.php">
   <testsuites>
       <testsuite name="PUGXI18nBundle test suite">
           <directory suffix="Test.php">./Tests</directory>
       </testsuite>
   </testsuites>

    <filter>
          <whitelist>
              <directory>./</directory>
              <exclude>
                   <directory>./Resources</directory>
                   <directory>./Tests</directory>
              </exclude>
          </whitelist>
    </filter>
</phpunit>
Servizio rivolto alla comunità open source per
la continuos integration di progetti pubblicati su
                       github

                 https://travis-ci.org/
//src/PUGX/I18nBundle/.travis.yml

language: php

php:
   - 5.3
   - 5.4

before_script:
    - curl -s http://getcomposer.org/installer | php
    - php composer.phar install –dev
Ora basta creare un repository su github e
avremo dato il nostro piccolo contributo alla
         comunità open source.
Credits


symfony.com/it/doc/2.0/book/internals.html

symfony.com/it/doc/2.0/cookbook/bundles/best_practices.html

symfony.com/it/doc/2.0/cookbook/bundles/extension.html

sviluppoagile.it

PUG Roma
GRAZIE :-)

Mais conteúdo relacionado

Mais procurados

Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
Fabien Potencier
 

Mais procurados (20)

Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony application
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
 
Rich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 Application
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 

Semelhante a Symfony2, creare bundle e valore per il cliente

Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)
Fabien Potencier
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
Fabien Potencier
 

Semelhante a Symfony2, creare bundle e valore per il cliente (20)

Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Filesystem abstractions and msg queue sergeev - symfony camp 2018
Filesystem abstractions and msg queue   sergeev - symfony camp 2018Filesystem abstractions and msg queue   sergeev - symfony camp 2018
Filesystem abstractions and msg queue sergeev - symfony camp 2018
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Oops in php
Oops in phpOops in php
Oops in php
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Event Sourcing with php
Event Sourcing with phpEvent Sourcing with php
Event Sourcing with php
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 

Último

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Último (20)

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

Symfony2, creare bundle e valore per il cliente

  • 1. Symfony2, creare bundle e valore per il cliente Leonardo Proietti @_leopro_ Symfony day Torino, 5 ottobre 2012
  • 2.
  • 3. valore per il cliente = benefici / costi
  • 6. collaborazione responsabilità reciproca soddisfazione
  • 7. Il processo di sviluppo basato sulla collaborazione, sulla reciproca soddisfazione e sul senso di responsabilità permette di ottenere un alto valore per il cliente.
  • 8. bundle = è una cartella con una struttura ben definita, che può ospitare qualsiasi cosa, dalle classi ai controllori e alle risorse web http://symfony.com/it/doc/current/cookbook/bundles/best_practices.html
  • 9. bundle = uno spazio dei nomi di PHP ovvero un namespace, con con una classe Bundle http://symfony.com/it/doc/current/cookbook/bundles/best_practices.html
  • 10. bundle = una libreria sufficientemente astratta da essere utilizzata in contesti diversi tra loro
  • 11. la realizzazione di un bundle non è valore per il cliente
  • 12. Richiesta un sito web con contenuti aggiornabili disponibili in diverse lingue
  • 13. Analisi gli strumenti esistenti sono valutati come non adatti
  • 15. Sarà una libreria riutilizzabile?
  • 16. Sarà una libreria riutilizzabile? Non è importante perchè l'obiettivo principale è produrre valore per il cliente
  • 17. Ma non vogliamo spaghetti code
  • 18. Test Driven Development ovvero sviluppare guidati dai test
  • 19. Test Driven Development ovvero sviluppi meglio, vivi meglio
  • 20. $article->getTitle(); /it/{article} “Il mio articolo” /en/{article} “My article”
  • 21. Acme CoreBundle Listener LocaleListener.php EntityListener.php AnotherListener.php Locale Locale.php LocaleInterface.php Model Translatable.php TranslatableInterface.php TranslatingInterface.php AnotherModelUtil.php Tests ...
  • 22. Acme CoreBundle Listener LocaleListener.php EntityListener.php AnotherListener.php Locale Locale.php LocaleInterface.php Model Translatable.php TranslatableInterface.php TranslatingInterface.php AnotherModelUtil.php Tests ...
  • 23. interface LocaleInterface { function setLocale($locale); function getLocale(); function getDefaultLocale(); }
  • 24. use AcmeCoreBundleModelTranslatingInterface; use AcmeCoreBundleLocaleLocaleInterface; interface TranslatableInterface { function addTranslation(TranslatingInterface $translation); function getTranslations(); function setLocale(LocaleInterface $locale); }
  • 25. use AcmeCoreBundleModelTranslatableInterface; interface TranslatingInterface { function setTranslatable(TranslatableInterface $translatable); function getLocale(); function setLocale($string); }
  • 26. class Article { /** * @ORMOneToMany * (targetEntity="ArticleI18n", mappedBy="translatable") */ protected $translations; public function getTitle() { return $this->getTranslation()->getTitle(); } }
  • 27. class Article { /** * @ORMOneToMany * (targetEntity="ArticleI18n", mappedBy="translatable") */ protected $translations; public function getTitle() { return $this->getTranslation()->getTitle(); } }
  • 28. class ArticleI18n { /** * @ORMManyToOne(targetEntity="Article", inversedBy="translations" * @ORMJoinColumn(name="article_id", referencedColumnName="id") */ protected $translatable; /** * @ORMColumn(type="string", length=128) */ private $title; public function getTitle() { return $this->title; } }
  • 30. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 31. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 32. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 33. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 34. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 35. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 36. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 37. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 38. public function testOnKernelRequest() { //SymfonyComponentHttpKernelEventGetResponseEvent $this->event->expects($this->once() ->method('getRequest') ->will($this->returnValue($this->request)); //SymfonyComponentHttpFoundationRequest $this->request->expects($this->once()) ->method('getLocale') ->will($this->returnValue('en')); //AcmeCoreBundleLocaleLocaleInterface $this->locale->expects($this->once()) ->method('setLocale') ->with('en'); //AcmeCoreBundleListenerLocaleListener $this->listener = new LocaleListener($this->locale); $this->listener->onKernelRequest($this->event); }
  • 40. public function testPostLoad() { //AcmeCoreBundleLocaleLocaleInterface $this->locale; //DoctrineORMEventLifecycleEventArgs $this->args->expects($this->once()) ->method('getEntity') ->will($this->returnValue($this->entity)); //AcmeCoreBundleModelTranslatableInterface $this->entity->expects($this->once()) ->method('setLocale') ->with($this->locale); //AcmeCoreBundleListenerEntityListener $this->listener = new TranslatableListener($this->locale); $this->listener->postLoad($this->event); }
  • 41. public function testPostLoad() { //AcmeCoreBundleLocaleLocaleInterface $this->locale; //DoctrineORMEventLifecycleEventArgs $this->args->expects($this->once()) ->method('getEntity') ->will($this->returnValue($this->entity)); //AcmeCoreBundleModelTranslatableInterface $this->entity->expects($this->once()) ->method('setLocale') ->with($this->locale); //AcmeCoreBundleListenerEntityListener $this->listener = new TranslatableListener($this->locale); $this->listener->postLoad($this->event); }
  • 42. public function testPostLoad() { //AcmeCoreBundleLocaleLocaleInterface $this->locale; //DoctrineORMEventLifecycleEventArgs $this->args->expects($this->once()) ->method('getEntity') ->will($this->returnValue($this->entity)); //AcmeCoreBundleModelTranslatableInterface $this->entity->expects($this->once()) ->method('setLocale') ->with($this->locale); //AcmeCoreBundleListenerEntityListener $this->listener = new TranslatableListener($this->locale); $this->listener->postLoad($this->event); }
  • 43. public function testPostLoad() { //AcmeCoreBundleLocaleLocaleInterface $this->locale; //DoctrineORMEventLifecycleEventArgs $this->args->expects($this->once()) ->method('getEntity') ->will($this->returnValue($this->entity)); //AcmeCoreBundleModelTranslatableInterface $this->entity->expects($this->once()) ->method('setLocale') ->with($this->locale); //AcmeCoreBundleListenerEntityListener $this->listener = new TranslatableListener($this->locale); $this->listener->postLoad($this->event); }
  • 44. public function testPostLoad() { //AcmeCoreBundleLocaleLocaleInterface $this->locale; //DoctrineORMEventLifecycleEventArgs $this->args->expects($this->once()) ->method('getEntity') ->will($this->returnValue($this->entity)); //AcmeCoreBundleModelTranslatableInterface $this->entity->expects($this->once()) ->method('setLocale') ->with($this->locale); //AcmeCoreBundleListenerEntityListener $this->listener = new TranslatableListener($this->locale); $this->listener->postLoad($this->event); }
  • 45. public function testPostLoad() { //AcmeCoreBundleLocaleLocaleInterface $this->locale; //DoctrineORMEventLifecycleEventArgs $this->args->expects($this->once()) ->method('getEntity') ->will($this->returnValue($this->entity)); //AcmeCoreBundleModelTranslatableInterface $this->entity->expects($this->once()) ->method('setLocale') ->with($this->locale); //AcmeCoreBundleListenerEntityListener $this->listener = new TranslatableListener($this->locale); $this->listener->postLoad($this->event); }
  • 46. //tranlsations, defaultLocale, locale, tranlsationExpected public function getTranslationProvider() { return array( array( array('it' => 'translationIt', 'en' => 'translationEn'), 'en', 'en', 'translationEn'), array( array('en' => 'translationEn', 'it' => 'translationIt'), 'en', 'it', 'translationIt'), array( array('en' => 'translationEn'), 'en', 'it', 'translationEn'), ) }
  • 47. //tranlsations, defaultLocale, locale, tranlsationExpected public function getTranslationProvider() { return array( array( array('it' => 'translationIt', 'en' => 'translationEn'), 'en', 'en', 'translationEn'), array( array('en' => 'translationEn', 'it' => 'translationIt'), 'en', 'it', 'translationIt'), array( array('en' => 'translationEn'), 'en', 'it', 'translationEn'), ) }
  • 48. //tranlsations, defaultLocale, locale, tranlsationExpected public function getTranslationProvider() { return array( array( array('it' => 'translationIt', 'en' => 'translationEn'), 'en', 'en', 'translationEn'), array( array('en' => 'translationEn', 'it' => 'translationIt'), 'en', 'it', 'translationIt'), array( array('en' => 'translationEn'), 'en', 'it', 'translationEn'), ) }
  • 49. //tranlsations, defaultLocale, locale, tranlsationExpected public function getTranslationProvider() { return array( array( array('it' => 'translationIt', 'en' => 'translationEn'), 'en', 'en', 'translationEn'), array( array('en' => 'translationEn', 'it' => 'translationIt'), 'en', 'it', 'translationIt'), array( array('en' => 'translationEn'), 'en', 'it', 'translationEn'), ) }
  • 50. public function testGetTranslation($translations, $defaultLocale, $locale, $translationExpected) { $this->translatable = new Translatable(); $this->translatable->setLocale($this->locale); foreach ($translations as $language => $translation) { $this->$translation->expects($this->exactly(2))->method('getLocale') ->will($this->returnValue($language)); $this->translatable->addTranslation($this->$translation); } $this->locale->expects($this->exactly(1)) ->method('getDefaultLocale') ->will($this->returnValue($defaultLocale)); $this->locale->expects($this->exactly(1)) ->method('getLocale') ->will($this->returnValue($locale)); $result = $this->translatable->getTranslation(); $this->assertEquals($this->$translationExpected, $result); }
  • 51. public function testGetTranslation($translations, $defaultLocale, $locale, $translationExpected) { $this->translatable = new Translatable(); $this->translatable->setLocale($this->locale); foreach ($translations as $language => $translation) { $this->$translation->expects($this->exactly(2))->method('getLocale') ->will($this->returnValue($language)); $this->translatable->addTranslation($this->$translation); } $this->locale->expects($this->exactly(1)) ->method('getDefaultLocale') ->will($this->returnValue($defaultLocale)); $this->locale->expects($this->exactly(1)) ->method('getLocale') ->will($this->returnValue($locale)); $result = $this->translatable->getTranslation(); $this->assertEquals($this->$translationExpected, $result); }
  • 52. Non resta che soddisfare i test scrivendo del codice funzionante :-)
  • 53. configuriamo i servizi //src/Acme/CoreBundle/Resources/config/services.yml services: acme_core.locale: class: AcmeCoreBundleServiceLocale arguments: [%locale%] acme_core.listener.locale: class: AcmeCoreBundleServiceLocaleListener arguments: ["@acme.core.locale"] tags: - { name: kernel.event_listener, event: kernel.request } acme_core.listener.entity: class: AcmeCoreBundleServiceEntityListener arguments: ["@acme.core.locale"] tags: - { name: doctrine.event_listener, event: postLoad }
  • 54. configuriamo i servizi //src/Acme/CoreBundle/Resources/config/services.yml services: acme_core.locale: class: AcmeCoreBundleServiceLocale arguments: [%locale%] acme_core.listener.locale: class: AcmeCoreBundleServiceLocaleListener arguments: ["@acme.core.locale"] tags: - { name: kernel.event_listener, event: kernel.request } acme_core.listener.entity: class: AcmeCoreBundleServiceEntityListener arguments: ["@acme.core.locale"] tags: - { name: doctrine.event_listener, event: postLoad }
  • 55. class Article extends Translatable { /** * @ORMOneToMany * (targetEntity="ArticleI18n", mappedBy="translatable") */ protected $translations; public function getTitle() { return $this->getTranslation()->getTitle(); } }
  • 56. Una volta testata anche l'integrazione e verificato che la richiesta del cliente è stata soddisfatta, abbiamo prodotto il valore richiesto e ci possiamo fermare.
  • 58. Prendiamo il codice e lo isoliamo PUGX/I18nBundle
  • 59. AcmePlus PUGX I18nBundle Listener LocaleListener.php EntityListener.php Locale Locale.php LocaleInterface.php Model Translatable.php TranslatableInterface.php TranslatingInterface.php Tests
  • 60. Il grosso è fatto, ora dovremo: - esporre una configurazione semantica - gestire le dipendenze (composer) e la configurazione dei test - aggiungere la documentazione, la licenza ecc.
  • 61. AcmePlus PUGX I18nBundle DependencyInjection Configuration.php PUGXI18nExtension.php […] Tests bootstrap.php PUGXI18nBundle.php composer.json phpunit.xml.dist
  • 62. namespace PUGXI18nBundle; use SymfonyComponentHttpKernelBundleBundle; use PUGXI18nBundleDependencyInjectionPUGXI18nExtension; class PUGXI18nBundle extends Bundle { public function getContainerExtension() { return new PUGXI18nExtension(); } }
  • 63. namespace PUGXI18nBundleDependencyInjection; use SymfonyComponentConfigDefinitionBuilderTreeBuilder; use SymfonyComponentConfigDefinitionConfigurationInterface; class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('pugx_i18n'); return $treeBuilder; } }
  • 64. namespace PUGXI18nBundleDependencyInjection; use SymfonyComponentDependencyInjectionContainerBuilder; use SymfonyComponentConfigFileLocator; use SymfonyComponentHttpKernelDependencyInjectionExtension; use SymfonyComponentDependencyInjectionLoaderYamlFileLoader; class PUGXI18nExtension implements Extension { public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); $path = __DIR__.'/../Resources/config' $loader = new YamlFileLoader($container, new FileLocator($path)); $loader->load('services.yml'); } public function getAlias() { return 'pugx_i18n'; } }
  • 66. //src/PUGX/I18nBundle/composer.json { "name": "pugx/i18n-bundle", "type": "symfony-bundle", "description": "Manage i18n", "keywords": ["symfony2, i18n, translation"], "license": "MIT", "authors": [ { "name":"Leonardo Proietti", "email":"leonardo.proietti@gmail.com" } ], "minimum-stability": "dev", "require": { "php": ">=5.3.2", "symfony/framework-bundle": "2.1.*", "doctrine/orm": ">=2.2.3,<2.4-dev", "symfony/yaml": "2.1.*" }, "autoload": { "psr-0": { "PUGXI18nBundle": "" } }, "target-dir": "PUGX/I18nBundle"
  • 67. //src/PUGX/I18nBundle/Tests/bootstrap.php if (!is_file($autoloadFile = __DIR__.'/../vendor/autoload.php')) { throw new LogicException('Could not find autoload.php'); } require $autoloadFile;
  • 68. //src/PUGX/I18nBundle/phpunit.xml.dist <?xml version="1.0" encoding="UTF-8"?> <phpunit bootstrap="./Tests/bootstrap.php"> <testsuites> <testsuite name="PUGXI18nBundle test suite"> <directory suffix="Test.php">./Tests</directory> </testsuite> </testsuites> <filter> <whitelist> <directory>./</directory> <exclude> <directory>./Resources</directory> <directory>./Tests</directory> </exclude> </whitelist> </filter> </phpunit>
  • 69. Servizio rivolto alla comunità open source per la continuos integration di progetti pubblicati su github https://travis-ci.org/
  • 70. //src/PUGX/I18nBundle/.travis.yml language: php php: - 5.3 - 5.4 before_script: - curl -s http://getcomposer.org/installer | php - php composer.phar install –dev
  • 71. Ora basta creare un repository su github e avremo dato il nostro piccolo contributo alla comunità open source.