symfony 2.0 on php 5.3

118
Symfony 2.0 on PHP 5.3! Fabien Potencier

Upload: fabien-potencier

Post on 10-May-2015

10.398 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Symfony 2.0 on PHP 5.3

Symfony 2.0 on PHP 5.3!

Fabien Potencier

Page 2: Symfony 2.0 on PHP 5.3

Fabien Potencier •  Serial entrepreneur and developer by passion •  Founder of Sensio (in 1998)

–  A services and consulting company specialized in Web technologies and Internet marketing (France and USA)

–  70 people –  Open-Source specialists –  Big corporate customers –  Consulting, training, development, web design, … and more –  Sponsor of a lot of Open-Source projects

like symfony and Doctrine

Page 3: Symfony 2.0 on PHP 5.3

Fabien Potencier •  Creator and lead developer of symfony… •  and creator and lead developer of some more:

–  symfony components –  Swift Mailer : Powerful component based mailing library for PHP –  Twig : Fexible, fast, and secure template language for PHP –  Pirum : Simple PEAR Channel Server Manager –  Sismo : PHP continuous integration server –  Lime : Easy to use unit testing library for PHP –  Twitto : A web framework in a tweet –  Twittee : A Dependency Injection Container in a tweet –  Pimple : A small PHP 5.3 dependency injection container

Page 4: Symfony 2.0 on PHP 5.3

Fabien Potencier

•  Read my technical blog: http://fabien.potencier.org/

•  Follow me on Twitter: @fabpot

•  Fork my code on Github: http://github.com/fabpot/

Page 5: Symfony 2.0 on PHP 5.3

How many of you have used symfony?

1.0? 1.1? 1.2? 1.3?

Page 6: Symfony 2.0 on PHP 5.3

symfony 1.0 – January 2007

•  Started as a glue between existing Open-Source libraries:

– Mojavi (heavily modified), Propel, Prado i18n, …

•  Borrowed concepts from other languages and frameworks:

– Routing, CLI, functional tests, YAML, Rails helpers…

•  Added new concepts to the mix

– Web Debug Toolbar, admin generator, configuration cascade, …

Page 7: Symfony 2.0 on PHP 5.3

symfony 1.2 – November 2008

•  Decoupled but cohesive components: the symfony platform

–  Forms, Routing, Cache, YAML, ORMs, …

•  Controller still based on Mojavi

–  View, Filter Chain, …

Page 8: Symfony 2.0 on PHP 5.3

Roadmap

•  1.0 – January 2007 •  1.1 – June 2008 •  1.2 – November 2008 •  1.3 – November 2009 •  1.4 – Last 1.X version (LTS release : 3 years of support)

– same as 1.3 but without deprecated features •  Version 2.0 – Hopefully at the end of 2010

Page 9: Symfony 2.0 on PHP 5.3

Symfony 2.0

•  PHP 5.3 only - http://sf-to.org/sf20onPHP53

•  Same Symfony core components (updated for PHP 5.3)

•  Different controller implementation

•  Oh! Symfony now takes a capital S!!!

Page 10: Symfony 2.0 on PHP 5.3

Symfony Components •  Standalone components •  Packaged individually •  Upcoming dedicated website

–  http://components.symfony-project.org/ •  Dedicated section for each component •  Dedicated documentation •  Dedicated Subversion repository

–  http://svn.symfony-project.com/components/

•  Git mirror –  http://github.com/fabpot

•  Already published components: –  YAML, Dependency Injection, Event Dispatcher, Templating

Page 11: Symfony 2.0 on PHP 5.3

Symfony Components

•  Existing components

– will soon be released as 1.0 (for PHP 5.2)

– will then be migrated to PHP 5.3 (mainly introducing namespaces)

•  New components:

– will work with PHP 5.3 only right from the start

Page 12: Symfony 2.0 on PHP 5.3

Symfony 2 main goals

Flexibility

Fast

Smart

Page 13: Symfony 2.0 on PHP 5.3

Symfony 2 core

Event Dispatcher

Dependency Injection Container

Controller Handling

Page 14: Symfony 2.0 on PHP 5.3

Symfony 2 •  Obviously not yet available as a full-stack MVC framework •  Some components have already been merged into Symfony 1

–  Event Dispatcher –  Form Framework

•  Other new components will be released as standalone components: –  Controller Handling –  Output Escaping –  Forms –  Routing –  Templating Framework (done) –  Dependency Injection Container (done)

will be

migrated to

PHP 5.3 soon

Page 15: Symfony 2.0 on PHP 5.3

