SlideShare a Scribd company logo
1 of 125
Download to read offline
Symfony2 en pièces détachées
   Symfony Live 2011 - 4 mars 2011 - Paris
Hugo Hamon aka @hhamon


² Responsable des formations Sensio Labs

² Ancien membre du Bureau de l’AFUP
² Auteur d’ouvrage PHP / Symfony chez Eyrolles

² http://www.hugohamon.com
Avant d’oublier…




  http://joind.in/talk/view/2766
Quelques questions…



Qui développe encore des
applications sans framework ou
bibliothèques ?
Quelques questions…



Qui réutilise des composants
éprouvés ?
Zend Framework, PEAR, EZ Components…
Quelques questions…




Qui réinvente à la roue ?
Symfony2 est bâti autour d’une
bibliothèque de composants indépendants
Les composants
§    BrowserKit             §    HTTP Kernel
§    ClassLoader            §    Locale
§    Console                §    Process
§    CSS Selector           §    Routing
§    Dependency Injection   §    Security
§    Dom Crawler            §    Serializer
§    Event Dispatcher       §    Templating
§    Finder                 §    Translation
§    Form                   §    Validator
§    HTTP Foundation        §    YAML
ClassLoader




              ClassLoader
ClassLoader




              UniversalClassLoader
ClassLoader
  UniversalClassLoader

use SymfonyComponentClassLoaderUniversalClassLoader;

$loader = new UniversalClassLoader();

$loader->registerNamespaces(array(
    'Symfony' => __DIR__ .'/symfony/src',
    'Doctrine' => __DIR__ .'/doctrine/lib',
    'Zend' => __DIR__ .'/zend/library',
));                                                           ty
                                                   ro perabili
                                       PHP 5.3 Inte d
$loader->register();                           standar
ClassLoader
  UniversalClassLoader

use SymfonyComponentClassLoaderUniversalClassLoader;

$loader = new UniversalClassLoader();

$loader->registerNamespaces(array(
    'Sensio' => array(__DIR__ .'/src', __DIR__.'/sensio-extra')
    'Symfony' => __DIR__ .'/symfony/src',
    'Doctrine' => __DIR__ .'/doctrine/lib',
    'Zend' => __DIR__ .'/zend/library',
));

$loader->register();                              Fallback
ClassLoader
 UniversalClassLoader

use SymfonyComponentClassLoaderUniversalClassLoader;

$loader = new UniversalClassLoader();

$loader->registerPrefixes(array(
    'Swift_' => __DIR__ .'/swiftmailer/lib/classes',
    'Twig_' => __DIR__ .'/twig/lib/classes',
));

$loader->register();                                 le
                                           P EAR sty
HttpFoundation




            HttpFoundation
HttpFoundation




                 Request
HttpFoundation

Classe     Dé nition
           Gestion des entêtes et paramètres GET, POST, Cookie,
Request
           Server…

Response   Gestion des entêtes et contenu de la réponse

Session    Gestion de la session PHP
Cookie     Génère un nouveau cookie
File       Gestion des chiers
HttpFoundation
  Request
require_once __DIR__ .'/../src/autoload.php';

use SymfonyComponentHttpFoundationRequest;

$request = Request::createFromGlobals();

$name     =   $request->query->get('name');     //   Get query string variable
$name     =   $request->request->get('name');   //   Get post variable
$name     =   $request->cookies->get('name');   //   Get cookie value
$file     =   $request->files->get('avatar');   //   Get uploaded file
$method   =   $request->getMethod();            //   Get the request method
$ip       =   $request->getClientIp();          //   Get remote address
$https    =   $request->isSecure();             //   True if HTTPS
$ajax     =   $request->isXmlHttpRequest();     //   True if ajax request
HttpFoundation




                 Session
HttpFoundation
Session
§  Lecture et écriture de variables de session
§  Lecture et écriture de messages ash
§  Invalidation et nettoyage de la session
§  Choix du moteur de stockage

   § ArraySessionStorage : session non persistente
   § NativeSessionStorage : session PHP native
   § PdoSessionStorage : session en base de données
HttpFoundation
   Session native de PHP
use SymfonyComponentHttpFoundationSession;
use SymfonyComponentHttpFoundationSessionStorageNativeSessionStorage;

$session = new Session(new NativeSessionStorage());

$session->start();

// Read the session id
$id = $session->getId();

// Set a session variable
$session->set('username', 'hhamon');

// Set a flash message
$session->setFlash('notice', 'You win!');
HttpFoundation
   Session native de PHP
use SymfonyComponentHttpFoundationSession;
use SymfonyComponentHttpFoundationSessionStorageNativeSessionStorage;

$session = new Session(new NativeSessionStorage());
$session->start();

// Read the session variable
echo $session->get('username');

// Read a flash message
if ($session->hasFlash('notice')) {
  echo $session->getFlash('notice');
}

// Remove a session variable
$session->remove('username');
$session->clear();
HttpFoundation
 Session en base de données
 §  Utilisation des objets PdoSessionStorage et PDO
require_once __DIR__ .'/../src/autoload.php';

use SymfonyComponentHttpFoundationSession;
use SymfonyComponentHttpFoundationSessionStoragePdoSessionStorage;

$pdo = new PDO('mysql:host=localhost;dbname=sflive2011', 'root', '', array(
  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));

$storage = new PdoSessionStorage($pdo, array('db_table' => 'php_session'));

