Who am I?Who am I?
Raúl Fraile
@raulfraile
PHP/Symfony2 freelance developer
What do I do?What do I do?
SensioLabsSensioLabsConnectConnect
Why?Why?
app[_dev].phpapp[_dev].php
Front controller
app[_dev].phpapp[_dev].php
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
bootstrap.php.cachebootstrap.php.cache
Several classes/interfaces
in the same file
bootstrap.php.cachebootstrap.php.cache
// app/bootstrap.php.cache
namespace { require_once __DIR__.'/autoload.php'; }
namespace Symfony\Component\DependencyInjection{ interface ContainerAwareInterface { function setContainer(ContainerInterface $container = null); } ...}
bootstrap.php.cachebootstrap.php.cache
Reduces I/O operations
bootstrap.php.cachebootstrap.php.cache
Loads autoload.php
autoload.phpautoload.php// app/autoload.php
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();$loader->registerNamespaces(array( 'Symfony' => array( __DIR__.'/../vendor/symfony/src', __DIR__.'/../vendor/bundles'), 'Assetic' => __DIR__.'/../vendor/assetic/src',));$loader->registerPrefixes(array( 'Twig_' => __DIR__.'/../vendor/twig/lib',));
ClassLoaderClassLoader
Autoloading of
classes/interfaces in
Symfony2
ClassLoader
ClassLoaderClassLoader
Implements PSR-0
PSR-0PSR-0
Approved by the “Framework Interop Group”
github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
PSR-0PSR-0
Fully Qualified Name
Filesystem
\Symfony\Core\Request\Zend\Mail\Message
[vendor_path]/Symfony/Core/Request.php[vendor_path]/Zend/Mail/Message.php
ClassLoaderClassLoader// namespaced class name$namespace = substr($class, 0, $pos);foreach ($this->namespaces as $ns => $dirs) { if (0 !== strpos($namespace, $ns)) { continue; }
foreach ($dirs as $dir) { $className = substr($class, $pos + 1); $file = $dir . DIR_SEPARATOR . str_replace('\\',DIR_SEPARATOR, $namespace) . DIR_SEPARATOR . str_replace('_', DIR_SEPARATOR, $className) . '.php'; if (file_exists($file)) { return $file; } }}
ClassLoaderClassLoader
$loader->findFile( 'Symfony\Component\HttpFoundation\Request');
/Sites/desymfony/app/../vendor/symfony/src/ Symfony/Component/HttpFoundation/Request.php
app[_dev].phpapp[_dev].php
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
AppKernel.phpAppKernel.php// src/AppKernel.php
use Symfony\Component\HttpKernel\Kernel;use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel{ public function registerBundles() { $bundles = array( new Symfony\Bundle\TwigBundle\TwigBundle(), ... ); return $bundles; }
public function registerContainerConfiguration(LoaderInterface $loader) { $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); }}
app[_dev].phpapp[_dev].php
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
Environment
Debug
AppKernel.phpAppKernel.php
If (true === $debug) {
} else {
Saves initial time (microtime)
display_errors = 1
error_reporting = -1
DebugUniversalClassLoader
}display_errors = 0
app[_dev].phpapp[_dev].php
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
LoadClassCacheLoadClassCache
Objective: map
FQN/filenames of
classes and interfaces
LoadClassCacheLoadClassCache
It is cached in
classes.map and
classes.php.meta
app[_dev].phpapp[_dev].php
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
RequestRequest
HttpFoundation
Component
RequestRequest
OO abstraction of a
HTTP request
RequestRequest
GET /index.php HTTP/1.1␍␊ Host: test.com␍␊ Accept-Language:en;q=0.8␍␊ Accept-Encoding:gzip␍␊ User-Agent: Mozilla/5.0␍␊ ␍␊
$_GET
$_POST
$_COOKIE
$_FILES
$_SERVER
Request
queryrequestcookies
filesserver
headers
getHostgetClientIp
...
app[_dev].phpapp[_dev].php
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
HttpKernelHttpKernel
Wrapper on top of
Request/Response to
handle the dynamic
part of HTTP
HttpKernelHttpKernel
Handles an
environment consisting
of bundles, DIC...
Initialize
bundles and DIC
$kernel->boot()$kernel->boot()
Loads bundles defined in
AppKernel::registerBundles()
$kernel->initializeBundles()$kernel->initializeBundles()
Generated using the
ContainerBuilder from
DependencyInjection
$kernel->initializeContainer()$kernel->initializeContainer()
ContainerBuilderContainerBuilder
// example.com/src/container.phpuse Symfony\Component\DependencyInjection;use Symfony\Component\DependencyInjection\Reference;
$sc = new DependencyInjection\ContainerBuilder(); $sc->register('context', 'Symfony\Component\Routing\RequestContext');$sc->register('matcher', 'Symfony\Component\Routing\Matcher\UrlMatcher') ->setArguments(array($routes, new Reference('context')));
$sc->register('framework', 'Simplex\Framework') ->setArguments(array(new Reference('dispatcher'), new Reference('resolver'))) ;
http://fabien.potencier.org/article/62/create-your-own-framework-on-top-of-the-symfony2-components-part-12
{rootDir}{Environment}
[Debug]ProjectContainer
$kernel->initializeContainer()$kernel->initializeContainer()
For each bundle,
Bundle::build() method is
executed and extensions
are loaded
$kernel->initializeContainer()$kernel->initializeContainer()
For each bundle, the
container is injected and
the boot() method is
executed
$kernel->boot()$kernel->boot()
Goal: Return a Response
object
$kernel->handle()$kernel->handle()
Dispatched as soon as
the request arrives
Event kernel.requestEvent kernel.request
Any listener can return
a Response and 'end'
the execution
Event kernel.requestEvent kernel.request
Used by
FrameworkBundle to set
the _controller value
Event kernel.requestEvent kernel.request
Uses a RouterMatcher
(autogenerated by the
Routing component)
RouterListenerRouterListener
RouterListenerRouterListener
// app/cache/dev/appdevUrlMatcher.php
class appdevUrlMatcher extends RedirectableUrlMatcher{ ... public function match($pathinfo) { ... // _demo_hello if (0 === strpos($pathinfo, '/demo/hello') && preg_match('#^/demo/hello/(?P<name>[^/]+?)$#s', $pathinfo, $m)) { return array_merge($this->mergeDefaults($m, array( '_controller' => 'Acme\\DemoBundle\\Controller\\DemoController::helloAction') ), array( '_route' => '_demo_hello')); } ... }
Must return the controller
+ arguments from
_controller
ControllerResolverControllerResolver
Ties components and
libraries together to make
a MVC framework
FrameworkBundleFrameworkBundle
Moreover...
FrameworkBundleFrameworkBundle
php app/console
FrameworkBundleFrameworkBundle
FrameworkBundleFrameworkBundle// app/console
#!/usr/bin/env php<?php
require_once __DIR__.'/bootstrap.php.cache';require_once __DIR__.'/AppKernel.php';
use Symfony\Bundle\FrameworkBundle\Console\Application;use Symfony\Component\Console\Input\ArgvInput;
$input = new ArgvInput();$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');$debug = !$input->hasParameterOption(array('--no-debug', ''));
$kernel = new AppKernel($env, $debug);$application = new Application($kernel);$application->run();
Commands
FrameworkBundleFrameworkBundle
assets:install
cache:clear
cache:warmup
container:debug
router:dump-apache
router:debug
Base Controller
FrameworkBundleFrameworkBundle
FrameworkBundleFrameworkBundle
// src/Acme/DemoBundle/Controller/DemoController
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DemoController extends Controller{ public function helloAction($name) { ... }}
And much more: ESI,
WebTestCase,
DataCollectors...
FrameworkBundleFrameworkBundle
Once the controller has
been resolved, this
event is generated
Event kernel.controllerEvent kernel.controller
Any listener can
manipulate the
Controller callable
Event kernel.controllerEvent kernel.controller
This event is called only
if the Controller does
not return a Response
Event kernel.viewEvent kernel.view
Goal: build a Response
object from the return
value of the Controller
Event kernel.viewEvent kernel.view
Allows to modify or
replace the Response
object after its creation
Event kernel.responseEvent kernel.response
Last change to convert a
Exception into a
Response object
Event kernel.exceptionEvent kernel.exception
Extend from KernelEvent
EventsEvents
getRequestType(): MASTER_REQUEST or SUB_REQUEST
getKernel();
getRequest();
HTTP/1.1 200 OK Content-type: text/html Date:Thu, 31 May 2012 17:54:50 GMT
<!DOCTYPE HTML> <html lang="es"> <head> <meta charset="utf-8"> ...
Response
Headers
Version
Content
Status code
Status text
Charset
ResponseResponse
// web/app[_env].php
1. require_once __DIR__.'/../app/bootstrap.php.cache';2. require_once __DIR__.'/../app/AppKernel.php';
3. use Symfony\Component\HttpFoundation\Request;
4. $kernel = new AppKernel('dev', true);5. $kernel->loadClassCache();6. $kernel->handle(Request::createFromGlobals())->send();
app[_dev].phpapp[_dev].php
Send headers and
content
Response::send()Response::send()
Response::send()Response::send()
https://github.com/raulfraile/internals-desymfony2012
DemoDemo
¡Thank you!
http://www.flickr.com/photos/connectirmeli/7233514862
http://www.flickr.com/photos/barretthall/6070677596
http://www.flickr.com/photos/f-oxymoron/5005673112/
PhotosPhotos
Questions?Questions?