symfony 1.X Not fast enough?

Page 16: Symfony 2.0 on PHP 5.3

symfony 1 is one of the slowest framework

when you test it against a simple Hello World application

Page 17: Symfony 2.0 on PHP 5.3

!"#$%&!'!&

()"#*&

+,& -./0)%.&123&

4&

144&

344&

544&

644&

744&

844&

944&

:44&

;44&

1444&

1144&

1344&

1544&

1644&

x 19.5

based on numbers from http://paul-m-jones.com/?p=315

x 2.3

Hello World

Benchmark

Page 18: Symfony 2.0 on PHP 5.3

Conclusion?

Page 19: Symfony 2.0 on PHP 5.3

Don’t use symfony for your next « Hello World » website

Use PHP ;)

Page 20: Symfony 2.0 on PHP 5.3

By the way, the fastest implemention

of a Hello World application with PHP:

die('Hello World');

Page 21: Symfony 2.0 on PHP 5.3

But symfony 1 is probably fast enough for your next website

Page 22: Symfony 2.0 on PHP 5.3

… anyway, it is fast enough for Yahoo!

Yahoo! Bookmarks sf-to.org/bookmarks

Yahoo! Answers sf-to.org/answers

delicious.com sf-to.org/delicious

Page 23: Symfony 2.0 on PHP 5.3

… and recently dailymotion.com announced

its migration to Symfony

sf-to.org/dailymotion

Page 24: Symfony 2.0 on PHP 5.3

Second most popular video sharing website

One of the top 30 websites in the world

59 million unique users in July 2009

Page 25: Symfony 2.0 on PHP 5.3

…and of course many other smaller websites…

Page 26: Symfony 2.0 on PHP 5.3

Symfony 2 Faster?

Page 27: Symfony 2.0 on PHP 5.3

Symfony 2 core is so light and flexible that its raw performance

is outstanding

Page 28: Symfony 2.0 on PHP 5.3

require_once dirname(__FILE__).'/sf20/autoload2/sfCore2Autoload.class.php'; sfCore2Autoload::register();

$app = new HelloApplication(); $app->run()->send();

class HelloApplication { public function __construct() { $this->dispatcher = new sfEventDispatcher(); $this->dispatcher->connect('application.load_controller', array($this, 'loadController')); }

public function run() { $request = new sfWebRequest($this->dispatcher); $handler = new sfRequestHandler($this->dispatcher); $response = $handler->handle($request);

return $response; }

public function loadController(sfEvent $event) { $event->setReturnValue(array(array($this, 'hello'), array($this->dispatcher, $event['request'])));

return true; }

public function hello($dispatcher, $request) { $response = new sfWebResponse($dispatcher); $response->setContent('Hello World');

return $response; } }

Hello World

with Symfony 2.0

OUTDATED

Page 29: Symfony 2.0 on PHP 5.3

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';

use Symfony\Components\EventDispatcher\Event; use Symfony\Components\EventDispatcher\EventDispatcher; use Symfony\Components\RequestHandler\RequestHandler; use Symfony\Components\RequestHandler\Request; use Symfony\Components\RequestHandler\Response;

$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();

$dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function (Request $request) { return new Response('Hello '.$request->getQueryParameter('name')); }, array($event['request']) ));

return true; });

$request = new Request(); $request->setQueryParameters(array('name' => 'Fabien'));

$handler = new RequestHandler($dispatcher); $response = $handler->handle($request); $response->send();

Hello World

with Symfony 2.0

on PHP 5.3

Page 30: Symfony 2.0 on PHP 5.3

!"#$%&!'!&()$*+&

,-./+%-&012&

3+"#4&

56& ,-./+%-&710&

2&

722&

022&

822&

922&

:22&

;22&

<22&

=22&

>22&

7222&

7722&

7022&

7822&

7922&

x 3 x 7

based on numbers from http://paul-m-jones.com/?p=315

Hello World

Benchmark

Symfony 2.0 on PHP 5.3

x 10

Page 31: Symfony 2.0 on PHP 5.3

10 times faster?!

You won’t have such a difference for real applications as most of the time, the limiting factor

is not the framework itself

Page 32: Symfony 2.0 on PHP 5.3

… and PHP 5.3 helps

•  The Hello World code on PHP 5.3 is 50% faster than the one on PHP 5.2 (for the same code!)

•  All frameworks will benefit from some speed improvements •  Again, real applications won’t have such a speed difference just by

upgrading to PHP 5.3

Upgrade to PHP 5.3!

It means performance

improvements for FREE

Page 33: Symfony 2.0 on PHP 5.3

