These slides describe how symfony 1 and Symfony2 are RESTful frameworks, and ho to implement RESTful web services in both. The talk was given during Symfony Live 2011 Paris.
For more informations, please see http://symfpony-project.org/
RESTful avec symfony et Symfony2
Damien Alexandre, Xavier Lacot – 03 mars 2011
Symfony Day – 4. Juni 2009
Clever Age | Xavier Lacot
Clever Age
Création en 2001 à Paris par des managers expérimentés
Plusieurs agences en France :
Paris
Bordeaux
Lyon
Nantes
Valeurs fondatrices : Indépendance, Veille technologique,
Conviction
Quelques chiffres :
CA 2009 : 6 M€
Effectif au 01/03/2011 : 90 personnes
Notre Mission : « Concevoir des systèmes informatiques flexibles en
limitant la dépendance vis-à-vis des prestataires et des éditeurs »
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 2
Qui sommes nous ?
Damien :
Spécialiste Web full stack
Plusieurs contributions, notamment à symfony
Expert technique PHP chez Clever Age
Éleveur de poneys
http://twitter.com/damienalexandre
Xavier :
Expert Frameworks, développeur symfony depuis fin 2005
Plusieurs contributions (plugins, doc, patches, etc.)
Leader PHP chez Clever Age + en charge du pôle d'expertise
Vice-président de l'AFUP
http://twitter.com/xavierlacot
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 3
Sommaire
2 ou 3 rappels sur REST
symfony, un framework RESTFul
Et dans Symfony2 ?
howto
benchmarks
Autour de Symfony – Plugins et Bundles
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 4
2 ou 3 rappels sur REST
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 5
2 ou 3 rappels sur REST
Développement d'APIs : de nombreux cas d'utilisation :
favoriser l'interopérabilité
contextes répartis
plusieurs applications différentes
plusieurs langages
exposer un référentiel de données
exposer des données publiques (OpenData, etc.)
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 6
2 ou 3 rappels sur REST
Un service Web
Un fournisseur (le « service »)
Un agent (le « client »)
requête
client service
réponse
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 7
REST et SOAP sont sur un bateau
REST
Representational state transfer
exposition de ressources
"colle" à HTTP
simple et compréhensible
WS-*
SOAP + WSDL
approche plus standardisée
plus verbeux
moins adapté à la description de ressources
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 8
De l'utilisation d'HTTP avec REST
REST != HTTP
mais REST <3 HTTP :
les codes de réponse
les URL
les content-type
les méthodes
Roy Fielding
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 9
http://www.flickr.com/photos/bblfish/637617442/
De l'utilisation d'HTTP avec REST
Les verbes :
GET : Obtenir une ressource
POST + http content : Créer une ressource
PUT + http content : Modifier une ressource
DELETE : Supprimer une ressource
HEAD : Obtenir les headers d'une ressource
OPTIONS : Obtenir les méthodes acceptés
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 10
De l'utilisation d'HTTP avec REST
Les codes de succès :
200 : OK
201 : Créé
Les codes de redirection :
301 : Ressource déplacée
304 : Ressource non modifiée
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 11
De l'utilisation d'HTTP avec REST
Les codes d'erreur client :
400 : Bad Request
404 : Ressource introuvable
405 : Méthode non autorisé
406 : Non acceptable
418 : I'm a teapot
Les codes d'erreur serveur :
500 : Erreur générale
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 12
De l'utilisation d'HTTP avec REST
L'URL
Uniform Resource Locator
http://domaine.tld/ressource/id : Désigne une ressource
http://domaine.tld/ressource : Désigne toutes les
ressources
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 13
symfony 1, un framework RESTful
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 14
Introducing Pony !
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 15
Ressource Pony
Pony Pony:
id integer columns:
name:
name string(255) type: string(255)
picture_url string(255) picture_url:
type: string(255)
description text description:
slug string(255) type: text
actAs:
Sluggable:
unique: true
fields: [name]
canUpdate: false
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 16
Ressource Pony
New forest => new-forest
Magic Pony => magic-pony
GET http://domain.tld/pony/new-forest.xml
ou
GET http://domain.tld/pony/8.xml
Le routing décide.
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 17
Le routing dans symfony 1
gérer le plan d'adressage d'une application symfony
jolies urls
obfuscation des technos employées
validation des paramètres passés
découpler les urls exposées de l'organisation interne du projet
routing.yml
plusieurs classes de routing
sfRequestRoute / sfPatternRoute / sfRouteCollection
sfDoctrineRoute / sfDoctrineRouteCollection
etc...
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 18
sfDoctrineRoute
routing.yml
pony_show:
url: /pony/:slug.:sf_format
param: { module: pony, action: show, sf_format: xml }
class: sfDoctrineRoute
options: { model: Pony, column: slug, type: object }
requirements: { sf_method: GET, sf_format: (xml|json|yml) }
actions.class.php
public function executeShow(sfWebRequest $request)
{
$pony = $this->getRoute()->getObject();
// etc.
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 19
Routing et format
sf_format est html par défaut
pony_show:
url: /pony/:slug.:sf_format
param: { module: pony, action: show, sf_format: xml }
class: sfDoctrineRoute
options: { model: Pony, column: slug, type: object }
requirements: { sf_method: GET, sf_format: (xml|json|yml) }
actions.class.php
public function executeShow(sfWebRequest $request)
{
$format = $request->getRequestFormat();
// etc.
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 20
Les formats
GET http://domain/pony/new-forest.xml
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<response>
<name><![CDATA[New Forest]]></name>
<picture_url>
<![CDATA[http://www.feracheval.com/nvxsite/newforest.jpg]]>
</picture_url>
<description>
<![CDATA[Le poney New-Forest...]]>
</description>
<slug><![CDATA[new-forest]]></slug>
</response>
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 21
Les formats
GET http://domain/pony/new-forest.json
{
"name": "New Forest",
"picture_url": "http://www.feracheval.com/nvxsite/newforest.jpg",
"description": "Le poney New-Forest...",
"slug": "new-forest"
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 22
Format et template
Le template utilisé change suivant sf_format :
html => showSuccess.php
xml => showSuccess.xml.php
json => showSuccess.json.php
Content-Type automatique pour les formats suivants :
txt, js, css, json, xml, rdf, atom.
Exemple :
GET http://domain/pony/connemara.json
Content-Type: application/json
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 23
Format et template
showSuccess.json.php
{
"name": <?php echo json_encode($pony->getName()) ?>,
"picture_url": <?php echo json_encode($pony->getPictureUrl(ESC_RAW)) ?>,
"description": <?php echo json_encode($pony->getDescription(ESC_RAW)) ?>,
"slug": <?php echo json_encode($pony->getSlug())."n" ?>
}
Bon courage pour les listes d'objets...
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 24
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 25
Format sans template
Sans template, on spécifie le Content-Type à la main :
$format = $request->getRequestFormat();
$this->getResponse()->setContentType(
$request->getMimeType($format)
);
return sfView::NONE;
La solution consiste à employer un Serializer...
Pas de serializer dans symfony 1
Pas de serializer XML dans Zend
Doctrine peut le faire pour vous :
$this->getResponse()->setContent(
$query->execute()->exportTo($format)
);
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 26
Format sans template
Le cas particulier de json...
$this->getResponse()->setContent(
json_encode($pony->toArray())
);
facile
plus rapide (natif)
écriture compacte (moins verbeux que XML)
Cool pour la bande passante
Javascript compliant
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 27
Validation des paramètres
Exposer une interface = nécessité de valider les entrées
en GET : valider les restrictions
http://api.domain.tld/pony.json?country=france
que doit faire l'API sur un appel à l'url suivante ?
http://api.domain.tld/pony.json?speaks=german
en écriture (POST / PUT) :
valider la présence du payload (HTTP content)
format attendu
contenu du payload
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 28
Validation des paramètres
symfony 1 offre une série complète de validateurs
Email
Url
Date
etc.
public function executeShow(sfWebRequest $request)
{
$name = $request->getParameter('name');
$validator = new sfValidatorString(array('required' => true));
// throws an exception if not valid
$cleaned = $validator->clean($name)
// etc.
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 29
REST en haute Sécurité
Plusieurs approches de la sécurité :
qui a accès (authentification) ?
à quel rythme / fréquence (throttling) ?
Authentification :
approche naïve par preExecute
approche OAuth
Throttling
aidez vous d'Apache – mod_cband http://codee.pl/cband.html
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 30
Authentification d'API par api_key
ajout d'un paramètre à chaque requête
dans l'url
ou en header http
approche dite "naïve" :
pas très sécurisée (man in the middle = le secret est connu)
mode d'authentification persistant dans le temps (clé
compromise → changement de clé)
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 31
Authentification d'API par api_key
class ponyApiActions extends sfActions
{
public function preExecute()
{
$request = $this->getRequest();
$key = $request->getParameter('ApiKey');
if (!Doctrine::getTable('ApiKey')->findOneByApiKey($key))
{
$this->getResponse()->setStatusCode(401);
throw new sfException('Invalid authentication credentials.');
}
}
// etc
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 32
Authentification d'API par OAuth
OAuth :
plus robuste et rassurant
plus long à mettre en place
protocole adapté à la gestion de l'authentification sur APIs
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 33
Authentification d'API par OAuth
redirection vers page de login
Application
cliente réponse (code)
Passage du code
API
getToken (code) REST
réponse (token)
Application
serveur appel de l'API (token)
réponse (donnée demandée)
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 34
Gestion du cache
Du cache sur une API ?
Oui, même de courte durée
cache.yml
default:
enabled: true
with_layout: true
lifetime: 120 # 2 minutes cache
settings.yml
prod:
.settings:
cache: true
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 35
Gestion du cache
Bootstrap = config, plugins, config BDD, routing,
autoloading, session...
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 36
Gestion du cache
Invalidation du cache
if ($cache = $this->getContext()->getViewCacheManager())
{
$cache->remove('pony/index');
$cache->remove('pony/show?slug='.$slug);
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 37
Et avec Symfony2 ?
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 38
Pony2, des poneys en Doctrine2
entité Doctrine2 = modèle Doctrine 1
définition du schéma en PHP, yml ou XML
aussi possible à l'aide des annotations
pas d'héritage de Doctrine_Record :
src/CleverAge/SymfponyBundle/Entity/Pony.php
class Pony
{
protected $id;
protected $name;
protected $picture_url;
protected $description;
protected $slug;
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 39
Pony2, des poneys en Doctrine2
les annotations permettent d'indiquer à Doctrine comment
persister les données
/**
* @orm:Table(name="pony")
* @orm:Entity
*/
class Pony
{
/**
* @orm:Column(name="id", type="integer")
* @orm:Id
* @orm:GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @orm:Column(name="name", type="string", length=110)
*/
protected $name;
// etc.
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 40
Pony2 - Générer getter et setters
$ php app/console doctrine:generate:entities CleverAgeSymfponyBundle
Generating entities for "CleverAgeSymfponyBundle"
> generating CleverAgeSymfponyBundleEntityPony
/**
* Get id
* @return integer $id
*/
public function getId()
{
return $this->id;
}
/**
* Set name
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
}
Clever Age | Damien Alexandre, Xavier Lacot 41
Le routing avec Symfony2
app/config/routing.yml :
symfpony:
resource: "@CleverAgeSymfponyBundle/Resources/config/routing.yml"
src/CleverAge/SymfponyBundle/Resources/config/routing.yml :
pony_list:
pattern: /pony.{_format}
defaults:
- _controller: CleverAgeSymfponyBundle:Default:index
- _format: xml
requirements: { _format: (xml|json), _method: GET }
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 42
Le routing avec Symfony2
Dumpable en RewriteRule Apache :
$ php app/console router:dump-apache
RewriteCond %{REQUEST_METHOD} ^(GET) [NC]
RewriteCond %{PATH_INFO} ^/pony(?:.((xml|json)))?$
RewriteRule .* app.php
[QSA,L,E=_ROUTING__route:pony_list,E=_ROUTING__format:
%1,E=_ROUTING__controller:CleverAgeSymfponyBundleControllerDefaul
tController::indexAction,E=_ROUTING__format:xml]
RewriteCond %{REQUEST_METHOD} ^(GET) [NC]
RewriteCond %{PATH_INFO} ^/pony/([a-z0-9-]+)(?:.((xml|json)))?$
RewriteRule .* app.php
[QSA,L,E=_ROUTING__route:pony_show,E=_ROUTING_slug:
%1,E=_ROUTING__format:
%2,E=_ROUTING__controller:CleverAgeSymfponyBundleControllerDefaul
tController::showAction,E=_ROUTING__format:xml]
etc.
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 43
Le routing avec Symfony2
Pas de sfDoctrineRoute :'(
pony_show:
pattern: /pony/{slug}.{_format}
Defaults:
- _controller: CleverAgeSymfponyBundle:Default:show
- _format: xml
requirements: { _format: (xml|json), _method: GET, slug: "[a-z0-9-]+" }
Mais FrameworkExtraBundle est là...
http://bundles.symfony-reloaded.org/frameworkextrabundle/
ParamConverter FTW :
/**
* the Pony is automaticaly fetched by the ParamConverter.
* @param Pony $pony
* @param string $_format
*/
public function showAction(Pony $pony, $_format)
{
RESTful avec symfony do Symfony2 – 3 mars 2011
// 1 et what you want with $pony
Clever Age | Damien Alexandre, Xavier Lacot 44
}
Serializer component
Finally !
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 45
Les “normalizers”
Transformation ressource → array
CustomNormalizer
normalize() et denormalize() sont implémentées sur l'objet
GetSetMethodNormalizer
inspecte les getters et les setters de l'objet
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 46
Les “encodeurs”
Transformation array → format
JsonEncoder
simple implémentation de json_encode
XmlEncoder
Utilisation de DOMDocument
[insérer un format ici]Encoder
Forkez moi !
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 47
Implémentation de CustomNormalizer
use SymfonyComponentSerializerNormalizerNormalizableInterface;
use SymfonyComponentSerializerNormalizerNormalizerInterface;
class Pony implements NormalizableInterface
{
function normalize(NormalizerInterface $normalizer, $format, $properties = null)
{
return array(
'name' => $this->getName(),
'picture_url' => $this->getPictureUrl(),
'description' => $this->getDescription(),
'slug' => $this->getSlug(),
);
}
// etc.
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 48
Utilisation du Serializer
$serializer = new SerializerSerializer();
$serializer->addNormalizer(
new SerializerNormalizerCustomNormalizer()
);
$serializer->setEncoder(
'xml',
new SerializerEncoderXmlEncoder()
);
$serializer->encode($pony, 'xml');
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 49
Utilisation du Serializer
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<response>
<name><![CDATA[New Forest]]></name>
<picture_url>
<![CDATA[http://www.feracheval.com/nvxsite/newforest.jpg]]>
</picture_url>
<description>
<![CDATA[Le poney New-Forest...]]>
</description>
<slug><![CDATA[new-forest]]></slug>
</response>
$xmlEncoder = new SerializerEncoderXmlEncoder();
$xmlEncoder->setRootNodeName('Pony');
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 50
Validation des entrées
Comme avec symfony 1 :
Nécessaire de valider les entrées
Symfony2 fournit toute une série de validateurs
classes étendant SymfonyComponentValidatorConstraint
aussi complet que les validators symfony1
Doctrine2 ne fournit aucun validateur (par choix)
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 51
Déclaration des validateurs
Format de déclaration des validateurs au choix
YML
XML
PHP
annotations
class Pony
{
/**
* @validation:NotBlank()
* @validation:MinLength(3)
*/
private $name;
...
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 52
Exécution de la validation
activer le service de validation
# app/config/config.yml
framework:
validation:
enabled: true
valider dans le contrôleur
$validator = $container->get('validator');
if (0 === count($validator->validate($pony)))
{
// persist the Pony
}
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 53
Le cache dans Symfony2
Présentation de Fabien demain à 11h30
Sujet majeur !
Conférence pas trop tôt
Conférencier pas trop mauvais :-)
Quelques détails quand même...
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 54
Cache HTTP
Le cache est vérifié avant d'instancier le framework.
gateway cache,
ou reverse proxy
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 55
Cache HTTP
Le cache est vérifié avant d'instancier le framework.
gateway cache,
ou reverse proxy
ou ou Symfony2
HttpCache
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 56
Expiration du cache HTTP
$response = new Response();
$response->setPublic();
$response->setSharedMaxAge(600);
Comme pour symfony1 mais sans invalidation.
Impossible d'invalider programmatiquement le cache
Possible de définir une durée de vie
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 57
Validation du cache HTTP
$response = new Response();
$response->setETag(md5(serialize($pony)));
if ($response->isNotModified($request))
{
return $response; // 304
}
else
{
$response->setContent(
$this->getSerializer($_format)
->encode($pony, $_format)
);
return $response;
}
Ressource expirée ?
Le meilleur des deux mondes.
Etag modifié ?
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 58
Les très nécessaires benchmarks
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 59
Méthodologie
même service Pony au format json :
symfony 1 mode dev
symfony 1 mode prod sans cache
symfony 1 mode prod avec cache
Symfony2 mode dev
Symfony2 mode prod sans cache
Symfony2 mode prod sans cache (format XML)
Symfony2 mode prod avec cache HTTP (PHP)
mêmes fonctionnalités
mesures faites à l'aide de siege -
http://www.joedog.org/index/siege-home
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 60
Commentaires
Symfony2 + cache HTTP est
4,5 fois plus performant que symfony 1 avec cache
7 fois plus performant que Symfony2 en mode dev (avec profiler)
10 fois plus que symfony 1 en mode dev
Symfony2 sans cache : 40% de gains de perfs face à symfony 1
le profiler Symfony2 est génial mais couteux
Préférez json à XML pour vos APIs
Chiffres à prendre avec précaution
Framework pas terminé vs. Framework vieux de 5 ans
Attention à la configuration
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 62
Traces Xdebug et XHProf
Nos premiers tests : Symfony2 était
plus lent que symfony 1
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 63
Traces Xdebug et XHProf
Xdebug
Kudos à Derick Rethans
Super outil depuis 2002
Traces exploitables par KcacheGrind ou WinCacheGrind
http://www.xdebug.org/
XHProf
Facebook, Mars 2009
Très pratique aussi
Interface Web de consultation des traces
Graphes d'exécution avec graphviz
https://github.com/facebook/xhprof
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 64
Traces Xdebug et XHProf
Vraiment ? Regardons la trace XHProf
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 65
Traces Xdebug et XHProf
Annotations Doctrine parsées à chaque requête !
# app/config/config.yml
doctrine:
orm:
metadata_cache_driver: apc
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 66
Traces Xdebug et XHProf
Après :
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 67
Encore plus parlant avec XDebug
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 68
Encore plus parlant avec XDebug
Interprétation
de la Query
Parsing des
annotations Doctrine
# app/config/config.yml
doctrine:
orm:
metadata_cache_driver: apc
query_cache_driver: apc
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 69
Memory usage
memory_get_peak_usage()
symfony 1 mode dev : 4 581 856 b
symfony 1 mode prod sans cache : 4 282 944 b
symfony 1 mode prod avec cache : 3 335 688 b
Symfony2 mode dev : 3 567 632 b
Symfony2 mode prod sans cache d'annotations : 3 027 240 b
Symfony2 mode prod sans cache HTTP : 2 800 600 b
Symfony2 mode prod avec cache HTTP : 1 012 496 b
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 70
Autour de Symfony
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 71
Des plugins pour symfony 1
sfDoctrineRestGeneratorPlugin :
admin generator like (generator.yml)
Serialization
facile à étendre
Validation
complexe mais puissant
sfRestWebServicePlugin :
Super-module
Template
facile à mettre en place
route api/*
support de PUT hacké (POST et sf_method=PUT)
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 72
Des bundles pour Symfony2
EverzetRestfulControllersBundle
création automatique des routes à partir de noms d'actions
pas de lien avec le modèle (actions à développer)
https://github.com/everzet/EverzetRestfulControllersBundle
# app/config/routing.yml
ponys:
type: restful
resource: CleverAgeSymfponyBundleControllerPonysController
class PonysController extends Controller
[GET] {
public function getPonyAction($slug)
/pony/connemara {
// etc.
}
[POST] public function postPonysAction()
/ponys {
RESTful avec symfony 1 et Symfony2 – 3 mars 2011 // etc.
Clever Age | Damien Alexandre, Xavier Lacot
}
73
Pour conclure...
REST c'est bien. Et avec symfony c'est facile.
Avec Symfony2, c'est encore mieux.
http://symfpony-project.org/
https://github.com/xavierlacot/symfpony-project.org
https://github.com/xavierlacot/symfpony-benchmark
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 74
Time to REST
Des questions ?
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 75
Récompense des projets Web innovants
HTML5
OpenData
Mobilité
etc.
Appel à candidatures :
candidat_awards@clever-age.com
Détails sur http://awards.clever-age.com/
RESTful avec symfony 1 et Symfony2 – 3 mars 2011
Clever Age | Damien Alexandre, Xavier Lacot 76