Symfony is a request and response framework. But what about all that magic that happens around your code? How does security work? Why isn’t autowring slowing things down? And how is it that symfony components can be so decoupled but still play so well together?
I will show you the symfony internals
This talk will go over the architecture of Symfony. We will follow the request and the response paths throw the framework. We will do some stops at the components that are more awesome than others.
This talk is perfect for those who's worked with Symfony or Laravel before. But if you've never touched a framework before, don't worry. You will still learn a lot from this talk.
27. @tobiasnyholm<?php // Cache.php
namespace AppMiddleware;
use CacheAdapterApcuApcuCachePool;
use PsrCacheCacheItemPoolInterface;
use PsrHttpMessageResponseInterface as Response;
use PsrHttpMessageServerRequestInterface as Request;
class Cache implements MiddlewareInterface
{
/*** @var CacheItemPoolInterface */
private $cache;
/** @var int */
private $ttl;
public function __construct()
{
$this->cache = new ApcuCachePool();
$this->ttl = 300;
}
public function __invoke(Request $request, Response $response, callable $next)
{
$uri = $request->getUri();
$cacheKey = 'url'.sha1($uri->getPath().'?'.$uri->getQuery());
$cacheItem = $this->cache->getItem($cacheKey);
28. @tobiasnyholm
Cache<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$response = new Response();
$middlewares[] = new AppMiddlewareCache();
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
$response = $runner($request, $response);
// Send response
echo $response->getBody();
32. @tobiasnyholm
Container
<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$response = new Response();
$middlewares[] = new AppMiddlewareCache();
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
$response = $runner($request, $response);
// Send response
echo $response->getBody();
33. @tobiasnyholm
Container
<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$kernel = new AppKernel('dev', true);
$response = $kernel->handle($request);
// Send response
echo $response->getBody();
34. <?php // Kernel.php
namespace App;
use NyholmPsr7Response;
use PsrHttpMessageRequestInterface;
use PsrHttpMessageResponseInterface;
use SymfonyComponentConfigExceptionFileLocatorFileNotFoundException;
use SymfonyComponentConfigFileLocator;
use SymfonyComponentDependencyInjectionContainer;
use SymfonyComponentDependencyInjectionContainerBuilder;
use SymfonyComponentDependencyInjectionDumperPhpDumper;
use SymfonyComponentDependencyInjectionLoaderYamlFileLoader;
class Kernel
{
private $booted = false;
private $debug;
private $environment;
/** @var Container */
private $container;
public function __construct(string $env, bool $debug = false)
{
$this->debug = $debug;
$this->environment = $env;
}
47. @tobiasnyholm
Security
<?php
namespace AppMiddleware;
use NyholmPsr7Response;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
class Security implements MiddlewareInterface
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callabl
{
$uri = $request->getUri()->getPath();
$ip = $request->getServerParams()['REMOTE_ADDR'];
if ($ip !== '127.0.0.1' && $uri === '/admin') {
return new Response(403, [], 'Forbidden');
}
if ($uri === '/images/4711/delete') {
if (true /* user is not "bob" */) {
return new Response(403, [], 'Forbidden');
}
}
return $next($request, $response);
}
}
48. @tobiasnyholm
<?php
namespace AppMiddleware;
use AppSecurityTokenStorage;
use NyholmPsr7Response;
use PsrHttpMessageResponseInterface ;
use PsrHttpMessageServerRequestInterface;
class Authentication implements MiddlewareInterface
{
private $tokenStorage;
/**
*
* @param $tokenStorage
*/
public function __construct(TokenStorage $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable
{
$uri = $request->getUri()->getPath();
$auth = $request->getServerParams()['PHP_AUTH_USER']??'';
$pass = $request->getServerParams()['PHP_AUTH_PW']??'';
49. @tobiasnyholm
Securityclass Kernel
{
// …
/**
* Handle a Request and turn it in to a response.
*/
public function handle(RequestInterface $request): ResponseInterface
{
$this->boot();
$middlewares[] = $this->container->get(‘middleware.auth');
$middlewares[] = $this->container->get('middleware.security');
$middlewares[] = $this->container->get('middleware.cache');
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
return $runner($request, new Response());
}
// …
}
53. @tobiasnyholm
Security
<?php
declare(strict_types=1);
namespace AppController;
use AppSecurityTokenStorage;
use NyholmPsr7Response;
use PsrHttpMessageRequestInterface;
class AdminController
{
private $tokenStorage;
public function __construct(TokenStorage $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function run(RequestInterface $request)
{
return new Response(200, [],
sprintf('Hello %s (admin)', $this->tokenStorage->getLastToken()['username']));
}
}
58. @tobiasnyholm
Securityclass Kernel
{
// …
/**
* Handle a Request and turn it in to a response.
*/
public function handle(RequestInterface $request): ResponseInterface
{
$this->boot();
$middlewares[] = $this->container->get(‘middleware.auth');
$middlewares[] = $this->container->get('middleware.security');
$middlewares[] = $this->container->get('middleware.cache');
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
return $runner($request, new Response());
}
// …
}
63. @tobiasnyholm
Autowiringclass Kernel
{
// …
/**
* Handle a Request and turn it in to a response.
*/
public function handle(RequestInterface $request): ResponseInterface
{
$this->boot();
$middlewares[] = $this->container->get(Authentication::class);
$middlewares[] = $this->container->get(SecurityVoters::class);
$middlewares[] = $this->container->get(Cache::class);
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
return $runner($request, new Response());
}
// …
}
72. @tobiasnyholm
Exception
<?php
namespace AppMiddleware;
use CacheAdapterApcuApcuCachePool;
use NyholmPsr7Response;
use PsrCacheCacheItemPoolInterface;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
class ExceptionHandler implements MiddlewareInterface
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, calla
{
try {
$response = $next($request, $response);
} catch (Throwable $exception) {
$response = new Response(500, [], $exception->getMessage());
}
return $response;
}
}
73. @tobiasnyholm
Exceptionclass Kernel
{
/**
* Handle a Request and turn it in to a response.
*/
public function handle(RequestInterface $request): ResponseInterface
{
$this->boot();
$middlewares[] = $this->container->get(ExceptionHandler::class);
$middlewares[] = $this->container->get(Authentication::class);
$middlewares[] = $this->container->get(SecurityVoters::class);
$middlewares[] = $this->container->get(Cache::class);
$middlewares[] = new AppMiddlewareRouter();
$middlewares[] = $this->container->get(Toolbar::class);
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
return $runner($request, new Response());
}
}