Symfony:
Your Next Microframework
by your friend:
Ryan Weaver
@weaverryan
by your friend:
Ryan Weaver
@weaverryan
KnpUniversity.com

github.com/weaverryan
Who is this guy?
> Lead for the Symfony documentation

> KnpLabs US - Symfony Con...
Thinking about 2
Problems
@weaverryan
Problem 1:

Symfony Sucks
@weaverryan
@weaverryan
@weaverryan
@weaverryan
@weaverryan
Symfony

is too hard
@weaverryan
The Symfony Framework

is too hard
@weaverryan
The components are not usually the
problem
Why?
@weaverryan
Route

Controller

Response
@weaverryan
WTF?
Useful Objects
1) Common tasks require

too much code
@weaverryan
2) Symfony is too big
@weaverryan
Too many files

==

A Perceived Complexity
@weaverryan
@weaverryan
~ 25 files
~ 10 directories
for Hello World
Problem 2:

Is my project 

macro or micro?
@weaverryan
Macro => Use Symfony
@weaverryan
Micro => Use Silex
@weaverryan
The fact we have this
option is incredible

but…
@weaverryan
Silex has a slightly
different tech stack
@weaverryan
Silex doesn’t have bundles
@weaverryan
Silex can’t evolve to a full
stack Symfony App
@weaverryan
What if we just made
Symfony smaller?
@weaverryan
6 files
62 lines of code
<?php



use SymfonyComponentHttpKernelKernel;

use SymfonyComponentConfigLoaderLoaderInterface;



class AppKernel extend...
How small can we go?
@weaverryan
What is a Symfony
Application?
@weaverryan
What is a Symfony App?
@weaverryan
1.A set of bundles
2.A container of services
3.Routes
Let’s create a new

Symfony project

from nothing
@weaverryan
{

"require": {

"symfony/symfony": "^2.8"

}

}
@weaverryan
composer.json
<?php



use SymfonyComponentConfigLoaderLoaderInterface;

use SymfonyComponentHttpKernelKernel;



require __DIR__.'/vend...
<?php



use SymfonyBundleFrameworkBundleKernelMicroKernelTrait;

use SymfonyComponentDependencyInjectionContainerBuilder;...
public function registerBundles()

{

return array(

new SymfonyBundleFrameworkBundleFrameworkBundle()

);

}
AppKernel
protected function configureContainer(ContainerBuilder $c, $loader)

{

$c->loadFromExtension('framework', array(

'secret...
protected function configureRoutes(RouteCollectionBuilder $routes)

{

$routes->add('/random/{limit}', 'kernel:randomActio...
public function randomAction($limit)

{

return new JsonResponse(array(

'number' => rand(0, $limit)

));

}
AppKernel
<?php



// ...



require __DIR__.'/vendor/autoload.php';





class AppKernel extends Kernel

{

// ...

}



$kernel = ...
How many files?
@weaverryan
How many lines of code?
2 files
52 lines of code
This is a full stack
framework
@weaverryan
@weaverryan
1. Service Container
2. Routing
3. Events
4. ESI & Sub-Requests
5. Compatible with 3rd party bundles
Fast as Hell
@weaverryan
The goal is not to create
single-file apps
@weaverryan
Clarity & Control
@weaverryan
Building a
Realistic App
@weaverryan
github.com/weaverryan/docs-micro_kernel
Requirements:
@weaverryan
1. Add some organization
2. Load annotation routes
3. Web Debug Toolbar + Profiler
4. Twig
Reorganize
class AppKernel extends Kernel

{

}

// web/index.php

$kernel = new AppKernel('dev', true);

$request = Reque...
public function registerBundles()

{

$bundles = array(

new FrameworkBundle(),

new TwigBundle(),

new SensioFrameworkExt...
protected function configureContainer(ContainerBuilder $c, $loader)

{

$loader->load(__DIR__.'/config/config.yml');



if...
app/config/config.yml
framework:

secret: S0ME_SECRET

templating:

engines: ['twig']

profiler: { only_exceptions: false }
...
protected function configureContainer(ContainerBuilder $c, $loader)

{

$loader->load(__DIR__.'/config/config.yml');



if...
protected function configureRoutes(RouteCollectionBuilder $routes)

{

if (isset($this->bundles['WebProfilerBundle'])) {

...
Clarity & Control
@weaverryan
@weaverryan
protected function configureContainer(ContainerBuilder $c, $loader)

{

$loader->load(__DIR__ . '/config/confi...
@weaverryan
protected function configureContainer(ContainerBuilder $c, $loader)

{

$loader->load(__DIR__.'/config/config....
@weaverryan
Build Services
protected function configureContainer(ContainerBuilder $c, $loader)

{

// ...



$c->register(...
@weaverryan
Build Routes
protected function configureRoutes(RouteCollectionBuilder $routes)

{

// ...

$routes->add('/san...
@weaverryan
Bundless
Applications?
@weaverryan
Wait, what does a
bundle even give me?
A bundle gives you:
@weaverryan
1. Services
2. A resource root (e.g. path to load templates)
3. Magic functionality (e.g. ...
@weaverryan
1) Services
protected function configureContainer(ContainerBuilder $c, $loader)

{

// ...



$c->register('sa...
@weaverryan
2) Resource Root
2) Resource Root
protected function configureContainer(ContainerBuilder $c, $loader)

{

// ...



$c->loadFromExtension('...
@weaverryan
3) Magic Functionality
1. Register commands as services
2. Configure Doctrine mappings to load your
Entity dire...
@weaverryan
4) Shortcuts
santa:

controller: AppBundle:Santa:xmas

controller: AppBundleControllerSantaController::xmasAct...
@weaverryan
One New Trick
protected function configureRoutes(RouteCollectionBuilder $routes)

{

$routes->import(__DIR__.’...
Multiple Kernels?
@weaverryan
Multiple kernels, why?
@weaverryan
1. micro service architecture in monolithic
repository
2. performance (less routes, ser...
Multiple kernels was
always possible
@weaverryan
Now they’re obvious
@weaverryan
// app/ApiKernel.php
class ApiKernel extends Kernel

{

use MicroKernelTrait;



public function registerBundles()

{

$bu...
class ApiKernel extends Kernel

{

// ...



protected function configureContainer($c, $loader)

{

$loader->load(__DIR__....
class ApiKernel extends Kernel

{

// ...



protected function configureRoutes($routes)

{

$routes->import(

__DIR__.'/....
Boot the correct kernel
however you want
@weaverryan
// web/index.php
use SymfonyComponentHttpFoundationRequest;



require __DIR__.'/../app/autoload.php';



$request = Reque...
But how does it work?
@weaverryan
There is one person

who *hates* the name

MicroKernelTrait
@weaverryan
@weaverryan
@weaverryan
trait MicroKernelTrait

{

abstract protected function configureRoutes(RouteCollectionBuilder $routes);

abstract protecte...
So what now?
@weaverryan
I have a big project…
@weaverryan
Use it for clarity
I’m teaching
@weaverryan
Show it for simplicity
I have a small app
@weaverryan
Show it for power
@weaverryan
PHP & Symfony Video Tutorials
KnpUniversity.com
Thank You!
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
Nächste SlideShare
Wird geladen in …5
×

Symfony: Your Next Microframework (SymfonyCon 2015)

6.086 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
2 Kommentare
15 Gefällt mir
Statistik
Notizen
  • 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
Keine Downloads
Aufrufe
Aufrufe insgesamt
6.086
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
780
Aktionen
Geteilt
0
Downloads
59
Kommentare
2
Gefällt mir
15
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

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!

×