Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Symfony Internals
Search
Andreas Hucks
January 27, 2018
Programming
970
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Symfony Internals
PHPBenelux 2018
Andreas Hucks
January 27, 2018
More Decks by Andreas Hucks
See All by Andreas Hucks
Divide and Conquer (LonghornPHP 2019)
meandmymonkey
0
220
Divide and Conquer
meandmymonkey
1
760
Deptrac - Keep Your Architecture Clean
meandmymonkey
0
860
Introduction to Docker at PHPBenelux2015
meandmymonkey
3
950
Best Practices in Symfony2
meandmymonkey
0
560
Introduction to Docker at PHPNW2014
meandmymonkey
4
440
O(ops), Authentication!
meandmymonkey
4
1k
Best Practices in Symfony2
meandmymonkey
15
1.9k
Best Practices in Symfony2
meandmymonkey
28
4.7k
Other Decks in Programming
See All in Programming
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
8.2k
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
2
300
SREの越境 / SRE Collaboration
y0hgi
2
270
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
650
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
2.7k
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
160
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
390
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
310
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
170
Workers Cache を知る
syumai
0
190
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
220
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
260
Featured
See All Featured
How to make the Groovebox
asonas
2
2.4k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Designing Experiences People Love
moore
143
24k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
820
Designing for humans not robots
tammielis
254
26k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
340
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
310
Git: the NoSQL Database
bkeepers
PRO
432
67k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
440
Transcript
Symfony Internals
Symfony Internals Andreas Hucks CTO @ SensioLabs Germany
2008
Conference Hotel
Auditorium
Lunch
Socials
VIP Lounge
Wellness
Survey
Motivation
What to expect
The Request $kernel = new Kernel($env, $debug); $request = Request::createFromGlobals();
$response = $kernel->handle($request); $response->send();
HttpKernel $kernel->handle($request);
Request-Response Flow Request Response Front Controller Kernel
Symfony is not an MVC framework
None
Symfony is a Request-Response Framework
Request-Response Flow Request Response Front Controller Kernel
Request-Response Flow Kernel
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
EventDispatcher $dispatcher = new EventDispatcher(); $dispatcher->addListener('kernel.request', $callable);
EventDispatcher $dispatcher->dispatch( 'kernel.request', $responseEvent );
EventDispatcher $dispatcher->dispatch( 'kernel.request', $responseEvent ); payload What happened.
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
GetResponseEvent class GetResponseEvent extends KernelEvent { public function getResponse() {
return $this->response; } public function setResponse(Response $response) { $this->response = $response; $this->stopPropagation(); } kernel.request
RouterListener /** * @Route(path="/books/{id}", name="book_show") */ $params = [ '_controller'
=> ‘App\Controller\BookController::showAction’, '_route' => 'book_show', '_route_params' => [ 'id' => '37' ], 'id' => ’37' ]; kernel.request
RouterListener $parameters = $this ->matcher->match($request->getPathInfo()); $request->attributes->add($parameters); unset( $parameters[‘_route'], $parameters[‘_controller'] );
$request->attributes->set( '_route_params', $parameters ); kernel.request
LocaleListener $request = $event->getRequest(); $request->setDefaultLocale($this->defaultLocale); if ($locale = $request->attributes->get('_locale')) {
$request->setLocale($locale); } kernel.request
Customize! • Content Negotiation - Parse headers and add attribute
• Verify signed Cookies • Redirects based on arbitrary criteria • Custom Locale stuff • … ?
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
FilterControllerEvent class FilterControllerEvent extends KernelEvent { public function getController() {
return $this->controller; } public function setController(callable $controller) { $this->controller = $controller; } kernel.controller
ControllerListener class ControllerListener implements EventSubscriberInterface { public function __construct(Reader $reader)
{ $this->reader = $reader; } public function onKernelController(FilterControllerEvent $event) { $controller = $event->getController(); // read annotations for class and method $request = $event->getRequest(); foreach ($configurations as $key => $attributes) { $request->attributes->set($key, $attributes); } kernel.controller
ParamConverterListener class ParamConverterListener implements EventSubscriberInterface { /** * @var ParamConverterManager
*/ private $manager; kernel.controller
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
Wait… Controllers?
HttpKernel $response = \call_user_func_array( $controller, $arguments );
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
GetResponseForControllerResultEvent class GetResponseForControllerResultEvent extends GetResponseEvent { public function getControllerResult() {
return $this->controllerResult; } public function setControllerResult($controllerResult) { $this->controllerResult = $controllerResult; } kernel.view
TemplateListener public function onKernelView( GetResponseForControllerResultEvent $event ) { /* @var
Template $template */ $request = $event->getRequest(); $template = $request->attributes->get(‘_template'); // … $event->setResponse( new Response( $this->twig->render($template->getTemplate()), $parameters ) ); kernel.view
Customize! • Auto serializing and encoding for web service responses
• Together with kernel.controller: Action Domain Responder, other patterns?
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
GetResponseForExceptionEvent class GetResponseForExceptionEvent extends GetResponseEvent { public function getException() {
return $this->exception; } kernel.exception
ExceptionListener public function onKernelException( GetResponseForExceptionEvent $event ) { $exception =
$event->getException(); $request = $event->getRequest(); $this->logException($exception kernel.exception
Customize! • Customize for every exception type you like •
Redirect for some errors • “were you looking for…” suggestions on 404 pages • Custom alerts • … ?
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
FilterResponseEvent class FilterResponseEvent extends KernelEvent { public function getResponse() {
return $this->response; } public function setResponse(Response $response) { $this->response = $response; } kernel.response
WebDebugToolbarListener $response->headers->set( 'X-Debug-Token-Link', $this->urlGenerator->generate( ‘_profiler', array( 'token' => $response->headers->get(‘X-Debug-Token') ),
UrlGeneratorInterface::ABSOLUTE_URL ) ); $this->injectToolbar($response, $request, $nonces); kernel.response
SaveSessionListener $session = $event->getRequest()->getSession(); if ($session && $session->isStarted()) { $session->save();
$event->getResponse() ->setPrivate() ->setMaxAge(0) ->headers->addCacheControlDirective('must-revalidate'); } kernel.response
Customize! • Sign cookies • Add custom headers • …
?
Request-Response Flow Kernel kernel.request kernel.controller kernel.response kernel.exception kernel.view kernel.terminate
PostResponseEvent class PostResponseEvent extends KernelEvent { public function getResponse() {
return $this->response; } kernel.terminate
EmailSenderListener public function onTerminate() { // send spooled Emails kernel.terminate
Other Listeners kernel.request • FirewallListener • Collector Listeners
Recap Request Response Front Controller Kernel
Container & Cache
Container & Cache protected function getRouterService() { $this->services[‘router'] = $instance
= new \Symfony\Bundle\…\Router( $this, ‘/app/config/routing_dev.yml' ) // [snip] return $instance; }
Container & Cache Cache class for this request? Does it
exists? require() it yes Build Container no
Container & Cache Cache class for this request? Does it
exists? require() it yes Build Container no
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers (quite a few)
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Registering Bundles public function registerBundles() { $bundles = [ new
Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), // [snip] ]; return $bundles; }
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Registering Extensions protected function prepareContainer(ContainerBuilder $container) { $extensions = array();
foreach ($this->bundles as $bundle) { if ($extension = $bundle->getContainerExtension()) { $container->registerExtension($extension); $extensions[] = $extension->getAlias(); } // [snip] }
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Register Project-Level Container Config public function registerContainerConfiguration( LoaderInterface $loader )
{ $loader->load( $this->getRootDir(). ’/config/config_’.$this->getEnvironment().'.yml' ); }
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Extensions class TwigExtension extends Extension { public function load(array $configs,
ContainerBuilder $container) { $loader = new XmlFileLoader( $container, new FileLocator(__DIR__.’/../Resources/config') ); $loader->load('twig.xml');
Customize! • Load config files • Do not load config
files depending on parameter • Set Parameters, manipulate parameters • BETTER NOT manipulate services (they are not complete at this point, see next slides)
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Compiler Passes public function process(ContainerBuilder $container) { if (!$container->has('app.myservice')) {
return; } $definition = $container->findDefinition( 'app.myservice' ); // find formatter service $definition->addMethodCall( 'addFormatter', array(new Reference($formatterId)) ); }
(A few) Compiler Passes • ServiceLocatorTagPass • DecoratorServicePass • ResolveParameterPlaceHoldersPass
• ResolveFactoryClassPass • ResolveNamedArgumentsPass • AutowirePass • RemovePrivateAliasesPass • ReplaceAliasByActualDefinitionPass • RemoveAbstractDefinitionsPass • InlineServiceDefinitionsPass • RemoveUnusedDefinitionsPass
(A few) Compiler Passes • ServiceLocatorTagPass • DecoratorServicePass • ResolveParameterPlaceHoldersPass
• ResolveFactoryClassPass • ResolveNamedArgumentsPass • AutowirePass • RemovePrivateAliasesPass • ReplaceAliasByActualDefinitionPass • RemoveAbstractDefinitionsPass • InlineServiceDefinitionsPass • RemoveUnusedDefinitionsPass
Customize! • Add method calls to services based on tags
• Manipulate services that depend on the full service config
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Dump Container protected function dumpContainer( ConfigCache $cache, ContainerBuilder $container, $class,
$baseClass ) { $dumper = new PhpDumper($container); $content = $dumper->dump(/*…*/);
… and use it $this->container = require $cache->getPath();
Container Build Register Bundles Register Extensions & Compiler Passes Register
Project Config Run Extensions Run compiler Passes Dump Container Run Cache Warmers
Cache Warmers public function warmUp($cacheDir) { $filesystem = new Filesystem();
$templates = array(); foreach ($this->finder->findAllTemplates() as $template) { // [snip] } // [snip] $this->writeCacheFile($cacheDir.’/templates.php', // [snip] }
Customize! • You have full access to services, the container
in ready • Create custom caches your application needs • Prefetch and cache data from external sources
None
Thank you :) https://joind.in/talk/bd64e