Practical Guided Tour of Symfony
Standalone Components
DependencyInjection EventDispatcher HttpFoundation DomCrawler ClassLoader BrowserKit CssSelector Filesystem HttpKernel Templating Translation Serializer Validator Console Process Routing Security Config Finder Locale Form Yaml
Full Stack Layer
Application bundles Third party bundles The Symfony2 stack Core Bundles Third party libraries Bridges Standalone Components
Bundles
What makes Symfony2 unique?
- PHP 5.3 - RFC2616 - PHPUnit - CI Ready - Jinja Templates - Design Patterns
Easy Installation http://symfony.com/download
Standard Edition Distribution
Want to give it a try?
Philosophy
class DefaultController extends Controller { /** * @Route("/hello/{name}") */ public function indexaction($name) { //... do things } } return new Response(sprintf('Hello %s!', $name));
class DefaultController extends Controller { /** * @Route("/hello/{name}") */ public function indexaction($name) { //... do things } } return $this->render( 'SensioHelloBundle:Default:index.html.twig', array('name' => $name) );
class DefaultController extends Controller { /** * @Route("/schedule") * @Template() */ public function indexaction() { $title = 'Conferences Schedule'; } } return array('title' => $title);
{% extends "SensioConferenceBundle::layout.html.twig" %} {% block content %} <h1> {{ title }} </h1> <ul> <li>http Caching, by Fabien Potencier</li> <li>hiphop for PHP, by Scott Mac Vicar</li> <li>xdebug, by Derick Rethans</li> <li>...</li> </ul> {% endblock %}
Twig is a modern template engine for PHP Fast Concise and rich syntax Automatic output escaping Modern features Extensible Flexible
{% extends "SensioConferenceBundle::layout.html.twig" %} {% block content %} <h1> {{ title }} </h1> <ul> <li>http Caching, by Fabien Potencier</li> <li>hiphop for PHP, by Scott Mac Vicar</li> <li>xdebug, by Derick Rethans</li> <li>...</li> </ul> {% endblock %}
{% extends "::base.html.twig" %} {% block body %} <img src="/images/logo.gif" alt="confoo 2011"/> {% block content %}{% endblock %} {% endblock %}
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title> {% block title %}Welcome!{% endblock %} </title> <link rel="shortcut icon" href="{{ asset('favicon.ico') }}" /> </head> <body> {% block body %}{% endblock %} </body> </html>
base.html.twig layout.html.twig index.html.twig
Routing System
/** * @Route( * "/{year}/talk/{month}/{day}/{slug}", * requirements={ * "year"="\d{4}", * "month"="\d{2}", * "day"="\d{2}" * } * ) * @Template() */ public function showaction($slug, $day, $month, $year) { //... }
/** * @Route("/talk/{id}") * @ParamConverter("talk", class="sensioconfbundle:talk") * @Template() */ public function showaction(talk $talk) { return array('talk' => $talk); }
Easy Debugging h"p://www.flickr.com/photos/artelaphe/
CODING STANDARDS
IDEs INTEGRATION
THE PROFILER
DEBUGGING TOOLS
h"p://www.flickr.com/photos/chanceprojects/
Doctrine2 Support Database Abstraction Layer on top of PDO Object Relational Mapper Migrations support Object Document Mapper (MongoDB) Object XML Mapper (XML databases)
/** * @ORM\Entity() */ class Talk { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** @ORM\Column(length=80) */ private $title; /** @ORM\Column(type="text") */ private $synopsis; /** @ORM\Column(type="datetime") */ private $schedule; } /** @ORM\ManyToMany(targetEntity="Speaker", mappedby="talks") */ private $speakers;
Validation
class Task { private $name; private $duedate; public function getname() { return $this->name; } public function setname($name) { $this->name = $name; } public function getduedate() { return $this->duedate; } } public function setduedate(\datetime $duedate = null) { $this->duedate = $duedate; }
class Task { /** * @Assert\NotBlank() * @Assert\MinLength(5) * @Assert\MaxLength(30) */ private $name; /** * @Assert\NotBlank() * @Assert\Type() * @Assert\MaxLength(30) */ private $duedate; } //...
Forms Management h"p://www.flickr.com/photos/miahz/
namespace Sensio\Bundle\TodoBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class TaskType extends AbstractType { public function buildform(formbuilder $builder, array $options) { $builder->add('name'); $builder->add('duedate', 'date'); } } public function getname() { return 'task'; }
public function newaction() { $task = new Task(); $task->setname('write a blog post'); $task->setduedate(new \DateTime('tomorrow')); $request = $this->getrequest(); $form = $this->createform(new TaskType(), $task); if ($request->getmethod() == 'POST') { $form->bindrequest($request); if ($form->isvalid()) { // save the task to the database... } } } return $this->redirect($this->generateurl('success'));
{% extends 'SensioTodoBundle::layout.html.twig' %} {% block content %} <form action="#" method="post"> {{ form_widget(form) }} <input type="submit" value="send!" /> </form> {% endblock %}
Automated Testing h"p://www.flickr.com/photos/kenstein/
UNIT TESTING
FUNCTIONAL TESTING
HTTP Compliance (RFC2616)
Expiration vs Validation
class DefaultController extends Controller { /** * @Route("/schedule") * @Template * @Cache(expires="tomorrow") */ public function indexaction() { $title = 'Conferences Schedule'; } } return array('title' => $title);
class DefaultController extends Controller { /** * @Route("/schedule") * @Template * @Cache(maxage="20") */ public function indexaction() { $title = 'Conferences Schedule'; } } return array('title' => $title);
PHP Reverse Proxy
Varnish Squid
http://varnish-cache.org
Edge Side Includes <esi:include src="http://..." />
No ESI
With ESI <esi:include />
Code Generation
$ php app/console generate:bundle
$ php app/console generate:doctrine:crud
h"p://www.flickr.com/photos/bwop/
<?xml version="1.0"?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="file.ext"> <body> <trans-unit id="1"> <source>symfony2 is great</source> <target>j'aime Symfony2</target> </trans-unit> </body> </file> </xliff>
{% set message = 'Symfony2 is great' %} {{ message trans }} {% set message = 'My name is %name%!' %} {{ message trans({'%name%': 'Hugo'}, "hello") }}
h"p://www.flickr.com/photos/cstein96/
Roadmap for 2.1? h"p://www.flickr.com/photos/mkrigsman/
Thank You!