Silex al límite

7,409 views
7,321 views

Published on

Published in: Technology
0 Comments
11 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,409
On SlideShare
0
From Embeds
0
Number of Embeds
3,626
Actions
Shares
0
Downloads
134
Comments
0
Likes
11
Embeds 0
No embeds

No notes for slide

Silex al límite

  1. 1. 20-22 junio 2013MadridSILEX AL LÍMITEJavier EguiluzdeSymfony
  2. 2. ¡muchas gracias a nuestros patrocinadores!deSymfony
  3. 3. ME PRESENTO
  4. 4. Sobre míJavier EguiluzFormador y programadorentusiasta de Symfony.javiereguiluz.com
  5. 5. 2011
  6. 6. NachoMartínMicroframework SilexNacho MartínJORNADAS SYMFONY 2011 1-3 JULIO, CASTELLÓN DESYMFONY.COMdeSymfony 2011
  7. 7. AGENDA
  8. 8. RENDIMIENTOAL LÍMITECARACTERÍSTICASAL LÍMITE
  9. 9. RENDIMIENTOAL LÍMITECARACTERÍSTICASAL LÍMITE
  10. 10. RENDIMIENTOAL LÍMITECARACTERÍSTICASAL LÍMITE
  11. 11. PRIMERA PARTERENDIMIENTOAL LÍMITE
  12. 12. PASOS PREVIOS
  13. 13. 1. El backend «casi» no importaBACKEND-10 ms BBDD-200 ms PHP-5 ms Apache215 msFRONTEND-5 seg imágenes-1 seg CSS-2 seg JavaScript8 seg
  14. 14. 1. El backend «casi» no importaBACKEND-10 ms BBDD-200 ms PHP-5 ms Apache215 msFRONTEND-5 seg imágenes-1 seg CSS-2 seg JavaScript8 seg8.000 ms
  15. 15. 1. El backend «casi» no importaBACKEND215 msFRONTEND8.000 ms
  16. 16. no te pierdasesta charlaMiquelCompany
  17. 17. 2. Tu aplicación «casi» no importaTU APLICACIÓNS.O.BBDD SERVIDOR WEBPHPAPCVARNISH
  18. 18. 2. Tu aplicación «casi» no importaTU APLICACIÓNS.O.BBDD SERVIDOR WEBPHPAPCVARNISHTU APLICACIÓN
  19. 19. no te pierdasesta charlaRicardClauy tampoco te pierdas sublog: ricardclau.com
  20. 20. 3. Nada importa si no lo mirasMySQL SlowQuery LogAPC log¿cada cuántomiráis estosarchivos?
  21. 21. 3. Nada importa si no lo mirasMySQL SlowQuery LogAPC log¿cada cuántomiráis estosarchivos?¿los miráisalguna vez?
  22. 22. APC log
  23. 23. APC logHttpCacheESI.php
  24. 24. APC log
  25. 25. APC loghttp_cache.esi => null
  26. 26. CristinaQuintanano te pierdasesta charla
  27. 27. SILEXINTERNALS
  28. 28. Una aplicación Silex típicarequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});$app->run();
  29. 29. Una aplicación Silex típicarequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});$app->run();12345
  30. 30. Mejorando el rendimientorequire_once __DIR__./../vendor/autoload.php;1
  31. 31. Mejorando el rendimientorequire_once __DIR__./../vendor/autoload.php;1$ composer install --optimize-autoloader
  32. 32. Mejorando el rendimientorequire_once __DIR__./../vendor/autoload.php;1$ composer install --optimize-autoloader$ composer dump-autoload --optimize
  33. 33. Mejorando el rendimientorequire_once __DIR__./../vendor/autoload.php;1$vendorDir = dirname(dirname(__FILE__));$baseDir = dirname($vendorDir);return array(SessionHandlerInterface => $vendorDir . /symfony/http-foundation/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php,);vendor/composer/autoload_classmap.php original
  34. 34. Mejorando el rendimientorequire_once __DIR__./../vendor/autoload.php;1// autoload_classmap.php generated by Composer$vendorDir = dirname(dirname(__FILE__));$baseDir = dirname($vendorDir);return array(DoctrineDBALCacheArrayStatement => $vendorDir . /doctrine/dbal/ ... /ArrayStatement.php,DoctrineDBALCacheCacheException => $vendorDir . /doctrine/dbal/ ... /CacheException.php,// ...MonologFormatterChromePHPFormatter => $vendorDir . /monolog/... /ChromePHPFormatter.php,MonologFormatterFormatterInterface => $vendorDir . /monolog/ ... /FormatterInterface.php,// ...Pimple => $vendorDir . /pimple/pimple/lib/Pimple.php,PsrLogAbstractLogger => $vendorDir . /psr/log/Psr/Log/AbstractLogger.php,vendor/composer/autoload_classmap.php optimizado1.762 elementos
  35. 35. Revisa tu composer.jsonrequire_once __DIR__./../vendor/autoload.php;1{"require": {"php": ">=5.3.3","silex/silex": "~1.0","silex/web-profiler": "1.0.*","symfony/stopwatch": "~2.2","twig/twig": "~1.13","symfony/form": "~2.2","symfony/translation": "~2.2","symfony/validator": "~2.2",...}}
  36. 36. Revisa tu composer.jsonrequire_once __DIR__./../vendor/autoload.php;1{"require": {"php": ">=5.3.3","silex/silex": "~1.0","silex/web-profiler": "1.0.*","symfony/stopwatch": "~2.2","twig/twig": "~1.13","symfony/form": "~2.2","symfony/translation": "~2.2","symfony/validator": "~2.2",...}}¿realmentelos usas?
  37. 37. Una aplicación Silex típicarequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});$app->run();12345✔
  38. 38. Mejorando el rendimiento$app = new SilexApplication();2
  39. 39. Mejorando el rendimiento$app = new SilexApplication();2class Application extends Pimpleimplements HttpKernelInterface, TerminableInterface {public function __construct() {$this[logger] = ...$this[routes] = ...$this[controllers] = ...$this[route_factory] = ...$this[exception_handler] = ...$this[dispatcher] = ...}}
  40. 40. Mejorando el rendimiento$app = new SilexApplication();2class Application extends Pimpleimplements HttpKernelInterface, TerminableInterface {public function __construct() {$this[logger] = ...$this[routes] = ...$this[controllers] = ...$this[route_factory] = ...$this[exception_handler] = ...$this[dispatcher] = ...}}~100 líneas~12 servicios
  41. 41. mini truco
  42. 42. Configurando la aplicación$app = new SilexApplication();$app = new SilexApplication([request.http_port => 80]);
  43. 43. Configurando la aplicación$app = new SilexApplication();$app = new SilexApplication([request.http_port => 80]);$app = new SilexApplication([request.http_port => 80,request.https_port => 443,debug => false,charset => UTF-8,locale => en,]);
  44. 44. Configurando la aplicación$app = new SilexApplication();$app = new SilexApplication([request.http_port => 80,mi_app.mi_opcion_1 => ...,mi_app.mi_opcion_2 => ...,]);
  45. 45. Mejorando el rendimiento$app->register( ... );3
  46. 46. Mejorando el rendimiento$app->register( ... );3class Application extends Pimpleimplements HttpKernelInterface, TerminableInterface {public function register($provider, $values){$this->providers[] = $provider;$provider->register($this);foreach ($values as $key => $value) {$this[$key] = $value;}}
  47. 47. Mejorando el rendimiento$app->register( ... );3class Application extends Pimpleimplements HttpKernelInterface, TerminableInterface {public function register($provider, $values){$this->providers[] = $provider;$provider->register($this);foreach ($values as $key => $value) {$this[$key] = $value;}}
  48. 48. Mejorando el rendimiento$app->register( ... );3class Application extends Pimpleimplements HttpKernelInterface, TerminableInterface {public function register($provider, $values){$this->providers[] = $provider;$provider->register($this);foreach ($values as $key => $value) {$this[$key] = $value;}}
  49. 49. Mejorando el rendimiento$app->register( ... );3$app->register(new SilexProviderDoctrineServiceProvider(), [db.options => [driver => pdo_mysql,host => localhost,dbname => ...,user => ...,password => ...,charset => utf8,]]);afecta a lamemoriaconsumida
  50. 50. Mejorando el rendimiento$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});4
  51. 51. Mejorando el rendimiento$app->run();5
  52. 52. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}
  53. 53. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}
  54. 54. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}
  55. 55. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}
  56. 56. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}
  57. 57. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}$this->boot();$response = $this[kernel]->handle($request, $type, $catch);return $response;
  58. 58. Mejorando el rendimiento$app->run();5public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}$response = $this->handle($request);$response->send();$this->terminate($request, $response);}$this->boot();$response = $this[kernel]->handle($request, $type, $catch);return $response;foreach ($this->providers as $provider) {$provider->boot();}
  59. 59. En resumen1. Se carga un array de ~1.500 elementos.2. Se crea un objeto SilexApplication.3. Se ejecuta el register() de todos los servicios.4. Se crea un objeto Request.5. Se ejecuta el boot() de todos los servicios.6. Se crea un objeto Response (con tu controlador).7. Se envía la respuesta al usuario.8. Se ejecuta el terminate() de la aplicación.App. Silex
  60. 60. mini truco
  61. 61. ini_set(display_errors, 0);require_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;if ($app[debug]) {$app->run();} else {$app[http_cache]->run();}Típico controlador de producción
  62. 62. ini_set(display_errors, 0);require_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;if ($app[debug]) {$app->run();} else {$app[http_cache]->run();}Típico controlador de produccióninnecesario
  63. 63. ini_set(display_errors, 0);require_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;if ($app[debug]) {$app->run();} else {$app[http_cache]->run();}Típico controlador de produccióninnecesariomuy mal
  64. 64. ini_set(display_errors, 0);require_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;if ($app[debug]) {$app->run();} else {$app[http_cache]->run();}Típico controlador de produccióninnecesariomuy malPHP_FUNCTION(ini_set) {char *varname, *new_value;int varname_len, new_value_len;char *old_value;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&varname, &varname_len, &new_value, &new_value_len) == FAILURE) {return;}old_value = zend_ini_string(varname, varname_len + 1, 0);// ...
  65. 65. TIPOS DERESPUESTAS
  66. 66. Tipos de respuestas Silex / Sf2ResponseRedirectResponseStreamedResponseJsonResponseBinaryFileResponse
  67. 67. Response vs. JsonResponse$app->get(/, function () use ($app) {return new Response(json_encode( $datos ), 200,array(Content-Type => application/json));});
  68. 68. Response vs. JsonResponse$app->get(/, function () use ($app) {return new Response(json_encode( $datos ), 200,array(Content-Type => application/json));});$app->get(/, function () use ($app) {return new JsonResponse($datos);});
  69. 69. Response vs. JsonResponse$app->get(/, function () use ($app) {return new Response(json_encode( $datos ), 200,array(Content-Type => application/json));});$app->get(/, function () use ($app) {return new JsonResponse($datos);});$app->get(/, function () use ($app) {return $app->json($datos);});
  70. 70. Response vs. JsonResponse$app->get(/, function () use ($app) {return new Response( json_encode( $datos ), ... );});class JsonResponse extends Response{// RFC4627-compliant JSON$this->data = json_encode($datos,JSON_HEX_TAG | JSON_HEX_APOS| JSON_HEX_AMP | JSON_HEX_QUOT);
  71. 71. Tipos de respuestas Silex / Sf2ResponseRedirectResponseStreamedResponseJsonResponseBinaryFileResponse
  72. 72. Response vs. BinaryFileResponse$app->get(/, function () use ($app) {return new Response(file_get_contents($archivo));});
  73. 73. Response vs. BinaryFileResponse$app->get(/, function () use ($app) {return new Response(file_get_contents($archivo));});Rendimiento
  74. 74. Response vs. BinaryFileResponse$app->get(/, function () use ($app) {return new Response(file_get_contents($archivo));});Rendimiento$app->get(/, function () use ($app) {return new BinaryFileResponse($archivo);});
  75. 75. Response vs. BinaryFileResponse$app->get(/, function () use ($app) {return new Response(file_get_contents($archivo));});Rendimiento$app->get(/, function () use ($app) {return new BinaryFileResponse($archivo);});$app->get(/, function () use ($app) {return $app->sendFile($archivo);});
  76. 76. Response vs. BinaryFileResponseX-Sendfile-TypeX-Accel-RedirectX-Accel-Mapping
  77. 77. Response vs. BinaryFileResponseAPLICACIÓNAPACHE / NGINXKERNELX-Sendfile-TypeX-Accel-RedirectX-Accel-MappingSILEX
  78. 78. Response vs. BinaryFileResponseAPLICACIÓNAPACHE / NGINXKERNELsendfile()X-Sendfile-TypeX-Accel-RedirectX-Accel-MappingSILEX
  79. 79. REUTILIZANDOAPLICACIONES
  80. 80. usuariosweb/index.php/.../noticias/Una aplicación Silex típica
  81. 81. usuariosweb/index.phpadministrador/.../noticias/Una aplicación Silex típica
  82. 82. usuariosweb/index.phpadministrador/.../noticias/Una aplicación Silex típica/admin/admin/.../.../noticias/
  83. 83. Mezclando frontend y backend$app->get(/admin, function() { ... });$app->get(/admin/noticias, function() { ... });$app->get(/noticias, function() { ... });$app->get(/, function() { ... });
  84. 84. Mezclando frontend y backend$app->get(/admin, function() { ... });$app->get(/admin/noticias, function() { ... });$app->get(/noticias, function() { ... });$app->get(/, function() { ... });¡horrible!
  85. 85. Mezclando frontend y backend$app->mount(/admin, new AdminControllerProvider());$app->get(/noticias, function() { ... });$app->get(/, function() { ... });
  86. 86. Mezclando frontend y backend$app->mount(/admin, new AdminControllerProvider());$app->get(/noticias, function() { ... });$app->get(/, function() { ... });$app->register(new SilexProviderServiceControllerServiceProvider());penaliza elrendimiento
  87. 87. Mezclando frontend y backend$app->mount(/admin, new AdminControllerProvider());$app->get(/noticias, function() { ... });$app->get(/, function() { ... });
  88. 88. Mezclando frontend y backend$app->mount(/admin, new AdminControllerProvider());$app->get(/noticias, function() { ... });$app->get(/, function() { ... });class AdminControllerProviderimplements ControllerProviderInterface {public function connect(Application $app){$controllers = $app[controllers_factory];$controllers->before(function() use ($app) {// seguridad});$controllers->get(/, function (Application $app) { ... });}}
  89. 89. Mezclando frontend y backend$app->mount(/admin, new AdminControllerProvider());$app->get(/noticias, function() { ... });$app->get(/, function() { ... });class AdminControllerProviderimplements ControllerProviderInterface {public function connect(Application $app){$controllers = $app[controllers_factory];$controllers->before(function() use ($app) {// seguridad});$controllers->get(/, function (Application $app) { ... });}}
  90. 90. BACKENDusuarios administradorFRONTENDSeguridad obligatoria en frontend
  91. 91. BACKENDusuarios administradorFRONTENDSeguridad obligatoria en frontend
  92. 92. BACKENDusuarios administradorFRONTENDSeguridad obligatoria en frontend
  93. 93. BACKENDusuarios administradorFRONTENDSeguridad obligatoria en frontendpenaliza muchoel rendimiento
  94. 94. 1 proyecto2 aplicacionesN módulosfrontend y backend1 proyecto1 aplicaciónN bundles
  95. 95. Aplicación backendrequire_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;$app[http_cache]->run();web/index.php
  96. 96. Aplicación backendrequire_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;$app[http_cache]->run();web/index.phprequire_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/backend.php;$app->run();web/backend.php
  97. 97. Aplicación backendrequire_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/app.php;require __DIR__./../config/prod.php;require __DIR__./../src/controllers.php;$app[http_cache]->run();web/index.phprequire_once __DIR__./../vendor/autoload.php;$app = require __DIR__./../src/backend.php;$app->run();web/backend.php
  98. 98. src/backend.php$app = require __DIR__./app.php;$app->register(new SilexProviderSecurityServiceProvider());// ... configurar seguridad ...require __DIR__./../config/dev.php;require __DIR__./../src/controllers.php;$app[monolog.logfile] = __DIR__./../logs/backend.log;$app->mount(/admin, new AdminControllerProvider());return $app;
  99. 99. src/backend.php$app = require __DIR__./app.php;$app->register(new SilexProviderSecurityServiceProvider());// ... configurar seguridad ...require __DIR__./../config/dev.php;require __DIR__./../src/controllers.php;$app[monolog.logfile] = __DIR__./../logs/backend.log;$app->mount(/admin, new AdminControllerProvider());return $app;
  100. 100. src/backend.php$app = require __DIR__./app.php;$app->register(new SilexProviderSecurityServiceProvider());// ... configurar seguridad ...require __DIR__./../config/dev.php;require __DIR__./../src/controllers.php;$app[monolog.logfile] = __DIR__./../logs/backend.log;$app->mount(/admin, new AdminControllerProvider());return $app;
  101. 101. src/backend.php$app = require __DIR__./app.php;$app->register(new SilexProviderSecurityServiceProvider());// ... configurar seguridad ...require __DIR__./../config/dev.php;require __DIR__./../src/controllers.php;$app[monolog.logfile] = __DIR__./../logs/backend.log;$app->mount(/admin, new AdminControllerProvider());return $app;
  102. 102. src/backend.php$app = require __DIR__./app.php;$app->register(new SilexProviderSecurityServiceProvider());// ... configurar seguridad ...require __DIR__./../config/dev.php;require __DIR__./../src/controllers.php;$app[monolog.logfile] = __DIR__./../logs/backend.log;$app->mount(/admin, new AdminControllerProvider());return $app;
  103. 103. src/backend.php$app = require __DIR__./app.php;$app->register(new SilexProviderSecurityServiceProvider());// ... configurar seguridad ...require __DIR__./../config/dev.php;require __DIR__./../src/controllers.php;$app[monolog.logfile] = __DIR__./../logs/backend.log;$app->mount(/admin, new AdminControllerProvider());return $app;
  104. 104. /admin/admin/.../.../noticias/usuariosadministradorweb/index.php/.../noticias/Aplicaciones Silex compartidasweb/backend.php
  105. 105. Ventajas de reutilizar aplicaciones• Sólo se aplica la seguridad en laaplicación backend.• El rendimiento de la parte pública nose ve afectado.• En el backend están disponibles todaslas rutas y controladores públicos.
  106. 106. MIDDLEWARES
  107. 107. Middlewares de aplicación$app->before(function ($request) {// ...});$app->after(function ($request, $response) {// ...});$app->finish(function ($request, $response) {// ...});
  108. 108. Middlewares de controlador$before = function ($request) use ($app) {// ...};$after = function ($request, $response) use ($app) {// ...};$app->get(..., function () {// ...})->before($before)->after($after);
  109. 109. El middleware before()public function before($callback, $priority = 0){$this->on(KernelEvents::REQUEST,function ($event) use ($callback) {$ret = call_user_func($callback, $event->getRequest());if ($ret instanceof Response) {$event->setResponse($ret);}},$priority);}
  110. 110. El middleware before()public function before($callback, $priority = 0){$this->on(KernelEvents::REQUEST,function ($event) use ($callback) {$ret = call_user_func($callback, $event->getRequest());if ($ret instanceof Response) {$event->setResponse($ret);}},$priority);}public function on($eventName, $callback, $priority = 0){// ...$dispatcher->addListener($eventName, $callback, $priority);}
  111. 111. Middlewares «obligatorios»$app->before(function() use ($app) {if (!$app[security]->isGranted(ROLE_ADMIN)) {return $app->redirect(/);}});
  112. 112. Middlewares «prescindibles»$app->before(function(Request $request) {$request->query->set(token, ...);$request->server->set(SERVER_ADDR, ::1);});
  113. 113. Mismo ejemplo sin middlewaresrequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});$app->run();
  114. 114. Mismo ejemplo sin middlewaresrequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});$app->run();public function run(Request $request = null){if (null === $request) {$request = Request::createFromGlobals();}// ...}
  115. 115. Mismo ejemplo sin middlewaresrequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(/, function() use($app) {return $app[twig]->render(portada.twig),});$request = Request::createFromGlobals();$request->query->set(token, ...);$request->server->set(SERVER_ADDR, ::1);$app->run($request);
  116. 116. Middlewares «prescindibles»$app->before(function() use ($app) {$app[time.start] = microtime(true);});$app->after(function() use ($app) {$app[time.end] = microtime(true);});$app->finish(function() use ($app) {$elapsed = $app[time.start] - $app[time.end];$app[monolog]->addDebug(...);});
  117. 117. Mismo ejemplo «sin middlewares»$app->finish(function(Request $request) use ($app) {$elapsed = 1000 * (microtime(true) - $request->server->get(REQUEST_TIME_FLOAT));$app[monolog]->addDebug(...);});
  118. 118. SERVICEPROVIDERS
  119. 119. Anatomía de un ServiceProvideruse SilexServiceProviderInterface;class XXXServiceProviderimplements ServiceProviderInterface{public function register(Application $app){$app[xxx] = $app->share(function () use ($app) { // ... });$app[yyy] = $app->share(function () { // ... });}public function boot(Application $app){$app[dispatcher]->addListener(KernelEvents::REQUEST, array($this, onEarlyKernelRequest), 128);$app->before(function (Request $request) use ($app) { // ... });$app->error(function (Exception $e) use ($app) { // ... }, 255);$app->after(function (Request $request, Response $response) use ($app) { // ... });}}
  120. 120. Anatomía de un ServiceProvideruse SilexServiceProviderInterface;class XXXServiceProviderimplements ServiceProviderInterface{public function register(Application $app){$app[xxx] = $app->share(function () use ($app) { // ... });$app[yyy] = $app->share(function () { // ... });}public function boot(Application $app){$app[dispatcher]->addListener(KernelEvents::REQUEST, array($this, onEarlyKernelRequest), 128);$app->before(function (Request $request) use ($app) { // ... });$app->error(function (Exception $e) use ($app) { // ... }, 255);$app->after(function (Request $request, Response $response) use ($app) { // ... });}}defines los servicios
  121. 121. Anatomía de un ServiceProvideruse SilexServiceProviderInterface;class XXXServiceProviderimplements ServiceProviderInterface{public function register(Application $app){$app[xxx] = $app->share(function () use ($app) { // ... });$app[yyy] = $app->share(function () { // ... });}public function boot(Application $app){$app[dispatcher]->addListener(KernelEvents::REQUEST, array($this, onEarlyKernelRequest), 128);$app->before(function (Request $request) use ($app) { // ... });$app->error(function (Exception $e) use ($app) { // ... }, 255);$app->after(function (Request $request, Response $response) use ($app) { // ... });}}defines los serviciosmodificas la aplicación
  122. 122. Servicio básico$app[logger] = function () {return new Logger();};se crea una nuevainstancia cada vezque lo usas
  123. 123. Servicio compartido$app[logger] = $app->share(function () {return new Logger();});se reutiliza lamisma instanciauna y otra vez
  124. 124. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = function () {$logger = new Logger();$logger->metodoXXX();return $logger;};lo que tengolo que quiero
  125. 125. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = $app->extend(logger, function($logger, $app) {$logger->metodoXXX();return $logger;});
  126. 126. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = $app->extend(logger, function($logger, $app) {$logger->metodoXXX();return $logger;});
  127. 127. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = $app->extend(logger, function($logger, $app) {$logger->metodoXXX();return $logger;});modifica este servicio
  128. 128. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = $app->extend(logger, function($logger, $app) {$logger->metodoXXX();return $logger;});modifica este servicio
  129. 129. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = $app->extend(logger, function($logger, $app) {$logger->metodoXXX();return $logger;});
  130. 130. Extendiendo servicios$app[logger] = function () {return new Logger();};$app[logger] = $app->extend(logger, function($logger, $app) {$logger->metodoXXX();return $logger;});lo que devuelva
  131. 131. Extendiendo servicios compartidos$app[logger] = $app->share(function () {return new Logger();});$app[logger] = $app->share( $app->extend(logger,function($logger, $app) {$logger->metodoXXX();return $logger;}));
  132. 132. Extendiendo servicios compartidos$app[logger] = $app->share(function () {return new Logger();});$app[logger] = $app->share( $app->extend(logger,function($logger, $app) {$logger->metodoXXX();return $logger;}));
  133. 133. Ejemplo extensión serviciosclass ServiceControllerServiceProviderimplements ServiceProviderInterface{public function register(Application $app){$app[resolver] = $app->share($app->extend(resolver,function ($resolver, $app) {return new ServiceControllerResolver($resolver, $app);}));}public function boot(Application $app) { // ... }}
  134. 134. Ejemplo extensión serviciosclass ServiceControllerServiceProviderimplements ServiceProviderInterface{public function register(Application $app){$app[resolver] = $app->share($app->extend(resolver,function ($resolver, $app) {return new ServiceControllerResolver($resolver, $app);}));}public function boot(Application $app) { // ... }}
  135. 135. SILEX 1.1
  136. 136. Silex 1.0public function before($callback, $priority = 0){$this[dispatcher]->addListener(KernelEvents::REQUEST,function (GetResponseEvent $event) use ($callback) {// ...}Los métodos on(), before(), after(), error() fuerzan lacreación del dispatcher y todas sus dependencias.
  137. 137. Lazy dispatcherpublic function before($callback, $priority = 0){$this[dispatcher] = $this->share($this->extend(dispatcher,function ($dispatcher, $app) use ($callback, $priority) {$dispatcher->addListener(KernelEvents::REQUEST, $callback, $priority);return $dispatcher;}));}En Silex 1.1, los métodos on(), before(), after(),error() crean el dispatcher en el último momento.
  138. 138. SEGUNDA PARTECARACTERÍSTICASAL LÍMITE
  139. 139. INSTALACIÓN
  140. 140. No instales Silex asícomposer.json has been updatedLoading composer repositories with package informationUpdating dependencies (including require-dev)- Installing psr/log (1.0.0)- Installing symfony/routing (v2.3.0)- Installing symfony/debug (v2.3.1)- Installing symfony/http-foundation (v2.3.1)- Installing symfony/event-dispatcher (v2.3.0)- Installing symfony/http-kernel (v2.3.0)- Installing pimple/pimple (v1.0.2)- Installing silex/silex (v1.0.0)Writing lock fileGenerating autoload files$ cd mi_proyecto$ composer require silex/silex 1.0
  141. 141. silex/silex 1.0
  142. 142. silex/silex 1.0¿controladores?¿configuración?¿index.php?
  143. 143. MICRO DOES NOT MEANLESS CODE. MICROMEANS LESS STRUCTUREAND LESS DECISIONSMADE FOR YOU.FABIEN POTENCIERCREADOR DE SYMFONY, SILEX Y TWIG
  144. 144. Instala una «distribución» de Silex$ composer create-project fabpot/Silex-Skeletonmi_proyecto1.0- Installing psr/log (1.0.0)- Installing twig/twig (v1.13.1)- Installing symfony/icu (v1.2.0)- Installing symfony/intl (v2.3.1)- Installing symfony/stopwatch (v2.3.1)- Installing symfony/twig-bridge (v2.3.1)- Installing symfony/routing (v2.3.0)- Installing symfony/debug (v2.3.1)- Installing symfony/http-foundation (v2.3.1)- Installing symfony/event-dispatcher (v2.3.0)- Installing symfony/http-kernel (v2.3.0)- Installing symfony/web-profiler-bundle (v2.3.1)- Installing pimple/pimple (v1.0.2)- Installing silex/silex (1.0.x-dev a6dde11)- Installing silex/web-profiler (v1.0.0)- Installing symfony/dom-crawler (v2.3.1)- Installing symfony/browser-kit (v2.3.1)- Installing symfony/class-loader (v2.3.1)- Installing symfony/filesystem (v2.3.1)- Installing symfony/config (v2.3.1)- Installing symfony/console (v2.3.1)- Installing symfony/css-selector (v2.3.0)- Installing symfony/finder (v2.3.1)- Installing symfony/property-access (v2.3.1)- Installing symfony/options-resolver (v2.3.1)- Installing symfony/form (v2.3.1)- Installing monolog/monolog (1.5.0)- Installing symfony/monolog-bridge (v2.3.1)- Installing symfony/process (v2.3.1)- Installing symfony/security (v2.3.1)- Installing symfony/translation (v2.3.0)- Installing symfony/validator (v2.3.1)
  145. 145. fabpot/Silex-Skeleton
  146. 146. fabpot/Silex-SkeletonControladoresfrontales
  147. 147. fabpot/Silex-SkeletonTu código
  148. 148. fabpot/Silex-SkeletonPlantillas
  149. 149. fabpot/Silex-SkeletonConfiguracióny registro deservicios
  150. 150. fabpot/Silex-SkeletonIgual queSymfony2
  151. 151. Silex Kitchen Sink Edition$ composer create-project lyrixx/Silex-Kitchen-Editionmi_proyecto1.0
  152. 152. Silex Kitchen Sink Edition+ + +AsseticDoctrineSilex HTML5BoilerplateTwitterBootstrap$ composer create-project lyrixx/Silex-Kitchen-Editionmi_proyecto1.0
  153. 153. mini truco
  154. 154. Controladores frontalesindex.php index_dev.php
  155. 155. Controladores frontalesindex.php index_dev.phpPara las aplicaciones complejas usamosseis entornos de ejecución:DEV PROD TEST BETA STAGING ROLLOUTFuente: http://37signals.com/svn/posts/3535-beyond-the-default-rails-environments37signals
  156. 156. Controladores frontalesindex.php index_dev.phpprod.php dev.php
  157. 157. Controladores frontalesindex.php index_dev.phpprod.php dev.php beta.php staging.php
  158. 158. TRAITS
  159. 159. TRAITS IS JUSTCOMPILER-ASSISTEDCOPY-AND-PASTESTEFAN MARRSOFTWARE LANGUAGES LAB / VRIJE UNIVERSITEIT
  160. 160. Traits en PHPtrait metodosComunes {function metodo1() { ... }function metodo2() { ... }}class miClase {use metodosComunes;// ...}
  161. 161. Traits en PHPtrait metodosComunes {function metodo1() { ... }function metodo2() { ... }}class miClase {use metodosComunes;// ...}$objeto = new MiClase();$objeto->metodo1();$objeto->metodo2();
  162. 162. Traits en PHPtrait metodosComunes {function metodo1() { ... }function metodo2() { ... }}class miClase {use metodosComunes;// ...}$objeto = new MiClase();$objeto->metodo1();$objeto->metodo2();PHP 5.4o superior
  163. 163. FormTraitMonologTraitSecurityTraitSwiftmailerTraitTranslationTraitTwigTraitUrlGeneratorTraittraits
  164. 164. Traits en aplicaciones Silexrequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(...);$app->run();
  165. 165. Traits en aplicaciones Silexrequire_once __DIR__./../vendor/autoload.php;$app = new SilexApplication();$app->register( ... );$app->get(...);$app->run();class Application extends SilexApplication {use SilexApplicationTwigTrait;use SilexApplicationUrlGeneratorTrait;}$app = new Application();
  166. 166. Sin usar UrlGeneratorTrait$app->get(/, function () use ($app) {$url = $this[url_generator]->generate($ruta, $params);$urlAbsoluta = $this[url_generator]->generate($ruta, $params, true);});
  167. 167. Usando UrlGeneratorTrait$app->get(/, function () use ($app) {$url = $app->path($ruta, $params);$urlAbsoluta = $app->url($ruta, $params);});
  168. 168. Sin usar TwigTrait$app->get(/, function () use ($app) {return new Response($app[twig]->render(plantilla.twig, $params),200,[Cache-Control => public, s-maxage=3600]);});
  169. 169. Usando TwigTrait$app->get(/, function () use ($app) {return $app->render(plantilla.twig,$params,(new Response)->setTtl(3600));});
  170. 170. RESPONSIBLECONTROLLERS
  171. 171. APIs con múltiples formatos$app->get(/api/..., function(Request $request) {$datos = ...if (json == $request->getRequestFormat()) {return new JsonResponse($datos);} elseif (xml == $request->getRequestFormat()) {return new Response($datosEnXml,200,[Content-Type => application/xml]);}});
  172. 172. APIs con múltiples formatos$app->get(/api/..., function(Request $request) {$datos = ...return $datos;});
  173. 173. TobiasSjöstengithub.com/tobiassjosten/ResponsibleServiceProviderResponsibleServiceProviderFormateo automágico de larespuesta en función del formatode la petición (JSON o XML).
  174. 174. ResponsibleServiceProvider$ composer requiretobiassjosten/ResponsibleServiceProvider$app->register(new TobiassjostenSilexResponsibleServiceProvider());
  175. 175. APIs con múltiples formatos$app->get(/api/..., function(Request $request) {$datos = ...return $datos;});
  176. 176. ResponsibleServiceProviderclass ResponsibleServiceProvider implements ServiceProviderInterface{public function register(Application $app){if (empty($app[serializer])) {$app->register(new SerializerServiceProvider());}}public function boot(Application $app){$app[dispatcher]->addSubscriber(new ResponsibleListener($app[serializer]));}}
  177. 177. ResponsibleListenerclass ResponsibleListener implements EventSubscriberInterface{public static function getSubscribedEvents(){return array(KernelEvents::VIEW => array(onKernelView, -10));}public function onKernelView(GetResponseForControllerResultEvent $event){$result = $event->getControllerResult();$supported = array(json, xml);$accepted = $request->getAcceptableContentTypes();// ...$event->setResponse(new Response($this->encoder->encode($result, $format),200, array(Content-Type => $type)));// ...
  178. 178. ResponsibleListenerclass ResponsibleListener implements EventSubscriberInterface{public static function getSubscribedEvents(){return array(KernelEvents::VIEW => array(onKernelView, -10));}public function onKernelView(GetResponseForControllerResultEvent $event){$result = $event->getControllerResult();$supported = array(json, xml);$accepted = $request->getAcceptableContentTypes();// ...$event->setResponse(new Response($this->encoder->encode($result, $format),200, array(Content-Type => $type)));// ...
  179. 179. ResponsibleListenerclass ResponsibleListener implements EventSubscriberInterface{public static function getSubscribedEvents(){return array(KernelEvents::VIEW => array(onKernelView, -10));}public function onKernelView(GetResponseForControllerResultEvent $event){$result = $event->getControllerResult();$supported = array(json, xml);$accepted = $request->getAcceptableContentTypes();// ...$event->setResponse(new Response($this->encoder->encode($result, $format),200, array(Content-Type => $type)));// ...
  180. 180. ResponsibleListenerclass ResponsibleListener implements EventSubscriberInterface{public static function getSubscribedEvents(){return array(KernelEvents::VIEW => array(onKernelView, -10));}public function onKernelView(GetResponseForControllerResultEvent $event){$result = $event->getControllerResult();$supported = array(json, xml);$accepted = $request->getAcceptableContentTypes();// ...$event->setResponse(new Response($this->encoder->encode($result, $format),200, array(Content-Type => $type)));// ...
  181. 181. CONFIGURACIÓN
  182. 182. Configuración en Silex-Skeleton$app[db.options] = array(dbname => ..., user => ..., password => ...);$app[debug] = false;config/prod.phpconfig/dev.phprequire __DIR__./prod.php;$app[db.options] = array(dbname => ..., user => ..., password => ...);$app[debug] = true;
  183. 183. IgorWiedlergithub.com/igorw/ConfigServiceProviderConfigServiceProviderAñade un servicio de configuracióna Silex con soporte para archivosYAML, JSON, PHP, TOML.
  184. 184. igorw / ConfigServiceProvider$ composer require igorw/ConfigServiceProvider$app->register(new IgorwSilexConfigServiceProvider("config.json"));
  185. 185. igorw / ConfigServiceProvider$ composer require igorw/ConfigServiceProvider$app->register(new IgorwSilexConfigServiceProvider("config.json"));{"debug": true}$app[debug] = true;
  186. 186. "config.yml""config.php""config.toml"$app->register(new IgorwSilexConfigServiceProvider("config.json"));Múltiples formatos
  187. 187. $app->register(new IgorwSilexConfigServiceProvider("config.yml"));$app->register(new IgorwSilexConfigServiceProvider("params.php"));$app->register(new IgorwSilexConfigServiceProvider("dev.json"));Múltiples archivos
  188. 188. $app->register(new IgorwSilexConfigServiceProvider(__DIR__."/config/config.json",array(debug => true, version => 2)));Configurar en ejecuciónconfig/config.json{"enable_cache": %debug%,"api_endpoint": "http://api.acme.org/%version%"}
  189. 189. $app->register(new IgorwSilexConfigServiceProvider(__DIR__."/config/config.json",array(debug => true, version => 2)));Configurar en ejecuciónconfig/config.json{"enable_cache": %debug%,"api_endpoint": "http://api.acme.org/%version%"}
  190. 190. $app->register(new IgorwSilexConfigServiceProvider(__DIR__."/config/config.json",array(debug => true, version => 2)));Configurar en ejecuciónconfig/config.json{"enable_cache": %debug%,"api_endpoint": "http://api.acme.org/%version%"}
  191. 191. public function registerContainerConfiguration(LoaderInterface $loader){$loader->load(__DIR__./config/config_.$this->getEnvironment()..yml);}Configuración por entorno (Sf2)app/AppKernel.phppublic function getEnvironment(){return $this->container->getParameter(kernel.environment);}
  192. 192. $env = getenv(APP_ENV) ?: prod;$app->register(new IgorwSilexConfigServiceProvider(__DIR__."/../config/$env.json"));Configuración por entorno (Silex)app.phphttpd-vhosts.conf<VirtualHost *:80>ServerName acme.devSetEnv APP_ENV dev...</VirtualHost>
  193. 193. EXCEPCIONES
  194. 194. Excepciones clásicas en Silex$app->error(function (Exception $e, $code) use ($app) {if ($app[debug]) {return;}$page = 404 == $code ? 404.html : 500.html;return new Response($app[twig]->render($page, array(code => $code)),$code);});
  195. 195. Excepciones clásicas en Silex$app->error(function (Exception $e, $code) use ($app) {if ($app[debug]) {return;}$page = 404 == $code ? 404.html : 500.html;return new Response($app[twig]->render($page, array(code => $code)),$code);});
  196. 196. INBOXStarredDraftsAll mailSpam
  197. 197. INBOXStarredDraftsAll mailSpam1
  198. 198. INBOXStarredDraftsAll mailSpam12
  199. 199. Google y los códigos de estado50X40X20X
  200. 200. Excepciones que devuelven 404$app->error(function (Exception $e, $code) use ($app) {if ($app[debug]) {return;}$page = 404 == $code ? 404.html : 500.html;return new Response($app[twig]->render($page, array(code => $code)),404);});
  201. 201. APLICACIONESDESACOPLADAS
  202. 202. APLICACIÓN PHPSILEXSILEXTU APLICACIÓNAplicaciones acopladasdependes totalmentede Silex
  203. 203. SILEXTU APLICACIÓNSILEXAPLICACIÓN PHPAplicaciones acopladasdependes totalmentede Silexaplicación PHPdesacoplada de Silex
  204. 204. Controladores Silex clásicos$app->get(/, function() use($app) {// ...return $app[twig]->render(portada.twig);});
  205. 205. Controladores Silex en clases$app->get(/, AcmeControladores::index);use SilexApplication;use SymfonyComponentHttpFoundationRequest;namespace Acme {class Controladores {public function index(Application $app, Request $request) {// ...return $app[twig]->render(portada.twig),}}}
  206. 206. Controladores Silex en clases$app->get(/, AcmeControladores::index);use SilexApplication;use SymfonyComponentHttpFoundationRequest;namespace Acme {class Controladores {public function index(Application $app, Request $request) {// ...return $app[twig]->render(portada.twig),}}}
  207. 207. Controladores Silex en clases$app->get(/, AcmeControladores::index);use SilexApplication;use SymfonyComponentHttpFoundationRequest;namespace Acme {class Controladores {public function index(Application $app, Request $request) {// ...return $app[twig]->render(portada.twig),}}}
  208. 208. Controladores Silex en servicios$app->get(/, "controladores:indexAction");use AcmeControladores;$app[controladores] = $app->share(function(Request $request) use ($app) {return new Controladores($app, $request);});use SilexApplication;use SymfonyComponentHttpFoundationRequest;namespace Acme {class Controladores {protected $app;protected $request;public function __construct(Application $app, Request $request) {$this->app = $app;$this->request = $request;}public function indexAction() {// ...return $app[twig]->render(portada.twig),}}}
  209. 209. Controladores Silex en servicios$app->get(/, "controladores:indexAction");use AcmeControladores;$app[controladores] = $app->share(function(Request $request) use ($app) {return new Controladores($app, $request);});use SilexApplication;use SymfonyComponentHttpFoundationRequest;namespace Acme {class Controladores {protected $app;protected $request;public function __construct(Application $app, Request $request) {$this->app = $app;$this->request = $request;}public function indexAction() {// ...return $app[twig]->render(portada.twig),}}}
  210. 210. Controladores Silex en servicios$app->get(/, "controladores:indexAction");use AcmeControladores;$app[controladores] = $app->share(function(Request $request) use ($app) {return new Controladores($app, $request);});use SilexApplication;use SymfonyComponentHttpFoundationRequest;namespace Acme {class Controladores {protected $app;protected $request;public function __construct(Application $app, Request $request) {$this->app = $app;$this->request = $request;}public function indexAction() {// ...return $app[twig]->render(portada.twig),}}}
  211. 211. La aplicación no está desacopladaLa aplicación sigue dependiendo delos objetos de Silex ($app, $request).class Controladores {public function __construct(Application $app, Request $request) {$this->app = $app;$this->request = $request;}public function indexAction() {// ...return $app[twig]->render(portada.twig),}}
  212. 212. La aplicación no está desacopladaLa aplicación sigue dependiendo delos objetos de Silex ($app, $request).class Controladores {public function __construct(Application $app, Request $request) {$this->app = $app;$this->request = $request;}public function indexAction() {// ...return $app[twig]->render(portada.twig),}}
  213. 213. IgorWiedlergithub.com/igorw/doucheswagDaveMarshallspeakerdeck.com/igorw/silex-an-implementation-detail
  214. 214. TU APLICACIÓN SILEXSILEXTU APLICACIÓN PHPAplicaciones desacopladas
  215. 215. SILEXTU APLICACIÓN PHPAplicaciones desacopladasTU APLICACIÓN SILEXdesacopladade Silexinterfaz entretu aplicacióny Silex
  216. 216. Controlador clásico$app->get(/auction/{id}, function() use($app) {$datos = $this->app[db]->fetchAssoc(...);return $app[twig]->render(auction_view.twig);});
  217. 217. Controlador desacoplado$app->get(/auction/{id}, interactor.auction_view)->value(controller, auction_view)->convert(request, function ($_, Request $request) {$id = $request->attributes->get(id)return new AuctionViewRequest($id);});
  218. 218. Controlador desacoplado$app->get(/auction/{id}, interactor.auction_view)->value(controller, auction_view)->convert(request, function ($_, Request $request) {$id = $request->attributes->get(id)return new AuctionViewRequest($id);});123
  219. 219. 1. Controladores como servicios$app->get(/auction/{id}, interactor.auction_view)$app[resolver] = $app->share($app->extend(resolver,function ($resolver, $app) {$resolver = new ControllerResolver($resolver, $app);return $resolver;}));
  220. 220. 1. ControllerResolver propioclass ControllerResolver implements ControllerResolverInterface{public function getController(Request $request){$controller = $request->attributes->get(_controller);if (!is_string($controller) || !isset($this->container[$controller])) {return $this->resolver->getController($request);}return $this->container[$controller];}}
  221. 221. 1. Definiendo los controladoresclass ServiceProvider implements ServiceProviderInterface{public function register(Application $app){$app[interactor.auction_view] = $app->share(function () {return new AuctionView( ... );});// ...}public function boot(Application $app) { ... }}
  222. 222. 1. Definiendo los controladoresclass ServiceProvider implements ServiceProviderInterface{public function register(Application $app){$app[interactor.auction_view] = $app->share(function () {return new AuctionView( ... );});// ...}public function boot(Application $app) { ... }}clase de miaplicación PHP
  223. 223. 1. AuctionViewclass AuctionView{public function __construct(AuctionRepository $repo){// ...}public function __invoke(AuctionViewRequest $request){// ...}}
  224. 224. 1. AuctionViewclass AuctionView{public function __construct(AuctionRepository $repo){// ...}public function __invoke(AuctionViewRequest $request){// ...}}método mágico:objeto()
  225. 225. 1. AuctionViewclass AuctionView{// ...public function __invoke(AuctionViewRequest $request){$auction = $this->repo->find($request->id);$view = AuctionViewDto::fromEntity($auction);return new AuctionViewResponse($view);}}
  226. 226. 1. AuctionViewclass AuctionView{// ...public function __invoke(AuctionViewRequest $request){$auction = $this->repo->find($request->id);$view = AuctionViewDto::fromEntity($auction);return new AuctionViewResponse($view);}}Request()
  227. 227. 1. AuctionViewclass AuctionView{// ...public function __invoke(AuctionViewRequest $request){$auction = $this->repo->find($request->id);$view = AuctionViewDto::fromEntity($auction);return new AuctionViewResponse($view);}}Request()Doctrine
  228. 228. 1. AuctionViewclass AuctionView{// ...public function __invoke(AuctionViewRequest $request){$auction = $this->repo->find($request->id);$view = AuctionViewDto::fromEntity($auction);return new AuctionViewResponse($view);}}Request()DoctrineTwig
  229. 229. Desacoplando aplicacionesTU APLICACIÓNPHPAuctionViewResponseAuctionViewRequestAuctionViewRequest
  230. 230. Controlador desacoplado$app->get(/auction/{id}, interactor.auction_view)->value(controller, auction_view)->convert(request, function ($_, Request $request) {$id = $request->attributes->get(id)return new AuctionViewRequest($id);});123
  231. 231. 2. Usando mis propios objetos$app->...->convert(request, function ($_, Request $request) {return new AuctionViewRequest($request->attributes->get(id));});
  232. 232. 2. Usando mis propios objetos$app->...->convert(request, function ($_, Request $request) {return new AuctionViewRequest($request->attributes->get(id));});Silex
  233. 233. 2. Usando mis propios objetos$app->...->convert(request, function ($_, Request $request) {return new AuctionViewRequest($request->attributes->get(id));});SilexMi aplicación PHP
  234. 234. 2. AuctionViewRequestclass AuctionViewRequest{public $id;public function __construct($id){$this->id = $id;}}
  235. 235. Controlador desacoplado$app->get(/auction/{id}, interactor.auction_view)->value(controller, auction_view)->convert(request, function ($_, Request $request) {$id = $request->attributes->get(id)return new AuctionViewRequest($id);});123
  236. 236. 3. Generando la respuesta$app->...->value(controller, auction_view)
  237. 237. 3. Generando la respuesta$app->...->value(controller, auction_view)¿?¿?¿?
  238. 238. 3. Generando la respuesta$app[dispatcher] = $app->share($app->extend(dispatcher, function ($dispatcher, $app){$dispatcher->addListener(KernelEvents::VIEW, function ($event) use ($app) {// ...$view = $event->getControllerResult();$controller = $request->attributes->get(controller);$template = "$controller.html";$view = (object) $view;$body = $app[mustache]->render($template, $view);$response = new Response($body);$event->setResponse($response);});return $dispatcher;}));
  239. 239. 3. Generando la respuesta$app[dispatcher] = $app->share($app->extend(dispatcher, function ($dispatcher, $app){$dispatcher->addListener(KernelEvents::VIEW, function ($event) use ($app) {// ...$view = $event->getControllerResult();$controller = $request->attributes->get(controller);$template = "$controller.html";$view = (object) $view;$body = $app[mustache]->render($template, $view);$response = new Response($body);$event->setResponse($response);});return $dispatcher;}));
  240. 240. 3. Generando la respuesta$app[dispatcher] = $app->share($app->extend(dispatcher, function ($dispatcher, $app){$dispatcher->addListener(KernelEvents::VIEW, function ($event) use ($app) {// ...$view = $event->getControllerResult();$controller = $request->attributes->get(controller);$template = "$controller.html";$view = (object) $view;$body = $app[mustache]->render($template, $view);$response = new Response($body);$event->setResponse($response);});return $dispatcher;}));
  241. 241. 3. Generando la respuesta$app[dispatcher] = $app->share($app->extend(dispatcher, function ($dispatcher, $app){$dispatcher->addListener(KernelEvents::VIEW, function ($event) use ($app) {// ...$view = $event->getControllerResult();$controller = $request->attributes->get(controller);$template = "$controller.html";$view = (object) $view;$body = $app[mustache]->render($template, $view);$response = new Response($body);$event->setResponse($response);});return $dispatcher;}));
  242. 242. 3. Generando la respuesta$app[dispatcher] = $app->share($app->extend(dispatcher, function ($dispatcher, $app){$dispatcher->addListener(KernelEvents::VIEW, function ($event) use ($app) {// ...$view = $event->getControllerResult();$controller = $request->attributes->get(controller);$template = "$controller.html";$view = (object) $view;$body = $app[mustache]->render($template, $view);$response = new Response($body);$event->setResponse($response);});return $dispatcher;}));
  243. 243. Una visión generalsrcDoucheDoucheWeb
  244. 244. Una visión generalsrcDoucheDoucheWebSilexPHP
  245. 245. Una visión generalDoucheWebapp.phpviewsControllerResolver.phpServiceProvider.php
  246. 246. Una visión generalDoucheEntity ExceptionInteractor RepositoryService StorageValue View
  247. 247. SINGLE-FILEAPPLICATIONS
  248. 248. Inline templates (Ruby / Sinatra)require sinatraget / dohaml :indexend__END__@@ layout%html= yield@@ index%div.title Hello world.
  249. 249. Inline templates (Ruby / Sinatra)require sinatraget / dohaml :indexend__END__@@ layout%html= yield@@ index%div.title Hello world.controladores, rutas yplantillas en 1 solo archivo
  250. 250. Inline templates (Ruby / Sinatra)require sinatraget / dohaml :indexend__END__@@ layout%html= yield@@ index%div.title Hello world.controladores, rutas yplantillas en 1 solo archivo
  251. 251. JustinHilemangithub.com/bobthecow/mustache-silex-providermustache / silex-providerPermite utilizar plantillas Mustacheen Silex, incluyendo soporte paralas inline templates.
  252. 252. __halt_compiler()
  253. 253. __halt_compiler() en PHAR<?php/* This file is part of the Silex framework.(c) Fabien Potencier <fabien@symfony.com> */Phar::mapPhar(silex.phar);require_once phar://silex.phar/vendor/autoload.php;// ...__halt_compiler(); ?>jsilex.phar&src/Silex/ExceptionListenerWrapper.php.콩Q.܎Ŷsrc/Silex/HttpCache.php¡ì½©Q¡•¯2—³¶!src/Silex/Route/SecurityTrait.php:콩Q:ŽsµÌ¶ src/Silex/ControllerResolver.php콩QÄ–±2¶src/Silex/WebTestCase.php»ì½©Q»ÝW¹¶src/Silex/Controller.php8콩Q8código PHP quese ejecutadatos de laaplicación
  254. 254. Inline templates (PHP / Silex)$app->get(..., function() use ($app) {// ...});__halt_compiler();@@ portada<ul>{{#secciones}}<li><a href="{{ enlace }}">{{ titulo }}</a></li>{{/secciones}}</ul>@@ categoria<h1>{{ titulo }}</h1>controladoresplantillaportadaplantillacategoria
  255. 255. mustache / silex-provider$ composer require mustache/silex-provider 1.0$app->register(new MustacheSilexProviderMustacheServiceProvider, array(mustache.loader => new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__)));
  256. 256. mustache / silex-provider$ composer require mustache/silex-provider 1.0$app->register(new MustacheSilexProviderMustacheServiceProvider, array(mustache.loader => new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__)));este mismoarchivo
  257. 257. mustache / silex-provider$ composer require mustache/silex-provider 1.0$app->register(new MustacheSilexProviderMustacheServiceProvider, array(mustache.loader => new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__)));este mismoarchivoel lugar en el que se encuentre lallamada a __halt_compiler()
  258. 258. Single-File Application$app->get(/, function() use ($app) {return $app[mustache]->render(portada, array(‘secciones’ => array(...)));});$app->get(/{slug}, function($slug) use ($app) {return $app[mustache]->render(categoria, array(‘titulo’ => $slug));});__halt_compiler();@@ portada<ul>{{#secciones}}<li><a href="{{ enlace }}">{{ titulo }}</a></li>{{/secciones}}</ul>@@ categoria<h1>{{ titulo }}</h1>
  259. 259. Single-File Application$app->get(/, function() use ($app) {return $app[mustache]->render(portada, array(‘secciones’ => array(...)));});$app->get(/{slug}, function($slug) use ($app) {return $app[mustache]->render(categoria, array(‘titulo’ => $slug));});__halt_compiler();@@ portada<ul>{{#secciones}}<li><a href="{{ enlace }}">{{ titulo }}</a></li>{{/secciones}}</ul>@@ categoria<h1>{{ titulo }}</h1>
  260. 260. Mustache_Loader_InlineLoaderclass Mustache_Loader_InlineLoaderimplements Mustache_Loader{// ...protected function loadTemplates(){$this->templates = array();$data = file_get_contents($this->fileName, false, null, $this->offset);foreach (preg_split("/^@@(?= [wd.]+$)/m", $data, -1) as $chunk) {if (trim($chunk)) {list($name, $content) = explode("n", $chunk, 2);$this->templates[trim($name)] = trim($content);}}}}
  261. 261. Referencias
  262. 262. GonzaloAyusoFranMorenoMatthiasNobackgonzalo123.com/tag/silex/showmethecode.es/category/php/silex/php-and-symfony.matthiasnoback.nl/category/silex/
  263. 263. GRACIAS.
  264. 264. PREGUNTASpuedes valorar esta charla enjoind.in/talk/view/8851
  265. 265. ContactoJavier Eguiluzjaviereguiluz.comtwitter.com/javiereguiluzgithub.com/javiereguiluzlinkedin.com/in/javiereguiluz

×