10 times faster?!

•  Raw speed matters because –  It demonstrates that the core « kernel » is very light –  It allows you to use several Symfony frameworks within a single

application with the same behavior but different optimizations:

•  One full-stack framework optimized for ease of use (think symfony 1)

•  One light framework optimized for speed (think Rails Metal ;))

Page 34: Symfony 2.0 on PHP 5.3

How many of you have used PHP 5.3?

Page 35: Symfony 2.0 on PHP 5.3

This presentation is full of

\ … the new PHP developer best friend

Page 36: Symfony 2.0 on PHP 5.3

Namespaces

from sfRequest to Symfony\Core\Request

use Symfony\Core\Request;

$request = new Request();

Page 37: Symfony 2.0 on PHP 5.3

Anonymous Functions

$a = function ($msg) { echo $msg; }

$a('Hello World');

Page 38: Symfony 2.0 on PHP 5.3

Symfony 2 The Event Dispatcher

Page 39: Symfony 2.0 on PHP 5.3

EventDispatcher •  Observer Design Pattern •  Based on Cocoa Notification Center

•  I18N and User are decoupled •  An event is defined by a unique string •  « Anybody » can listen to any event •  You can notify existing events or create new ones easily

// sfI18N $callback = array($this, 'listenToChangeCultureEvent'); $dispatcher->connect('user.change_culture', $callback);

// sfUser $event = new Event($this, 'user.change_culture', array('culture' => $culture)); $dispatcher->notify($event);

Page 40: Symfony 2.0 on PHP 5.3

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';

use Symfony\Components\EventDispatcher\Event; use Symfony\Components\EventDispatcher\EventDispatcher;

$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();

$dispatcher = new EventDispatcher();

$listener = function ($event) { echo sprintf("Hello %s!\n", $event['name']); }; $dispatcher->connect('foo', $listener);

$event = new Event(null, 'foo', array('name' => 'Fabien')); $dispatcher->notify($event);

Can be any PHP callable

Page 41: Symfony 2.0 on PHP 5.3

Symfony 2 The Request Handler

Page 42: Symfony 2.0 on PHP 5.3

The Request Handler

•  The backbone of Symfony 2 controller implementation •  Class to build web frameworks, not only MVC ones •  Based on a simple assumption:

–  The input is a Request object –  The output is a Response object

•  The Request object can be anything you want •  The Response object must implement a send() method

Page 43: Symfony 2.0 on PHP 5.3

The Request Handler

use Symfony\Components\RequestHandler\RequestHandler; use Symfony\Components\RequestHandler\Request;

$handler = new RequestHandler($dispatcher);

$request = new Request(); $response = $handler->handle($request);

$response->send();

Page 44: Symfony 2.0 on PHP 5.3

The Request Handler

•  The RequestHandler does several things:

–  Notifies events

–  Executes a callable (the controller)

–  Ensures that the Request is converted to a Response object

•  The framework is responsible for choosing the controller

•  The controller is responsible for the conversion of the Request to a Response

Page 45: Symfony 2.0 on PHP 5.3

namespace Symfony\Components\RequestHandler;

use Symfony\Components\EventDispatcher\Event; use Symfony\Components\EventDispatcher\EventDispatcher;

class RequestHandler { protected $dispatcher = null;

public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; }

public function handle(RequestInterface $request) { try { return $this->handleRaw($request); } catch (\Exception $e) { // exception $event = $this->dispatcher->notifyUntil(new Event($this, 'core.exception', array('request' => $request, 'exception' => $e))); if ($event->isProcessed()) { return $this->filterResponse($event->getReturnValue(), 'An "core.exception" listener returned a non response object.'); }

throw $e; } }

public function handleRaw(RequestInterface $request) { // request $event = $this->dispatcher->notifyUntil(new Event($this, 'core.request', array('request' => $request))); if ($event->isProcessed())

{ return $this->filterResponse($event->getReturnValue(), 'An "core.request" listener returned a non response object.'); }

// load controller $event = $this->dispatcher->notifyUntil(new Event($this, 'core.load_controller', array('request' => $request))); if (!$event->isProcessed()) { throw new \LogicException('Unable to load the controller.'); }

list($controller, $arguments) = $event->getReturnValue();

// controller must be a callable if (!is_callable($controller)) { throw new \LogicException(sprintf('The controller must be a callable (%s).', var_export($controller, true))); }

// controller $event = $this->dispatcher->notifyUntil(new Event($this, 'core.controller', array('request' => $request, 'controller' => &$controller, 'arguments' => &$arguments))); if ($event->isProcessed()) { try {

return $this->filterResponse($event->getReturnValue(), 'An "core.controller" listener returned a non response object.'); } catch (\Exception $e) { $retval = $event->getReturnValue(); } } else { // call controller $retval = call_user_func_array($controller, $arguments); }

// view $event = $this->dispatcher->filter(new Event($this, 'core.view'), $retval);

return $this->filterResponse($event->getReturnValue(), sprintf('The controller must return a response (instead of %s).', is_object($event->getReturnValue()) ? 'an object of class '.get_class($event->getReturnValue()) : (string) $event->getReturnValue())); }

