Sunteți pe pagina 1din 118

Symfony 2.0 on PHP 5.3!

Fabien Potencier

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

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

Fabien Potencier
Read my technical blog: http://fabien.potencier.org/ Follow me on Twitter: @fabpot Fork my code on Github: http://github.com/fabpot/

How many of you have used symfony? 1.0? 1.1? 1.2? 1.3?

symfony 1.0 January 2007


Started as a glue between existing Open-Source libraries:
Mojavi (heavily modied), 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, conguration cascade,

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,

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

Symfony 2.0
PHP 5.3 only - http://sf-to.org/sf20onPHP53 Same Symfony core components (updated for PHP 5.3) Dierent controller implementation Oh! Symfony now takes a capital S!!!

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

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

Symfony 2 main goals

Flexibility Fast Smart

Symfony 2 core

Event Dispatcher Dependency Injection Container Controller Handling

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

symfony 1.X Not fast enough?

symfony 1 is one of the slowest framework when you test it against a simple Hello World application

1644& 1544& 1344& 1144& Hello World 1444& Benchmark ;44& :44& 944& 844& 744& 644& 544& 344& 144& 4& ()"#*& +,& !"#$%&!'!&

x 19.5

x 2.3
-./0)%.&123&

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

Conclusion?

Dont use symfony for your next Hello World website Use PHP ;)

By the way, the fastest implemention of a Hello World application with PHP:
die('Hello World');

But symfony 1 is probably fast enough for your next website

anyway, it is fast enough for Yahoo!


Yahoo! Bookmarks sf-to.org/bookmarks Yahoo! Answers delicious.com
sf-to.org/answers sf-to.org/delicious

and recently dailymotion.com announced its migration to Symfony


sf-to.org/dailymotion

Second most popular video sharing website One of the top 30 websites in the world 59 million unique users in July 2009

and of course many other smaller websites

Symfony 2 Faster?

Symfony 2 core is so light and exible that its raw performance is outstanding

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; }

Hello World 0 h Symfony 2. wit

OUTDATED

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; }

require __DIR__.'/lib/Symfony/Core/ClassLoader.php'; use use use use use Symfony\Components\EventDispatcher\Event; Symfony\Components\EventDispatcher\EventDispatcher; Symfony\Components\RequestHandler\RequestHandler; Symfony\Components\RequestHandler\Request; Symfony\Components\RequestHandler\Response;

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

Hello World ymfony 2.0 with S on PHP 5.3

$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();

7922& 7822& 7022& 7722& 7222& >22& =22& <22& ;22& :22& 922& 822& 022& 722& 2& ,-./+%-&012&
Symfony 2.0 on PHP 5.3

!"#$%&!'!&

()$*+&

Hello World Benchmark

x 10 x 3 x 7

3+"#4& 56& ,-./+%-&710&

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

10 times faster?!

You wont have such a dierence for real applications as most of the time, the limiting factor is not the framework itself

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 benet from some speed improvements Again, real applications wont have such a speed dierence just by upgrading to PHP 5.3
! e to PHP 5.3 Upgrad e s performanc It mean nts for FREE improveme

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 dierent optimizations:
One full-stack framework optimized for ease of use (think symfony 1) One light framework optimized for speed (think Rails Metal ;))

How many of you have used PHP 5.3?

This presentation is full of

\
the new PHP developer best friend

Namespaces
from sfRequest to Symfony\Core\Request use Symfony\Core\Request; $request = new Request();

Anonymous Functions
$a = function ($msg) { echo $msg; } $a('Hello World');

Symfony 2 The Event Dispatcher

EventDispatcher
Observer Design Pattern Based on Cocoa Notication Center
// 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);

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

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']); }; Can be any PHP callable $dispatcher->connect('foo', $listener); $event = new Event(null, 'foo', array('name' => 'Fabien')); $dispatcher->notify($event);

Symfony 2 The Request Handler

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

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();

The Request Handler


The RequestHandler does several things:
Noties 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

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!

Request Handler Events


core.request core.load_controller core.controller core.view core.response core.exception

core.response

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

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

core.request

The very rst event notied It can act as a short-circuit event If one listener returns a Response object, it stops the processing

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

return true; } );

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

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

core.view

The controller must return a Response object except if a listener can convert the controller returned value to a Response

core.view

$dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function () { return 'Hello World'; }, array() )); The controller returns a string, return true; } ); not a Response

