90
Symfony: Your Next Microframework by your friend: Ryan Weaver @weaverryan

Symfony: Your Next Microframework (SymfonyCon 2015)

Embed Size (px)

Citation preview

Page 1: Symfony: Your Next Microframework (SymfonyCon 2015)

Symfony: Your Next Microframework

by your friend:

Ryan Weaver @weaverryan

by your friend:

Ryan Weaver @weaverryan

Page 2: Symfony: Your Next Microframework (SymfonyCon 2015)

KnpUniversity.comgithub.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

Page 3: Symfony: Your Next Microframework (SymfonyCon 2015)

Thinking about 2 Problems

@weaverryan

Page 4: Symfony: Your Next Microframework (SymfonyCon 2015)

Problem 1:Symfony Sucks

@weaverryan

Page 5: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Page 6: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Page 7: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Page 8: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Page 9: Symfony: Your Next Microframework (SymfonyCon 2015)

Symfonyis too hard

@weaverryan

Page 10: Symfony: Your Next Microframework (SymfonyCon 2015)

The Symfony Frameworkis too hard

@weaverryan

The components are not usually the problem

Page 11: Symfony: Your Next Microframework (SymfonyCon 2015)

Why?

@weaverryan

Page 12: Symfony: Your Next Microframework (SymfonyCon 2015)

Route

Controller

Response@weaverryan

WTF?

Useful Objects

Page 13: Symfony: Your Next Microframework (SymfonyCon 2015)

1) Common tasks requiretoo much code

@weaverryan

Page 14: Symfony: Your Next Microframework (SymfonyCon 2015)

2) Symfony is too big

@weaverryan

Page 15: Symfony: Your Next Microframework (SymfonyCon 2015)

Too many files==

A Perceived Complexity

@weaverryan

Page 16: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

~ 25 files ~ 10 directories for Hello World

Page 17: Symfony: Your Next Microframework (SymfonyCon 2015)

Problem 2:

Is my project macro or micro?

@weaverryan

Page 18: Symfony: Your Next Microframework (SymfonyCon 2015)

Macro => Use Symfony

@weaverryan

Page 19: Symfony: Your Next Microframework (SymfonyCon 2015)

Micro => Use Silex

@weaverryan

Page 20: Symfony: Your Next Microframework (SymfonyCon 2015)

The fact we have this option is incredible

but…

@weaverryan

Page 21: Symfony: Your Next Microframework (SymfonyCon 2015)

Silex has a slightly different tech stack

@weaverryan

Page 22: Symfony: Your Next Microframework (SymfonyCon 2015)

Silex doesn’t have bundles

@weaverryan

Page 23: Symfony: Your Next Microframework (SymfonyCon 2015)

Silex can’t evolve to a full stack Symfony App

@weaverryan

Page 24: Symfony: Your Next Microframework (SymfonyCon 2015)

What if we just made Symfony smaller?

@weaverryan

Page 25: Symfony: Your Next Microframework (SymfonyCon 2015)
Page 26: Symfony: Your Next Microframework (SymfonyCon 2015)

6 files 62 lines of code

Page 27: Symfony: Your Next Microframework (SymfonyCon 2015)

<?phpuse Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Config\Loader\LoaderInterface; class AppKernel extends Kernel{ public function registerBundles() { return array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), ); } public function registerContainerConfiguration($loader) { $loader->load( __DIR__.'/config/config_'.$this->getEnvironment().'.yml' ); }}

Page 28: Symfony: Your Next Microframework (SymfonyCon 2015)

How small can we go?

@weaverryan

Page 29: Symfony: Your Next Microframework (SymfonyCon 2015)

What is a Symfony Application?

@weaverryan

Page 30: Symfony: Your Next Microframework (SymfonyCon 2015)

What is a Symfony App?

@weaverryan

1.A set of bundles 2.A container of services 3.Routes

Page 31: Symfony: Your Next Microframework (SymfonyCon 2015)

Let’s create a newSymfony project

from nothing

@weaverryan

Page 32: Symfony: Your Next Microframework (SymfonyCon 2015)