protected function filterResponse($response, $message) { if (!$response instanceof ResponseInterface) { throw new \RuntimeException($message); }

$event = $this->dispatcher->filter(new Event($this, 'core.response'), $response); $response = $event->getReturnValue();

if (!$response instanceof ResponseInterface) { throw new \RuntimeException('An "core.response" listener returned a non response object.'); }

return $response; }

public function getEventDispatcher() { return $this->dispatcher; } }

RequestHandler is

less than 100 lines

of PHP code!

Page 46: Symfony 2.0 on PHP 5.3

Request Handler Events core.request

core.load_controller

core.controller

core.view

core.response

core.exception

Page 47: Symfony 2.0 on PHP 5.3

core.response

As the very last event notified, a listener can modify the Response object just before it is returned to the user

Page 48: Symfony 2.0 on PHP 5.3

core.response

$dispatcher->connect('core.response', function (Event $event, Response $response) { $response->setContent( $response->getContent(). 'The Web Debug Toolbar' );

return $response; } );

Content of the response is changed

Page 49: Symfony 2.0 on PHP 5.3

core.request

•  The very first event notified

•  It can act as a short-circuit event

•  If one listener returns a Response object, it stops the processing

Page 50: Symfony 2.0 on PHP 5.3

core.request

$dispatcher->connect('core.request', function (Event $event) { $event->setReturnValue( new Response('Website unavailable...') );

return true; } );

Don’t go any further!

Page 51: Symfony 2.0 on PHP 5.3

core.load_controller

•  The only event for which at least one listener must be connected to

•  A listener must return –  A PHP callable (the controller) –  The arguments to pass to the callable

Page 52: Symfony 2.0 on PHP 5.3

core.load_controller

$dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function () { return new Response('Hello World'); }, array() ));

return true; } );

Whatever the request, always return Hello World

Page 53: Symfony 2.0 on PHP 5.3

core.view

The controller must return a Response object except if a listener can convert

the controller returned value to a Response

Page 54: Symfony 2.0 on PHP 5.3

core.view

$dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function () { return 'Hello World'; }, array() ));

return true; } );

The controller returns a string, not a Response

Page 55: Symfony 2.0 on PHP 5.3

core.view

$dispatcher->connect('core.view', function (Event $event, $value) { if (is_string($value)) { return new Response($value); }

return $value; } );

The view “convert” the controller returned value to a Response if it’s a string

If not, it just returns the original value and it lets another view handle it if needed

The value returned by the controller

Page 56: Symfony 2.0 on PHP 5.3

core.exception

The request handler catches all exceptions and give a chance to listeners

to return a Response object

Page 57: Symfony 2.0 on PHP 5.3

core.exception

$dispatcher->connect('core.exception', function (Event $event) { $event->setReturnValue( new Response( 'An error occurred: '.$event['exception']->getMessage() ) );

return true; } );

Mask the exception and return a “nice” message to the user

Page 58: Symfony 2.0 on PHP 5.3

Request Handler

•  Several listeners can be attached to a single event

•  Listeners are called in turn

Page 59: Symfony 2.0 on PHP 5.3

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';

use Symfony\Components\EventDispatcher\Event; use Symfony\Components\EventDispatcher\EventDispatcher; use Symfony\Components\RequestHandler\RequestHandler; use Symfony\Components\RequestHandler\Request; use Symfony\Components\RequestHandler\Response;

$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();

$dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function (Request $request) { return new Response('Hello '.$request->getQueryParameter('name')); }, array($event['request']) ));

return true; });

$request = new Request(); $request->setQueryParameters(array('name' => 'Fabien'));

$handler = new RequestHandler($dispatcher); $response = $handler->handle($request); $response->send();

Hello World

with

Symfony 2.0 Components

Page 60: Symfony 2.0 on PHP 5.3

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';

