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

Silex - Symfony goes micro

Silex - Symfony goes micro

Talk on the Silex microframework as given at symfonyday 2011.

A4b95be2145cc46f891707b6db9dd82d?s=128

Igor Wiedler

October 21, 2011
Tweet

Transcript

  1. None
  2. • phpBB • Symfony2 • Silex igorw

  3. None
  4. Silex Symfony goes micro μ

  5. Silex is not Symfony

  6. Microframework

  7. None
  8. What? • Bare bones • Routes mapped to controllers •

    The ‘C’ of ‘MVC’ • REST • Single file app
  9. Why?

  10. Sometimes a full-stack framework is too much for a simple

    task.
  11. simple

  12. What makes silex special?

  13. • concise • extensible • testable

  14. • concise • extensible • testable

  15. • concise • extensible • testable

  16. • concise • extensible • testable

  17. • concise • extensible • testable

  18. Http Kernel Interface

  19. Response handle(Request $request)

  20. client

  21. request client

  22. reponse client request

  23. clean

  24. PSR-0

  25. None
  26. Silex is not Symfony

  27. Silex is a user interface for Symfony

  28. require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return

    "Hello world!"; });
  29. Phar require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {

    return "Hello world!"; });
  30. Application require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() {

    return "Hello world!"; });
  31. require_once __DIR__.'/silex.phar'; $app = new Silex\Application(); $app->get('/', function() { return

    "Hello world!"; }); Controller
  32. $app->run();

  33. None
  34. <IfModule mod_rewrite.c> RewriteEngine On RewriteBase /some/path RewriteCond %{REQUEST_FILENAME} !-f RewriteCond

    %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </IfModule>
  35. server { location / { if (-f $request_filename) { break;

    } rewrite ^(.*) /index.php last; } location ~ index\.php$ { fastcgi_pass /var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } }
  36. Wait a minute!

  37. Lambdas λ

  38. $(function () { $("a").click(function (event) { alert("Thanks for visiting!"); });

    });
  39. PHP 5.3

  40. $f = function ($a, $b) { return $a + $b;

    }; $f(1, 2);
  41. lazy $f = function () { exit; };

  42. nested $f = function () { return function () {

    return true; }; }; $g = $f(); $value = $g();
  43. scope $outer = 'world'; $f = function () use ($outer)

    { $inner = 'hello'; return "$inner $outer"; }; => "hello world"
  44. scope $helloWorld = function () { $outer = 'world'; $f

    = function () use ($outer) { $inner = 'hello'; return "$inner $outer"; }; return $f(); }
  45. passing $output = function ($info) { echo $info."\n"; }; $doStuff

    = function ($output) { $output('doing some magic'); doMagic(); $output('did some magic'); };
  46. factory $userFactory = function ($name) { return new User($name); };

    // ... $user = $userFactory($_POST['name']);
  47. Usage

  48. $app->get('/', function () { return "Hello world!"; });

  49. Dynamic Routing

  50. $app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });

  51. $app->get('/hello/{name}', function ($name) use ($app) { return "Hello ".$app->escape($name); });

  52. Controllers

  53. assert $app->get('/blog/{id}', function ($id) { ... }) ->assert('id', '\d+');

  54. value $app->get('/{page}', function ($page) { ... }) ->value('page', 'index');

  55. bind $app->get('/', function () { ... }) ->bind('homepage'); $app['url_generator']->generate('homepage')

  56. bind $app->get('/blog/{id}', function ($id) { ... }) ->bind('blog_post'); $app['url_generator'] ->generate('blog_post',

    array('id' => $id))
  57. convert $app->get('/blog/{post}', function (Post $post) { ... }) ->convert('post', function

    ($post) use ($app) { $id = (int) $post; return $app['posts']->find($id); });
  58. Before & After

  59. $app->before(function () { ... }); $app->get('/', function () { ...

    }); $app->after(function () { ... });
  60. $app->before(function (Request $request) { $loggedIn = $request ->getSession() ->get('logged_in'); if

    (!$loggedIn) { return new RedirectResponse('/login'); } });
  61. $app->after(function (Request $request, Response $response) { // tweak the Response

    });
  62. $app->after(function ( Request $request, Response $response, ) use ($app) {

    $response->headers->set('x-csrf-token', $app['csrf_token']); });
  63. REST

  64. • get • post • put • delete • head

    • options • patch
  65. $app->get('/posts/{id}', ...); $app->post('/posts', ...); $app->put('/posts/{id}', ...); $app->delete('/post/{id}', ...);

  66. use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $app->post('/message', function (Request $request) { mail(

    'me@me.me', 'New message', $request->get('body') ); return new Response('Email has been sent!', 201); });
  67. Caching

  68. Error Handling

  69. use Symfony\Component\HttpFoundation\Response; $app->error(function (\Exception $e, $code) { return new Response('Whoops!',

    $code); });
  70. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; throw new NotFoundHttpException("Could not find what you were

    looking for.");
  71. $app->abort(404, "Could not find the thing.");

  72. $app['debug'] = true;

  73. Redirecting

  74. $app->get('/', function () use ($app) { return $app->redirect('/hello'); });

  75. Pimple

  76. 50 NCLOC

  77. Symfony2 DIC Pimple

  78. Symfony2 DIC Pimple Container

  79. Symfony2 DIC Pimple Container Builder

  80. Symfony2 DIC Pimple Container Builder Extension

  81. Symfony2 DIC Pimple Container Builder Extension Loader

  82. Symfony2 DIC Pimple Container Builder Extension XML/Yaml Loader

  83. Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader

  84. Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader Container

  85. Symfony2 DIC Pimple Container Builder Extension XML/Yaml Compiler Loader Container

    ServiceProvider ( )
  86. $container = new Pimple();

  87. $app = new Silex\Application();

  88. Parameters $app['some_parameter'] = 'value'; $app['asset.host'] = 'http://cdn.mysite.com/'; $app['database.dsn'] = 'mysql:dbname=myapp';

  89. Services $app['some_service'] = function () { return new Service(); };

  90. $service = $app['some_service'];

  91. Dependencies $app['some_service'] = function ($app) { return new Service( $app['some_other_service'],

    $app['some_service.config'] ); };
  92. Shared $app['some_service'] = $app->share(function () { return new Service(); });

  93. Protected $app['lambda_parameter'] = $app->protect( function ($a, $b) { return $a

    + $b; }); // will not execute the lambda $add = $app['lambda_parameter']; // calling it now echo $add(2, 3);
  94. Exposed Services • debug • request • autoloader • routes

    • controllers • dispatcher • resolver • kernel
  95. Service Providers

  96. interface ServiceProviderInterface { function register(Application $app); }

  97. Core Service Providers • doctrine • form • http cache

    • monolog • session • swiftmailer • symfony bridges • translation • twig • url generator • validator
  98. Twig

  99. $app->register( new Silex\ServiceProvider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views', 'twig.class_path' => __DIR__.'/vendor/twig/lib',

    ) );
  100. $app->get('/', function () use ($app) { return $app['twig']->render('hello.twig'); });

  101. 3rd Party • doctrine orm • pomm (postgres) • predis

    • mongo • KyotoTycoon • memcache • rest • markdown • gravatar • buzz • config • solr • profiler • ...
  102. Functional Testing

  103. • src • app.php • web • index.php • tests

    • bootstrap.php • YourTest.php
  104. src/app.php require_once __DIR__.'/../vendor/silex.phar'; ... return $app;

  105. web/index.php $app = require_once __DIR__.'/../src/app.php'; $app->run();

  106. tests/bootstrap.php require_once __DIR__.'/../vendor/silex.phar';

  107. use Silex\WebTestCase; class YourTest extends WebTestCase { public function createApp()

    { return require __DIR__.'/../src/app.php'; } // tests... } tests/YourTest.php
  108. public function testAbout() { $client = $this->createClient(); $client->request('GET', '/about'); $response

    = $client->getResponse(); $this->assertTrue($response->isOk()); $this->assertContains('trashbin', $response->getContent()); $this->assertContains('github', $response->getContent()); $this->assertContains('igorw', $response->getContent()); }
  109. phpunit.xml.dist <?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true"

    convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" syntaxCheck="false" bootstrap="tests/bootstrap.php" > <testsuites> <testsuite name="YourApp Test Suite"> <directory>./tests/</directory> </testsuite> </testsuites> </phpunit>
  110. $ phpunit

  111. None
  112. None
  113. • smallish sites • well-defined scope • prototyping • restful

    apis When to use
  114. and many more...

  115. The future

  116. The future • Cookbooks

  117. The future • Cookbooks • Best practices

  118. The future • Cookbooks • Best practices • Symfony2 integration

  119. The future • Cookbooks • Best practices • Symfony2 integration

    • FOSUserBundle
  120. The future • Cookbooks • Best practices • Symfony2 integration

    • FOSUserBundle • Composer
  121. on github fabpot/Silex fabpot/Pimple

  122. silex.sensiolabs.org

  123. Ω

  124. Questions? joind.in/3699 @igorwesome speakerdeck.com /u/igorw