$session = new Session($storage, array('default_locale' => 'fr'));
$session->start();
$session->set('username', 'hhamon');
HttpFoundation
Session en base de données
§  Création de la table dans la base de données
   CREATE TABLE `php_session` (
     `sess_id` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
     `sess_data` text COLLATE utf8_unicode_ci,
     `sess_time` INTEGER(10) UNSIGNED NOT NULL,
     PRIMARY KEY (`sess_id`)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


§  Contrôle des données de session dans la table
HttpFoundation




                 Response
HttpFoundation
Response
§  Support des entêtes HTTP
   §  Content-Type
   §  Status-Code
§  Support du cache HTTP
   §  Expires
   §  Etag
   §  Cache-Control (max-age, s-maxage…)
§  Support des cookies
HttpFoundation
  Response - Headers
use SymfonyComponentHttpFoundationResponse;

$response = Response('<html>...</html>', 200);
$response->headers->set('Content-Type', 'text/html; charset=utf-8');
$response->setEtag('article-1337');
$response->setSharedMaxAge(3600);

$response->send();


HTTP/1.0 200 OK
cache-control: s-maxage=3600
content-type: text/html; charset=utf-8
etag: "article-1337"

<html>...</html>
HttpFoundation




                 Cookie
HttpFoundation
  Response - Cookie
require_once __DIR__ .'/../src/autoload.php';

use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentHttpFoundationCookie;

$cookie = new Cookie('last-viewed', '1337', time()+3600*24);

$response = new Response('<html>...</html>', 200);
$response->headers->setCookie($cookie);
$response->send();


HTTP/1.0 200 OK
content-type: text/html; charset=utf-8
set-cookie: last-viewed=1337; expires=Mon, 10-Jan-2011 00:52:24 GMT; path=/;
httponly

<html>...</html>
HttpFoundation




                 File
HttpFoundation
  Fichiers et uploads
use SymfonyComponentHttpFoundationFileFile;

// Set the document root
File::setDocumentRoot(__DIR__);

$file = new File(__DIR__.'/../tmp/avatar.png');

// Change the file location & rename it on the fly
$file->move(__DIR__.'/images', 'hhamon.png');

$ext = $file->getExtension();     // Get the file extension
$size = $file->getMimeType();     // Get the file type
$path = $file->getPath();         // Get the file path

echo '<img src="', $file->getWebPath() ,'" alt="" />';
HttpFoundation
  Fichier et uploads
§  Uploader un chier avec Request et UploadedFile
require __DIR__ .'/../src/autoload.php';

use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationFileUploadedFile;

$request = Request::createFromGlobals();

$avatar = $request->files->get('avatar');
if ($avatar instanceOf UploadedFile && UPLOAD_ERR_OK == $avatar->getError()) {
    $avatar->move(__DIR__.'/images');
}

<form action="upload.php" method="post" enctype="multipart/form-data">
  <input type="file" name="avatar"/>
  <button type="submit">upload</button>
</form>
Event Dispatcher




             Event Dispatcher
Event Dispatcher
Introduction

§  Implémentation du pattern « Observateur »
§  2 classes et 2 interfaces
§  Faciliter le découplage entre les classes
§  Améliorer la exibilité / réutilisabilité du code
§  Simpli er l’intégration de plugins tiers
Event Dispatcher
La classe EventDispatcher
§  Connecte des écouteurs (« callables ») à des événements
$dispatcher = new EventDispatcher();
$dispatcher->connect('the.event.name', $callable);

§  Les sujets « noti ent » des événements aux écouteurs
class Subject {
    public $dispatcher;

    public function doThings() {
        $event = new Event($this, 'the.event.name');
        $this->dispatcher->notify($event);
    }
}
Event Dispatcher



     « Forcer le nettoyage d’un cache
     lorsque certains événements se
                produisent »
Event Dispatcher
    Vider un cache
class WikiPage
{
    public $id;
    public $title;
    public $content;

      public function save(PDO $conn)
      {
          if (!$this->id) {
              $conn->query('INSERT INTO ...');
          } else {
              $conn->exec('UPDATE ...');
          }
      }                                  En cas de modi cation, la page html
}                                        statique du cache doit être régénérée…
namespace MyDomain;

use SymfonyComponentEventDispatcherEventDispatcher;
use SymfonyComponentEventDispatcherEvent;

class WikiPage
{
    // ...
    private $dispatcher;

    public function __construct(EventDispatcher $dispatcher) {
        $this->dispatcher = $dispatcher;
    }

    public function save(PDO $conn) {
        if (!$this->id) {                                  Un événement est noti é pour
            // ...                                         demander aux écouteurs de
        } else {                                           vider le cache de l’objet.
            $conn->exec('UPDATE ...');

            $args = array('type' => 'wiki', 'id' => $this->id);
            $event = new Event($this, 'cache.flush', $args);
            $this->dispatcher->notify($event);
        }
    }
}
namespace MyCache;

use SymfonyComponentEventDispatcherEvent;

class CacheManager
{
    private $cacheDir;

    public function __construct($cacheDir)
    {
        $this->cacheDir = $cacheDir;                   Ecouteur invoqué à la
    }                                                  noti cation de l’événement.
    public function listenToCacheFlushEvent(Event $event)
    {
        // The WikiPage object
        $object = $event->getSubject();

        // Retrieve all extra arguments
        $args = $event->all();

        $path = $this->cacheDir .'/'. $args['type'] .'/'. $args['id'] .'.html';
        if (file_exists($path)) {
            @unlink($path);
        }
    }
}
use SymfonyComponentEventDispatcherEventDispatcher;
use MyDomainWikiPage;
use MyCacheCacheManager;

$pdo = new PDO('...');
$cache = new CacheManager('/path/to/cache');

# Register a new listener.
$dispatcher = new EventDispatcher();
$dispatcher->connect('cache.flush', array($cache, 'listenToCacheFlushEvent'));

# Find the wiki page object with its id.
$page = WikiPage::findById($_GET['id']);
$page->setEventDispatcher($dispatcher);

# Page properties are edited.
$page->title = 'New title';
$page->content = 'New content';

# The CacheManager::listenToCacheFlushEvent method is called.
$page->save($pdo);
Event Dispatcher




   « Filtrer / transformer une valeur »
Event Dispatcher
    Filtrer une donnée
class WikiPage
{
    private $rawContent;
    private $parsedContent;

      public function setRawContent($rawContent)
      {
          $this->rawContent = $rawContent;

          $parser = new WikiParser();

          $this->parsedContent = $parser->parse($rawContent);
      }
}
Event Dispatcher
Problème ?

§  Les objets « WikiPage » et « WikiParser » sont fortement couplés

§  Changer le parser implique de modi er la classe « WikiPage »

§  Idem, si l’on veut ajouter des ltres supplémentaires

§  Testabilité du code réduite due à la dépendance
Event Dispatcher
    Solution?
    §  Filtrer la valeur en appelant une série de ltres (« écouteurs »).
class WikiPage
{
    private $rawContent;
    private $parsedContent;

      public function setRawContent($rawContent)
      {
          $$this->rawContent = $rawContent;

           $event = new Event('wiki.filter_content', $rawContent);

           $this->parsedContent = $this->dispatcher->filter($event);
      }
}
use SymfonyComponentEventDispatcherEventDispatcher;
use MyDomainWikiPage;
use MyFilterWikiSyntaxParser;

$dispatcher = new EventDispatcher();

# Register a first filter
$dispatcher->connect('wiki.filter_content', function(Event $e, $value) {
    return striptags($value, '<code>')
});

$wikiParser = new WikiSyntaxParser();

# Register a second filter
$dispatcher->connect('wiki.filter_content', array($wikiParser, 'parse'));

$wikiPage = new WikiPage();
$wikiPage->setEventDispatcher($dispatcher);

# Set and filter the raw content value
$wiki->setRawContent('Some **wiki** content with <script>alert("foo")</script>
<code>$c = $a + $b</code>.');
Event Dispatcher
  Filtrer une valeur

  §  La propriété « parsedContent » aura la valeur suivante.

Some <strong>wiki</strong> content with <code>$c = $a + $b</code>.



  §  La balise <script> a été ltrée
  §  La balise <code> a été conservée
  §  La syntaxe Wiki a été transformée en HTML
Dependency Injection




          Dependency Injection
Dependency Injection
Introduction

§  « Inversion de contrôle »
§  Composant au cœur de Symfony2
§  Instanciation et initialisation de services à la demande
§  Supporte les dépendances entre les différents services
§  Dé nition des services en PHP, XML ou YAML
Dependency Injection
    Dé nition d’un service SOAP
# config/services.xml

<?xml version="1.0" ?>
<container xmlns="http://www.symfony-project.org/schema/dic/services"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://
www.symfony-project.org/schema/dic/services/services-1.0.xsd">

 <parameters>
   <parameter key="soap_server.wsdl.uri">
     http://www.components.local/soap-server.php?wsdl
   </parameter>
   <parameter key="soap_server.response.return">true</parameter>
   <parameter key="soap_server.options.encoding">utf-8</parameter>
   <parameter key="calculator_service.class">ApplicationCalculator</parameter>
 </parameters>

  <services>
    <!-- ... -->                      Paramètres	
  de	
  configura1on	
  des	
  services.	
  
  </services>
</container>
Dependency Injection
     Dé nition d’un service SOAP
<?xml version="1.0" ?>
<container ... >

 <!-- ... -->
 <services>
   <!-- SOAP Server -->                                         Défini1on	
  d’un	
  serveur	
  Zend	
  
   <service id="soap_server" class="ZendSoapServer">
     <argument>%soap_server.wsdl.uri%</argument>
                                                               Soap	
  comme	
  étant	
  un	
  service	
  
     <argument type="collection">
       <argument key="encoding">%soap_server.options.encoding%</argument>
     </argument>
     <call method="setReturnResponse">
       <argument>%soap_server.response.return%</argument>
     </call>
     <call method="setObject"><argument type="service" id="calculator_service" /></call>
   </service>
   <!-- SOAP Autodiscovery -->
   <service id="soap_autodiscover" class="ZendSoapAutodiscover">
     <call method="setClass"><argument type="string">%calculator_service.class%</argument></call>
   </service>
   <!-- Calculator service used by the SOAP server -->
   <service id="calculator_service" class="%calculator_service.class%"/>
 </services>

</container>
Dependency Injection
    Dé nition d’un service SOAP
<!-- Identification du service : identifiant + type -->
<service id="soap_server" class="ZendSoapServer">

 <!-- 1er argument du constructeur : valeur d’un paramètre défini précédemment -->
 <argument>%soap_server.wsdl.uri%</argument>

 <!-- 2nd argument du constructeur : tableau associatif d’options -->
 <argument type="collection">
   <argument key="encoding">utf-8</argument>
 </argument>

 <!– 1ère méthode à appeler juste après l’instanciation du service -->
 <call method="setReturnResponse">
   <argument>true</argument>
 </call>

 <!– 2nd méthode à appeler avec une instance du service calculator_service en argument -->
 <call method="setObject">
   <argument type="service" id="calculator_service" />
 </call>

</service>
Dependency Injection
     Dé nition du service Calculator
namespace Application;

class Calculator
{
    /**                                            Documenta1on	
  avec	
  de	
  la	
  PHPDoc	
  afin	
  de	
  
      * Returns the sum of two numbers.             générer	
  le	
  WSDL	
  correspondant	
  grâce	
  à	
  
      *                                                   Zend_Soap_Autodiscover	
  
      * @param float $a The first operand
      * @param float $b The second operand
      * @return float The result
      * @throws SoapFault
      */
    public function sum($a, $b)
    {
         if (!is_numeric($a) || !is_numeric($b)) {
             throw new SoapFault('The sum() operation only accepts numeric arguments.');
         }

         return $a + $b;
    }
}
Dependency Injection
     Obtenir le conteneur de services
# web/soap-server.php
use SymfonyComponentConfigContainerBuilder;
use SymfonyComponentDependencyInjectionContainerBuilder;
use SymfonyComponentDependencyInjectionParameterBagParameterBag;
use SymfonyComponentDependencyInjectionLoaderXmlFileLoader;

$container = new ContainerBuilder(new ParameterBag());
$loader    = new XmlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.xml');

                                                            Lecture	
  du	
  fichier	
  services.xml	
  et	
  
if (isset($_GET['wsdl'])) {
    $autodiscover = $container->get('soap_autodiscover');
                                                            chargement	
  de	
  la	
  défini1on	
  dans	
  le	
  
    $response = $autodiscover->toXml();                     conteneur	
  d’injec1on	
  de	
  dépendances	
  
} else {
    $soapServer = $container->get('soap_server');
    $response = $soapServer->handle();
}
                                                            Récupéra1on	
  du	
  serveur	
  SOAP	
  Zend	
  
header('Content-Type: text/xml');
                                                            correctement	
  instancié	
  et	
  ini1alisé.	
  
echo $response;
Finder




         Finder
Finder
Rechercher des chiers
§  Rechercher des chiers dans une arborescence
§  Filtres sur des critères
   §  Type ( chiers ou répertoires)
   §  Nom et extension (patterns)
   §  Taille
   §  Date
   §  …
§  Tri les résultats sur des attributs de chiers
Finder
  Rechercher des chiers
use SymfonyComponentFinderFinder;

$finder = new Finder();

// All files in the current folder
$files = $finder->files()->in(__DIR__);

// All directories in the current folder
$files = $finder->directories()->in(__DIR__);

// All PHP files in the current folder only
$files = $finder->files()->name('/.php$/')->depth(0)->in(__DIR__);

// All files whose size is between 1K and 2K inclusive
$files = $finder->files()->size('>= 1K')->size('<= 2K')->in(__DIR__);
Finder
   Rechercher des chiers
// Search files in several folders
$files = $finder->files()->in(array(__DIR__, __DIR__.'/../src'));

// Sort file by name
$files = $finder->files()->name('/.php$/')->in(__DIR__)->sortByName();

// Sort files by type
$files = $finder->files()->name('/.php$/')->in(__DIR__)->sortByType();

// Filter by date
$files = $finder->files()->name('/.(png|jpg|jpeg|gif)$/i')->
    date('>= 2011-01-09')->
    date('<= 2011-02-03')->in(__DIR__);

$files = $finder->files()->name('/.(png|jpg|jpeg|gif)$/i')->
    date('since 2011-01-09')->
    date('before 2011-02-03')->in(__DIR__);
Finder
   Filtres personnalisés
# Create a lambda function that acts as a filter.
$onlyWritableFiles = function(SplFileInfo $file) {
    return $file->isWritable();
};                                     Un ltre personnalisé est une fonction
                                            anonyme qui reçoit une instance de
# Find writeable TXT files
$finder = new Finder();
                                            SplFileInfo et retourne une valeur booléenne.

$files = $finder->files()->
  name('/.txt$/')->
  filter($onlyWritableFiles)->
  in(__DIR__.'/../cache');

foreach (iterator_to_array($files) as $path => $file) {
    echo $file->getFilename();
}
Templating




             Templating
Templating
Introduction
§  Système de templating simple et efficace
§  Supporte des moteurs de stockage différents
   §  Fichiers
   §  Chaînes de caractères
§  Supporte des fonctionnalités « modernes »
   §  Héritage de templates
   §  Slots
   §  Aide de vue (« helpers »)
§  Extensible
Templating
  Génération d’un template simple
  §  Chargement et rendu d’un template simple
require_once __DIR__ .'/../src/autoload.php';

use SymfonyComponentTemplatingPhpEngine;
use SymfonyComponentTemplatingTemplateNameParser;
use SymfonyComponentTemplatingLoaderFilesystemLoader;

$loader = new FilesystemLoader(array(
  __DIR__.'/../src/tpl/%name%.php',             Mo1fs	
  de	
  chemins	
  de	
  
  __DIR__.'/../src/tpl/hello/%name%.php',       fichiers	
  de	
  templates	
  
));

$engine   = new PhpEngine(new TemplateNameParser(), $loader);

echo $engine->render('index', array('name' => 'Hugo'));             Variables	
  du	
  template	
  
Templating
Génération d’un template simple

§  La variable $view correspond à l’objet $engine précédent.
# src/tpl/index.php

<p>
  Hello <?php echo $view->escape($name) ?>!
</p>


§  L’échappement des variables est assuré par la méthode
    escape() de l’objet $view.
Templating
      Génération d’un template avancé
use   SymfonyComponentTemplatingPhpEngine;
use   SymfonyComponentTemplatingTemplateNameParser;
use   SymfonyComponentTemplatingLoaderFilesystemLoader;
use   SymfonyComponentTemplatingHelperSlotsHelper;

$loader = new FilesystemLoader(array(             Support des aides de vue et
  __DIR__.'/../src/tpl/%name%.php',
  __DIR__.'/../src/tpl/hello/%name%.php',
                                                  de l’héritage de templates.
));

$engine = new PhpEngine(new TemplateNameParser(), $loader, array(
    new SlotsHelper()
));

$content = $engine->render('index', array('name' => 'Hugo'));

echo $content;
Templating
   Génération d’un template avancé
# src/tpl/index.php                   Extension du template de base
<?php $view->extend('layout') ?>
<?php $view['slots']->set('title', 'Hello Application') ?>

<p>
  Hello <?php echo $view->escape($name) ?>!        Dé nition de la valeur d’un slot
</p>


# src/tpl/layout.php
<html>
  <head>
    <title>
       <?php $view['slots']->output('title', 'Templating component') ?>
    </title>
  </head>
  <body>
    <h1>Welcome!</h1>
                                                      Affichage du slot ou une valeur par
    <?php $view['slots']->output('_content') ?>       défaut si non dé ni
  </body>
</html>               Contenu évalué de index.php
Templating
  Génération d’un template avancé
  §  Le rendu nal est le suivant :

<!DOCTYPE html>
<html>
  <head>
    <title>Hello Application</title>
  </head>
  <body>
    <h1>Welcome!</h1>
    <p>
       Hello Hugo!
    </p>
  </body>
</html>
Translation




              Translation
Translation
Introduction
§  Gestionnaire de dictionnaires de traduction
§  Supporte différents formats de stockage
   §  Array
   §  PHP
   §  YAML
   §  XLIFF
   §  CSV
§  Supporte les chaînes dynamiques
§  Embarque des algorithmes de pluralisation
Translation
   Dé nition d’un dictionnaire XLIFF
# i18n/fr/messages.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/
committees/xliff/documents/xliff.dtd">
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="messages.xml">
    <header/>
    <body>
      <trans-unit id="1">
         <source>Hello</source>
         <target>Salut</target>
      </trans-unit>
      <trans-unit id="2">
         <source>Hello %name%</source>
         <target>Bonjour %name%</target>
      </trans-unit>
    </body>
  </file>
</xliff>
Translation
   Traduire des chaînes d’un catalogue
require __DIR__ .'/../src/autoload.php';

use SymfonyComponentTranslationTranslator;
use SymfonyComponentTranslationMessageSelector;
use SymfonyComponentTranslationLoaderXliffFileLoader;

// Création d’un objet Translator
$translator = new Translator('fr', new MessageSelector());

// Chargement du dictionnaire XLIFF
$translator->addLoader('xliff', new XliffFileLoader());
$translator->addResource('xliff', __DIR__.'/../i18n/fr/messages.xml', 'fr');

// Returns "Salut"
echo $translator->trans('Hello');

// Returns "Bonjour Hugo"
echo $translator->trans('Hello %name%', array('%name%' => 'Hugo'));
Translation
  Utiliser une locale par défaut
§  Dé nition d’un second dictionnaire pour l’allemand
# i18n/de/messages.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/
committees/xliff/documents/xliff.dtd">
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="messages.xml">
    <header/>
    <body>
      <trans-unit id="1">
         <source>Welcome in %city%</source>
         <target>Wilkommen in %city%</target>
      </trans-unit>
    </body>
  </file>
</xliff>
Translation
  Utiliser une locale par défaut
§  Le gestionnaire de traduction peut charger plusieurs catalogues de
    traduction et forcer une locale par défaut.
$trans = new Translator('fr', new MessageSelector());

$trans->addLoader('xliff', new XliffFileLoader());

// Load two distinct dictionaries
$trans->addResource('xliff', __DIR__.'/../i18n/de/messages.xml', 'de');
$trans->addResource('xliff', __DIR__.'/../i18n/fr/messages.xml', 'fr');

// Set the default fallback locale
$trans->setFallbackLocale('de');

// Translation only exists in german catalog even if the locale is fr
echo $trans->trans('Welcome in %city%', array('%city%' => 'Paris'));
Translation
    Pluralisation des chaînes
# i18n/fr/messages.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/
committees/xliff/documents/xliff.dtd">
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="messages.xml">
    <header/>
    <body>
      <!-- ... -->
      <trans-unit id="3">
         <source>{0} There is no apples|{1} There is one apple|]1,Inf] There is
