The State of Symfony2 Fabien Potencier
@fabpot fabien.potencier.org
How many of you have already played with Symfony2? http://www.flickr.com/photos/bartworldv6/4206815555
Symfony2 is not ready for production http://www.flickr.com/photos/rknickme/2205111920
Current guestimate for stable release March 2011 http://www.flickr.com/photos/pictureperfectpose/76138988
Crazy people do use Symfony2 http://www.flickr.com/photos/funky64/4267353106/
http://www.flickr.com/photos/lululemonathletica/4229883622
http://www.flickr.com/photos/cayusa/1209794692
http://www.flickr.com/photos/y-a-n/29789408
Symfony2 Translation Component http://www.flickr.com/photos/migrainechick/3704150226
http://www.flickr.com/photos/muffytyrone/4096351705
symfony vs Symfony2 http://www.flickr.com/photos/thebusybrain/2492945625
Messages Domains Locales http://www.flickr.com/photos/rinux/631345826
$t->trans('Symfony2 is great!')
$t->trans('Hello {{ name }}!', array('{{ name }}' => 'Symfony2'))
$t->trans('Symfony2 is great!', array(), 'app')
Pluralization vs Choice http://www.flickr.com/photos/orinrobertjohn/114430223
$t->transChoice($string, $count, $vars)
One apple|{{ count }} apples
one: One apple|some: {{ count }} apples
{1} One apple|[0,Inf] {{ count }} apples
0 apples No apples
{0} No apples| {1} One apple| ]1,Inf] {{ count }} apples
[-Inf,0[ WTF?!| {0} No apples| {1} One apple| [2,19] Some apples| [20,Inf] Many apples
{0} No apples| One apple| {{ count }} apples
<app:translator fallback="en" /> fr_FR fr en
PHP vs Twig http://www.flickr.com/photos/danielmarenco/4775410299
« All templating engines are equal in the eyes of Symfony2 »
$this->render('BlogBundle:Post:index.php', array()); PHP renderer
$this->render('BlogBundle:Post:index.twig', array()); Twig renderer
$this->render('BlogBundle:Post:index.twig', array()); Template logical name
« Template engines are all equals, but some are more equals than others »
<?php echo $view['translator'] ->trans('Symfony2 is great!') ?> vs {% trans "Symfony2 is great!" %}
<?php echo $view['translator'] ->trans('Symfony2 is {{ what }}!', array('{{ what }}' => 'great'), 'app') ?> vs {% trans from app %} Symfony2 is {{ what }}! {% endtrans %}
<?php echo $view['translator'] ->transChoice( 'No apples|One apple|{{ count }} apples', 1, array('{{ count }}' => 1), 'app') ?> vs {% transchoice 1 from app %} No apples|One apple|{{ count }} apples {% endtranschoice %}
<?php echo $view['translator'] ->transChoice( 'No apples|One apple|{{ count }} apples', 1, array('{{ count }}' => 1), 'app') ?>
<?php echo $view['translator'] ->transChoice( 'No apples|One apple|{{ count }} apples', 1, array('{{ count }}' => 1), 'app') ?>
<?php echo $view['translator'] ->transChoice( 'No apples|One apple|{{ count }} apples', 1, array('{{ count }}' => 1), 'app') ?>
{% transchoice 1 from app %} No apples|One apple|{{ count }} apples {% endtranschoice %}
<?php echo $view['session']->getFlash('notice') ?> vs {% flash "notice" %}
<?php $view['slots']->start('title') ?> Post: <?php echo $post->getTitle() ?> <?php $view['slots']->stop() ?> vs {% block title %} Post: {{ post.title }} {% endblock title %}
Customizing Forms http://www.flickr.com/photos/blackbutterfly/2304084815
{{ form|render_enctype }} {{ form|render_errors }} {{ form|render_hidden }} {{ form.name|render_widget }} {{ form.name|render_label }} {{ form.name|render_errors }} {{ form.name|render_data }}
{{ form.name|render_widget }}
An InputField instance is rendered by an input_field template block
{% block input_field %} {% tag "input" with attributes %} {% endblock %} {% block textarea_field %} {% contenttag "textarea" with attributes %} {{ field.displayedData }} {% endcontenttag %} {% endblock %}
{{ form.name|render_widget }}
{{ form.user.name|render_widget }}
How can I customize the rendering of the widget?
{{ form.name|render_widget("BlogBundle::widgets.twig") }}
{% block input_field %} <span class="input_field"> {% tag "input" with attributes %} </span> {% endblock %}
{% extends 'TwigBundle::widgets.twig' %} {% block input_field %} <span class="input_field"> {% parent %} </span> {% endblock %}
How can I customize the rendering of all input widgets for a given form?
{% form_theme form "BlogBundle::widgets.twig" %}
How can I customize the rendering of all input widgets for all forms?
<twig:config> <twig:form> <twig:resource> BlogBundle::widgets.twig </twig:resource> </twig:form> </twig:config>
Nice inheritance/fallback templating system
Same questions as before but now for several widgets
{% block input_field %} <span class="input_field"> {% parent %} </span> {% endblock %} {% block textarea_field %} <span class="textarea_field"> {% parent %} </span> {% endblock %} ...
{% block input_field %} {% tag "input" with attributes %} {% endblock input_field %} {% block textarea_field %} {% contenttag "textarea" with attributes %}{{ field.displayedData }}{% endcontenttag %} {% endblock textarea_field %} {% block choice_field %} {% if field.options.expanded %} {% for child in field %}{{ child|render_widget }}{% endfor %} {% else %} {% contenttag "select" with attributes %}{{ field|render_choices }}{% endcontenttag %} {% endif %} {% endblock choice_field %} {% block toggle_field %} {% display input_field %} {% if field.options.label %}{% contenttag "label" with ['for': field.id] %}{% trans field.options.label %}{% endcontenttag %}{% endif %} {% endblock toggle_field %} {% block date_time_field %} {{ field.date|render_widget }}{{ field.time|render_widget }} {% endblock date_time_field %} {% block date_field %} {% if field.field %} {% display input_field %} {% else %} {{ field.pattern|replace(['{{ year }}': field.year|render_widget, '{{ month }}': field.month|render_widget, '{{ day }}': field.day| render_widget,]) }} {% endif %} {% endblock date_field %} {% block time_field %} {% if field.isfield %} {% display input_field %} {% else %} {{ field.hour|render_widget }}:{{ field.minute|render_widget }} {% if field.options.with_seconds %}:{{ field.second|render_widget }}{% endif %} {% endif %} {% endblock time_field %} {% block money_field %} {% set widget %}{% display input_field %}{% endset %}{{ field.pattern|replace(['{{ widget }}': widget]) }} {% endblock money_field %} {% block percent_field %} {% display input_field %} % {% endblock percent_field %}
Symfony2 Security http://www.flickr.com/photos/powerbooktrance/466709245
XSS CSRF SQL Injection http://www.flickr.com/photos/mastrobiggo/2322337810
Authentication Authorization http://www.flickr.com/photos/stevendepolo
symfony Core sf*GuardPlugin Your Code $this->getUser()->getGuardUser()->getProfile()
OO Composition $this->getUser()->getGuardUser()->getProfile() sfBasicSecurityUser sfGuardUser Your object tied to the session tied to an ORM tied to an ORM comes from sf*GuardPlugin
What if I don’t want to use an ORM?
Symfony2 Core Your Code $this['security.context']->getUser()
$this['security.context']->getUser() Your POPO Implements AccountInterface
How does Symfony2 know about your Users?
AccountInterface UserProviderInterface
namespace BundleAccountBundleModel; use SymfonyComponentSecurityUserAccountInterface; class User implements AccountInterface { // ... }
<provider> <class="AccountBundleModelUser" /> </provider>
namespace BundleAccountBundleEntity; use SymfonyComponentSecurityUserAccountInterface; /** * @Entity */ class User implements AccountInterface { // ... }
<provider> <entity class="AccountBundle:User" /> </provider>
namespace BundleAccountBundleEntityRepository; use DoctrineORMEntityRepository; use SymfonyComponentSecurityUserUserProviderInterface; class UserRepository extends EntityRepository implements UserProviderInterface { public function loadUserByUsername($username) { return $this->findOneBy(array('user' => $username)); } }
<provider> <entity class="AccountBundle:User" property="user" /> </provider>
What if I want to use the email for the username?
namespace BundleBlogBundleEntity; use SymfonyComponentSecurityUserAccountInterface; /** * @Entity */ class User implements AccountInterface { public function getUsername() { return $this->email; } // ... }
But, I just have one administrator or… How can I secure my personal website backend?
<provider> <user name="fabien" password="C00!" role="ROLE_ADMIN" /> </provider>
<provider> <password-encoder hash="sha1" /> <user name="fabien" password="0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" role="ROLE_ADMIN" /> </provider>
namespace BundleBlogBundleEntity; use SymfonyComponentSecurityUserAccountInterface; /** * @Entity */ class User implements AccountInterface { public function getSalt() { return $this->id; } // ... }
Also useful for testing and prototyping
What if I want to use LDAP, in-memory, and a DB for my users?
<provider> <password-encoder hash="sha1" /> <user name="fabien" password="..." role="ROLE_ADMIN" /> </provider> <provider> <entity class="AccountBundle:User" property="user" /> </provider>
How is Security plugged in?
Request core.request getController() core.controller core.exception getArguments() core.view core.response Response
Symfony2 Firewall http://www.flickr.com/photos/mederic/68456509
Request core.request core.security HttpKernelSecurityFirewall getController() core.controller getArguments() core.view core.response Response
Authentication http://www.flickr.com/photos/ul_marga/755378645
<firewall> <http-basic /> </firewall>
What if I want stateless authentication?
<firewall stateless="true"> <http-basic /> </firewall>
What if I want different authentication strategies in one app?
<firewall pattern="/api/.*" stateless="true"> <http-basic /> </firewall> <firewall pattern=".*" security="none" />
<firewall pattern="/api/.*" stateless="true"> <http-basic /> </firewall> <firewall pattern="/public/.*" security="none" /> <firewall> <form-login /> </firewall>
One Application per Symfony2 Project http://www.flickr.com/photos/cdell/548548453
What if I want to support different authentication strategies in one section of an app?
<firewall> <form-login /> <http-basic /> </firewall>
Using LDAP/certificate/OpenID authentication is really easy
Authorization http://www.flickr.com/photos/theodevil/4911737917
<access> <url path="/api/.*" role="ROLE_REMOTE" /> </access>
<access> <url role="ROLE_USER"> <attribute key="_controller" pattern=".*BlogBundle.*" /> </url> </access>
/article/:id <access> <url role="ROLE_ADMIN"> <attribute key="id" pattern="21" /> </url> </access> <access> <url path="/article/21" role="ROLE_ADMIN" /> </access>
<access> <url path="/admin/.*" ip="10.0.0.0/24" role="ROLE_ADMIN" /> </access>
<access> <url path="/api/.*" role="ROLE_REMOTE" /> <url path="/public/.*" role="IS_AUTHENTICATED_ANONYMOUSLY" /> <url role='ROLE_USER'> <attribute key="controller" pattern=".*BlogBundle.*" /> </url> </access>
… and much more
Implementation based on Spring Security
First proof-of-concept available next week
Symfony2: The Web Operating System? Kernel Events Proxy Firewall Bundles http://www.flickr.com/photos/declanjewell/2687934284
Questions?
The state of Symfony2 - SymfonyDay 2010

The state of Symfony2 - SymfonyDay 2010