{ "require": { "symfony/symfony": "^2.8" }}

@weaverryan

composer.json

Page 33: Symfony: Your Next Microframework (SymfonyCon 2015)

<?phpuse Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\HttpKernel\Kernel; require __DIR__.'/vendor/autoload.php'; class AppKernel extends Kernel{ public function registerBundles() { } public function registerContainerConfiguration($loader) { }}

index.php

Page 34: Symfony: Your Next Microframework (SymfonyCon 2015)

<?phpuse Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Routing\RouteCollectionBuilder; // ...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

Page 35: Symfony: Your Next Microframework (SymfonyCon 2015)

public function registerBundles(){ return array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle() );}

AppKernel

Page 36: Symfony: Your Next Microframework (SymfonyCon 2015)

protected function configureContainer(ContainerBuilder $c, $loader) { $c->loadFromExtension('framework', array( 'secret' => 'S0ME_SECRET', ));}

AppKernel

// config.yml framework: secret: S0ME_SECRET

Page 37: Symfony: Your Next Microframework (SymfonyCon 2015)

protected function configureRoutes(RouteCollectionBuilder $routes) { $routes->add('/random/{limit}', 'kernel:randomAction');}

AppKernelNew in 2.8!

service:methodName(Symfony’s controller as a service syntax)

Page 38: Symfony: Your Next Microframework (SymfonyCon 2015)

public function randomAction($limit) { return new JsonResponse(array( 'number' => rand(0, $limit) ));}

AppKernel

Page 39: Symfony: Your Next Microframework (SymfonyCon 2015)

<?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

Page 40: Symfony: Your Next Microframework (SymfonyCon 2015)

How many files?

@weaverryan

How many lines of code?

Page 41: Symfony: Your Next Microframework (SymfonyCon 2015)

2 files 52 lines of code

Page 42: Symfony: Your Next Microframework (SymfonyCon 2015)

This is a full stack framework

@weaverryan

Page 43: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

1. Service Container 2. Routing 3. Events 4. ESI & Sub-Requests 5. Compatible with 3rd party bundles

Page 44: Symfony: Your Next Microframework (SymfonyCon 2015)

Fast as Hell

@weaverryan

Page 45: Symfony: Your Next Microframework (SymfonyCon 2015)

The goal is not to create single-file apps

@weaverryan

Page 46: Symfony: Your Next Microframework (SymfonyCon 2015)

Clarity & Control

@weaverryan

Page 47: Symfony: Your Next Microframework (SymfonyCon 2015)

Building a Realistic App

@weaverryan

github.com/weaverryan/docs-micro_kernel

Page 48: Symfony: Your Next Microframework (SymfonyCon 2015)

Requirements:

@weaverryan

1. Add some organization 2. Load annotation routes 3. Web Debug Toolbar + Profiler 4. Twig

Page 49: Symfony: Your Next Microframework (SymfonyCon 2015)

Reorganizeclass AppKernel extends Kernel{ }

// web/index.php$kernel = new AppKernel('dev', true);$request = Request::createFromGlobals();$response = $kernel->handle($request);$response->send();

Page 50: Symfony: Your Next Microframework (SymfonyCon 2015)

public function registerBundles(){ $bundles = array( new FrameworkBundle(), new TwigBundle(), new SensioFrameworkExtraBundle() ); if ($this->getEnvironment() == 'dev') { $bundles[] = new WebProfilerBundle(); } return $bundles; }

app/AppKernel.php

Page 51: Symfony: Your Next Microframework (SymfonyCon 2015)

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

Page 52: Symfony: Your Next Microframework (SymfonyCon 2015)

app/config/config.yml

framework: secret: S0ME_SECRET templating: engines: ['twig'] profiler: { only_exceptions: false }

@weaverryan

Page 53: Symfony: Your Next Microframework (SymfonyCon 2015)

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

Page 54: Symfony: Your Next Microframework (SymfonyCon 2015)

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.phpGoodbye routing_dev.yml

Page 55: Symfony: Your Next Microframework (SymfonyCon 2015)
Page 56: Symfony: Your Next Microframework (SymfonyCon 2015)

