Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Symfony 2, un framework robuste et moderne

ubermuda
September 06, 2012

Symfony 2, un framework robuste et moderne

Présentation du framework PHP 5 Symfony 2

ubermuda

September 06, 2012
Tweet

More Decks by ubermuda

Other Decks in Technology

Transcript

  1. Codes d’état (200, 404, ...) Redirections Verbes (GET, POST, ...)

    Tirer parti du protocole HTTP HTTP mercredi 5 septembre 12
  2. Codes d’état (200, 404, ...) Redirections Verbes (GET, POST, ...)

    Cache (etags, validation, ...) Tirer parti du protocole HTTP HTTP mercredi 5 septembre 12
  3. Codes d’état (200, 404, ...) Redirections Verbes (GET, POST, ...)

    Cache (etags, validation, ...) Négociation de contenu Tirer parti du protocole HTTP HTTP mercredi 5 septembre 12
  4. Codes d’état (200, 404, ...) Redirections Verbes (GET, POST, ...)

    Cache (etags, validation, ...) Négociation de contenu ... Tirer parti du protocole HTTP HTTP mercredi 5 septembre 12
  5. <?php /** @Entity **/ class Post { /** @Id @GeneratedValue

    @Column(type="integer") **/ protected $id; /** @Column(type="string") **/ protected $title; /** @Column(type="text") **/ protected $body; public function getAbbrTitle() { return substr($this->title, 0, 15); } } http://doctrine-project.org/ MVC mercredi 5 septembre 12
  6. <?php /** @Entity **/ class Post { /** @Id @GeneratedValue

    @Column(type="integer") **/ protected $id; /** @Column(type="string") **/ protected $title; /** @Column(type="text") **/ protected $body; public function getAbbrTitle() { return substr($this->title, 0, 15); } } http://doctrine-project.org/ MVC Données mercredi 5 septembre 12
  7. <?php /** @Entity **/ class Post { /** @Id @GeneratedValue

    @Column(type="integer") **/ protected $id; /** @Column(type="string") **/ protected $title; /** @Column(type="text") **/ protected $body; public function getAbbrTitle() { return substr($this->title, 0, 15); } } http://doctrine-project.org/ MVC Métier mercredi 5 septembre 12
  8. <?xml version="1.0" encoding="UTF-8"?> <database> <table name="post"> <column name="id" type="integer" required="true"

    primaryKey="true" autoIncrement="true" /> <column name="title" type="varchar" required="true" /> <column name="body" type="text" required="true" /> </table> </database> http://propelorm.org/ MVC mercredi 5 septembre 12
  9. <?xml version="1.0" encoding="UTF-8"?> <database> <table name="post"> <column name="id" type="integer" required="true"

    primaryKey="true" autoIncrement="true" /> <column name="title" type="varchar" required="true" /> <column name="body" type="text" required="true" /> </table> </database> http://propelorm.org/ MVC Données mercredi 5 septembre 12
  10. <?php /** * Skeleton subclass for representing a row from

    the 'user' table. * * You should add additional methods to this class to meet the * application requirements. This class will only be generated as * long as it does not already exist in the output directory. */ class Post extends BasePost { public function getAbbrTitle() { return substr($this->title, 0, 15); } } http://propelorm.org/ MVC mercredi 5 septembre 12
  11. <?php /** * Skeleton subclass for representing a row from

    the 'user' table. * * You should add additional methods to this class to meet the * application requirements. This class will only be generated as * long as it does not already exist in the output directory. */ class Post extends BasePost { public function getAbbrTitle() { return substr($this->title, 0, 15); } } http://propelorm.org/ MVC Métier mercredi 5 septembre 12
  12. {% extends 'layout.html.twig' %} {% for post in posts %}

    <div class="post" id="post-{{ post.id }}"> <h2>{{ post.title }}</h2> <div class="post-body"> {{ post.body | markdown }} </div> </div> {% endfor %} Twig http://twig.sensiolabs.org/ MVC mercredi 5 septembre 12
  13. {% extends 'layout.html.twig' %} {% for post in posts %}

    <div class="post" id="post-{{ post.id }}"> <h2>{{ post.title }}</h2> <div class="post-body"> {{ post.body | markdown }} </div> </div> {% endfor %} http://twig.sensiolabs.org/ MVC Layout mercredi 5 septembre 12
  14. {% extends 'layout.html.twig' %} {% for post in posts %}

    <div class="post" id="post-{{ post.id }}"> <h2>{{ post.title }}</h2> <div class="post-body"> {{ post.body | markdown }} </div> </div> {% endfor %} http://twig.sensiolabs.org/ MVC Boucles mercredi 5 septembre 12
  15. {% extends 'layout.html.twig' %} {% for post in posts %}

    <div class="post" id="post-{{ post.id }}"> <h2>{{ post.title }}</h2> <div class="post-body"> {{ post.body | markdown }} </div> </div> {% endfor %} http://twig.sensiolabs.org/ MVC Variables mercredi 5 septembre 12
  16. {% extends 'layout.html.twig' %} {% for post in posts %}

    <div class="post" id="post-{{ post.id }}"> <h2>{{ post.title }}</h2> <div class="post-body"> {{ post.body | markdown }} </div> </div> {% endfor %} http://twig.sensiolabs.org/ MVC Filtres mercredi 5 septembre 12
  17. <?php namespace MyBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class PostController extends Controller {

    public function listAction() { return $this->render('MyBundle:Post:list', array( 'posts' => PostQuery::create()->find() )); } } MVC mercredi 5 septembre 12
  18. <?php namespace MyBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class PostController extends Controller {

    public function listAction() { return $this->render('MyBundle:Post:list', array( 'posts' => PostQuery::create()->find() )); } } MVC Template mercredi 5 septembre 12
  19. <?php namespace MyBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class PostController extends Controller {

    public function listAction() { return $this->render('MyBundle:Post:list', array( 'posts' => PostQuery::create()->find() )); } } MVC Données mercredi 5 septembre 12
  20. class User { public function __construct() { $this->storage = new

    SessionStorage('SESSION_ID'); } public function setLanguage($language) { $this->storage->set('language', $language); } } $user = new User(); INJECTION DE DÉPENDANCE mercredi 5 septembre 12
  21. class User { public function __construct() { $this->storage = new

    SessionStorage('SESSION_ID'); } public function setLanguage($language) { $this->storage->set('language', $language); } } $user = new User(); INJECTION DE DÉPENDANCE Dépendance forte mercredi 5 septembre 12
  22. class User { private $storage; public function __construct(StorageInterface $storage) {

    $this->storage = $storage; } } $storage = new SessionStorage('SESSION_ID'); $user = new User($storage); INJECTION DE DÉPENDANCE Injection mercredi 5 septembre 12
  23. class User { private $storage; public function __construct(StorageInterface $storage) {

    $this->storage = $storage; } } $storage = new SessionStorage('my_session_name'); $user = new User($storage); INJECTION DE DÉPENDANCE mercredi 5 septembre 12
  24. class User { private $storage; public function __construct(StorageInterface $storage) {

    $this->storage = $storage; } } $storage = new MemcacheStorage(); $user = new User($storage); INJECTION DE DÉPENDANCE mercredi 5 septembre 12
  25. class User { private $storage; public function __construct(StorageInterface $storage) {

    $this->storage = $storage; } } $storage = new MemcacheStorage($memcacheClient); $user = new User($storage); INJECTION DE DÉPENDANCE mercredi 5 septembre 12
  26. COMPOSANTS ClassLoader Config Console DependencyInjection EventDispatcher Finder Form HttpFoundation Locale

    Process Routing Security Templating Validation YAML ... mercredi 5 septembre 12
  27. CLASSLOADER <?php $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/../vendor/symfony/src',

    'Monolog' => __DIR__.'/../vendor/monolog/src', )); $loader->registerPrefixes(array( 'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes', 'Twig_' => __DIR__.'/vendor/twig/lib', )); $loader->register(); COMPOSANTS mercredi 5 septembre 12
  28. CLASSLOADER <?php $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/../vendor/symfony/src',

    'Monolog' => __DIR__.'/../vendor/monolog/src', )); $loader->registerPrefixes(array( 'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes', 'Twig_' => __DIR__.'/vendor/twig/lib', )); $loader->register(); COMPOSANTS Namespaces mercredi 5 septembre 12
  29. CLASSLOADER <?php $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/../vendor/symfony/src',

    'Monolog' => __DIR__.'/../vendor/monolog/src', )); $loader->registerPrefixes(array( 'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes', 'Twig_' => __DIR__.'/vendor/twig/lib', )); $loader->register(); COMPOSANTS Préfixes mercredi 5 septembre 12
  30. CONFIG Gestion avancée de configuration Chargement de fichiers de configuration

    Mise en cache de la configuration COMPOSANTS mercredi 5 septembre 12
  31. CONFIG Gestion avancée de configuration Chargement de fichiers de configuration

    Mise en cache de la configuration Définition du format de configuration COMPOSANTS mercredi 5 septembre 12
  32. CONFIG Gestion avancée de configuration Chargement de fichiers de configuration

    Mise en cache de la configuration Définition du format de configuration Multi-source (fichiers, base de données) COMPOSANTS mercredi 5 septembre 12
  33. CONFIG Gestion avancée de configuration Chargement de fichiers de configuration

    Mise en cache de la configuration Définition du format de configuration Multi-source (fichiers, base de données) Multi-format (YAML, XML, JSON) COMPOSANTS mercredi 5 septembre 12
  34. DEPENDENCYINJECTION parameters: mailer.transport: sendmail services: mailer: class: Mailer arguments: [%mailer.transport%]

    newsletter_manager: class: NewsletterManager calls: - [ setMailer, [ @mailer ] ] COMPOSANTS mercredi 5 septembre 12
  35. DEPENDENCYINJECTION parameters: mailer.transport: sendmail services: mailer: class: Mailer arguments: [%mailer.transport%]

    newsletter_manager: class: NewsletterManager calls: - [ setMailer, [ @mailer ] ] COMPOSANTS mercredi 5 septembre 12
  36. DEPENDENCYINJECTION parameters: mailer.transport: sendmail services: mailer: class: Mailer arguments: [%mailer.transport%]

    newsletter_manager: class: NewsletterManager calls: - [ setMailer, [ @mailer ] ] COMPOSANTS Paramètre mercredi 5 septembre 12
  37. DEPENDENCYINJECTION parameters: mailer.transport: sendmail services: mailer: class: Mailer arguments: [%mailer.transport%]

    newsletter_manager: class: NewsletterManager calls: - [ setMailer, [ @mailer ] ] COMPOSANTS Service mercredi 5 septembre 12
  38. DEPENDENCYINJECTION use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; $container = new

    ContainerBuilder(); $loader = new YamlFileLoader($container, new FileLocator(__DIR__)); $loader->load('services.yml'); $manager = $container->get('newsletter_manager'); COMPOSANTS mercredi 5 septembre 12
  39. DEPENDENCYINJECTION use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; $container = new

    ContainerBuilder(); $loader = new YamlFileLoader($container, new FileLocator(__DIR__)); $loader->load('services.yml'); $manager = $container->get('newsletter_manager'); COMPOSANTS mercredi 5 septembre 12
  40. EVENTDISPATCHER use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); $dispatcher->addListener('foo.action',

    function (Event $event) { // will be executed when the foo.action event is dispatched }); $dispatcher->dispatch('foo.action', new Event()); COMPOSANTS mercredi 5 septembre 12
  41. EVENTDISPATCHER use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); $dispatcher->addListener('foo.action',

    function (Event $event) { // will be executed when the foo.action event is dispatched }); $dispatcher->dispatch('foo.action', new Event()); COMPOSANTS mercredi 5 septembre 12
  42. EVENTDISPATCHER use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); $dispatcher->addListener('foo.action',

    function (Event $event) { // will be executed when the foo.action event is dispatched }); $dispatcher->dispatch('foo.action', new Event()); COMPOSANTS Listener mercredi 5 septembre 12
  43. EVENTDISPATCHER use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); $dispatcher->addListener('foo.action',

    function (Event $event) { // will be executed when the foo.action event is dispatched }); $dispatcher->dispatch('foo.action', new Event()); COMPOSANTS Événement mercredi 5 septembre 12
  44. FINDER use Symfony\Component\Finder\Finder; $finder = new Finder(); $finder->files()->in(__DIR__); foreach ($finder

    as $file) { // Print the absolute path print $file->getRealpath()."\n"; // Print the relative path to the file, omitting the filename print $file->getRelativePath()."\n"; // Print the relative path to the file print $file->getRelativePathname()."\n"; } COMPOSANTS mercredi 5 septembre 12
  45. FINDER use Symfony\Component\Finder\Finder; $finder = new Finder(); $finder->files()->in(__DIR__); foreach ($finder

    as $file) { // Print the absolute path print $file->getRealpath()."\n"; // Print the relative path to the file, omitting the filename print $file->getRelativePath()."\n"; // Print the relative path to the file print $file->getRelativePathname()."\n"; } SplFileInfo COMPOSANTS mercredi 5 septembre 12
  46. FINDER use Symfony\Component\Finder\Finder; $finder = new Finder(); $finder->files()->in(__DIR__); foreach ($finder

    as $file) { // Print the absolute path print $file->getRealpath()."\n"; // Print the relative path to the file, omitting the filename print $file->getRelativePath()."\n"; // Print the relative path to the file print $file->getRelativePathname()."\n"; } COMPOSANTS mercredi 5 septembre 12
  47. FINDER use Symfony\Component\Finder\Finder; $finder = new Finder(); $finder->files()->in(__DIR__); foreach ($finder

    as $file) { // Print the absolute path print $file->getRealpath()."\n"; // Print the relative path to the file, omitting the filename print $file->getRelativePath()."\n"; // Print the relative path to the file print $file->getRelativePathname()."\n"; } COMPOSANTS mercredi 5 septembre 12
  48. FINDER use Symfony\Component\Finder\Finder; $finder = new Finder(); $finder->files()->in(__DIR__); foreach ($finder

    as $file) { // Print the absolute path print $file->getRealpath()."\n"; // Print the relative path to the file, omitting the filename print $file->getRelativePath()."\n"; // Print the relative path to the file print $file->getRelativePathname()."\n"; } COMPOSANTS mercredi 5 septembre 12
  49. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers COMPOSANTS mercredi 5 septembre 12
  50. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers Recherche par taille COMPOSANTS mercredi 5 septembre 12
  51. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers Recherche par taille Recherche par date COMPOSANTS mercredi 5 septembre 12
  52. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers Recherche par taille Recherche par date Tri standard (nom, type) COMPOSANTS mercredi 5 septembre 12
  53. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers Recherche par taille Recherche par date Tri standard (nom, type) Tri personnalisé (“callback”) COMPOSANTS mercredi 5 septembre 12
  54. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers Recherche par taille Recherche par date Tri standard (nom, type) Tri personnalisé (“callback”) Compatible avec les “streams” PHP COMPOSANTS mercredi 5 septembre 12
  55. FINDER Recherche dans plusieurs répertoires Exclusion de répertoire Recherche sur

    masques de fichiers Recherche par taille Recherche par date Tri standard (nom, type) Tri personnalisé (“callback”) Compatible avec les “streams” PHP ... COMPOSANTS mercredi 5 septembre 12
  56. FORM Gestion de formulaires complexes Rendu personnalisable via Twig Validation

    des données Encore en beta (prévu pour la 2.1) COMPOSANTS mercredi 5 septembre 12
  57. COMPOSANTS ClassLoader Config Console DependencyInjection EventDispatcher Finder Form HttpFoundation Locale

    Process Routing Security Templating Validation YAML ... mercredi 5 septembre 12
  58. Un Bundle peut contenir : Des extensions pour l’injection de

    dépendance BUNDLES mercredi 5 septembre 12
  59. Un Bundle peut contenir : Des extensions pour l’injection de

    dépendance Des contrôleurs BUNDLES mercredi 5 septembre 12
  60. Un Bundle peut contenir : Des extensions pour l’injection de

    dépendance Des contrôleurs Des gabarits Twig BUNDLES mercredi 5 septembre 12
  61. Un Bundle peut contenir : Des extensions pour l’injection de

    dépendance Des contrôleurs Des gabarits Twig La couche modèle BUNDLES mercredi 5 septembre 12
  62. Un Bundle peut contenir : Des extensions pour l’injection de

    dépendance Des contrôleurs Des gabarits Twig La couche modèle Tout le nécessaire pour votre application BUNDLES mercredi 5 septembre 12
  63. // src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php namespace Acme\DemoBundle\Tests\Utility; use Acme\DemoBundle\Utility\Calculator; class CalculatorTest extends \PHPUnit_Framework_TestCase

    { public function testAdd() { $calc = new Calculator(); $result = $calc->add(30, 12); // assert that our calculator added the numbers correctly! $this->assertEquals(42, $result); } } CONTRÔLE QUALITÉ mercredi 5 septembre 12
  64. // src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php namespace Acme\DemoBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DemoControllerTest extends WebTestCase

    { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/demo/hello/Fabien'); $count = $crawler ->filter('html:contains("Hello Fabien")') ->count(); $this->assertGreaterThan(0, $count); } } CONTRÔLE QUALITÉ mercredi 5 septembre 12
  65. // src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php namespace Acme\DemoBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DemoControllerTest extends WebTestCase

    { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/demo/hello/Fabien'); $count = $crawler ->filter('html:contains("Hello Fabien")') ->count(); $this->assertGreaterThan(0, $count); } } CONTRÔLE QUALITÉ Navigateur mercredi 5 septembre 12
  66. // src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php namespace Acme\DemoBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DemoControllerTest extends WebTestCase

    { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/demo/hello/Fabien'); $count = $crawler ->filter('html:contains("Hello Fabien")') ->count(); $this->assertGreaterThan(0, $count); } } CONTRÔLE QUALITÉ mercredi 5 septembre 12
  67. // src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php namespace Acme\DemoBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DemoControllerTest extends WebTestCase

    { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/demo/hello/Fabien'); $count = $crawler ->filter('html:contains("Hello Fabien")') ->count(); $this->assertGreaterThan(0, $count); } } CONTRÔLE QUALITÉ Assertion mercredi 5 septembre 12
  68. Feature: buy an article In order to be happy As

    a consumer I want to be able to buy something Scenario: Given I am on the homepage When I search for "fridge" And I follow "Awesome Fridge" And I add the article to my cart And I follow "checkout" # steps that describe the checkout process Then I should see "Your order is complete!" And I should be happy to have a new fridge CONTRÔLE QUALITÉ mercredi 5 septembre 12
  69. Feature: buy an article In order to be happy As

    a consumer I want to be able to buy something Scenario: Given I am on the homepage When I search for "fridge" And I follow "Awesome Fridge" And I add the article to my cart And I follow "checkout" # steps that describe the checkout process Then I should see "Your order is complete!" And I should be happy to have a new fridge CONTRÔLE QUALITÉ Step mercredi 5 septembre 12
  70. CONTRÔLE QUALITÉ /** * @When /^I search for "(?P<term>[^"]*)"$/ */

    public function iSearchFor($term) { $this->fillField('Search', $term); $this->pressButton('Find'); } mercredi 5 septembre 12