The state of Symfony2 - SymfonyDay 2010

Post on 15-Jan-2015

7043 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

Transcript

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?

top related