Clarity & Control

@weaverryan

Page 57: Symfony: Your Next Microframework (SymfonyCon 2015)

@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

Page 58: Symfony: Your Next Microframework (SymfonyCon 2015)

@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

Page 59: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Build Services

protected function configureContainer(ContainerBuilder $c, $loader) { // ... $c->register('santa.controller', SantaController::class) ->setAutowired(true); }

Page 60: Symfony: Your Next Microframework (SymfonyCon 2015)

@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); }

Page 61: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Bundless Applications?

Page 62: Symfony: Your Next Microframework (SymfonyCon 2015)
Page 63: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Wait, what does a bundle even give me?

Page 64: Symfony: Your Next Microframework (SymfonyCon 2015)

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)

Page 65: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

1) Services

protected function configureContainer(ContainerBuilder $c, $loader) { // ... $c->register('santa.controller', SantaController::class) ->setAutowired(true); }

!

Page 66: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

2) Resource Root

Page 67: Symfony: Your Next Microframework (SymfonyCon 2015)

2) Resource Rootprotected 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 ]);}

!

Page 68: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

3) Magic Functionality

!

1. Register commands as services 2. Configure Doctrine mappings to load your

Entity directory

Page 69: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

4) Shortcuts

!

santa: controller: AppBundle:Santa:xmas controller: AppBundle\Controller\SantaController::xmasAction

$em->getRepository('AppBundle:App'); $em->getRepository('AppBundle\Entity\App');

Page 70: Symfony: Your Next Microframework (SymfonyCon 2015)

@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') }

Page 71: Symfony: Your Next Microframework (SymfonyCon 2015)

Multiple Kernels?

@weaverryan

Page 72: Symfony: Your Next Microframework (SymfonyCon 2015)

Multiple kernels, why?

@weaverryan

1. micro service architecture in monolithic repository

2. performance (less routes, services & listeners)

Page 73: Symfony: Your Next Microframework (SymfonyCon 2015)

Multiple kernels was always possible

@weaverryan

Page 74: Symfony: Your Next Microframework (SymfonyCon 2015)

Now they’re obvious

@weaverryan

Page 75: Symfony: Your Next Microframework (SymfonyCon 2015)

// app/ApiKernel.php

class ApiKernel extends Kernel{ use MicroKernelTrait; public function registerBundles() { $bundles = array( new FrameworkBundle(), new SensioFrameworkExtraBundle() ); return $bundles; }}

No TwigBundle

Page 76: Symfony: Your Next Microframework (SymfonyCon 2015)

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

Page 77: Symfony: Your Next Microframework (SymfonyCon 2015)

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

Page 78: Symfony: Your Next Microframework (SymfonyCon 2015)

Boot the correct kernel however you want

@weaverryan

Page 79: Symfony: Your Next Microframework (SymfonyCon 2015)

// web/index.php use Symfony\Component\HttpFoundation\Request; 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();

Page 80: Symfony: Your Next Microframework (SymfonyCon 2015)
Page 81: Symfony: Your Next Microframework (SymfonyCon 2015)

But how does it work?

@weaverryan

Page 82: Symfony: Your Next Microframework (SymfonyCon 2015)

There is one personwho *hates* the name

MicroKernelTrait

@weaverryan

Page 83: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Page 84: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

Page 85: Symfony: Your Next Microframework (SymfonyCon 2015)

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

Page 86: Symfony: Your Next Microframework (SymfonyCon 2015)

So what now?

@weaverryan

Page 87: Symfony: Your Next Microframework (SymfonyCon 2015)

I have a big project…

@weaverryan

Use it for clarity

Page 88: Symfony: Your Next Microframework (SymfonyCon 2015)

I’m teaching

@weaverryan

Show it for simplicity

Page 89: Symfony: Your Next Microframework (SymfonyCon 2015)

I have a small app

@weaverryan

Show it for power

Page 90: Symfony: Your Next Microframework (SymfonyCon 2015)

@weaverryan

PHP & Symfony Video Tutorials KnpUniversity.com

Thank You!