%count% apples</source>
         <target>{0} Il n'y a pas de pomme|{1} Il y a une pomme|]1,Inf] Il y a
%count% pommes</target>
      </trans-unit>
    </body>
  </file>
</xliff>
Translation
   Pluralisation des chaînes
§  La méthode transChoice() facilite la pluralisation des chaînes
$count = 5;

$translator = new Translator('fr', new MessageSelector());

$translator->addLoader('xliff', new XliffFileLoader());
$translator->addResource('xliff', __DIR__.'/../i18n/fr/messages.xml', 'fr');

// Returns "Il y a <strong>5</strong> pommes"
echo $translator->transChoice(
   '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count%
apples',
   $count,
   array('%count%' => '<strong>' . $count . '</strong>')
);
Locale




         Locale
Locale
Introduction

§  Surcharge la classe Locale de PHP 5.3
§  Supporte les formatages des noms de pays
§  Supporte les formatages des noms de langues


§  L’API se compose uniquement de méthodes statiques
Locale
   Obtenir la listes des pays
use SymfonyComponentLocaleLocale;

print_r(Locale::getDisplayCountries('fr'));
print_r(Locale::getDisplayCountries('en'));
print_r(Locale::getDisplayCountries('de'));


§  Les pays sont retournés dans des tableaux associatifs triés sur les valeurs

Array                         Array                         Array
(                             (                             (
    [AF] => Afghanistan           [AF] => Afghanistan           [AF] => Afghanistan
    [ZA] => Afrique du Sud        [AL] => Albania               [AL] => Albanien
    [AL] => Albanie               [ZA] => South Africa          [ZA] => Südafrika
    ...                           ...                           ...
)                             )                             )
Locale
  Codes ISO des pays
use SymfonyComponentLocaleLocale;

print_r(Locale::getCountries());


Array ( [0] => AF [1] => AX [2] => AL [3] => DZ [4] => AS [5] => AD [6] => AO
[7] => AI [8] => AQ [9] => AG [10] => AR [11] => AM [12] => AW [13] => AC [14]
=> AU [15] => AT [16] => AZ [17] => BS [18] => BH [19] => BD [20] => BB [21]
=> BY [22] => BE [23] => BZ [24] => BJ [25] => BM [26] => BT [27] => BO [28]
=> BA [29] => BW [30] => BV [31] => BR [32] => IO [33] => VG [34] => BN [35]
=> BG [36] => BF [37] => BI [38] => KH [39] => CM [40] => CA [41] => IC [42]
=> CV [43] => KY [44] => CF [45] => EA [46] => TD [47] => CL [48] => CN [49]
=> CX [50] => CP [51] => CC [52] => CO [53] => KM [54] => CG [55] => CD [56]
=> CK [57] => CR [58] => CI [59] => HR [60] => CU [61] => CY [62] => CZ [63]
=> DK [64] => DG [65] => DJ [66] => DM [67] => DO [68] => EC [69] => EG [70]
=> SV [71] => GQ [72] => ER [73] => EE ...)
Locale
    Obtenir la listes des locales
use SymfonyComponentLocaleLocale;

print_r(Locale::getDisplayLocales('fr'));
print_r(Locale::getDisplayLocales('en'));


§  Les locales sont retournées dans des tableaux associatifs triés sur les valeurs

Array                                        Array
(                                            (
    [fr_BE]   =>   français   (Belgique)       [fr_BE]   =>   French   (Belgium)
    [fr_CA]   =>   français   (Canada)         [fr_CA]   =>   French   (Canada)
    [fr_DJ]   =>   français   (Djibouti)       [fr_DJ]   =>   French   (Djibouti)
    [fr_LU]   =>   français   (Luxembourg)     [fr_LU]   =>   French   (Luxembourg)
    [fr_CH]   =>   français   (Suisse)         [fr_CH]   =>   French   (Switzerland)
    ...                                        ...
)                                            )
Locale
  Codes ISO des locales
use SymfonyComponentLocaleLocale;

print_r(Locale::getLocales());



Array ( [0] => af [1] => af_NA [2] => ak [3] => sq [4] => am [5] => am_ET [6] => ar
[7] => ar_DZ [8] => ar_BH [9] => ar_EG [10] => ar_IQ [11] => ar_JO [12] => ar_KW
[13] => ar_LB [14] => ar_LY [15] => ar_MA [16] => ar_OM [17] => ar_QA [18] => ar_SA
[19] => ar_SD [20] => ar_SY [21] => ar_TN [22] => ar_AE [23] => ar_YE [24] => hy
[25] => as [26] => as_IN [27] => asa [28] => az [29] => az_Cyrl [30] => az_Cyrl_AZ
[31] => az_Latn [32] => az_Latn_AZ [33] => bm [34] => eu [35] => be [36] => bem
[37] => bez [38] => bn [39] => bn_IN [40] => bs [41] => bg [42] => my [43] => my_MM
[44] => ca [45] => tzm [46] => tzm_Latn [47] => tzm_Latn_MA [48] => chr [49] =>
chr_US [50] => cgg [51] => zh [52] => kw [53] => hr [54] => cs [55] => da [56] =>
nl [57] => nl_BE [58] => ebu [59] => ebu_KE [60] => en [61] => en_AS [62] => en_AU
[63] => en_BE [64] => en_BZ [65] => en_BW [66] => en_CA [67] => en_GU [68] => en_HK
[69] => en_IN ...)
Locale
   Obtenir la listes des langues
use SymfonyComponentLocaleLocale;

print_r(Locale::getDisplayLanguages('fr'));
print_r(Locale::getDisplayLanguages('en'));


§  Les langues sont retournées dans des tableaux associatifs triés sur les valeurs
Array                                        Array
(                                            (
  [en]      =>   anglais                       [en]      =>   English
  [en_US]   =>   anglais   américain           [en_AU]   =>   Australian English
  [en_AU]   =>   anglais   australien          [en_GB]   =>   British English
  [en_GB]   =>   anglais   britannique         [en_CA]   =>   Canadian English
  [en_CA]   =>   anglais   canadien            [en_US]   =>   U.S. English
  ...                                          ...
)                                            )
Locale
  Codes ISO des langues
use SymfonyComponentLocaleLocale;

print_r(Locale::getLanguages());



Array ( [0] => ab [1] => ace [2] => ach [3] => ada [4] => ady [5] => aa [6] => afh
[7] => af [8] => afa [9] => ain [10] => ak [11] => akk [12] => sq [13] => ale [14]
=> alg [15] => tut [16] => am [17] => egy [18] => grc [19] => anp [20] => apa [21]
=> ar [22] => an [23] => arc [24] => arp [25] => arn [26] => arw [27] => hy [28] =>
rup [29] => art [30] => as [31] => ast [32] => asa [33] => ath [34] => cch [35] =>
en_AU [36] => aus [37] => de_AT [38] => map [39] => av [40] => ae [41] => awa [42]
=> ay [43] => az [44] => ban [45] => bat [46] => bal [47] => bm [48] => bai [49] =>
bad [50] => bnt [51] => bas [52] => ba [53] => eu [54] => btk [55] => bej [56] =>
be [57] => bem [58] => bez [59] => bn [60] => ber [61] => bho [62] => bh [63] =>
bik [64] => bin [65] => bi [66] => byn [67] => zbl [68] => brx [69] => bs [70] =>
bra [71] => pt_BR [72] => br [73] => en_GB [74] => bug [75] => bg [76] => bua [77]
=> my [78] => cad [79] => en_CA [80] => fr_CA [81] => yue [82] => car [83] ...)
Console




          Console
Console
Introduction

§  Automatiser des tâches pénibles (génération de code…)

§  Exécuter des tâches qui prennent du temps

§  Béné cier des ressources du serveur

§  Plani er des tâches dans une crontab
Console
Introduction
§  Arguments et options
§  Codes de sortie
§  Shell
§  Coloration de la sortie
§  Testabilité
§  Messages d’erreur
§  …
Console
Amorcer le CLI

§  Création d’un chier « console.php » exécutable (chmod +x)

#!/usr/bin/php	
<?php	
	
require __DIR__ .'/src/autoload.php';	
	
use SymfonyComponentConsoleApplication;	
	
$application = new Application('Console', '1.0');	
$application->run();	
  
Console
Amorcer le CLI
namespace ApplicationCommand;

use   SymfonyComponentConsoleCommandCommand;
use   SymfonyComponentConsoleInputInputArgument;
use   SymfonyComponentConsoleInputInputOption;
use   SymfonyComponentConsoleInputInputInterface;
use   SymfonyComponentConsoleOutputOutputInterface;

use ApplicationServiceGoogleWeather;

class WeatherCommand extends Command
{
                                             Dé nition des meta données de la commande :
    protected function configure()           nom, manuel, arguments, options…
    {
        $this->
          addArgument('city', InputArgument::REQUIRED, 'The city')->
          addOption('lang', null, InputOption::VALUE_REQUIRED, 'The lang', 'en')->
          setName('google:weather')->
          setDescription('Fetches weather information.')->
          setHelp(<<<EOF
The <info>google:weather</info> command fetches weather data for a given city:

<info>google:weather paris --lang fr</info>
EOF
        );
    }}
Console
    Dé nir la logique de la commande
                                                $input : arguments + options
                                                $output : sortie de la console
