Upload
fabien-potencier
View
7.044
Download
2
Tags:
Embed Size (px)
DESCRIPTION
Citation preview
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
http://www.flickr.com/photos/migrainechick/3704150226
Symfony2 Translation Component
http://www.flickr.com/photos/muffytyrone/4096351705
symfony vs Symfony2
http://www.flickr.com/photos/thebusybrain/2492945625
http://www.flickr.com/photos/rinux/631345826
Messages
Domains
Locales
$t->trans('Symfony2 is great!')
$t->trans('Hello {{ name }}!', array('{{ name }}' => 'Symfony2'))
$t->trans('Symfony2 is great!', array(), 'app')
http://www.flickr.com/photos/orinrobertjohn/114430223
Pluralization vs Choice
$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 %}
http://www.flickr.com/photos/powerbooktrance/466709245
Symfony2 Security
XSS CSRF SQL Injection
http://www.flickr.com/photos/mastrobiggo/2322337810
Authentication Authorization
http://www.flickr.com/photos/stevendepolo
$this->getUser()->getGuardUser()->getProfile()
symfony Core sf*GuardPlugin Your Code
$this->getUser()->getGuardUser()->getProfile()
sfBasicSecurityUser tied to the session
sfGuardUser tied to an ORM
comes from sf*GuardPlugin
Your object tied to an ORM
OO Composition
What if I don’t want to use an ORM?
$this['security.context']->getUser()
Symfony2 Core Your Code
$this['security.context']->getUser()
Your POPO Implements AccountInterface
How does Symfony2 know about your Users?
AccountInterface
UserProviderInterface
namespace Bundle\AccountBundle\Model;
use Symfony\Component\Security\User\AccountInterface;
class User implements AccountInterface { // ... }
<provider> <class="AccountBundle\\Model\\User" /> </provider>
namespace Bundle\AccountBundle\Entity;
use Symfony\Component\Security\User\AccountInterface;
/** * @Entity */ class User implements AccountInterface { // ... }
<provider> <entity class="AccountBundle:User" /> </provider>
namespace Bundle\AccountBundle\Entity\Repository;
use Doctrine\ORM\EntityRepository; use Symfony\Component\Security\User\UserProviderInterface;
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 Bundle\BlogBundle\Entity;
use Symfony\Component\Security\User\AccountInterface;
/** * @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 Bundle\BlogBundle\Entity;
use Symfony\Component\Security\User\AccountInterface;
/** * @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
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
core.exception
Symfony2 Firewall
http://www.flickr.com/photos/mederic/68456509
Request
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
core.security HttpKernel\Security\Firewall
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?
http://www.flickr.com/photos/declanjewell/2687934284
Kernel
Events
Proxy
Firewall
Bundles
Questions?