Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Symfony: Your Next Microframework (SymfonyCon 2015)

6.479 Aufrufe

Veröffentlicht am

Microservices are a huge trend, and microframeworks are perfect for them: put together just a few files, write some code, and your done!

But Symfony is a big framework, right? Wrong! Symfony can be as small as a single file!

In this talk, we'll learn how to use Symfony as a micro-framework for your next project. Your app will stay small and clear, but without needing to give up the features or third-party bundles that you love. And if the project grows, it can evolve naturally into a full Symfony project.

So yes, Symfony can also be a microframework. Tell the world!

Veröffentlicht in: Technologie
  • Slide 41+42: How do you managed to put full stack framework into 52 lines of code in 2 files? What about those thousands of lines in /vendor, which have to be processed as well on each request?
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • Silex can evolve to a full stack framework https://github.com/saxulum/saxulum
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier

Symfony: Your Next Microframework (SymfonyCon 2015)

  1. 1. Symfony: Your Next Microframework by your friend: Ryan Weaver @weaverryan by your friend: Ryan Weaver @weaverryan
  2. 2. KnpUniversity.com github.com/weaverryan Who is this guy? > Lead for the Symfony documentation
 > KnpLabs US - Symfony Consulting, training & general Kumbaya > Writer for KnpUniversity.com Tutorials > Husband of the much more talented @leannapelham
  3. 3. Thinking about 2 Problems @weaverryan
  4. 4. Problem 1: Symfony Sucks @weaverryan
  5. 5. @weaverryan
  6. 6. @weaverryan
  7. 7. @weaverryan
  8. 8. @weaverryan
  9. 9. Symfony is too hard @weaverryan
  10. 10. The Symfony Framework is too hard @weaverryan The components are not usually the problem
  11. 11. Why? @weaverryan
  12. 12. Route Controller Response @weaverryan WTF? Useful Objects
  13. 13. 1) Common tasks require
 too much code @weaverryan
  14. 14. 2) Symfony is too big @weaverryan
  15. 15. Too many files == A Perceived Complexity @weaverryan
  16. 16. @weaverryan ~ 25 files ~ 10 directories for Hello World
  17. 17. Problem 2: Is my project macro or micro? @weaverryan
  18. 18. Macro => Use Symfony @weaverryan
  19. 19. Micro => Use Silex @weaverryan
  20. 20. The fact we have this option is incredible but… @weaverryan
  21. 21. Silex has a slightly different tech stack @weaverryan
  22. 22. Silex doesn’t have bundles @weaverryan
  23. 23. Silex can’t evolve to a full stack Symfony App @weaverryan
  24. 24. What if we just made Symfony smaller? @weaverryan
  25. 25. 6 files 62 lines of code
  26. 26. <?php
 
 use SymfonyComponentHttpKernelKernel;
 use SymfonyComponentConfigLoaderLoaderInterface;
 
 class AppKernel extends Kernel
 {
 public function registerBundles()
 {
 return array(
 new SymfonyBundleFrameworkBundleFrameworkBundle(),
 new SymfonyBundleTwigBundleTwigBundle(),
 );
 }
 
 public function registerContainerConfiguration($loader)
 {
 $loader->load(
 __DIR__.'/config/config_'.$this->getEnvironment().'.yml'
 );
 }
 }
  27. 27. How small can we go? @weaverryan
  28. 28. What is a Symfony Application? @weaverryan
  29. 29. What is a Symfony App? @weaverryan 1.A set of bundles 2.A container of services 3.Routes
  30. 30. Let’s create a new Symfony project from nothing @weaverryan
  31. 31. {
 "require": {
 "symfony/symfony": "^2.8"
 }
 } @weaverryan composer.json
  32. 32. <?php
 
 use SymfonyComponentConfigLoaderLoaderInterface;
 use SymfonyComponentHttpKernelKernel;
 
 require __DIR__.'/vendor/autoload.php';
 
 class AppKernel extends Kernel
 {
 public function registerBundles()
 {
 }
 
 public function registerContainerConfiguration($loader)
 {
 }
 }
 index.php
  33. 33. <?php
 
 use SymfonyBundleFrameworkBundleKernelMicroKernelTrait;
 use SymfonyComponentDependencyInjectionContainerBuilder;
 use SymfonyComponentRoutingRouteCollectionBuilder; // ...
 
 class AppKernel extends Kernel
 {
 use MicroKernelTrait;
 
 public function registerBundles()
 {
 }
 
 protected function configureRoutes(RouteCollectionBuilder $routes)
 {
 }
 
 protected function configureContainer(ContainerBuilder $c, $loader)
 {
 }
 }
 index.php 1) A set of bundles 2) Routes 3) A container of services
  34. 34. public function registerBundles()
 {
 return array(
 new SymfonyBundleFrameworkBundleFrameworkBundle()
 );
 } AppKernel
  35. 35. protected function configureContainer(ContainerBuilder $c, $loader)
 {
 $c->loadFromExtension('framework', array(
 'secret' => 'S0ME_SECRET',
 ));
 } AppKernel // config.yml framework:
 secret: S0ME_SECRET
  36. 36. protected function configureRoutes(RouteCollectionBuilder $routes)
 {
 $routes->add('/random/{limit}', 'kernel:randomAction');
 } AppKernel New in 2.8! service:methodName (Symfony’s controller as a service syntax)
  37. 37. public function randomAction($limit)
 {
 return new JsonResponse(array(
 'number' => rand(0, $limit)
 ));
 } AppKernel
  38. 38. <?php
 
 // ...
 
 require __DIR__.'/vendor/autoload.php';
 
 
 class AppKernel extends Kernel
 {
 // ...
 }
 
 $kernel = new AppKernel('dev', true);
 $request = Request::createFromGlobals();
 $response = $kernel->handle($request);
 $response->send();
 $kernel->terminate($request, $response);
 index.php
  39. 39. How many files? @weaverryan How many lines of code?
  40. 40. 2 files 52 lines of code
  41. 41. This is a full stack framework @weaverryan
  42. 42. @weaverryan 1. Service Container 2. Routing 3. Events 4. ESI & Sub-Requests 5. Compatible with 3rd party bundles
  43. 43. Fast as Hell @weaverryan
  44. 44. The goal is not to create single-file apps @weaverryan
  45. 45. Clarity & Control @weaverryan
  46. 46. Building a Realistic App @weaverryan github.com/weaverryan/docs-micro_kernel
  47. 47. Requirements: @weaverryan 1. Add some organization 2. Load annotation routes 3. Web Debug Toolbar + Profiler 4. Twig
  48. 48. Reorganize class AppKernel extends Kernel
 {
 }
 // web/index.php
 $kernel = new AppKernel('dev', true);
 $request = Request::createFromGlobals();
 $response = $kernel->handle($request);
 $response->send();
  49. 49. public function registerBundles()
 {
 $bundles = array(
 new FrameworkBundle(),
 new TwigBundle(),
 new SensioFrameworkExtraBundle()
 );
 
 if ($this->getEnvironment() == 'dev') {
 $bundles[] = new WebProfilerBundle();
 }
 
 return $bundles;
 } app/AppKernel.php
  50. 50. protected function configureContainer(ContainerBuilder $c, $loader)
 {
 $loader->load(__DIR__.'/config/config.yml');
 
 if (isset($this->bundles['WebProfilerBundle'])) {
 $c->loadFromExtension('web_profiler', array(
 'toolbar' => true,
 'intercept_redirects' => false,
 ));
 }
 } app/AppKernel.php @weaverryan
  51. 51. app/config/config.yml framework:
 secret: S0ME_SECRET
 templating:
 engines: ['twig']
 profiler: { only_exceptions: false } @weaverryan
  52. 52. protected function configureContainer(ContainerBuilder $c, $loader)
 {
 $loader->load(__DIR__.'/config/config.yml');
 
 if (isset($this->bundles['WebProfilerBundle'])) {
 $c->loadFromExtension('web_profiler', array(
 'toolbar' => true,
 'intercept_redirects' => false,
 ));
 }
 } app/AppKernel.php @weaverryan Goodbye config_dev.yml
  53. 53. protected function configureRoutes(RouteCollectionBuilder $routes)
 {
 if (isset($this->bundles['WebProfilerBundle'])) {
 $routes->import(
 '@WebProfilerBundle/Resources/config/routing/wdt.xml',
 '_wdt'
 );
 $routes->import(
 '@WebProfilerBundle/Resources/config/routing/profiler.xml',
 '/_profiler'
 );
 }
 
 $routes->import(__DIR__.'/../src/App/Controller/', '/', 'annotation')
 } app/AppKernel.php Goodbye routing_dev.yml
  54. 54. Clarity & Control @weaverryan
  55. 55. @weaverryan protected function configureContainer(ContainerBuilder $c, $loader)
 {
 $loader->load(__DIR__ . '/config/config.yml');
 
 $c->setParameter('secret', getenv('SECRET'));
 $c->loadFromExtension('doctrine', [
 'dbal' => [
 'driver' => 'pdo_mysql',
 'host' => getenv('DATABASE_HOST'),
 'user' => getenv('DATABASE_USER'),
 'password' => getenv('DATABASE_PASS'),
 ]
 ]);
 // ...
 } Environment Variables
  56. 56. @weaverryan protected function configureContainer(ContainerBuilder $c, $loader)
 {
 $loader->load(__DIR__.'/config/config.yml');
 
 if (in_array($this->getEnvironment(), ['dev', 'test'])) {
 
 $c->loadFromExtension('framework', [
 'profiler' => ['only_exceptions' => false]
 ]);
 
 }
 
 // ...
 } Environment Control
  57. 57. @weaverryan Build Services protected function configureContainer(ContainerBuilder $c, $loader)
 {
 // ...
 
 $c->register('santa.controller', SantaController::class)
 ->setAutowired(true);
 
 }
  58. 58. @weaverryan Build Routes protected function configureRoutes(RouteCollectionBuilder $routes)
 {
 // ...
 $routes->add('/santa', 'AppBundle:Santa:northPole');
 
 $routes->add(‘/naughty-list/{page}’, 'AppBundle:Santa:list')
 ->setRequirement('list', 'd+')
 ->setDefault('page', 1);
 }
  59. 59. @weaverryan Bundless Applications?
  60. 60. @weaverryan Wait, what does a bundle even give me?
  61. 61. A bundle gives you: @weaverryan 1. Services 2. A resource root (e.g. path to load templates) 3. Magic functionality (e.g. commands) 4. Shortcuts (_controller, AppBundle:User)
  62. 62. @weaverryan 1) Services protected function configureContainer(ContainerBuilder $c, $loader)
 {
 // ...
 
 $c->register('santa.controller', SantaController::class)
 ->setAutowired(true);
 
 }
  63. 63. @weaverryan 2) Resource Root
  64. 64. 2) Resource Root protected function configureContainer(ContainerBuilder $c, $loader)
 {
 // ...
 
 $c->loadFromExtension('twig', [
 'paths' => [__DIR__.'/Resources/views' => 'north_pole']
 ]);
 } public function randomAction($limit)
 {
 $number = rand(0, $limit);
 
 return $this->render(‘@north_pole/micro/random.html.twig’, [
 'number' => $number
 ]);
 }
  65. 65. @weaverryan 3) Magic Functionality 1. Register commands as services 2. Configure Doctrine mappings to load your Entity directory
  66. 66. @weaverryan 4) Shortcuts santa:
 controller: AppBundle:Santa:xmas
 controller: AppBundleControllerSantaController::xmasAction $em->getRepository('AppBundle:App');
 $em->getRepository('AppBundleEntityApp');
  67. 67. @weaverryan One New Trick protected function configureRoutes(RouteCollectionBuilder $routes)
 {
 $routes->import(__DIR__.’@AppBundle/Controller/‘, '/', 'annotation')
 } protected function configureRoutes(RouteCollectionBuilder $routes)
 {
 $routes->import(__DIR__.'/../src/App/Controller/', '/', 'annotation')
 }
  68. 68. Multiple Kernels? @weaverryan
  69. 69. Multiple kernels, why? @weaverryan 1. micro service architecture in monolithic repository 2. performance (less routes, services & listeners)
  70. 70. Multiple kernels was always possible @weaverryan
  71. 71. Now they’re obvious @weaverryan
  72. 72. // app/ApiKernel.php class ApiKernel extends Kernel
 {
 use MicroKernelTrait;
 
 public function registerBundles()
 {
 $bundles = array(
 new FrameworkBundle(),
 new SensioFrameworkExtraBundle()
 );
 
 return $bundles;
 }
 } No TwigBundle
  73. 73. class ApiKernel extends Kernel
 {
 // ...
 
 protected function configureContainer($c, $loader)
 {
 $loader->load(__DIR__.'/config/config.yml');
 $loader->load(__DIR__.'/config/api.yml');
 }
 } Use PHP logic to load share config, and custom config
  74. 74. class ApiKernel extends Kernel
 {
 // ...
 
 protected function configureRoutes($routes)
 {
 $routes->import(
 __DIR__.'/../src/Api/Controller/',
 '/api',
 'annotation'
 );
 }
 
 public function getCacheDir()
 {
 return __DIR__.’/../var/cache/api/' .$this->getEnvironment();
 }
 } Load different routes cacheDir ~= the cache key
  75. 75. Boot the correct kernel however you want @weaverryan
  76. 76. // web/index.php use SymfonyComponentHttpFoundationRequest;
 
 require __DIR__.'/../app/autoload.php';
 
 $request = Request::createFromGlobals();
 
 if (strpos($request->getPathInfo(), '/api') === 0) {
 require __DIR__.'/../app/ApiKernel.php';
 $kernel = new ApiKernel('dev', true);
 } else {
 require __DIR__.'/../app/WebKernel.php';
 $kernel = new WebKernel('dev', true);
 }
 
 $response = $kernel->handle($request);
 $response->send();

  77. 77. But how does it work? @weaverryan
  78. 78. There is one person who *hates* the name MicroKernelTrait @weaverryan
  79. 79. @weaverryan
  80. 80. @weaverryan
  81. 81. trait MicroKernelTrait
 {
 abstract protected function configureRoutes(RouteCollectionBuilder $routes);
 abstract protected function configureContainer(ContainerBuilder $c, $loader);
 
 public function registerContainerConfiguration($loader)
 {
 $loader->load(function ($container) use ($loader) {
 $container->loadFromExtension('framework', array(
 'router' => array(
 'resource' => 'kernel:loadRoutes',
 'type' => 'service',
 ),
 ));
 
 $this->configureContainer($container, $loader);
 });
 }
 
 public function loadRoutes(LoaderInterface $loader)
 {
 $routes = new RouteCollectionBuilder($loader);
 $this->configureRoutes($routes);
 
 return $routes->build();
 }
 } Closure Loader New service route loader
  82. 82. So what now? @weaverryan
  83. 83. I have a big project… @weaverryan Use it for clarity
  84. 84. I’m teaching @weaverryan Show it for simplicity
  85. 85. I have a small app @weaverryan Show it for power
  86. 86. @weaverryan PHP & Symfony Video Tutorials KnpUniversity.com Thank You!

×