class WeatherCommand extends Command
{
    # ...
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $city = $input->getArgument('city');
        $lang = $input->getOption('lang');

        $weather = new GoogleWeather($city, $lang);

        $output->writeln(sprintf('<info>City</info>: %s', $weather->getCity()));
        $output->writeln(sprintf('<info>Temperature</info>: %s', $weather->getTemperature()));
        $output->writeln(sprintf('<info>Latitude</info>: %s', $weather->getLatitude()));
        $output->writeln(sprintf('<info>Longitude</info>: %s', $weather->getLongitude()));
        $output->writeln(sprintf('<info>Condition</info>: %s', $weather->getCondition()));
        $output->writeln(sprintf('<info>Wind</info>: %s', $weather->getWindCondition()));
    }
}
Console
Enregistrer la commande

#!/usr/bin/php	
<?php	
	
require __DIR__ .'/src/autoload.php';	
	
use SymfonyComponentConsoleApplication;	
use ApplicationCommandWeatherCommand;	
	
$application = new Application('Console', '1.0');	
$application->add(new WeatherCommand());	
$application->run();	
  
Console
Consulter la liste des commandes
Console
Obtenir de l’aide de la commande
            ./console help google:weather	
  
Console
Exécuter la commande

      ./console google:weather Berlin --lang fr	
  
Process




          Process
Process
Introduction


§  Exécuter des lignes de commande depuis un script PHP


§  Récupérer la sortie générée par la console


§  Récupérer le statut de l’exécution de la console
Process
Mise en oeuvre
use SymfonyComponentProcessProcess;

$process = new Process('ls -lah', __DIR__);
$process->run();

if (!$process->isSuccessful()) {
  $output = $process->getErrorOutput();
} else {
  $output = $process->getOutput();
}

echo $output;
Process
Mise en oeuvre
total 176
drwxr-xr-x 25 Hugo   staff   850B   Feb   23   22:53   .
drwxr-xr-x  9 Hugo   staff   306B   Feb   13   19:39   ..
-rw-r--r--@ 1 Hugo   staff   607B   Feb   19   12:48   crawler.php
-rw-r--r--@ 1 Hugo   staff   1.9K   Feb   13   12:08   event-dispatcher.php
-rw-r--r--@ 1 Hugo   staff   914B   Feb   13   13:43   event-dispatcher2.php
-rw-r--r--@ 1 Hugo   staff   678B   Jan   31   21:55   file.php
-rw-r--r--@ 1 Hugo   staff   1.7K   Feb   12   14:40   finder.php
drwxrwxrwx  3 Hugo   staff   102B   Jan   31   21:55   images
-rw-r--r--@ 1 Hugo   staff   276B   Jan    9   23:39   locale.php
-rw-r--r--@ 1 Hugo   staff   454B   Feb   23   22:53   process.php
-rw-r--r--@ 1 Hugo   staff   746B   Jan   31   22:26   read-request.php
-rw-r--r--@ 1 Hugo   staff   545B   Jan   31   22:41   response.php
-rw-r--r--@ 1 Hugo   staff   1.3K   Feb    9   23:58   routing.php
-rw-r--r--@ 1 Hugo   staff   718B   Feb    1   23:38   serializer.php
-rw-r--r--@ 1 Hugo   staff   502B   Jan    9   00:37   session1.php
-rw-r--r--@ 1 Hugo   staff   682B   Jan    9   00:37   session2.php
-rw-r--r--@ 1 Hugo   staff   520B   Jan    9   01:15   session3.php
-rw-r--r--@ 1 Hugo   staff   241B   Feb    6   11:28   soap-client.php
-rw-r--r--@ 1 Hugo   staff   737B   Feb   19   10:45   soap-server.php
-rw-r--r--@ 1 Hugo   staff   558B   Feb   19   10:56   templating-advanced.php
-rw-r--r--@ 1 Hugo   staff   476B   Feb   19   10:56   templating-basic.php
PhpProcess
Exécuter un script PHP

use SymfonyComponentProcessPhpProcess;

$process = new PhpProcess('<?php echo "Hello World!" ?>');
$process->run();

if (!$process->isSuccessful()) {
  $output = $process->getErrorOutput();
} else {
  $output = $process->getOutput();
}

echo $output;
Serializer




             Serializer
Serializer
Introduction




 Le composant « Serializer » convertit des objets PHP en
     représentations XML ou JSON par introspection.
Serializer
Architecture
Serializer
Architecture
§  L’objet « Serializer » transforme un objet PHP en
    représentation XML (ou JSON) et inversement.

§  Les objets « Normalizer » transforment un objet en tableau
    PHP.

§  Les objets « Encoder » transforment un tableau PHP en
    représentations XML ou JSON.
class Author
{
    private $firstName;
    private $lastName;

    public function __construct($firstName, $lastName)
    {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    public function getFirstName()
    {
        return $this->firstName;
    }

    public function getLastName()
    {
        return $this->lastName;
    }

    public function getFullName()
    {
        return $this->firstName .' '. $this->lastName;
    }
}
class Book
{
    private $title;
    private $author;

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setAuthor(Author $author)
    {
        $this->author = $author;
    }

    public function getAuthor()
    {
        return $this->author;
    }
}
Serializer
   Sérialiser un objet en XML
use SymfonyComponentSerializerSerializer;
use SymfonyComponentSerializerEncoderXmlEncoder;
use SymfonyComponentSerializerNormalizerGetSetMethodNormalizer;

$serializer = new Serializer();

# Register the XML encoder
$serializer->setEncoder('xml', new XmlEncoder());

# Register a getter / setter normalizer
$serializer->addNormalizer(new GetSetMethodNormalizer());

$book = new Book();
$book->setAuthor(new Author('Agatha', 'Christie'));
$book->setTitle('Ten Little Niggers');

header('Content-Type: text/xml; charset=utf-8');
echo $serializer->serialize($book, 'xml');
Serializer
Sérialiser un objet en XML
Serializer
   Sérialiser un objet en JSON
use SymfonyComponentSerializerSerializer;
use SymfonyComponentSerializerEncoderJsonEncoder;
use SymfonyComponentSerializerNormalizerGetSetMethodNormalizer;

$serializer = new Serializer();

# Register the JSON encoder
$serializer->setEncoder('json', new JsonEncoder());

# Register a getter / setter normalizer
$serializer->addNormalizer(new GetSetMethodNormalizer());

$book = new Book();
$book->setAuthor(new Author('Agatha', 'Christie'));
$book->setTitle('Ten Little Niggers');

header('Content-Type: application/json; charset=utf-8');
echo $serializer->serialize($book, 'json');
Serializer
Sérialiser un objet en JSON

      {
          "title":"Ten Little Niggers",
          "author":
          {
              "firstname":"Agatha",
              "lastname":"Christie",
              "fullname":"Agatha Christie"
          }
      }
use SymfonyComponentSerializerSerializer;
use SymfonyComponentSerializerEncoderJsonEncoder;
use SymfonyComponentSerializerNormalizerGetSetMethodNormalizer;

$serializer = new Serializer();
$serializer->setEncoder('json', new JsonEncoder());
$serializer->addNormalizer(new GetSetMethodNormalizer());

$jsonEncoded = '{
    "title":"Ten Little Niggers",
    "author":
    {
        "firstname":"Agatha",
        "lastname":"Christie",
        "fullname":"Agatha Christie"
    }
}';

header('Content-Type: text/plain; charset=utf-8');

print_r($serializer->decode($jsonEncoded, 'json'));
Serializer
Désérialiser un objet JSON

    Array
    (
        [title] => Ten Little Niggers
        [author] => Array
            (
                [firstname] => Agatha
                [lastname] => Christie
                [fullname] => Agatha Christie
            )

    )
YAML




       YAML
YAML
Introduction



 YAML signi e « Ain't Markup Language ». C’est un format
    standard de sérialisation de données pour tous les
               langages de programmation.
YAML
  Parser un chier YAML
parameters:

    # Twitter module
    twitter.timeline.cache: true
    twitter.auth.username: hhamon
    twitter.auth.password: s3cr3t

    # Blog module
    blog.post.max_per_page: 10

app:
    available_cultures:    [fr, en, de]

services:
    db_connection:
      class: PDO
      dsn: mysq:host=localhost;dbname=foo
      username: root
      password: ~
YAML
 Parser un chier YAML
 §  La classe « Parser » transforme une chaîne YAML en un
     tableau associatif PHP.

use SymfonyComponentYamlParser;	
	
$content = file_get_contents(__DIR__ . '/../config/config.yml');	
	
$yaml   = new Parser();	
$result = $yaml->parse($content);	
	
echo '<pre>’;	
print_r($result);	
echo '</pre>';
Array
(
    [parameters] => Array
        (
            [twitter.timeline.cache] => 1
            [twitter.auth.username] => hhamon
            [twitter.auth.password] => s3cr3t
            [blog.post.max_per_page] => 10
        )
    [app] => Array
        (
            [available_cultures] => Array
                (
                    [0] => fr
                    [1] => en
                    [2] => de
                )
        )
    [services] => Array
        (
            [db_connection] => Array
                (
                    [class] => PDO
                    [dsn] => mysq:host=localhost;dbname=foo
                    [username] => root
                    [password] =>
                )
        )
)
YAML
  Transformer un tableau en YAML

  §  La classe « Dumper » transforme un tableau PHP en YAML
use SymfonyComponentYamlParser;
use SymfonyComponentYamlDumper;

$yaml   = new Parser();
$result = $yaml->parse(file_get_contents(__DIR__ . '/../config/config.yml'));

$result['parameters']['twitter.timeline.cache'] = false;
$result['services']['db_connection']['class'] = 'PdoMock';

$dumper = new Dumper();
$data   = $dumper->dump($result, 2);

file_put_contents(__DIR__ . '/../config/config_test.yml', $data);
YAML
 Transformer un tableau en YAML

parameters:
  twitter.timeline.cache: false
  twitter.auth.username: hhamon
  twitter.auth.password: s3cr3t
  blog.post.max_per_page: 10

app:
  available_cultures: [fr, en, de]

services:
  db_connection: { class: PdoMock, dsn:
'mysq:host=localhost;dbname=foo', username: root, password: null }
CSS Selector




               CSS Selector
CSS Selector
 CSS3 vers XPath

use SymfonyComponentCssSelectorParser;

$doc = new DOMDocument();
$doc->loadHTMLFile(__DIR__.'/../src/tpl/page.html');

$xpath = new DOMXPath($doc);

$expr = Parser::cssToXpath('ul#menu > li a:contains("Home")');

$xpath->query($expr);

foreach ($xpath->query($expr) as $link) {
    printf('%s > %s', $link->nodeValue, $link->getAttribute('href'));
}
CSS Selector
 CSS3 vers XPath


Parser::cssToXpath('ul#menu > li a:contains("Home")');




descendant-or-self::ul[@id = 'menu']/li/descendant::a
[contains(string(.), 'Home')]
DomCrawler




             DomCrawler
DomCrawler
Introduction



Le composant DomCrawler offre une API simple pour analyser
un document SGML grâce au support intégral des sélecteurs
CSS3 et XPath.
DomCrawler
Introduction
§  Analyser et extraire des informations d’un document SGML
§  Supporte différentes sources de données
   Ø Chaîne HTML ou XML
   Ø Objet DOMNode ou DOMNodeList
   Ø Objet DOMDocument
§  Supporte les sélecteurs CSS3 et Xpath
§  Crawler s’appuie sur le composant CssSelector
DomCrawler
 Instancier un Crawler
use SymfonyComponentDomCrawlerCrawler;

// from an HTML string
$crawler = new Crawler(file_get_contents('http://www.google.com'));

// from a DomDocument object
$doc = new DOMDocument();
$doc->loadHTML(file_get_contents('http://www.google.com'));
$crawler = new Crawler($doc, 'http://www.google.com');

// from a DomNodeList object
$list = $doc->getElementsByTagName('ul');
$crawler = new Crawler($list);

