Paradoxalement, Symfony2 n'est pas qu'un framework "full-stack". Il s'agit avant tout d'une parfaite synergie de briques logicielles autonomes qui travaillent de concert sous la baguette d'un seul chef d'orchestre : le conteneur d'injection de dépendances. Mais savez-vous que vous pouvez aussi les utiliser sans le framework ? Tous ces composants indépendants sont distribués sous licence MIT et offrent aux développeurs la liberté de les utiliser dans leurs projets PHP. Au cours de cette session, nous mettrons en lumière les fonctionnalités offertes par les principaux composants de Symfony2 tels que DependencyInjection, Console, Finder, EventDispatcher, Translation et bien d'autres encore. Vous découvrirez comment les intégrer et les utiliser dans vos projets PHP, et ainsi devenir le prochain Maestro du web.
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
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
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
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
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>
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);
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
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;
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();
}
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>
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>')
);
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)
... ...
) )
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] ...)
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
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();
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;
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
)
)
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.
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>';
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);
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);