phpBB4 meets Symfony2 Fabien Potencier
symfony 1 vs Symfony2
MVC
namespace Application\HelloBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller;
class HelloController extends Controller { public function indexAction($name) { // Get things from the Model
return $this->render( 'HelloBundle:Hello:index', array('name' => $name) ); } }
<?php $view->extend('HelloBundle::layout') ?>
Hello <?php echo $name ?>!
<html> <head> <title> <?php $view['slots']->output('title') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
_content
title
layout
slot
{% extends "HelloBundle::layout" %}
{% block content %} Hello {{ name }}! {% endblock %}
<html> <head> <title> {% block title %}{% endblock %} </title> </head> <body> {% block body %}{% endblock %} </body> </html>
Routing
/blog.php?section=symfony&article_id=18475
web/ index.php
/index.php/blog/2010/08/21/symfony2-meets-phpBB4
/blog/2010/08/21/symfony2-meets-phpBB4
/blog/:year/:month/:day/:slug
post: pattern: /blog/:year/:month/:day/:slug defaults: { _controller: BlogBundle:Post:show }
<routes> <route id="post" pattern="/blog/:year/:month/:day/:slug"> <default key="_controller"> BlogBundle:Post:show </default> </route> </routes>
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route;
$collection = new RouteCollection();
$route = new Route( '/blog/:year/:month/:day/:slug', array('_controller' => 'BlogBundle:Post:show'));
$collection->addRoute('post', $route);
return $collection;
$router ->match('/blog/2010/08/21/sf2-meets-phpBB4')
$router ->generate('post', array('slug' => '...'))
post: pattern: /post/:slug defaults: { _controller: BlogBundle:Post:show }
$router ->generate('post', array('slug' => '...'))
Bundles
.../ SomeBundle/ Controller/ Entity/ Resources/ config/ views/ SomeBundle.php Tests/
public function registerBundleDirs() { return array( 'Application' => __DIR__.'/../src/Application', 'Bundle' => __DIR__.'/../src/Bundle', 'Symfony\Bundle' => __DIR__.'/../src/vendor/symfony/src/Symfony/Bundle', ); }
$this->render('SomeBundle:Hello:index', $params)
hello: pattern: /hello/:name defaults: { _controller: SomeBundle:... }
SomeBundle can be any of
Application\SomeBundle Bundle\SomeBundle Symfony\Bundle\SomeBundle
Environments
Developers Customer End Users
Development Environment
Staging Environment
Production Environment
cache cache cache
debug debug debug
logs logs logs
stats stats stats
Development Environment
Staging Environment
Production Environment
# config/config.yml doctrine.dbal: dbname: mydbname user: root password: %doctrine.dbal_password%
swift.mailer: transport: smtp host: localhost
# config/config_dev.yml imports: - { resource: config.yml }
zend.logger: priority: debug path: %kernel.root_dir%/logs/%kernel.environment%.log
doctrine.dbal: password: ~
swift.mailer: transport: gmail username: xxxxxxxx password: xxxxxxxx
# Doctrine Configuration doctrine.dbal: dbname: xxxxxxxx user: xxxxxxxx password: ~
# Swiftmailer Configuration swift.mailer: transport: smtp encryption: ssl auth_mode: login host: smtp.gmail.com username: xxxxxxxx password: xxxxxxxx
<!-- Doctrine Configuration --> <doctrine:dbal dbname="xxxxxxxx" user="xxxxxxxx" password="" /> <doctrine:orm />
<!-- Swiftmailer Configuration --> <swift:mailer transport="smtp" encryption="ssl" auth_mode="login" host="smtp.gmail.com" username="xxxxxxxx" password="xxxxxxxx" />
// Doctrine Configuration $container->loadFromExtension('doctrine', 'dbal', array( 'dbname' => 'xxxxxxxx', 'user' => 'xxxxxxxx', 'password' => '', )); $container->loadFromExtension('doctrine', 'orm');
// Swiftmailer Configuration $container->loadFromExtension('swift', 'mailer', array( 'transport' => "smtp", 'encryption' => "ssl", 'auth_mode' => "login", 'host' => "smtp.gmail.com", 'username' => "xxxxxxxx", 'password' => "xxxxxxxx", ));
Developer Tools
INFO: Matched route "blog_home" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'index', '_route' => 'blog_home',))
INFO: Using controller "Bundle\BlogBundle\Controller\PostController::indexAction"
INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ ORDER BY s0_.published_at DESC LIMIT 10 (array ())
INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',))
INFO: Using controller "Bundle\BlogBundle\Controller\PostController::showAction »
INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught Symfony\Components\RequestHandler\Exception\NotFoundHttpException exception)
INFO: Using controller "Symfony\Framework\WebBundle\Controller\ExceptionController::exceptionAction"
DEBUG: Notifying (until) event "core.request" to listener "(Symfony\Framework\WebBundle\Listener\RequestParser, resolve)" INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) DEBUG: Notifying (until) event "core.load_controller" to listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" INFO: Using controller "Bundle\BlogBundle\Controller\PostController::showAction" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" processed the event "core.load_controller" INFO: Trying to get post "3456" from database INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) DEBUG: Notifying (until) event "core.exception" to listener "(Symfony\Framework\WebBundle\Listener\ExceptionHandler, handle)" ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught Symfony\Components\RequestHandler\Exception\NotFoundHttpException exception) DEBUG: Notifying (until) event "core.request" to listener "(Symfony\Framework\WebBundle\Listener\RequestParser, resolve)" DEBUG: Notifying (until) event "core.load_controller" to listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" INFO: Using controller "Symfony\Framework\WebBundle\Controller\ExceptionController::exceptionAction" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" processed the event "core.load_controller" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Listener\ResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\DataCollector\DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\WebDebugToolbar, handle)" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ExceptionHandler, handle)" processed the event "core.exception" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Listener\ResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\DataCollector\DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\WebDebugToolbar, handle)"
Security
XSS / CSRF / SQL Injection
<doctrine:dbal dbname="sfweb" username="root" password="SuperSecretPasswordThatAnyoneCanSee" />
SetEnv SYMFONY__DOCTRINE__DBAL__PASSWORD "foobar"
in a .htaccess or httpd.conf file
%doctrine.dbal.password%
<doctrine:dbal dbname="sfweb" username="root" password="%doctrine.dbal.password%" />
Functional Tests
$client = $this->createClient();
$crawler = $client->request( 'GET', '/hello/Fabien');
$this->assertTrue($crawler->filter( 'html:contains("Hello Fabien")')->count());
$this->assertEquals( 10, $crawler->filter('div.hentry')->count());
$this->assertTrue( $client->getResponse()->isSuccessful());
$crawler = $client->request( 'GET', 'hello/Lucas' );
$link = $crawler->selectLink("Greet Lucas");
$client->click($link);
$form = $crawler->selectButton('submit');
$client->submit($form, array( 'name' => 'Lucas', 'country' => 'France', 'like_symfony' => true, 'photo' => '/path/to/lucas.jpg', ));
$harry = $this->createClient(); $sally = $this->createClient();
$harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages');
$this->assertEquals(201, $harry->getResponse()->getStatusCode());
$this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
$harry = $this->createClient(); $sally = $this->createClient();
$harry->insulate(); $sally->insulate();
$harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages');
$this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
Caching
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
cacheable for 10 seconds cacheable for 5 seconds
main controller
embedded controller
layout
<?php $view->extend('...:layout') ?>
<?php $view['slots']->start('sidebar') ?>
<?php echo $view['actions']->render('...:list') ?>
<?php $view['slots']->stop() ?>
cacheable for 10 seconds
cacheable for 5 seconds
$view['actions']->render('...:list', array( 'standalone' => true, ))
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
<esi:include src="..." />
ESI… or Edge Side Includes
Symf
ony2
Appli
catio
n
Reve
rse Pr
oxy
Clien
t Lorem ipsum dolor sit amet,
Lorem ipsum dolor
Lorem ipsum dolor sit amet,
Lorem ipsum dolor
1
2
3
4
Symfony2 app
Web Server
Requests
Response
Symfony2 app
Symfony2 HTTP proxy
Web Server
Requests
Response
Symfony2 app
Web Server
Reverse proxy
Requests
Response
HttpKernel: The framework construction kit
namespace Symfony\Component\HttpKernel;
interface HttpKernelInterface { const MASTER_REQUEST = 1; const SUB_REQUEST = 2;
public function handle( Request $request = null, $type = self::MASTER_REQUEST, $raw = false); }
Request
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
Request
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
Request
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
core.exception
HttpFoundation
HttpKernel
Framework
FrameworkBundle
Routing
Console
SwiftmailerBundle
TwigBundle
DependencyInjection
...
...
Components
Bundles
Event Dispatcher
Templating
DoctrineBundle
ZendBundle
MOD author
Theme author
Core Developer
End Users
Everybody
Questions?
Top Related