SlideShare une entreprise Scribd logo
1  sur  93
Télécharger pour lire hors ligne
Tobias Nyholm, @tobiasnyholm
Deep dive into Symfony4 internals
@tobiasnyholm
Why?
@tobiasnyholm
Tobias Nyholm
• Full stack unicorn on Happyr.com
• Certified Symfony developer
• Symfony core member
• PHP-Stockholm
• Open source
@tobiasnyholm
Open source
PHP-cache
HTTPlug
Mailgun
LinkedIn API clientSwap
Stampie
BazingaGeocoderBundle
PHP-Geocoder
FriendsOfApi/boilerplate
Guzzle Buzz
CacheBundlePSR7
SymfonyBundleTest
NSA
SimpleBus integrations
PSR HTTP clients
Neo4j
KNP Github API
PHP-Translation
Puli
Assert
Backup-manager/symfony
php-http/httplug-bundle php-http/multipart-stream
php-http/discovery
happyr/normal-distribution-bundle
nyholm/effective-interest-rate
MailgunBundle
league/geotools
@tobiasnyholm
Building your own
framework
@tobiasnyholm
Just a bunch of files
<?php // index.php
if (isset($_GET['page']) && $_GET['page'] === 'foo') {
echo "Foo page <br>";
} else {
echo "Welcome to index! <br>";
}
if ($_SERVER['REMOTE_ADDR'] === '127.0.0.1') {
echo "(admin stuff)";
}
@tobiasnyholm
Just a bunch of files
@tobiasnyholm
Just a bunch of files
<?php // index.php
if (isset($_GET['page']) && $_GET['page'] === 'foo') {
echo "Foo page <br>";
} else {
echo "Welcome to index! <br>";
}
if ($_SERVER['REMOTE_ADDR'] === '127.0.0.1') {
echo "(admin stuff)";
}
@tobiasnyholm
HTTP objects
@tobiasnyholm
HTTP objects
<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$query = $request->getQueryParams();
if (isset($query['page']) && $query['page'] === 'foo') {
$response = new Response(200, [], 'Foo page');
} else {
$response = new Response(200, [], 'Welcome to index!');
}
// Send response
echo $response->getBody();
@tobiasnyholm
HTTP objects
@tobiasnyholm
HTTP objects
@tobiasnyholm
HTTP objects
<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$query = $request->getQueryParams();
if (isset($query['page']) && $query['page'] === 'foo') {
$response = new Response(200, [], 'Foo page');
} else {
$response = new Response(200, [], 'Welcome to index!');
}
// Send response
echo $response->getBody();
@tobiasnyholm
Controllers
@tobiasnyholm
Controllers
@tobiasnyholm
Controllers
@tobiasnyholm
Controllers<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$uri = $request->getUri()->getPath();
if ($uri === '/') {
$response = (new AppControllerStartpageController())->run($request);
} elseif ($uri === '/foo') {
$response = (new AppControllerFooController())->run($request);
} else {
$response = new Response(404, [], 'Not found');
}
// Send response
echo $response->getBody();
@tobiasnyholm
Controllers
<?php
declare(strict_types=1);
namespace AppController;
use NyholmPsr7Response;
use PsrHttpMessageRequestInterface;
class StartpageController
{
public function run(RequestInterface $request)
{
return new Response(200, [], 'Welcome to index!');
}
}
@tobiasnyholm
Controllers
@tobiasnyholm
Controllers<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$uri = $request->getUri()->getPath();
if ($uri === '/') {
$response = (new AppControllerStartpageController())->run($request);
} elseif ($uri === '/foo') {
$response = (new AppControllerFooController())->run($request);
} else {
$response = new Response(404, [], 'Not found');
}
// Send response
echo $response->getBody();
@tobiasnyholm
Event loop
@tobiasnyholm
Event loop<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$response = new Response();
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
$response = $runner($request, $response);
// Send response
echo $response->getBody();
@tobiasnyholmnamespace AppMiddleware;
use PsrHttpMessageResponseInterface as Response;
use PsrHttpMessageServerRequestInterface as Request;
class Router implements MiddlewareInterface
{
public function __invoke(Request $request, Response $response, callable $next)
{
$uri = $request->getUri()->getPath();
switch ($uri) {
case '/':
$response = (new AppControllerStartpageController())->run($request);
break;
case '/foo':
$response = (new AppControllerFooController())->run($request);
break;
default:
$response = $response->withStatus(404);
$response->getBody()->write('Not Found');
break;
}
return $next($request, $response);
}
}
@tobiasnyholm
Event loop
@tobiasnyholm
Event loop<?php // index.php
use NyholmPsr7FactoryServerRequestFactory;
use NyholmPsr7Response;
require __DIR__.'/../vendor/autoload.php';
$request = (new ServerRequestFactory())->createServerRequestFromGlobals();
$response = new Response();
$middlewares[] = new AppMiddlewareRouter();
$runner = (new RelayRelayBuilder())->newInstance($middlewares);
$response = $runner($request, $response);
// Send response
echo $response->getBody();
@tobiasnyholm
Cache
@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);
@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();
@tobiasnyholm
Cache
@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();
@tobiasnyholm
Container
@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();
@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();
<?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;
}
@tobiasnyholm
Container
@tobiasnyholm
Container
@tobiasnyholm
Container
@tobiasnyholm
Container
@tobiasnyholm
Router
@tobiasnyholm
<?php
namespace AppMiddleware;
use PsrHttpMessageResponseInterface as Response;
use PsrHttpMessageServerRequestInterface as Request;
class Router implements MiddlewareInterface
{
public function __invoke(Request $request, Response $response, callable $next)
{
$uri = $request->getUri()->getPath();
switch ($uri) {
case '/':
$response = (new AppControllerStartpageController())->run($request);
break;
case '/foo':
$response = (new AppControllerFooController())->run($request);
break;
default:
$response = $response->withStatus(404);
$response->getBody()->write('Not Found');
break;
}
return $next($request, $response);
}
}
@tobiasnyholm
public function __invoke(Request $request, Response $response, callable $next)
{
$uri = $request->getUri()->getPath();
switch ($uri) {
case '/':
$response = (new AppControllerStartpageController())->run($request);
break;
case '/foo':
$response = (new AppControllerFooController())->run($request);
break;
default:
$response = $response->withStatus(404);
$response->getBody()->write('Not Found');
break;
}
return $next($request, $response);
}
@tobiasnyholm
Router
/admin/account
/admin/password
/images/upload
/images/{id}/show
/images/{id}/delete
/foo
/
public function __invoke(Request $request, Response $response, callable $next)
{
$uri = $request->getUri()->getPath();
if (0 === strpos($uri, '/admin')) {
if (0 === strpos($uri, '/admin/account')) {
$response = (new AppControllerManagerController())->accountAction($request);
}
if (0 === strpos($uri, '/admin/password')) {
$response = (new AppControllerManagerController())->passwordAction($request);
}
} elseif (0 === strpos($uri, '/images')) {
if (0 === strpos($uri, '/images/upload')) {
$response = (new AppControllerImageController())->uploadAction($request);
}
if (preg_match('#^/images/(?P<id>[^/]++)/show#sD', $uri, $matches)) {
$response = (new AppControllerImageController())->showAction($request, $matches[
}
if (preg_match('#^/images/(?P<id>[^/]++)/delete#sD', $uri, $matches)) {
$response = (new AppControllerImageController())->deleteAction($request, $matche
}
} elseif ($uri === '/') {
$response = (new AppControllerStartpageController())->run($request);
} elseif ($uri === '/foo') {
$response = (new AppControllerFooController())->run($request);
} else {
$response = $response->withStatus(404);
$response->getBody()->write('Not Found');
}
public function __invoke(Request $request, Response $response, callable $next)
{
$uri = $request->getUri()->getPath();
$routes = array(
'/foo' => 'AppControllerFooController::FooAction',
'/images/upload' => 'AppControllerImageController::uploadAction',
'/admin/account' => 'AppControllerManagerController::accountAction',
'/admin/password' => 'AppControllerManagerController::passwordAction',
// More static routes
'/' => 'AppControllerStartpageController::startpageAction',
);
if (isset($routes[$uri])) {
$response = call_user_func($routes[$uri], $request);
return $next($request, $response);
}
$regex =
'{^(?'
.'|/images/([^/]++)/(?'
.'|show(*:31)'
.'|delete(*:44)'
// my dynamic and complex regex
.')'
.')$}sD';
@tobiasnyholm
Router
@tobiasnyholm
Security
@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);
}
}
@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']??'';
@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());
}
// …
}
@tobiasnyholm
Security
@tobiasnyholm
Security
@tobiasnyholm
Security
@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']));
}
}
@tobiasnyholm
Security
Authentication vs Authorisation
@tobiasnyholm
class SecurityVoters implements MiddlewareInterface
{
/** @var VoterInterface[] */
private $voters;
public function __construct(array $voters)
{
$this->voters = $voters;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable
{
$deny = 0;
foreach ($this->voters as $voter) {
$result = $voter->vote($request);
switch ($result) {
case VoterInterface::ACCESS_GRANTED:
return $next($request, $response);
case VoterInterface::ACCESS_DENIED:
++$deny;
break;
default:
break;
}
}
if ($deny > 0) {
return new Response(403, [], 'Forbidden');
}
return $next($request, $response);
@tobiasnyholm
Security
declare(strict_types=1);
namespace AppSecurityVoter;
use AppSecurityTokenStorage;
use PsrHttpMessageServerRequestInterface;
class AdminVoter implements VoterInterface
{
private $tokenStorage;
public function __construct(TokenStorage$tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function vote(ServerRequestInterface $request)
{
$uri = $request->getUri()->getPath();
$token = $this->tokenStorage->getLastToken();
if ($token['username'] !== 'Tobias' && $uri === '/admin') {
return VoterInterface::ACCESS_DENIED;
}
return VoterInterface::ACCESS_ABSTAIN;
}
}
@tobiasnyholm
Security
@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());
}
// …
}
@tobiasnyholm
Security
@tobiasnyholm
Autowiring
@tobiasnyholm
Autowiring
@tobiasnyholm
Autowiring
P
P
P
@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());
}
// …
}
@tobiasnyholm
Autowiring
@tobiasnyholm
Toolbar
@tobiasnyholmclass Toolbar implements MiddlewareInterface
{
private $cacheDataCollector;
public function __construct(CacheDataCollector $cacheDataCollector)
{
$this->cacheDataCollector = $cacheDataCollector;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable
{
$calls = $this->cacheDataCollector->getCalls();
$getItemCalls = count($calls['getItem']);
$content = $response->getBody()->__toString();
$toolbar = <<<HTML
<br><br><br><hr>
URL: {$request->getUri()->getPath()}<br>
IP: {$request->getServerParams()['REMOTE_ADDR']}<br>
Cache calls: {$getItemCalls}<br>
HTML;
$stream = (new StreamFactory())->createStream($content.$toolbar);
$response = $response->withBody($stream);
return $next($request, $response);
}
}
@tobiasnyholm<?php
namespace AppDataCollector;
use PsrCacheCacheItemInterface;
use PsrCacheCacheItemPoolInterface;
class CacheDataCollector implements CacheItemPoolInterface
{
/** @var CacheItemPoolInterface */
private $real;
private $calls;
public function __construct(CacheItemPoolInterface $cache)
{
$this->real = $cache;
}
public function getCalls()
{
return $this->calls;
}
public function getItem($key)
{
$this->calls['getItem'][] = ['key'=>$key];
return $this->real->getItem($key);
}
@tobiasnyholm
Toolbar
@tobiasnyholmclass Toolbar implements MiddlewareInterface
{
private $cacheDataCollector;
public function __construct(CacheDataCollector $cacheDataCollector)
{
$this->cacheDataCollector = $cacheDataCollector;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable
{
$calls = $this->cacheDataCollector->getCalls();
$getItemCalls = count($calls['getItem']);
$content = $response->getBody()->__toString();
$toolbar = <<<HTML
<br><br><br><hr>
URL: {$request->getUri()->getPath()}<br>
IP: {$request->getServerParams()['REMOTE_ADDR']}<br>
Cache calls: {$getItemCalls}<br>
HTML;
$stream = (new StreamFactory())->createStream($content.$toolbar);
$response = $response->withBody($stream);
return $next($request, $response);
}
}
@tobiasnyholm
Exception
@tobiasnyholm
Exception
<?php
declare(strict_types=1);
namespace AppController;
use NyholmPsr7Response;
use PsrHttpMessageRequestInterface;
class ExceptionController
{
public function run(RequestInterface $request)
{
throw new RuntimeException('This is an exception');
}
}
@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;
}
}
@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());
}
}
@tobiasnyholm
Exception
@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;
}
}
@tobiasnyholm
@tobiasnyholm
@tobiasnyholm
Where is Symfony?
@tobiasnyholm
HTTP objects
@tobiasnyholm
Controllers
@tobiasnyholm
Event loop
kernel.request
kernel.controller
kernel.view
kernel.response
kernel.finish_request
kernel.terminate
@tobiasnyholm
Cache
PSR-6
PSR-16
@tobiasnyholm
Container
@tobiasnyholm
Router
@tobiasnyholm
Security
@tobiasnyholm
Autowiring
@tobiasnyholm
Toolbar
@tobiasnyholm
Exception
@tobiasnyholm
This was Symfony
sim
ple
@tobiasnyholm
What is Symfony?
nyholm/psr7 symfony/http-foundation
relay/relay symfony/event-dispatcher
php-cache/* symfony/cache
Custom kernel symfony/http-kernel
Custom security symfony/security
@tobiasnyholm
Questions?
https://joind.in/talk/8b9dd
Tobias Nyholm "Deep dive into Symfony 4 internals"

Contenu connexe

Tendances

Legacy applications - 4Developes konferencja, Piotr Pasich
Legacy applications  - 4Developes konferencja, Piotr PasichLegacy applications  - 4Developes konferencja, Piotr Pasich
Legacy applications - 4Developes konferencja, Piotr PasichPiotr Pasich
 
Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010Binh Nguyen
 
Codeigniter4の比較と検証
Codeigniter4の比較と検証Codeigniter4の比較と検証
Codeigniter4の比較と検証ME iBotch
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know Aboutjoshua.mcadams
 
Power Shell and Sharepoint 2013
Power Shell and Sharepoint 2013Power Shell and Sharepoint 2013
Power Shell and Sharepoint 2013Mohan Arumugam
 
10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming language10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming languageYaroslav Tkachenko
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service ManagerChris Tankersley
 
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...King Foo
 
Symfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSymfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSarah El-Atm
 
BASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationBASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationWorkhorse Computing
 
What's new in PHP 5.5
What's new in PHP 5.5What's new in PHP 5.5
What's new in PHP 5.5Tom Corrigan
 
Introduction to Modern Perl
Introduction to Modern PerlIntroduction to Modern Perl
Introduction to Modern PerlDave Cross
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.Workhorse Computing
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationWorkhorse Computing
 

Tendances (20)

Legacy applications - 4Developes konferencja, Piotr Pasich
Legacy applications  - 4Developes konferencja, Piotr PasichLegacy applications  - 4Developes konferencja, Piotr Pasich
Legacy applications - 4Developes konferencja, Piotr Pasich
 
New in php 7
New in php 7New in php 7
New in php 7
 
nginx mod PSGI
nginx mod PSGInginx mod PSGI
nginx mod PSGI
 
Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010
 
Codeigniter4の比較と検証
Codeigniter4の比較と検証Codeigniter4の比較と検証
Codeigniter4の比較と検証
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know About
 
Power Shell and Sharepoint 2013
Power Shell and Sharepoint 2013Power Shell and Sharepoint 2013
Power Shell and Sharepoint 2013
 
10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming language10 tips for making Bash a sane programming language
10 tips for making Bash a sane programming language
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service Manager
 
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
 
Modern Perl
Modern PerlModern Perl
Modern Perl
 
Getting testy with Perl
Getting testy with PerlGetting testy with Perl
Getting testy with Perl
 
Symfony2 Components - The Event Dispatcher
Symfony2 Components - The Event DispatcherSymfony2 Components - The Event Dispatcher
Symfony2 Components - The Event Dispatcher
 
Findbin libs
Findbin libsFindbin libs
Findbin libs
 
BASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationBASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic Interpolation
 
What's new in PHP 5.5
What's new in PHP 5.5What's new in PHP 5.5
What's new in PHP 5.5
 
Introduction to Modern Perl
Introduction to Modern PerlIntroduction to Modern Perl
Introduction to Modern Perl
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
 

Similaire à Tobias Nyholm "Deep dive into Symfony 4 internals"

GettingStartedWithPHP
GettingStartedWithPHPGettingStartedWithPHP
GettingStartedWithPHPNat Weerawan
 
Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Adam Tomat
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]Raul Fraile
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016
The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016
The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016Codemotion
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)Fabien Potencier
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkBo-Yi Wu
 
The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5Wim Godden
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overviewjsmith92
 
How to build a High Performance PSGI/Plack Server
How to build a High Performance PSGI/Plack Server How to build a High Performance PSGI/Plack Server
How to build a High Performance PSGI/Plack Server Masahiro Nagano
 
Php7 HHVM and co
Php7 HHVM and coPhp7 HHVM and co
Php7 HHVM and coweltling
 

Similaire à Tobias Nyholm "Deep dive into Symfony 4 internals" (20)

What's new with PHP7
What's new with PHP7What's new with PHP7
What's new with PHP7
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
GettingStartedWithPHP
GettingStartedWithPHPGettingStartedWithPHP
GettingStartedWithPHP
 
Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018Supercharging WordPress Development in 2018
Supercharging WordPress Development in 2018
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
PHP pod mikroskopom
PHP pod mikroskopomPHP pod mikroskopom
PHP pod mikroskopom
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016
The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016
The new features of PHP 7 - Enrico Zimuel - Codemotion Milan 2016
 
The new features of PHP 7
The new features of PHP 7The new features of PHP 7
The new features of PHP 7
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)The symfony platform: Create your very own framework (PHP Quebec 2008)
The symfony platform: Create your very own framework (PHP Quebec 2008)
 
Php hacku
Php hackuPhp hacku
Php hacku
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC Framework
 
The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overview
 
How to build a High Performance PSGI/Plack Server
How to build a High Performance PSGI/Plack Server How to build a High Performance PSGI/Plack Server
How to build a High Performance PSGI/Plack Server
 
Php7 HHVM and co
Php7 HHVM and coPhp7 HHVM and co
Php7 HHVM and co
 

Plus de Fwdays

"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...Fwdays
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil TopchiiFwdays
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro SpodaretsFwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym KindritskyiFwdays
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...Fwdays
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...Fwdays
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...Fwdays
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...Fwdays
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...Fwdays
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...Fwdays
 
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast..."Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...Fwdays
 
"Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others..."Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others...Fwdays
 
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?", Oleksandra MyronovaFwdays
 
"Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv..."Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv...Fwdays
 
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin..."How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...Fwdays
 

Plus de Fwdays (20)

"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
 
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast..."Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
 
"Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others..."Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others...
 
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
 
"Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv..."Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv...
 
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin..."How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
 

Dernier

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 

Dernier (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 

Tobias Nyholm "Deep dive into Symfony 4 internals"

  • 1. Tobias Nyholm, @tobiasnyholm Deep dive into Symfony4 internals
  • 3. @tobiasnyholm Tobias Nyholm • Full stack unicorn on Happyr.com • Certified Symfony developer • Symfony core member • PHP-Stockholm • Open source
  • 4. @tobiasnyholm Open source PHP-cache HTTPlug Mailgun LinkedIn API clientSwap Stampie BazingaGeocoderBundle PHP-Geocoder FriendsOfApi/boilerplate Guzzle Buzz CacheBundlePSR7 SymfonyBundleTest NSA SimpleBus integrations PSR HTTP clients Neo4j KNP Github API PHP-Translation Puli Assert Backup-manager/symfony php-http/httplug-bundle php-http/multipart-stream php-http/discovery happyr/normal-distribution-bundle nyholm/effective-interest-rate MailgunBundle league/geotools
  • 6. @tobiasnyholm Just a bunch of files <?php // index.php if (isset($_GET['page']) && $_GET['page'] === 'foo') { echo "Foo page <br>"; } else { echo "Welcome to index! <br>"; } if ($_SERVER['REMOTE_ADDR'] === '127.0.0.1') { echo "(admin stuff)"; }
  • 8. @tobiasnyholm Just a bunch of files <?php // index.php if (isset($_GET['page']) && $_GET['page'] === 'foo') { echo "Foo page <br>"; } else { echo "Welcome to index! <br>"; } if ($_SERVER['REMOTE_ADDR'] === '127.0.0.1') { echo "(admin stuff)"; }
  • 10. @tobiasnyholm HTTP objects <?php // index.php use NyholmPsr7FactoryServerRequestFactory; use NyholmPsr7Response; require __DIR__.'/vendor/autoload.php'; $request = (new ServerRequestFactory())->createServerRequestFromGlobals(); $query = $request->getQueryParams(); if (isset($query['page']) && $query['page'] === 'foo') { $response = new Response(200, [], 'Foo page'); } else { $response = new Response(200, [], 'Welcome to index!'); } // Send response echo $response->getBody();
  • 13. @tobiasnyholm HTTP objects <?php // index.php use NyholmPsr7FactoryServerRequestFactory; use NyholmPsr7Response; require __DIR__.'/vendor/autoload.php'; $request = (new ServerRequestFactory())->createServerRequestFromGlobals(); $query = $request->getQueryParams(); if (isset($query['page']) && $query['page'] === 'foo') { $response = new Response(200, [], 'Foo page'); } else { $response = new Response(200, [], 'Welcome to index!'); } // Send response echo $response->getBody();
  • 17. @tobiasnyholm Controllers<?php // index.php use NyholmPsr7FactoryServerRequestFactory; use NyholmPsr7Response; require __DIR__.'/../vendor/autoload.php'; $request = (new ServerRequestFactory())->createServerRequestFromGlobals(); $uri = $request->getUri()->getPath(); if ($uri === '/') { $response = (new AppControllerStartpageController())->run($request); } elseif ($uri === '/foo') { $response = (new AppControllerFooController())->run($request); } else { $response = new Response(404, [], 'Not found'); } // Send response echo $response->getBody();
  • 18. @tobiasnyholm Controllers <?php declare(strict_types=1); namespace AppController; use NyholmPsr7Response; use PsrHttpMessageRequestInterface; class StartpageController { public function run(RequestInterface $request) { return new Response(200, [], 'Welcome to index!'); } }
  • 20. @tobiasnyholm Controllers<?php // index.php use NyholmPsr7FactoryServerRequestFactory; use NyholmPsr7Response; require __DIR__.'/../vendor/autoload.php'; $request = (new ServerRequestFactory())->createServerRequestFromGlobals(); $uri = $request->getUri()->getPath(); if ($uri === '/') { $response = (new AppControllerStartpageController())->run($request); } elseif ($uri === '/foo') { $response = (new AppControllerFooController())->run($request); } else { $response = new Response(404, [], 'Not found'); } // Send response echo $response->getBody();
  • 22. @tobiasnyholm Event loop<?php // index.php use NyholmPsr7FactoryServerRequestFactory; use NyholmPsr7Response; require __DIR__.'/../vendor/autoload.php'; $request = (new ServerRequestFactory())->createServerRequestFromGlobals(); $response = new Response(); $middlewares[] = new AppMiddlewareRouter(); $runner = (new RelayRelayBuilder())->newInstance($middlewares); $response = $runner($request, $response); // Send response echo $response->getBody();
  • 23. @tobiasnyholmnamespace AppMiddleware; use PsrHttpMessageResponseInterface as Response; use PsrHttpMessageServerRequestInterface as Request; class Router implements MiddlewareInterface { public function __invoke(Request $request, Response $response, callable $next) { $uri = $request->getUri()->getPath(); switch ($uri) { case '/': $response = (new AppControllerStartpageController())->run($request); break; case '/foo': $response = (new AppControllerFooController())->run($request); break; default: $response = $response->withStatus(404); $response->getBody()->write('Not Found'); break; } return $next($request, $response); } }
  • 25. @tobiasnyholm Event loop<?php // index.php use NyholmPsr7FactoryServerRequestFactory; use NyholmPsr7Response; require __DIR__.'/../vendor/autoload.php'; $request = (new ServerRequestFactory())->createServerRequestFromGlobals(); $response = new Response(); $middlewares[] = new AppMiddlewareRouter(); $runner = (new RelayRelayBuilder())->newInstance($middlewares); $response = $runner($request, $response); // Send response echo $response->getBody();
  • 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();
  • 30. @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; }
  • 40. @tobiasnyholm <?php namespace AppMiddleware; use PsrHttpMessageResponseInterface as Response; use PsrHttpMessageServerRequestInterface as Request; class Router implements MiddlewareInterface { public function __invoke(Request $request, Response $response, callable $next) { $uri = $request->getUri()->getPath(); switch ($uri) { case '/': $response = (new AppControllerStartpageController())->run($request); break; case '/foo': $response = (new AppControllerFooController())->run($request); break; default: $response = $response->withStatus(404); $response->getBody()->write('Not Found'); break; } return $next($request, $response); } }
  • 41. @tobiasnyholm public function __invoke(Request $request, Response $response, callable $next) { $uri = $request->getUri()->getPath(); switch ($uri) { case '/': $response = (new AppControllerStartpageController())->run($request); break; case '/foo': $response = (new AppControllerFooController())->run($request); break; default: $response = $response->withStatus(404); $response->getBody()->write('Not Found'); break; } return $next($request, $response); }
  • 43. public function __invoke(Request $request, Response $response, callable $next) { $uri = $request->getUri()->getPath(); if (0 === strpos($uri, '/admin')) { if (0 === strpos($uri, '/admin/account')) { $response = (new AppControllerManagerController())->accountAction($request); } if (0 === strpos($uri, '/admin/password')) { $response = (new AppControllerManagerController())->passwordAction($request); } } elseif (0 === strpos($uri, '/images')) { if (0 === strpos($uri, '/images/upload')) { $response = (new AppControllerImageController())->uploadAction($request); } if (preg_match('#^/images/(?P<id>[^/]++)/show#sD', $uri, $matches)) { $response = (new AppControllerImageController())->showAction($request, $matches[ } if (preg_match('#^/images/(?P<id>[^/]++)/delete#sD', $uri, $matches)) { $response = (new AppControllerImageController())->deleteAction($request, $matche } } elseif ($uri === '/') { $response = (new AppControllerStartpageController())->run($request); } elseif ($uri === '/foo') { $response = (new AppControllerFooController())->run($request); } else { $response = $response->withStatus(404); $response->getBody()->write('Not Found'); }
  • 44. public function __invoke(Request $request, Response $response, callable $next) { $uri = $request->getUri()->getPath(); $routes = array( '/foo' => 'AppControllerFooController::FooAction', '/images/upload' => 'AppControllerImageController::uploadAction', '/admin/account' => 'AppControllerManagerController::accountAction', '/admin/password' => 'AppControllerManagerController::passwordAction', // More static routes '/' => 'AppControllerStartpageController::startpageAction', ); if (isset($routes[$uri])) { $response = call_user_func($routes[$uri], $request); return $next($request, $response); } $regex = '{^(?' .'|/images/([^/]++)/(?' .'|show(*:31)' .'|delete(*:44)' // my dynamic and complex regex .')' .')$}sD';
  • 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'])); } }
  • 55. @tobiasnyholm class SecurityVoters implements MiddlewareInterface { /** @var VoterInterface[] */ private $voters; public function __construct(array $voters) { $this->voters = $voters; } public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable { $deny = 0; foreach ($this->voters as $voter) { $result = $voter->vote($request); switch ($result) { case VoterInterface::ACCESS_GRANTED: return $next($request, $response); case VoterInterface::ACCESS_DENIED: ++$deny; break; default: break; } } if ($deny > 0) { return new Response(403, [], 'Forbidden'); } return $next($request, $response);
  • 56. @tobiasnyholm Security declare(strict_types=1); namespace AppSecurityVoter; use AppSecurityTokenStorage; use PsrHttpMessageServerRequestInterface; class AdminVoter implements VoterInterface { private $tokenStorage; public function __construct(TokenStorage$tokenStorage) { $this->tokenStorage = $tokenStorage; } public function vote(ServerRequestInterface $request) { $uri = $request->getUri()->getPath(); $token = $this->tokenStorage->getLastToken(); if ($token['username'] !== 'Tobias' && $uri === '/admin') { return VoterInterface::ACCESS_DENIED; } return VoterInterface::ACCESS_ABSTAIN; } }
  • 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()); } // … }
  • 66. @tobiasnyholmclass Toolbar implements MiddlewareInterface { private $cacheDataCollector; public function __construct(CacheDataCollector $cacheDataCollector) { $this->cacheDataCollector = $cacheDataCollector; } public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable { $calls = $this->cacheDataCollector->getCalls(); $getItemCalls = count($calls['getItem']); $content = $response->getBody()->__toString(); $toolbar = <<<HTML <br><br><br><hr> URL: {$request->getUri()->getPath()}<br> IP: {$request->getServerParams()['REMOTE_ADDR']}<br> Cache calls: {$getItemCalls}<br> HTML; $stream = (new StreamFactory())->createStream($content.$toolbar); $response = $response->withBody($stream); return $next($request, $response); } }
  • 67. @tobiasnyholm<?php namespace AppDataCollector; use PsrCacheCacheItemInterface; use PsrCacheCacheItemPoolInterface; class CacheDataCollector implements CacheItemPoolInterface { /** @var CacheItemPoolInterface */ private $real; private $calls; public function __construct(CacheItemPoolInterface $cache) { $this->real = $cache; } public function getCalls() { return $this->calls; } public function getItem($key) { $this->calls['getItem'][] = ['key'=>$key]; return $this->real->getItem($key); }
  • 69. @tobiasnyholmclass Toolbar implements MiddlewareInterface { private $cacheDataCollector; public function __construct(CacheDataCollector $cacheDataCollector) { $this->cacheDataCollector = $cacheDataCollector; } public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable { $calls = $this->cacheDataCollector->getCalls(); $getItemCalls = count($calls['getItem']); $content = $response->getBody()->__toString(); $toolbar = <<<HTML <br><br><br><hr> URL: {$request->getUri()->getPath()}<br> IP: {$request->getServerParams()['REMOTE_ADDR']}<br> Cache calls: {$getItemCalls}<br> HTML; $stream = (new StreamFactory())->createStream($content.$toolbar); $response = $response->withBody($stream); return $next($request, $response); } }
  • 71. @tobiasnyholm Exception <?php declare(strict_types=1); namespace AppController; use NyholmPsr7Response; use PsrHttpMessageRequestInterface; class ExceptionController { public function run(RequestInterface $request) { throw new RuntimeException('This is an exception'); } }
  • 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()); } }
  • 75. @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; } }
  • 76.
  • 91. @tobiasnyholm What is Symfony? nyholm/psr7 symfony/http-foundation relay/relay symfony/event-dispatcher php-cache/* symfony/cache Custom kernel symfony/http-kernel Custom security symfony/security