core.view
$dispatcher->connect('core.view', function (Event $event, $value) { if (is_string($value)) { return new Response($value); } return $value; } ); If not, it just returns the original value and it lets another view handle it if needed The value returned by the controller

The view convert the controller returned value to a Response if its a string

core.exception

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

core.exception
$dispatcher->connect('core.exception', function (Event $event) { $event->setReturnValue( new Response( 'An error occurred: '.$event['exception']->getMessage() ) ); Mask the exception and return a nice message to the user return true; } );

Request Handler
Several listeners can be attached to a single event Listeners are called in turn

require __DIR__.'/lib/Symfony/Core/ClassLoader.php'; use use use use use Symfony\Components\EventDispatcher\Event; Symfony\Components\EventDispatcher\EventDispatcher; Symfony\Components\RequestHandler\RequestHandler; Symfony\Components\RequestHandler\Request; Symfony\Components\RequestHandler\Response;

Hello World with ts 2.0 Componen Symfony

$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();

require __DIR__.'/lib/Symfony/Core/ClassLoader.php';
use use use use use Symfony\Components\EventDispatcher\Event; Symfony\Components\EventDispatcher\EventDispatcher; Symfony\Components\RequestHandler\RequestHandler; Symfony\Components\RequestHandler\Request; Symfony\Components\RequestHandler\Response;

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

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

Autoloading in PHP 5.3


Current proposal
http://groups.google.com/group/php-standards/web/php-codingstandard-version-2

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


Doctrine 2 Lithium Symfony 2 Components

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

$controllerLoader = function (Event $event) { $event->setReturnValue(array( Can be any PHP callable $controller, array($event['request']) ); } Arguments to pass
to the controller

Arguments passed to the controller

$controller = function (Request $request) { $name = $request->getQueryParameter('name'); return new Response('Hello '.$name); };
A controller should return a Response

$request = new Request(); $request->setQueryParameters(array('name' => 'Fabien')); $handler = new RequestHandler($dispatcher); $response = $handler->handle($request); $response->send();
Sends the response to the browser

Symfony 2 The Templating Framework

New Templating Framework


4 components
Template Engine Template Renderers Template Loaders Template Storages

Independant library

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'));

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');

Template Renderers
No assumption about the format of the templates Template names are prexed with the renderer name:
index == php:index user:index
$t = new Engine($loader, array( 'user' => new ProjectTemplateRenderer(), 'php' => new PhpRenderer(), ));

Template Embedding

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

Template Inheritance
<?php $this->extend('layout') ?> Hello <?php echo $name ?> <html> <head> </head> <body> <?php $this->output('content') ?> </body> </html>

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() ?>

Template Multiple Inheritance

A layout can be decorated by another layout Each layout can override slots

Templating A CMS example

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

The CMS and developer templates are stored on the lesystem 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 }}

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

articles/content.php

<h1>{{ title }}</h1> <p> {{ content }} </p>

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) ) ?>

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') ?>

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') ?>

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

Template Renderer

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

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; } }

Template Loaders

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

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', )), ));

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 }}")');

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; } }

Template Loader Cache

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

$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...'));

Symfony 2 Dependency Injection Container

Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into elds.
http://www.picocontainer.org/injection.html

The Symfony 2 dependency injection container replaces several symfony 1 concepts into one integrated system:
sfContext sfConguration sfCong factories.yml settings.yml / logging.yml / i18n.yml and some more

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" : '')); } }

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); } }

DI Hello World example

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

A DI container facilitates objects description and object relationships, congures and instantiates objects

DI Container Hello World example


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!');

$message = $container->message;
Get the conguration 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;

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

$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!');

PHP XML
XML is validated against an XSD

<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');

$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!');

PHP YAML

services: output: { class: FancyOutput } message: class: Message arguments: - @output - { with_newline: true }
$container = new Builder(); $loader = new YamlFileLoader($container); $loader->load('services.yml');

<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');

<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');

<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');

$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...'));

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

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

$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...'));

<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>

<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>

<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>

partners.sensiolabs.com SITE PARTNERS


Coming soon Contact me if you are interested

symfony-live.com

with Matthew Weier OPheinney

I will reveal the first alpha release of Symfony 2!

symfony-live.com

with Matthew Weier OPheinney

and with Matthew Weier O'Phinney as a special guest

Questions?

Sensio S.A. 92-98, boulevard Victor Hugo 92 115 Clichy Cedex FRANCE Tl. : +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/

S-ar putea să vă placă și