use Symfony\Components\EventDispatcher\Event; use Symfony\Components\EventDispatcher\EventDispatcher; use Symfony\Components\RequestHandler\RequestHandler; use Symfony\Components\RequestHandler\Request; use Symfony\Components\RequestHandler\Response;

$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();

Page 61: Symfony 2.0 on PHP 5.3

Autoloading in PHP 5.3

•  Will be hopefully standardized for major/all PHP 5.3 frameworks/libraries

•  Main goal: –  provide a better interoperability between PHP frameworks/libraries

•  A group of people is discussing this “standard” (nothing decided yet)

http://groups.google.com/group/php-standards

Page 62: Symfony 2.0 on PHP 5.3

Autoloading in PHP 5.3

•  Current proposal

http://groups.google.com/group/php-standards/web/php-coding-standard-version-2

•  Used for this presentation examples •  Tested by real-world projects:

–  Doctrine 2 –  Lithium –  Symfony 2 Components

Page 63: Symfony 2.0 on PHP 5.3

$dispatcher = new EventDispatcher(); $dispatcher->connect( 'core.load_controller', $controllerLoader );

Page 64: Symfony 2.0 on PHP 5.3

$controllerLoader = function (Event $event) { $event->setReturnValue(array( $controller, array($event['request']) ); }

Can be any PHP callable

Arguments to pass to the controller

Page 65: Symfony 2.0 on PHP 5.3

$controller = function (Request $request) { $name = $request->getQueryParameter('name');

return new Response('Hello '.$name); };

Arguments passed to the controller

A controller should return a Response

Page 66: Symfony 2.0 on PHP 5.3

$request = new Request(); $request->setQueryParameters(array('name' => 'Fabien'));

$handler = new RequestHandler($dispatcher); $response = $handler->handle($request); $response->send();

Sends the response to the browser

Page 67: Symfony 2.0 on PHP 5.3

Symfony 2 The Templating Framework

Page 68: Symfony 2.0 on PHP 5.3

New Templating Framework

•  4 components

–  Template Engine

–  Template Renderers

–  Template Loaders

–  Template Storages

•  Independant library

Page 69: Symfony 2.0 on PHP 5.3

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';

use Symfony\Components\Templating\Engine; use Symfony\Components\Templating\Loader\FilesystemLoader;

$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();

$loader = new FilesystemLoader(

'/path/to/templates/%name%.php'

);

$t = new Engine($loader);

echo $t->render('index', array('name' => 'Fabien'));

Page 70: Symfony 2.0 on PHP 5.3

Template Loaders

•  No assumption about where and how templates are to be found –  Filesystem –  Database – Memory, …

•  Template names are « logical » names:

$loader = new FilesystemLoader('/path/to/templates/%name%.php');

Page 71: Symfony 2.0 on PHP 5.3

Template Renderers

•  No assumption about the format of the templates •  Template names are prefixed with the renderer name:

– index == php:index – user:index

$t = new Engine($loader, array( 'user' => new ProjectTemplateRenderer(), 'php' => new PhpRenderer(), ));

Page 72: Symfony 2.0 on PHP 5.3

Template Embedding

Hello <?php echo $name ?>

<?php $this->render('embedded', array('name' => $name)) ?>

<?php $this->render('smarty:embedded') ?>

Page 73: Symfony 2.0 on PHP 5.3

Template Inheritance

<?php $this->extend('layout') ?>

Hello <?php echo $name ?>

<html> <head> </head> <body> <?php $this->output('content') ?> </body> </html>

Page 74: Symfony 2.0 on PHP 5.3

Template Slots <html> <head> <title><?php $this->output('title') ?></title> </head> <body> <?php $this->output('content') ?> </body> </html>

<?php $this->set('title', 'Hello World! ') ?>

<?php $this->start('title') ?> Hello World! <?php $this->stop() ?>

Page 75: Symfony 2.0 on PHP 5.3

Template Multiple Inheritance

A layout can be decorated by another layout

Each layout can override slots

Page 76: Symfony 2.0 on PHP 5.3

Templating A CMS example

Page 77: Symfony 2.0 on PHP 5.3

CMS Templating

•  Imagine a CMS with the following features: –  The CMS comes bundled with default templates –  The developer can override default templates for a specific project –  The webmaster can override some templates

•  The CMS and developer templates are stored on the filesystem and are written with pure PHP code

•  The webmaster templates are stored in a database and are written in a simple templating language: Hello {{ name }}

Page 78: Symfony 2.0 on PHP 5.3

CMS Templating

•  The CMS has several built-in sections and pages –  Each page is decorated by a layout, depending on the section –  Each section layout is decorated by a base layout

cms/templates/ base.php articles/ layout.php article.php

project/templates/ base.php articles/ layout.php article.php content.php

Page 79: Symfony 2.0 on PHP 5.3

articles/content.php

<h1>{{ title }}</h1>

<p>

{{ content }}

</p>

Page 80: Symfony 2.0 on PHP 5.3

articles/article.php

<?php $this->extend('articles/layout') ?>

<?php $this->set('title', $title) ?>

<?php echo $this->render(

'user:articles/content',

array('title' => $title, 'content' => $content)

) ?>

Page 81: Symfony 2.0 on PHP 5.3

articles/layout.php

<?php $this->extend ('base') ?>

<?php $this->set('title', 'Articles | '.$this->get('title')) ?>

<?php $this->start('head') ?> <?php $this->output('head') ?> <link rel="stylesheet" type="text/css" media="all" href="/css/articles.css" /> <?php $this->stop() ?>

<?php $this->output('content') ?>

Page 82: Symfony 2.0 on PHP 5.3

articles/layout.php

<?php $this->extend('base') ?>

<?php $this->set('title', 'Articles | '.$this->get('title')) ?>

<?php $this->stylesheets->add('/css/articles.css') ?>

<?php $this->output('content') ?>

Page 83: Symfony 2.0 on PHP 5.3

base.php

<html> <head> <title>

<?php $this->output('title') ?>

</title> <?php $this->output('head') ?> </head> <body> <?php $this->output('content') ?> </body> </html>

Page 84: Symfony 2.0 on PHP 5.3

Template Renderer

$t = new Engine($loader, array( 'user' => new ProjectTemplateRenderer(), 'php' => new PhpRenderer(), ));

Page 85: Symfony 2.0 on PHP 5.3

Template Renderer use Symfony\Components\Templating\Renderer\Renderer;

class ProjectTemplateRenderer extends Renderer { public function evaluate(Storage $template, array $parameters = array()) { if ($template instanceof FileStorage) { $template = file_get_contents($template); }

$this->parameters = $parameters;

return preg_replace_callback('/{{\s*(.+?)\s*}}/', array($this, 'replaceParameters'), $template); }

public function replaceParameters($matches) { return isset($this->parameters[$matches[1]]) ? $this->parameters[$matches[1]] : null; } }

Page 86: Symfony 2.0 on PHP 5.3

Template Loaders

$loader = new FilesystemLoader(array( '/path/to/project/templates/%name%.php', '/path/to/cms/templates/%name%.php', ));

Page 87: Symfony 2.0 on PHP 5.3

Template Loader Chain

$loader = new ChainLoader(array( new ProjectTemplateLoader($pdo), new FilesystemLoader(array( '/path/to/project/templates/%name%.php', '/path/to/cms/templates/%name%.php', )), ));

Page 88: Symfony 2.0 on PHP 5.3

Database Template Loader

$pdo = new \PDO('sqlite::memory:'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")');

Page 89: Symfony 2.0 on PHP 5.3

Database Template Loader use Symfony\Components\Templating\Loader\Loader;

class ProjectTemplateLoader extends Loader { protected $pdo;

public function __construct($pdo) { $this->pdo = $pdo; }

public function load($template, $renderer = 'php') { $stmt = $this->pdo->prepare('SELECT tpl FROM tpl WHERE name = :name'); try { $stmt->execute(array('name' => $template)); if (count($rows = $stmt->fetchAll(PDO::FETCH_NUM))) { return $rows[0][0]; } } catch (\PDOException $e) { }

return false; } }

Page 90: Symfony 2.0 on PHP 5.3

Template Loader Cache

$loader = new CacheLoader($loader, 'path/to/cache');

Page 91: Symfony 2.0 on PHP 5.3

$pdo = new \PDO('sqlite::memory:'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")');

$loader = new CacheLoader(

new ChainLoader(array( new ProjectTemplateLoader($pdo), new FilesystemLoader(array( '/path/to/project/templates/%name%.php', '/path/to/cms/templates/%name%.php', )), )),

'path/to/cache'

);

$t = new Engine($loader, array( 'user' => new ProjectTemplateRenderer() ));

$t->render('articles/article', array('title' => 'Title', 'content' => 'Lorem...'));

Page 92: Symfony 2.0 on PHP 5.3

Symfony 2 Dependency Injection Container

Page 93: Symfony 2.0 on PHP 5.3

« Dependency Injection is where components are given their dependencies through their

constructors, methods, or directly into fields. »

http://www.picocontainer.org/injection.html

Page 94: Symfony 2.0 on PHP 5.3

The Symfony 2 dependency injection container replaces several symfony 1 concepts into one integrated system:

–  sfContext –  sfConfiguration –  sfConfig –  factories.yml –  settings.yml / logging.yml / i18n.yml – … and some more

Page 95: Symfony 2.0 on PHP 5.3

DI Hello World example

class Message { public function __construct(OutputInterface $output, array $options) { $this->output = $output; $this->options = array_merge(array('with_newline' => false), $options); }

public function say($msg) { $this->output->render($msg.($this->options['with_newline'] ? "\n" : '')); } }

Page 96: Symfony 2.0 on PHP 5.3

DI Hello World example

interface OutputInterface { public function render($msg); }

class Output implements OutputInterface { public function render($msg) { echo $msg; } }

class FancyOutput implements OutputInterface { public function render($msg) { echo sprintf("\033[33m%s\033[0m", $msg); } }

Page 97: Symfony 2.0 on PHP 5.3

DI Hello World example

$output = new FancyOutput(); $message = new Message($output, array('with_newline' => true)); $message->say('Hello World');

Page 98: Symfony 2.0 on PHP 5.3

A DI container facilitates objects description and object relationships,

configures and instantiates objects

Page 99: Symfony 2.0 on PHP 5.3

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';

use Symfony\Components\DependencyInjection\Builder; use Symfony\Components\DependencyInjection\Reference;

$classLoader = new ClassLoader('Symfony', __DIR__.'/lib'); $classLoader->register();

$container = new Builder();

$container->register('output', 'FancyOutput');

$container-> register('message', 'Message')-> setArguments(array(new Reference('output'), array('with_newline' => true))) ;

$container->message->say('Hello World!');

DI Container Hello World example

Page 100: Symfony 2.0 on PHP 5.3

Get the configuration for the message service

The Message constructor must be given an output service

Get the output object from the container

Create a Message object by passing the constructor arguments

$message = $container->message;

Page 101: Symfony 2.0 on PHP 5.3

$message = $container->message;

is roughly equivalent to

$output = new FancyOutput(); $message = new Message($output, array('with_newline' => true));!

Page 102: Symfony 2.0 on PHP 5.3

$container = new Builder();

$container->register('output', 'FancyOutput'); $container-> register('message', 'Message')-> setArguments(array(new Reference('output'), array('with_newline' => true))) ;

$container->message->say('Hello World!');

<container xmlns="http://symfony-project.org/2.0/container"> <services> <service id="output" class="FancyOutput" />

<service id="message" class="Message"> <argument type="service" id="output" /> <argument type="collection"> <argument key="with_newline">true</argument> </argument> </service> </services> </container>

$container = new Builder(); $loader = new XmlFileLoader($container); $loader->load('services.xml');

PHP

XML XML is validated against an XSD

Page 103: Symfony 2.0 on PHP 5.3

$container = new Builder();

$container->register('output', 'FancyOutput'); $container-> register('message', 'Message')-> setArguments(array(new sfServiceReference('output'), array('with_newline' => true))) ;

$container->message->say('Hello World!');

services: output: { class: FancyOutput } message: class: Message arguments: - @output - { with_newline: true }

$container = new Builder(); $loader = new YamlFileLoader($container); $loader->load('services.yml');

PHP

YAML

Page 104: Symfony 2.0 on PHP 5.3

<container xmlns="http://symfony-project.org/2.0/container"> <parameters> <parameter key="output.class">FancyOutput</parameter> <parameter key="message.options" type="collection"> <parameter key="with_newline">true</parameter> </parameter> </parameters>

<services> <service id="output" class="%output.class%" />

<service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> </container>

$container = new rBuilder(); $loader = new XmlFileLoader($container); $loader->load('services.xml');

Page 105: Symfony 2.0 on PHP 5.3

<container xmlns="http://symfony-project.org/2.0/container"> <imports> <import resource="config.xml" /> </imports>

<services> <service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services> </container>

<container xmlns="http://symfony-project.org/2.0/container"> <parameters> <parameter key="output.class">FancyOutput</parameter> <parameter key="message.options" type="collection"> <parameter key="with_newline">true</parameter> </parameter> </parameters> </container>

$container = new Builder(); $loader = new FileXmlFileLoader($container); $loader->load('services.xml');

Page 106: Symfony 2.0 on PHP 5.3

<services> <import resource="config.yml" class="Symfony\Components\DependencyInjection\Loader\YamlFileLoader" />

<service id="output" class="%output.class%" /> <service id="message" class="Message"> <argument type="service" id="output" /> <argument>%message.options%</argument> </service> </services>

parameters: output.class: FancyOutput

message.options: { with_newline: true }

$container = new Builder(); $loader = new XmlFileLoader($container); $loader->load('services.xml');

Page 107: Symfony 2.0 on PHP 5.3

$pdo = new \PDO('sqlite::memory:'); $pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")');

$loader = new CacheLoader(

new ChainLoader(array( new ProjectTemplateLoader($pdo), new FilesystemLoader(array( '/path/to/project/templates/%name%.php', '/path/to/cms/templates/%name%.php', )), )),

'path/to/cache'

);

$t = new Engine($loader, array( 'user' => new ProjectTemplateRenderer() ));

$t->render('articles/article', array('title' => 'Title', 'content' => 'Lorem...'));

Page 108: Symfony 2.0 on PHP 5.3

$pdo = new \PDO('sqlite::memory:');

<service id="pdo" class="PDO"> <argument>sqlite::memory:</argument> </service>

Page 109: Symfony 2.0 on PHP 5.3

$container = new Builder(); $loader = new FileXmlLoader($container); $loader->load('cms.xml');

$pdo->exec('CREATE TABLE tpl (name, tpl)'); $pdo->exec('INSERT INTO tpl (name, tpl) VALUES ("articles/content", "{{ title }} {{ name }}")');

echo $container->template->render('articles/article', array('title' => 'Title', 'content' => 'Lorem...'));

Page 110: Symfony 2.0 on PHP 5.3

<container xmlns="http://symfony-project.org/2.0/container"> <imports> <import resource="config.yml" class="Symfony\Components\DependencyInjection\Loader\YamlFileLoader" /> <import resource="template_loader.xml" />

</imports>

<services> <service id="pdo" class="PDO"> <argument>sqlite::memory:</argument> </service>

<service id="template_renderer" class="ProjectTemplateRenderer" />

<service id="template" class="Symfony\Components\Templating\Engine"> <argument type="service" id="template_loader" /> <argument type="collection"> <argument type="service" key="user" id="template_renderer" /> </argument> </service> </services>

</container>

Page 111: Symfony 2.0 on PHP 5.3

<services>

<service id="template_loader_project" class="ProjectTemplateLoader"> <argument type="service" key="pdo" id="pdo" /> </service>

<service id="template_loader_filesystem" class="Symfony\Components\Templating\Loader\FilesystemLoader"> <argument>%template.filesystem_pattern%</argument> </service>

<service id="template_loader_chain" class="Symfony\Components\Templating\Loader\ChainLoader"> <argument type="collection"> <argument type="service" id="template_loader_project" /> <argument type="service" id="template_loader_filesystem" /> </argument> </service>

<service id="template_loader" class="Symfony\Components\Templating\Loader\CacheLoader"> <argument type="service" id="template_loader_chain" /> <argument>%application.dir%/cache</argument> </service>

</services>

Page 112: Symfony 2.0 on PHP 5.3

<services> <service id="template_loader" class="Symfony\Components\Templating\Loader\CacheLoader"> <argument type="service"> <service class="Symfony\Components\Templating\Loader\ChainLoader"> <argument type="collection"> <argument type="service"> <service class="ProjectTemplateLoader"> <argument type="service" key="pdo" id="pdo" /> </service> </argument> <argument type="service"> <service class="Symfony\Components\Templating\Loader\FilesystemLoader"> <argument>%template.filesystem_patterns%</argument> </service> </argument> </argument> </service> </argument> <argument>%application.dir%/cache</argument> </service> </services>

Page 113: Symfony 2.0 on PHP 5.3
Page 114: Symfony 2.0 on PHP 5.3

•  SITE PARTNERS

partners.sensiolabs.com

Coming soon…

Contact me

if you are

interested

Page 115: Symfony 2.0 on PHP 5.3

with Matthew Weier O’Pheinney

I will reveal the first alpha release of Symfony 2!

symfony-live.com

Page 116: Symfony 2.0 on PHP 5.3

with Matthew Weier O’Pheinney

and with Matthew Weier O'Phinney as a special guest

symfony-live.com

Page 117: Symfony 2.0 on PHP 5.3

Questions?

Page 118: Symfony 2.0 on PHP 5.3

Sensio S.A. 92-98, boulevard Victor Hugo

92 115 Clichy Cedex FRANCE

Tél. : +33 1 40 99 80 80

Contact Fabien Potencier

fabien.potencier at sensio.com

http://www.sensiolabs.com/

http://www.symfony-project.org/

http://fabien.potencier.org/