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

Silex Anatomy (phpne)

Silex Anatomy (phpne)

Igor Wiedler

March 19, 2013
Tweet

More Decks by Igor Wiedler

Other Decks in Programming

Transcript

  1. Silex Anatomy

  2. Simon Child, from The Noun Project

  3. Solène Troussé, from The Noun Project

  4. “Framework” Collection of tools Structural base Set of conventions

  5. “Library” Specific tool Does one thing Allows for configuration

  6. “Convention” Not opposite of configuration Sensible defaults Implicit inference

  7. “Configuration” Static vs runtime Hardcoding? Globals? Dependency Inversion

  8. DI is not user friendly!

  9. use Doctrine\Common\Cache\ArrayCache; use Guzzle\Common\Cache\DoctrineCacheAdapter; use Guzzle\Http\Client; use Guzzle\Log\MessageFormatter; use Guzzle\Log\Zf1LogAdapter;

    use Guzzle\Plugin\Cache\CachePlugin; use Guzzle\Plugin\Log\LogPlugin; $client = new Client('https://igor.io/'); $client->addSubscriber(new LogPlugin( new Zf1LogAdapter( new \Zend_Log(new \Zend_Log_Writer_Stream('php://output')) ), MessageFormatter::DEBUG_FORMAT )); $client->addSubscriber(new CachePlugin(array( 'adapter' => new DoctrineCacheAdapter(new ArrayCache()), ))); $response = $client->get('/')->send();
  10. + response object + logging + caching $data = file_get_contents('https://igor.io');

  11. FactoryFactory

  12. find src | grep Factory

  13. Security\Factory\SecurityFactoryInterface Security\UserProvider\UserProviderFactoryInterface Form\FormFactoryBuilderInterface Form\FormFactoryInterface Form\ResolvedFormTypeFactoryInterface Validator\Mapping\ClassMetadataFactoryAdapter Validator\Mapping\ClassMetadataFactoryInterface

  14. Cache\Service\StorageCacheFactory Db\Adapter\AdapterServiceFactory Mvc\Service\AbstractPluginManagerFactory Mvc\Service\DiAbstractServiceFactoryFactory Mvc\Service\DiFactory Mvc\Service\DiStrictAbstractServiceFactoryFactory Mvc\Service\SerializerAdapterPluginManagerFactory ServiceManager\AbstractFactoryInterface ServiceManager\Di\DiAbstractServiceFactory

  15. Service Container

  16. None
  17. ContainerFactory

  18. class Application extends Pimple { ... }

  19. class Application extends Pimple { public function __construct() { $this['kernel']

    = $this->share(function ($app) { return new HttpKernel($app['dispatcher'], $app['resolver']); }); ... } }
  20. $app = new Silex\Application();

  21. $app = new Silex\Application(); $app['debug'] = true; $app['resolver'] = $app->share(function

    ($app) { return new MuchBetterControllerResolver($app); });
  22. Silex\Application 500+ LOC

  23. 1900+ LOC Sinatra

  24. class Application extends Pimple implements HttpKernelInterface * route builder *

    container * http-kernel * utility functions
  25. None
  26. None
  27. “Swag” The most used word in the whole fucking universe.

    Douche bags use it, your kids use it, your mail man uses it, and your fucking dog uses it. If you got swag, you generally wear those shitty hats side way, and your ass hanging out like a fucking goof cause your pants are half way down your white ass legs.
  28. None
  29. None
  30. None
  31. None
  32. UNIX Philosophy

  33. None
  34. symfony - http-kernel - http-foundation - event-dispatcher - routing -

    dependency-injection
  35. === Framework User Interface

  36. HttpKernel EventDispatcher ControllerResolver Listener A Listener B Request Response

  37. HttpKernel Request Response request controller response

  38. request controller RouterListener UrlMatcher

  39. $kernel = new HttpKernel( $dispatcher, new ControllerResolver() ); use Symfony\Component\HttpKernel\HttpKernel;

    use Symfony\Component\HttpKernel\Controller\ControllerResolver;
  40. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher();

  41. use Symfony\Component\HttpKernel\EventListener\RouterListener; $dispatcher->addSubscriber( new RouterListener($matcher) );

  42. use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; $matcher = new UrlMatcher( $routes, new

    RequestContext() );
  43. use Symfony\Component\Routing\RouteCollection; $routes = new RouteCollection();

  44. use Symfony\Component\Routing\Route; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $route = new Route('/foo',

    [ '_controller' => function (Request $request) { return new Response('Hello foo!'); }, ]); $routes->add('foo', $route);
  45. $route = (new Route('/foo')) ->setDefault('_controller', ...) ->setRequirement('_method', 'POST');

  46. use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send();

  47. use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\Controller\ControllerResolver;

    use Symfony\Component\HttpKernel\EventListener\RouterListener; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $routes = new RouteCollection(); $routes->add('foo', new Route('/foo', [ '_controller' => function (Request $request) { return new Response('foo!'); }, ])); $dispatcher = new EventDispatcher(); $dispatcher->addSubscriber(new RouterListener( new UrlMatcher($routes, new RequestContext()) )); $kernel = new HttpKernel($dispatcher, new ControllerResolver()); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send();
  48. Tedious bootstrap. Do not want!

  49. services: routes: class: Symfony\Component\Routing\RouteCollection dispatcher: class: Symfony\Component\EventDispatcher\EventDispatcher calls: - ['addSubscriber',

    [@listener.router]] listener.router: class: Symfony\Component\HttpKernel\EventListener\RouterListener arguments: [@url_matcher] url_matcher: class: Symfony\Component\Routing\Matcher\UrlMatcher arguments: [@routes, @request_context] request_context: class: Symfony\Component\Routing\RequestContext http_kernel: class: Symfony\Component\HttpKernel\HttpKernel arguments: [@dispatcher, @controller_resolver] controller_resolver: class: Symfony\Component\HttpKernel\Controller\ControllerResolver
  50. $container = Yolo\createContainer();

  51. use Symfony\Component\Routing\Route; $routes = $container->get('routes'); $routes->add('foo', new Route('/foo', [ '_controller'

    => ..., ]));
  52. $kernel = $container->get('http_kernel');

  53. Annoying API. Do not want!

  54. $builder = $container->get('route_builder'); $builder->get('/', function ($request) { return 'Look at

    me! I was built!'; });
  55. class RouteBuilder { private $index = 0; private $routes; public

    function __construct(RouteCollection $routes) { $this->routes = $routes; } public function get($path, $controller) { return $this->match($path, $controller, 'GET'); } ... public function match($path, $controller, $method = null) { $name = $this->index++; $requirements = $method ? ['_method' => $method] : []; $route = new Route($path, ['_controller' => $controller], $requirements); $this->routes->add($name, $route); return $route; } }
  56. $container = Yolo\createContainer(); $builder = $container->get('route_builder'); $builder->get('/', function ($request) {

    return 'Hi'; }); $front = $container->get('front_controller'); $front->run();
  57. Application Facade

  58. $container = Yolo\createContainer(); $app = new Yolo\Application($container); $app->get('/', function ($request)

    { return 'App does not mean anything!'; }); $app->run();
  59. class Application { private $container; public function __construct(ContainerInterface $container =

    null) { $this->container = $container ?: createContainer(); } public function get($path, $controller) { return $this->container->get('route_builder')->get($path, $controller); } ... public function run() { $front = $this->container->get('front_controller'); $front->run(); } }
  60. $app = new Yolo\Application(); $app->get('/', function ($request) { return 'Hi';

    }); $app->run();
  61. None
  62. * joind.in/8387 * yolophp.com * github.com/igorw/yolo * @igorwesome ____ /.

    \__ /_ \_/ \ // \ ___ |\ |_| |_| ____ /. \__ /_ \_/ \ // \ ___ |\ |_| |_| ____ /. \__ /_ \_/ \ // \ ___ |\ |_| |_|
  63. None
  64. Configuration Parameters Extensions

  65. $container = Yolo\createContainer( [ 'debug' => true, ], [ new

    MonologExtension(), ] ); use Yolo\DependencyInjection\MonologExtension;
  66. Exception Handling kernel.error event ExceptionListener Application::error()

  67. use Symfony\Component\HttpKernel\KernelEvents; class Application { ... public function error($listener, $priority

    = 0) { $this->container ->get('dispatcher') ->addListener(KernelEvents::EXCEPTION, $listener, $priority); } ... }
  68. use Symfony\Component\HttpFoundation\Response; $app->error(function ($event) { $e = $event->getException(); $message =

    sprintf("Had problem '%s'.\n", $e->getMessage()); $event->setResponse(new Response($message)); });
  69. Service Controllers

  70. class HelloController { private $name; public function __construct($name) { $this->name

    = $name; } public function worldAction($request) { return "Hello, I'm {$this->name}."; } }
  71. $container = Yolo\createContainer( [ 'hello.name' => 'the amazing app', ],

    [ new ServiceControllerExtension(), new CallableExtension( 'controller', function ($configs, $container) { $container->register('hello.controller') ->setClass('HelloController') ->addArgument('%hello.name%'); } ), ] );
  72. $app->get('/', 'hello.controller:worldAction');

  73. "Hello, I'm the amazing app."

  74. Implicit Request/Response ControllerResolver RequestParameterListener StringResponseListener

  75. class RequestParameterListener implements EventSubscriberInterface { public function onKernelRequest(GetResponseEvent $event) {

    $request = $event->getRequest(); if (!$request->attributes->has('request')) { $request->attributes->set('request', $request); } } public static function getSubscribedEvents() { return [ KernelEvents::REQUEST => ['onKernelRequest'], ]; } }
  76. class StringResponseListener implements EventSubscriberInterface { public function onKernelView(GetResponseForControllerResultEvent $event) {

    $result = $event->getControllerResult(); $event->setResponse(new Response((string) $result)); } public static function getSubscribedEvents() { return [ KernelEvents::VIEW => [['onKernelView', -512]], ]; } }
  77. $app->get('/', function (Request $request) { return new Response('Response object here.');

    });
  78. $app->get('/', function (Request $request) { return new Response('Response object here.');

    });
  79. fin