// from a DomNode object
$logo = $doc->getElementById('logo');
$crawler = new Crawler($logo);
DomCrawler
Traverser un document
 /**
  * <div id="sidebar">
  *   <h2>Sidebar</h2>
  *   <ul>
  *     <li><a href="home.html">Home</a></li>
  *     <li><a href="about.html">About</a></li>
  *     <li>
  *        <a href="contact.html">Contact</a>
  *     </li>
  *   </ul>
  * </div>
  */

 $label = $crawler->filter('#sidebar ul li')->
     last()->children()->
     eq(0)->text();
DomCrawler
Traverser un document

/**
 * <div id="sidebar">
 *   <h2>Sidebar</h2>
 *   <ul>
 *     <li><a href="home.html">Home</a></li>
 *     <li><a href="about.html">About</a></li>
 *     <li>
 *        <a href="contact.html">Contact</a>
 *     </li>
 *   </ul>
 * </div>
 */

$links = $crawler->filter('#sidebar ul li a')->links();
The End…

               Questions ?

     http://joind.in/talk/view/2766

           hugo.hamon@sensio.com
                 @hhamon

More Related Content

Viewers also liked

Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantHugo Hamon
 
Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsHugo Hamon
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Designing for developers
Designing for developersDesigning for developers
Designing for developersKirsten Hunter
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Hugo Hamon
 
API 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceAPI 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceKirsten Hunter
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloudKirsten Hunter
 
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?Mark Heckler
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console componentHugo Hamon
 
Quantifying your-fitness
Quantifying your-fitnessQuantifying your-fitness
Quantifying your-fitnessKirsten Hunter
 
Api intensive - What they Are
Api intensive - What they AreApi intensive - What they Are
Api intensive - What they AreKirsten Hunter
 

Viewers also liked (20)

API First
API FirstAPI First
API First
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projects
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Facebook appsincloud
Facebook appsincloudFacebook appsincloud
Facebook appsincloud
 
Designing for developers
Designing for developersDesigning for developers
Designing for developers
 
Api 101
Api 101Api 101
Api 101
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)
 
Quantifying fitness
Quantifying fitnessQuantifying fitness
Quantifying fitness
 
API 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceAPI 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat Conference
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloud
 
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
 
Polyglot copy
Polyglot copyPolyglot copy
Polyglot copy
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
Quantifying your-fitness
Quantifying your-fitnessQuantifying your-fitness
Quantifying your-fitness
 
Api intensive - What they Are
Api intensive - What they AreApi intensive - What they Are
Api intensive - What they Are
 
Git store
Git storeGit store
Git store
 

More from Hugo Hamon

Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIHugo Hamon
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsHugo Hamon
 
Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyHugo Hamon
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2Hugo Hamon
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkHugo Hamon
 

More from Hugo Hamon (8)

Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CI
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
 
Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec Symfony
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
 

Symfony2 en pièces détachées

  • 1. Symfony2 en pièces détachées Symfony Live 2011 - 4 mars 2011 - Paris
  • 2. Hugo Hamon aka @hhamon ² Responsable des formations Sensio Labs ² Ancien membre du Bureau de l’AFUP ² Auteur d’ouvrage PHP / Symfony chez Eyrolles ² http://www.hugohamon.com
  • 3. Avant d’oublier… http://joind.in/talk/view/2766
  • 4. Quelques questions… Qui développe encore des applications sans framework ou bibliothèques ?
  • 5. Quelques questions… Qui réutilise des composants éprouvés ? Zend Framework, PEAR, EZ Components…
  • 7. Symfony2 est bâti autour d’une bibliothèque de composants indépendants
  • 8. Les composants §  BrowserKit §  HTTP Kernel §  ClassLoader §  Locale §  Console §  Process §  CSS Selector §  Routing §  Dependency Injection §  Security §  Dom Crawler §  Serializer §  Event Dispatcher §  Templating §  Finder §  Translation §  Form §  Validator §  HTTP Foundation §  YAML
  • 9. ClassLoader ClassLoader
  • 10. ClassLoader UniversalClassLoader
  • 11. ClassLoader UniversalClassLoader use SymfonyComponentClassLoaderUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__ .'/symfony/src', 'Doctrine' => __DIR__ .'/doctrine/lib', 'Zend' => __DIR__ .'/zend/library', )); ty ro perabili PHP 5.3 Inte d $loader->register(); standar
  • 12. ClassLoader UniversalClassLoader use SymfonyComponentClassLoaderUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Sensio' => array(__DIR__ .'/src', __DIR__.'/sensio-extra') 'Symfony' => __DIR__ .'/symfony/src', 'Doctrine' => __DIR__ .'/doctrine/lib', 'Zend' => __DIR__ .'/zend/library', )); $loader->register(); Fallback
  • 13. ClassLoader UniversalClassLoader use SymfonyComponentClassLoaderUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerPrefixes(array( 'Swift_' => __DIR__ .'/swiftmailer/lib/classes', 'Twig_' => __DIR__ .'/twig/lib/classes', )); $loader->register(); le P EAR sty
  • 14. HttpFoundation HttpFoundation
  • 15. HttpFoundation Request
  • 16. HttpFoundation Classe Dé nition Gestion des entêtes et paramètres GET, POST, Cookie, Request Server… Response Gestion des entêtes et contenu de la réponse Session Gestion de la session PHP Cookie Génère un nouveau cookie File Gestion des chiers
  • 17. HttpFoundation Request require_once __DIR__ .'/../src/autoload.php'; use SymfonyComponentHttpFoundationRequest; $request = Request::createFromGlobals(); $name = $request->query->get('name'); // Get query string variable $name = $request->request->get('name'); // Get post variable $name = $request->cookies->get('name'); // Get cookie value $file = $request->files->get('avatar'); // Get uploaded file $method = $request->getMethod(); // Get the request method $ip = $request->getClientIp(); // Get remote address $https = $request->isSecure(); // True if HTTPS $ajax = $request->isXmlHttpRequest(); // True if ajax request
  • 18. HttpFoundation Session
  • 19. HttpFoundation Session §  Lecture et écriture de variables de session §  Lecture et écriture de messages ash §  Invalidation et nettoyage de la session §  Choix du moteur de stockage § ArraySessionStorage : session non persistente § NativeSessionStorage : session PHP native § PdoSessionStorage : session en base de données
  • 20. HttpFoundation Session native de PHP use SymfonyComponentHttpFoundationSession; use SymfonyComponentHttpFoundationSessionStorageNativeSessionStorage; $session = new Session(new NativeSessionStorage()); $session->start(); // Read the session id $id = $session->getId(); // Set a session variable $session->set('username', 'hhamon'); // Set a flash message $session->setFlash('notice', 'You win!');
  • 21. HttpFoundation Session native de PHP use SymfonyComponentHttpFoundationSession; use SymfonyComponentHttpFoundationSessionStorageNativeSessionStorage; $session = new Session(new NativeSessionStorage()); $session->start(); // Read the session variable echo $session->get('username'); // Read a flash message if ($session->hasFlash('notice')) { echo $session->getFlash('notice'); } // Remove a session variable $session->remove('username'); $session->clear();
  • 22. HttpFoundation Session en base de données §  Utilisation des objets PdoSessionStorage et PDO require_once __DIR__ .'/../src/autoload.php'; use SymfonyComponentHttpFoundationSession; use SymfonyComponentHttpFoundationSessionStoragePdoSessionStorage; $pdo = new PDO('mysql:host=localhost;dbname=sflive2011', 'root', '', array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )); $storage = new PdoSessionStorage($pdo, array('db_table' => 'php_session')); $session = new Session($storage, array('default_locale' => 'fr')); $session->start(); $session->set('username', 'hhamon');
  • 23. HttpFoundation Session en base de données §  Création de la table dans la base de données CREATE TABLE `php_session` ( `sess_id` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `sess_data` text COLLATE utf8_unicode_ci, `sess_time` INTEGER(10) UNSIGNED NOT NULL, PRIMARY KEY (`sess_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; §  Contrôle des données de session dans la table
  • 24. HttpFoundation Response
  • 25. HttpFoundation Response §  Support des entêtes HTTP §  Content-Type §  Status-Code §  Support du cache HTTP §  Expires §  Etag §  Cache-Control (max-age, s-maxage…) §  Support des cookies
  • 26. HttpFoundation Response - Headers use SymfonyComponentHttpFoundationResponse; $response = Response('<html>...</html>', 200); $response->headers->set('Content-Type', 'text/html; charset=utf-8'); $response->setEtag('article-1337'); $response->setSharedMaxAge(3600); $response->send(); HTTP/1.0 200 OK cache-control: s-maxage=3600 content-type: text/html; charset=utf-8 etag: "article-1337" <html>...</html>
  • 27. HttpFoundation Cookie
  • 28. HttpFoundation Response - Cookie require_once __DIR__ .'/../src/autoload.php'; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentHttpFoundationCookie; $cookie = new Cookie('last-viewed', '1337', time()+3600*24); $response = new Response('<html>...</html>', 200); $response->headers->setCookie($cookie); $response->send(); HTTP/1.0 200 OK content-type: text/html; charset=utf-8 set-cookie: last-viewed=1337; expires=Mon, 10-Jan-2011 00:52:24 GMT; path=/; httponly <html>...</html>
  • 30. HttpFoundation Fichiers et uploads use SymfonyComponentHttpFoundationFileFile; // Set the document root File::setDocumentRoot(__DIR__); $file = new File(__DIR__.'/../tmp/avatar.png'); // Change the file location & rename it on the fly $file->move(__DIR__.'/images', 'hhamon.png'); $ext = $file->getExtension(); // Get the file extension $size = $file->getMimeType(); // Get the file type $path = $file->getPath(); // Get the file path echo '<img src="', $file->getWebPath() ,'" alt="" />';
  • 31. HttpFoundation Fichier et uploads §  Uploader un chier avec Request et UploadedFile require __DIR__ .'/../src/autoload.php'; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationFileUploadedFile; $request = Request::createFromGlobals(); $avatar = $request->files->get('avatar'); if ($avatar instanceOf UploadedFile && UPLOAD_ERR_OK == $avatar->getError()) { $avatar->move(__DIR__.'/images'); } <form action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="avatar"/> <button type="submit">upload</button> </form>
  • 32. Event Dispatcher Event Dispatcher
  • 33. Event Dispatcher Introduction §  Implémentation du pattern « Observateur » §  2 classes et 2 interfaces §  Faciliter le découplage entre les classes §  Améliorer la exibilité / réutilisabilité du code §  Simpli er l’intégration de plugins tiers
  • 34. Event Dispatcher La classe EventDispatcher §  Connecte des écouteurs (« callables ») à des événements $dispatcher = new EventDispatcher(); $dispatcher->connect('the.event.name', $callable); §  Les sujets « noti ent » des événements aux écouteurs class Subject { public $dispatcher; public function doThings() { $event = new Event($this, 'the.event.name'); $this->dispatcher->notify($event); } }
  • 35. Event Dispatcher « Forcer le nettoyage d’un cache lorsque certains événements se produisent »
  • 36. Event Dispatcher Vider un cache class WikiPage { public $id; public $title; public $content; public function save(PDO $conn) { if (!$this->id) { $conn->query('INSERT INTO ...'); } else { $conn->exec('UPDATE ...'); } } En cas de modi cation, la page html } statique du cache doit être régénérée…
  • 37. namespace MyDomain; use SymfonyComponentEventDispatcherEventDispatcher; use SymfonyComponentEventDispatcherEvent; class WikiPage { // ... private $dispatcher; public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function save(PDO $conn) { if (!$this->id) { Un événement est noti é pour // ... demander aux écouteurs de } else { vider le cache de l’objet. $conn->exec('UPDATE ...'); $args = array('type' => 'wiki', 'id' => $this->id); $event = new Event($this, 'cache.flush', $args); $this->dispatcher->notify($event); } } }
  • 38. namespace MyCache; use SymfonyComponentEventDispatcherEvent; class CacheManager { private $cacheDir; public function __construct($cacheDir) { $this->cacheDir = $cacheDir; Ecouteur invoqué à la } noti cation de l’événement. public function listenToCacheFlushEvent(Event $event) { // The WikiPage object $object = $event->getSubject(); // Retrieve all extra arguments $args = $event->all(); $path = $this->cacheDir .'/'. $args['type'] .'/'. $args['id'] .'.html'; if (file_exists($path)) { @unlink($path); } } }
  • 39. use SymfonyComponentEventDispatcherEventDispatcher; use MyDomainWikiPage; use MyCacheCacheManager; $pdo = new PDO('...'); $cache = new CacheManager('/path/to/cache'); # Register a new listener. $dispatcher = new EventDispatcher(); $dispatcher->connect('cache.flush', array($cache, 'listenToCacheFlushEvent')); # Find the wiki page object with its id. $page = WikiPage::findById($_GET['id']); $page->setEventDispatcher($dispatcher); # Page properties are edited. $page->title = 'New title'; $page->content = 'New content'; # The CacheManager::listenToCacheFlushEvent method is called. $page->save($pdo);
  • 40. Event Dispatcher « Filtrer / transformer une valeur »
  • 41. Event Dispatcher Filtrer une donnée class WikiPage { private $rawContent; private $parsedContent; public function setRawContent($rawContent) { $this->rawContent = $rawContent; $parser = new WikiParser(); $this->parsedContent = $parser->parse($rawContent); } }
  • 42. Event Dispatcher Problème ? §  Les objets « WikiPage » et « WikiParser » sont fortement couplés §  Changer le parser implique de modi er la classe « WikiPage » §  Idem, si l’on veut ajouter des ltres supplémentaires §  Testabilité du code réduite due à la dépendance
  • 43. Event Dispatcher Solution? §  Filtrer la valeur en appelant une série de ltres (« écouteurs »). class WikiPage { private $rawContent; private $parsedContent; public function setRawContent($rawContent) { $$this->rawContent = $rawContent; $event = new Event('wiki.filter_content', $rawContent); $this->parsedContent = $this->dispatcher->filter($event); } }
  • 44. use SymfonyComponentEventDispatcherEventDispatcher; use MyDomainWikiPage; use MyFilterWikiSyntaxParser; $dispatcher = new EventDispatcher(); # Register a first filter $dispatcher->connect('wiki.filter_content', function(Event $e, $value) { return striptags($value, '<code>') }); $wikiParser = new WikiSyntaxParser(); # Register a second filter $dispatcher->connect('wiki.filter_content', array($wikiParser, 'parse')); $wikiPage = new WikiPage(); $wikiPage->setEventDispatcher($dispatcher); # Set and filter the raw content value $wiki->setRawContent('Some **wiki** content with <script>alert("foo")</script> <code>$c = $a + $b</code>.');
  • 45. Event Dispatcher Filtrer une valeur §  La propriété « parsedContent » aura la valeur suivante. Some <strong>wiki</strong> content with <code>$c = $a + $b</code>. §  La balise <script> a été ltrée §  La balise <code> a été conservée §  La syntaxe Wiki a été transformée en HTML
  • 46. Dependency Injection Dependency Injection
  • 47. Dependency Injection Introduction §  « Inversion de contrôle » §  Composant au cœur de Symfony2 §  Instanciation et initialisation de services à la demande §  Supporte les dépendances entre les différents services §  Dé nition des services en PHP, XML ou YAML
  • 48. Dependency Injection Dé nition d’un service SOAP # config/services.xml <?xml version="1.0" ?> <container xmlns="http://www.symfony-project.org/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http:// www.symfony-project.org/schema/dic/services/services-1.0.xsd"> <parameters> <parameter key="soap_server.wsdl.uri"> http://www.components.local/soap-server.php?wsdl </parameter> <parameter key="soap_server.response.return">true</parameter> <parameter key="soap_server.options.encoding">utf-8</parameter> <parameter key="calculator_service.class">ApplicationCalculator</parameter> </parameters> <services> <!-- ... --> Paramètres  de  configura1on  des  services.   </services> </container>
  • 49. Dependency Injection Dé nition d’un service SOAP <?xml version="1.0" ?> <container ... > <!-- ... --> <services> <!-- SOAP Server --> Défini1on  d’un  serveur  Zend   <service id="soap_server" class="ZendSoapServer"> <argument>%soap_server.wsdl.uri%</argument> Soap  comme  étant  un  service   <argument type="collection"> <argument key="encoding">%soap_server.options.encoding%</argument> </argument> <call method="setReturnResponse"> <argument>%soap_server.response.return%</argument> </call> <call method="setObject"><argument type="service" id="calculator_service" /></call> </service> <!-- SOAP Autodiscovery --> <service id="soap_autodiscover" class="ZendSoapAutodiscover"> <call method="setClass"><argument type="string">%calculator_service.class%</argument></call> </service> <!-- Calculator service used by the SOAP server --> <service id="calculator_service" class="%calculator_service.class%"/> </services> </container>
  • 50. Dependency Injection Dé nition d’un service SOAP <!-- Identification du service : identifiant + type --> <service id="soap_server" class="ZendSoapServer"> <!-- 1er argument du constructeur : valeur d’un paramètre défini précédemment --> <argument>%soap_server.wsdl.uri%</argument> <!-- 2nd argument du constructeur : tableau associatif d’options --> <argument type="collection"> <argument key="encoding">utf-8</argument> </argument> <!– 1ère méthode à appeler juste après l’instanciation du service --> <call method="setReturnResponse"> <argument>true</argument> </call> <!– 2nd méthode à appeler avec une instance du service calculator_service en argument --> <call method="setObject"> <argument type="service" id="calculator_service" /> </call> </service>
  • 51. Dependency Injection Dé nition du service Calculator namespace Application; class Calculator { /** Documenta1on  avec  de  la  PHPDoc  afin  de   * Returns the sum of two numbers. générer  le  WSDL  correspondant  grâce  à   * Zend_Soap_Autodiscover   * @param float $a The first operand * @param float $b The second operand * @return float The result * @throws SoapFault */ public function sum($a, $b) { if (!is_numeric($a) || !is_numeric($b)) { throw new SoapFault('The sum() operation only accepts numeric arguments.'); } return $a + $b; } }
  • 52. Dependency Injection Obtenir le conteneur de services # web/soap-server.php use SymfonyComponentConfigContainerBuilder; use SymfonyComponentDependencyInjectionContainerBuilder; use SymfonyComponentDependencyInjectionParameterBagParameterBag; use SymfonyComponentDependencyInjectionLoaderXmlFileLoader; $container = new ContainerBuilder(new ParameterBag()); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../config')); $loader->load('services.xml'); Lecture  du  fichier  services.xml  et   if (isset($_GET['wsdl'])) { $autodiscover = $container->get('soap_autodiscover'); chargement  de  la  défini1on  dans  le   $response = $autodiscover->toXml(); conteneur  d’injec1on  de  dépendances   } else { $soapServer = $container->get('soap_server'); $response = $soapServer->handle(); } Récupéra1on  du  serveur  SOAP  Zend   header('Content-Type: text/xml'); correctement  instancié  et  ini1alisé.   echo $response;
  • 53. Finder Finder
  • 54. Finder Rechercher des chiers §  Rechercher des chiers dans une arborescence §  Filtres sur des critères §  Type ( chiers ou répertoires) §  Nom et extension (patterns) §  Taille §  Date §  … §  Tri les résultats sur des attributs de chiers
  • 55. Finder Rechercher des chiers use SymfonyComponentFinderFinder; $finder = new Finder(); // All files in the current folder $files = $finder->files()->in(__DIR__); // All directories in the current folder $files = $finder->directories()->in(__DIR__); // All PHP files in the current folder only $files = $finder->files()->name('/.php$/')->depth(0)->in(__DIR__); // All files whose size is between 1K and 2K inclusive $files = $finder->files()->size('>= 1K')->size('<= 2K')->in(__DIR__);
  • 56. Finder Rechercher des chiers // Search files in several folders $files = $finder->files()->in(array(__DIR__, __DIR__.'/../src')); // Sort file by name $files = $finder->files()->name('/.php$/')->in(__DIR__)->sortByName(); // Sort files by type $files = $finder->files()->name('/.php$/')->in(__DIR__)->sortByType(); // Filter by date $files = $finder->files()->name('/.(png|jpg|jpeg|gif)$/i')-> date('>= 2011-01-09')-> date('<= 2011-02-03')->in(__DIR__); $files = $finder->files()->name('/.(png|jpg|jpeg|gif)$/i')-> date('since 2011-01-09')-> date('before 2011-02-03')->in(__DIR__);
  • 57. Finder Filtres personnalisés # Create a lambda function that acts as a filter. $onlyWritableFiles = function(SplFileInfo $file) { return $file->isWritable(); }; Un ltre personnalisé est une fonction anonyme qui reçoit une instance de # Find writeable TXT files $finder = new Finder(); SplFileInfo et retourne une valeur booléenne. $files = $finder->files()-> name('/.txt$/')-> filter($onlyWritableFiles)-> in(__DIR__.'/../cache'); foreach (iterator_to_array($files) as $path => $file) { echo $file->getFilename(); }
  • 58. Templating Templating
  • 59. Templating Introduction §  Système de templating simple et efficace §  Supporte des moteurs de stockage différents §  Fichiers §  Chaînes de caractères §  Supporte des fonctionnalités « modernes » §  Héritage de templates §  Slots §  Aide de vue (« helpers ») §  Extensible
  • 60. Templating Génération d’un template simple §  Chargement et rendu d’un template simple require_once __DIR__ .'/../src/autoload.php'; use SymfonyComponentTemplatingPhpEngine; use SymfonyComponentTemplatingTemplateNameParser; use SymfonyComponentTemplatingLoaderFilesystemLoader; $loader = new FilesystemLoader(array( __DIR__.'/../src/tpl/%name%.php', Mo1fs  de  chemins  de   __DIR__.'/../src/tpl/hello/%name%.php', fichiers  de  templates   )); $engine = new PhpEngine(new TemplateNameParser(), $loader); echo $engine->render('index', array('name' => 'Hugo')); Variables  du  template  
  • 61. Templating Génération d’un template simple §  La variable $view correspond à l’objet $engine précédent. # src/tpl/index.php <p> Hello <?php echo $view->escape($name) ?>! </p> §  L’échappement des variables est assuré par la méthode escape() de l’objet $view.
  • 62. Templating Génération d’un template avancé use SymfonyComponentTemplatingPhpEngine; use SymfonyComponentTemplatingTemplateNameParser; use SymfonyComponentTemplatingLoaderFilesystemLoader; use SymfonyComponentTemplatingHelperSlotsHelper; $loader = new FilesystemLoader(array( Support des aides de vue et __DIR__.'/../src/tpl/%name%.php', __DIR__.'/../src/tpl/hello/%name%.php', de l’héritage de templates. )); $engine = new PhpEngine(new TemplateNameParser(), $loader, array( new SlotsHelper() )); $content = $engine->render('index', array('name' => 'Hugo')); echo $content;
  • 63. Templating Génération d’un template avancé # src/tpl/index.php Extension du template de base <?php $view->extend('layout') ?> <?php $view['slots']->set('title', 'Hello Application') ?> <p> Hello <?php echo $view->escape($name) ?>! Dé nition de la valeur d’un slot </p> # src/tpl/layout.php <html> <head> <title> <?php $view['slots']->output('title', 'Templating component') ?> </title> </head> <body> <h1>Welcome!</h1> Affichage du slot ou une valeur par <?php $view['slots']->output('_content') ?> défaut si non dé ni </body> </html> Contenu évalué de index.php
  • 64. Templating Génération d’un template avancé §  Le rendu nal est le suivant : <!DOCTYPE html> <html> <head> <title>Hello Application</title> </head> <body> <h1>Welcome!</h1> <p> Hello Hugo! </p> </body> </html>
  • 65. Translation Translation
  • 66. Translation Introduction §  Gestionnaire de dictionnaires de traduction §  Supporte différents formats de stockage §  Array §  PHP §  YAML §  XLIFF §  CSV §  Supporte les chaînes dynamiques §  Embarque des algorithmes de pluralisation
  • 67. Translation Dé nition d’un dictionnaire XLIFF # i18n/fr/messages.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/ committees/xliff/documents/xliff.dtd"> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="messages.xml"> <header/> <body> <trans-unit id="1"> <source>Hello</source> <target>Salut</target> </trans-unit> <trans-unit id="2"> <source>Hello %name%</source> <target>Bonjour %name%</target> </trans-unit> </body> </file> </xliff>
  • 68. Translation Traduire des chaînes d’un catalogue require __DIR__ .'/../src/autoload.php'; use SymfonyComponentTranslationTranslator; use SymfonyComponentTranslationMessageSelector; use SymfonyComponentTranslationLoaderXliffFileLoader; // Création d’un objet Translator $translator = new Translator('fr', new MessageSelector()); // Chargement du dictionnaire XLIFF $translator->addLoader('xliff', new XliffFileLoader()); $translator->addResource('xliff', __DIR__.'/../i18n/fr/messages.xml', 'fr'); // Returns "Salut" echo $translator->trans('Hello'); // Returns "Bonjour Hugo" echo $translator->trans('Hello %name%', array('%name%' => 'Hugo'));
  • 69. Translation Utiliser une locale par défaut §  Dé nition d’un second dictionnaire pour l’allemand # i18n/de/messages.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/ committees/xliff/documents/xliff.dtd"> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="messages.xml"> <header/> <body> <trans-unit id="1"> <source>Welcome in %city%</source> <target>Wilkommen in %city%</target> </trans-unit> </body> </file> </xliff>
  • 70. Translation Utiliser une locale par défaut §  Le gestionnaire de traduction peut charger plusieurs catalogues de traduction et forcer une locale par défaut. $trans = new Translator('fr', new MessageSelector()); $trans->addLoader('xliff', new XliffFileLoader()); // Load two distinct dictionaries $trans->addResource('xliff', __DIR__.'/../i18n/de/messages.xml', 'de'); $trans->addResource('xliff', __DIR__.'/../i18n/fr/messages.xml', 'fr'); // Set the default fallback locale $trans->setFallbackLocale('de'); // Translation only exists in german catalog even if the locale is fr echo $trans->trans('Welcome in %city%', array('%city%' => 'Paris'));
  • 71. Translation Pluralisation des chaînes # i18n/fr/messages.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/ committees/xliff/documents/xliff.dtd"> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="messages.xml"> <header/> <body> <!-- ... --> <trans-unit id="3"> <source>{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples</source> <target>{0} Il n'y a pas de pomme|{1} Il y a une pomme|]1,Inf] Il y a %count% pommes</target> </trans-unit> </body> </file> </xliff>
  • 72. Translation Pluralisation des chaînes §  La méthode transChoice() facilite la pluralisation des chaînes $count = 5; $translator = new Translator('fr', new MessageSelector()); $translator->addLoader('xliff', new XliffFileLoader()); $translator->addResource('xliff', __DIR__.'/../i18n/fr/messages.xml', 'fr'); // Returns "Il y a <strong>5</strong> pommes" echo $translator->transChoice( '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples', $count, array('%count%' => '<strong>' . $count . '</strong>') );
  • 73. Locale Locale
  • 74. Locale Introduction §  Surcharge la classe Locale de PHP 5.3 §  Supporte les formatages des noms de pays §  Supporte les formatages des noms de langues §  L’API se compose uniquement de méthodes statiques
  • 75. Locale Obtenir la listes des pays use SymfonyComponentLocaleLocale; print_r(Locale::getDisplayCountries('fr')); print_r(Locale::getDisplayCountries('en')); print_r(Locale::getDisplayCountries('de')); §  Les pays sont retournés dans des tableaux associatifs triés sur les valeurs Array Array Array ( ( ( [AF] => Afghanistan [AF] => Afghanistan [AF] => Afghanistan [ZA] => Afrique du Sud [AL] => Albania [AL] => Albanien [AL] => Albanie [ZA] => South Africa [ZA] => Südafrika ... ... ... ) ) )
  • 76. Locale Codes ISO des pays use SymfonyComponentLocaleLocale; print_r(Locale::getCountries()); Array ( [0] => AF [1] => AX [2] => AL [3] => DZ [4] => AS [5] => AD [6] => AO [7] => AI [8] => AQ [9] => AG [10] => AR [11] => AM [12] => AW [13] => AC [14] => AU [15] => AT [16] => AZ [17] => BS [18] => BH [19] => BD [20] => BB [21] => BY [22] => BE [23] => BZ [24] => BJ [25] => BM [26] => BT [27] => BO [28] => BA [29] => BW [30] => BV [31] => BR [32] => IO [33] => VG [34] => BN [35] => BG [36] => BF [37] => BI [38] => KH [39] => CM [40] => CA [41] => IC [42] => CV [43] => KY [44] => CF [45] => EA [46] => TD [47] => CL [48] => CN [49] => CX [50] => CP [51] => CC [52] => CO [53] => KM [54] => CG [55] => CD [56] => CK [57] => CR [58] => CI [59] => HR [60] => CU [61] => CY [62] => CZ [63] => DK [64] => DG [65] => DJ [66] => DM [67] => DO [68] => EC [69] => EG [70] => SV [71] => GQ [72] => ER [73] => EE ...)
  • 77. Locale Obtenir la listes des locales use SymfonyComponentLocaleLocale; print_r(Locale::getDisplayLocales('fr')); print_r(Locale::getDisplayLocales('en')); §  Les locales sont retournées dans des tableaux associatifs triés sur les valeurs Array Array ( ( [fr_BE] => français (Belgique) [fr_BE] => French (Belgium) [fr_CA] => français (Canada) [fr_CA] => French (Canada) [fr_DJ] => français (Djibouti) [fr_DJ] => French (Djibouti) [fr_LU] => français (Luxembourg) [fr_LU] => French (Luxembourg) [fr_CH] => français (Suisse) [fr_CH] => French (Switzerland) ... ... ) )
  • 78. Locale Codes ISO des locales use SymfonyComponentLocaleLocale; print_r(Locale::getLocales()); Array ( [0] => af [1] => af_NA [2] => ak [3] => sq [4] => am [5] => am_ET [6] => ar [7] => ar_DZ [8] => ar_BH [9] => ar_EG [10] => ar_IQ [11] => ar_JO [12] => ar_KW [13] => ar_LB [14] => ar_LY [15] => ar_MA [16] => ar_OM [17] => ar_QA [18] => ar_SA [19] => ar_SD [20] => ar_SY [21] => ar_TN [22] => ar_AE [23] => ar_YE [24] => hy [25] => as [26] => as_IN [27] => asa [28] => az [29] => az_Cyrl [30] => az_Cyrl_AZ [31] => az_Latn [32] => az_Latn_AZ [33] => bm [34] => eu [35] => be [36] => bem [37] => bez [38] => bn [39] => bn_IN [40] => bs [41] => bg [42] => my [43] => my_MM [44] => ca [45] => tzm [46] => tzm_Latn [47] => tzm_Latn_MA [48] => chr [49] => chr_US [50] => cgg [51] => zh [52] => kw [53] => hr [54] => cs [55] => da [56] => nl [57] => nl_BE [58] => ebu [59] => ebu_KE [60] => en [61] => en_AS [62] => en_AU [63] => en_BE [64] => en_BZ [65] => en_BW [66] => en_CA [67] => en_GU [68] => en_HK [69] => en_IN ...)
  • 79. Locale Obtenir la listes des langues use SymfonyComponentLocaleLocale; print_r(Locale::getDisplayLanguages('fr')); print_r(Locale::getDisplayLanguages('en')); §  Les langues sont retournées dans des tableaux associatifs triés sur les valeurs Array Array ( ( [en] => anglais [en] => English [en_US] => anglais américain [en_AU] => Australian English [en_AU] => anglais australien [en_GB] => British English [en_GB] => anglais britannique [en_CA] => Canadian English [en_CA] => anglais canadien [en_US] => U.S. English ... ... ) )
  • 80. Locale Codes ISO des langues use SymfonyComponentLocaleLocale; print_r(Locale::getLanguages()); Array ( [0] => ab [1] => ace [2] => ach [3] => ada [4] => ady [5] => aa [6] => afh [7] => af [8] => afa [9] => ain [10] => ak [11] => akk [12] => sq [13] => ale [14] => alg [15] => tut [16] => am [17] => egy [18] => grc [19] => anp [20] => apa [21] => ar [22] => an [23] => arc [24] => arp [25] => arn [26] => arw [27] => hy [28] => rup [29] => art [30] => as [31] => ast [32] => asa [33] => ath [34] => cch [35] => en_AU [36] => aus [37] => de_AT [38] => map [39] => av [40] => ae [41] => awa [42] => ay [43] => az [44] => ban [45] => bat [46] => bal [47] => bm [48] => bai [49] => bad [50] => bnt [51] => bas [52] => ba [53] => eu [54] => btk [55] => bej [56] => be [57] => bem [58] => bez [59] => bn [60] => ber [61] => bho [62] => bh [63] => bik [64] => bin [65] => bi [66] => byn [67] => zbl [68] => brx [69] => bs [70] => bra [71] => pt_BR [72] => br [73] => en_GB [74] => bug [75] => bg [76] => bua [77] => my [78] => cad [79] => en_CA [80] => fr_CA [81] => yue [82] => car [83] ...)
  • 81. Console Console
  • 82. Console Introduction §  Automatiser des tâches pénibles (génération de code…) §  Exécuter des tâches qui prennent du temps §  Béné cier des ressources du serveur §  Plani er des tâches dans une crontab
  • 83. Console Introduction §  Arguments et options §  Codes de sortie §  Shell §  Coloration de la sortie §  Testabilité §  Messages d’erreur §  …
  • 84. Console Amorcer le CLI §  Création d’un chier « console.php » exécutable (chmod +x) #!/usr/bin/php <?php require __DIR__ .'/src/autoload.php'; use SymfonyComponentConsoleApplication; $application = new Application('Console', '1.0'); $application->run();  
  • 86. namespace ApplicationCommand; use SymfonyComponentConsoleCommandCommand; use SymfonyComponentConsoleInputInputArgument; use SymfonyComponentConsoleInputInputOption; use SymfonyComponentConsoleInputInputInterface; use SymfonyComponentConsoleOutputOutputInterface; use ApplicationServiceGoogleWeather; class WeatherCommand extends Command { Dé nition des meta données de la commande : protected function configure() nom, manuel, arguments, options… { $this-> addArgument('city', InputArgument::REQUIRED, 'The city')-> addOption('lang', null, InputOption::VALUE_REQUIRED, 'The lang', 'en')-> setName('google:weather')-> setDescription('Fetches weather information.')-> setHelp(<<<EOF The <info>google:weather</info> command fetches weather data for a given city: <info>google:weather paris --lang fr</info> EOF ); }}
  • 87. Console Dé nir la logique de la commande $input : arguments + options $output : sortie de la console class WeatherCommand extends Command { # ... protected function execute(InputInterface $input, OutputInterface $output) { $city = $input->getArgument('city'); $lang = $input->getOption('lang'); $weather = new GoogleWeather($city, $lang); $output->writeln(sprintf('<info>City</info>: %s', $weather->getCity())); $output->writeln(sprintf('<info>Temperature</info>: %s', $weather->getTemperature())); $output->writeln(sprintf('<info>Latitude</info>: %s', $weather->getLatitude())); $output->writeln(sprintf('<info>Longitude</info>: %s', $weather->getLongitude())); $output->writeln(sprintf('<info>Condition</info>: %s', $weather->getCondition())); $output->writeln(sprintf('<info>Wind</info>: %s', $weather->getWindCondition())); } }
  • 88. Console Enregistrer la commande #!/usr/bin/php <?php require __DIR__ .'/src/autoload.php'; use SymfonyComponentConsoleApplication; use ApplicationCommandWeatherCommand; $application = new Application('Console', '1.0'); $application->add(new WeatherCommand()); $application->run();  
  • 89. Console Consulter la liste des commandes
  • 90. Console Obtenir de l’aide de la commande ./console help google:weather  
  • 91. Console Exécuter la commande ./console google:weather Berlin --lang fr  
  • 92. Process Process
  • 93. Process Introduction §  Exécuter des lignes de commande depuis un script PHP §  Récupérer la sortie générée par la console §  Récupérer le statut de l’exécution de la console
  • 94. Process Mise en oeuvre use SymfonyComponentProcessProcess; $process = new Process('ls -lah', __DIR__); $process->run(); if (!$process->isSuccessful()) { $output = $process->getErrorOutput(); } else { $output = $process->getOutput(); } echo $output;
  • 95. Process Mise en oeuvre total 176 drwxr-xr-x 25 Hugo staff 850B Feb 23 22:53 . drwxr-xr-x 9 Hugo staff 306B Feb 13 19:39 .. -rw-r--r--@ 1 Hugo staff 607B Feb 19 12:48 crawler.php -rw-r--r--@ 1 Hugo staff 1.9K Feb 13 12:08 event-dispatcher.php -rw-r--r--@ 1 Hugo staff 914B Feb 13 13:43 event-dispatcher2.php -rw-r--r--@ 1 Hugo staff 678B Jan 31 21:55 file.php -rw-r--r--@ 1 Hugo staff 1.7K Feb 12 14:40 finder.php drwxrwxrwx 3 Hugo staff 102B Jan 31 21:55 images -rw-r--r--@ 1 Hugo staff 276B Jan 9 23:39 locale.php -rw-r--r--@ 1 Hugo staff 454B Feb 23 22:53 process.php -rw-r--r--@ 1 Hugo staff 746B Jan 31 22:26 read-request.php -rw-r--r--@ 1 Hugo staff 545B Jan 31 22:41 response.php -rw-r--r--@ 1 Hugo staff 1.3K Feb 9 23:58 routing.php -rw-r--r--@ 1 Hugo staff 718B Feb 1 23:38 serializer.php -rw-r--r--@ 1 Hugo staff 502B Jan 9 00:37 session1.php -rw-r--r--@ 1 Hugo staff 682B Jan 9 00:37 session2.php -rw-r--r--@ 1 Hugo staff 520B Jan 9 01:15 session3.php -rw-r--r--@ 1 Hugo staff 241B Feb 6 11:28 soap-client.php -rw-r--r--@ 1 Hugo staff 737B Feb 19 10:45 soap-server.php -rw-r--r--@ 1 Hugo staff 558B Feb 19 10:56 templating-advanced.php -rw-r--r--@ 1 Hugo staff 476B Feb 19 10:56 templating-basic.php
  • 96. PhpProcess Exécuter un script PHP use SymfonyComponentProcessPhpProcess; $process = new PhpProcess('<?php echo "Hello World!" ?>'); $process->run(); if (!$process->isSuccessful()) { $output = $process->getErrorOutput(); } else { $output = $process->getOutput(); } echo $output;
  • 97. Serializer Serializer
  • 98. Serializer Introduction Le composant « Serializer » convertit des objets PHP en représentations XML ou JSON par introspection.
  • 100. Serializer Architecture §  L’objet « Serializer » transforme un objet PHP en représentation XML (ou JSON) et inversement. §  Les objets « Normalizer » transforment un objet en tableau PHP. §  Les objets « Encoder » transforment un tableau PHP en représentations XML ou JSON.
  • 101. class Author { private $firstName; private $lastName; public function __construct($firstName, $lastName) { $this->firstName = $firstName; $this->lastName = $lastName; } public function getFirstName() { return $this->firstName; } public function getLastName() { return $this->lastName; } public function getFullName() { return $this->firstName .' '. $this->lastName; } }
  • 102. class Book { private $title; private $author; public function setTitle($title) { $this->title = $title; } public function getTitle() { return $this->title; } public function setAuthor(Author $author) { $this->author = $author; } public function getAuthor() { return $this->author; } }
  • 103. Serializer Sérialiser un objet en XML use SymfonyComponentSerializerSerializer; use SymfonyComponentSerializerEncoderXmlEncoder; use SymfonyComponentSerializerNormalizerGetSetMethodNormalizer; $serializer = new Serializer(); # Register the XML encoder $serializer->setEncoder('xml', new XmlEncoder()); # Register a getter / setter normalizer $serializer->addNormalizer(new GetSetMethodNormalizer()); $book = new Book(); $book->setAuthor(new Author('Agatha', 'Christie')); $book->setTitle('Ten Little Niggers'); header('Content-Type: text/xml; charset=utf-8'); echo $serializer->serialize($book, 'xml');
  • 105. Serializer Sérialiser un objet en JSON use SymfonyComponentSerializerSerializer; use SymfonyComponentSerializerEncoderJsonEncoder; use SymfonyComponentSerializerNormalizerGetSetMethodNormalizer; $serializer = new Serializer(); # Register the JSON encoder $serializer->setEncoder('json', new JsonEncoder()); # Register a getter / setter normalizer $serializer->addNormalizer(new GetSetMethodNormalizer()); $book = new Book(); $book->setAuthor(new Author('Agatha', 'Christie')); $book->setTitle('Ten Little Niggers'); header('Content-Type: application/json; charset=utf-8'); echo $serializer->serialize($book, 'json');
  • 106. Serializer Sérialiser un objet en JSON { "title":"Ten Little Niggers", "author": { "firstname":"Agatha", "lastname":"Christie", "fullname":"Agatha Christie" } }
  • 107. use SymfonyComponentSerializerSerializer; use SymfonyComponentSerializerEncoderJsonEncoder; use SymfonyComponentSerializerNormalizerGetSetMethodNormalizer; $serializer = new Serializer(); $serializer->setEncoder('json', new JsonEncoder()); $serializer->addNormalizer(new GetSetMethodNormalizer()); $jsonEncoded = '{ "title":"Ten Little Niggers", "author": { "firstname":"Agatha", "lastname":"Christie", "fullname":"Agatha Christie" } }'; header('Content-Type: text/plain; charset=utf-8'); print_r($serializer->decode($jsonEncoded, 'json'));
  • 108. Serializer Désérialiser un objet JSON Array ( [title] => Ten Little Niggers [author] => Array ( [firstname] => Agatha [lastname] => Christie [fullname] => Agatha Christie ) )
  • 109. YAML YAML
  • 110. YAML Introduction YAML signi e « Ain't Markup Language ». C’est un format standard de sérialisation de données pour tous les langages de programmation.
  • 111. YAML Parser un chier YAML parameters: # Twitter module twitter.timeline.cache: true twitter.auth.username: hhamon twitter.auth.password: s3cr3t # Blog module blog.post.max_per_page: 10 app: available_cultures: [fr, en, de] services: db_connection: class: PDO dsn: mysq:host=localhost;dbname=foo username: root password: ~
  • 112. YAML Parser un chier YAML §  La classe « Parser » transforme une chaîne YAML en un tableau associatif PHP. use SymfonyComponentYamlParser; $content = file_get_contents(__DIR__ . '/../config/config.yml'); $yaml = new Parser(); $result = $yaml->parse($content); echo '<pre>’; print_r($result); echo '</pre>';
  • 113. Array ( [parameters] => Array ( [twitter.timeline.cache] => 1 [twitter.auth.username] => hhamon [twitter.auth.password] => s3cr3t [blog.post.max_per_page] => 10 ) [app] => Array ( [available_cultures] => Array ( [0] => fr [1] => en [2] => de ) ) [services] => Array ( [db_connection] => Array ( [class] => PDO [dsn] => mysq:host=localhost;dbname=foo [username] => root [password] => ) ) )
  • 114. YAML Transformer un tableau en YAML §  La classe « Dumper » transforme un tableau PHP en YAML use SymfonyComponentYamlParser; use SymfonyComponentYamlDumper; $yaml = new Parser(); $result = $yaml->parse(file_get_contents(__DIR__ . '/../config/config.yml')); $result['parameters']['twitter.timeline.cache'] = false; $result['services']['db_connection']['class'] = 'PdoMock'; $dumper = new Dumper(); $data = $dumper->dump($result, 2); file_put_contents(__DIR__ . '/../config/config_test.yml', $data);
  • 115. YAML Transformer un tableau en YAML parameters: twitter.timeline.cache: false twitter.auth.username: hhamon twitter.auth.password: s3cr3t blog.post.max_per_page: 10 app: available_cultures: [fr, en, de] services: db_connection: { class: PdoMock, dsn: 'mysq:host=localhost;dbname=foo', username: root, password: null }
  • 116. CSS Selector CSS Selector
  • 117. CSS Selector CSS3 vers XPath use SymfonyComponentCssSelectorParser; $doc = new DOMDocument(); $doc->loadHTMLFile(__DIR__.'/../src/tpl/page.html'); $xpath = new DOMXPath($doc); $expr = Parser::cssToXpath('ul#menu > li a:contains("Home")'); $xpath->query($expr); foreach ($xpath->query($expr) as $link) { printf('%s > %s', $link->nodeValue, $link->getAttribute('href')); }
  • 118. CSS Selector CSS3 vers XPath Parser::cssToXpath('ul#menu > li a:contains("Home")'); descendant-or-self::ul[@id = 'menu']/li/descendant::a [contains(string(.), 'Home')]
  • 119. DomCrawler DomCrawler
  • 120. DomCrawler Introduction Le composant DomCrawler offre une API simple pour analyser un document SGML grâce au support intégral des sélecteurs CSS3 et XPath.
  • 121. DomCrawler Introduction §  Analyser et extraire des informations d’un document SGML §  Supporte différentes sources de données Ø Chaîne HTML ou XML Ø Objet DOMNode ou DOMNodeList Ø Objet DOMDocument §  Supporte les sélecteurs CSS3 et Xpath §  Crawler s’appuie sur le composant CssSelector
  • 122. DomCrawler Instancier un Crawler use SymfonyComponentDomCrawlerCrawler; // from an HTML string $crawler = new Crawler(file_get_contents('http://www.google.com')); // from a DomDocument object $doc = new DOMDocument(); $doc->loadHTML(file_get_contents('http://www.google.com')); $crawler = new Crawler($doc, 'http://www.google.com'); // from a DomNodeList object $list = $doc->getElementsByTagName('ul'); $crawler = new Crawler($list); // from a DomNode object $logo = $doc->getElementById('logo'); $crawler = new Crawler($logo);
  • 123. DomCrawler Traverser un document /** * <div id="sidebar"> * <h2>Sidebar</h2> * <ul> * <li><a href="home.html">Home</a></li> * <li><a href="about.html">About</a></li> * <li> * <a href="contact.html">Contact</a> * </li> * </ul> * </div> */ $label = $crawler->filter('#sidebar ul li')-> last()->children()-> eq(0)->text();
  • 124. DomCrawler Traverser un document /** * <div id="sidebar"> * <h2>Sidebar</h2> * <ul> * <li><a href="home.html">Home</a></li> * <li><a href="about.html">About</a></li> * <li> * <a href="contact.html">Contact</a> * </li> * </ul> * </div> */ $links = $crawler->filter('#sidebar ul li a')->links();
  • 125. The End… Questions ? http://joind.in/talk/view/2766 hugo.hamon@sensio.com @hhamon