Symfony2 - WebExpo 2010
-
Upload
fabien-potencier -
Category
Technology
-
view
2.034 -
download
1
description
Transcript of Symfony2 - WebExpo 2010
![Page 1: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/1.jpg)
Symfony2 Fabien Potencier
![Page 2: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/2.jpg)
How many of you have already used symfony1?
![Page 3: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/3.jpg)
How many of you have already played with Symfony2?
![Page 4: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/4.jpg)
What is Symfony2?
![Page 5: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/5.jpg)
A set of decoupled and cohesive components
![Page 6: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/6.jpg)
DependencyInjection EventDispatcher HttpFoundation OutputEscaper
DomCrawler CssSelector Templating HttpKernel BrowserKit Validator Routing Console Process Finder Form Yaml
![Page 7: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/7.jpg)
git clone git://github.com/symfony/symfony.git
![Page 8: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/8.jpg)
A set of decoupled and cohesive components
Autoloading
![Page 9: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/9.jpg)
PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php
Swift_Mime_Message > Swift/Mime/Message.php Twig_Node_For > Twig/Node/For.php
![Page 10: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/10.jpg)
Symfony\Foundation\Kernel Symfony/Foundation/Kernel.php
Doctrine\DBAL\Driver Doctrine/DBAL/Driver.php
pdepend\reflection\ReflectionSession pdepend/reflection/ReflectionSession.php
http://groups.google.com/group/php-standards/web/psr-0-final-proposal
![Page 11: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/11.jpg)
require_once '.../Symfony/Framework/UniversalClassLoader.php';
use Symfony\Framework\UniversalClassLoader;
$loader = new UniversalClassLoader(); $loader->register();
![Page 12: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/12.jpg)
PHP 5.3 technical interoperability standards
$loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', 'pdepend' => '/path/to/reflection/source', ));
![Page 13: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/13.jpg)
$loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', ));
PEAR style
![Page 14: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/14.jpg)
A set of decoupled and cohesive components
Process
![Page 15: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/15.jpg)
use Symfony\Component\Process\Process;
$cmd = 'ssh 1.2.3.4 "ps waux"';
$process = new Process($cmd); $process->run();
if (!$process->isSuccessful()) { throw new \RuntimeException( $process->getErrorOutput()); }
echo $process->getOutput();
![Page 16: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/16.jpg)
$cmd = 'ssh 1.2.3.4 "tail -f /some/log"';
$process = new Process($cmd);
$process->run(function ($type, $buffer) { echo $buffer; });
![Page 17: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/17.jpg)
use Symfony\Component\Process\PhpProcess;
$process = new PhpProcess( '<?php echo "hello"; ?>'); $process->run();
if (!$process->isSuccessful()) { throw new \RuntimeException( $process->getErrorOutput()); }
echo $process->getOutput();
![Page 18: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/18.jpg)
A set of decoupled and cohesive components
CssSelector
![Page 19: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/19.jpg)
use Symfony\Component\CssSelector\Parser;
Parser::cssToXpath('h4 > a:contains("foo")');
![Page 20: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/20.jpg)
use Symfony\Component\CssSelector\Parser;
$document = new \DOMDocument(); $document->loadHTMLFile('...'); $xpath = new \DOMXPath($document);
$expr = Parser::cssToXpath('a.smart'); $nodes = $xpath->query($expr);
foreach ($nodes as $node) { printf("%s (%s)\n", $node->nodeValue, $node->getAttribute('href')); }
![Page 21: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/21.jpg)
A set of decoupled and cohesive components
Finder
![Page 22: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/22.jpg)
use Symfony\Component\Finder\Finder;
$finder = new Finder(); $finder ->files() ->in(__DIR__) ->...() ->sortByName() ;
![Page 23: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/23.jpg)
$finder ->name('*.php') ->depth('<= 1') ->date('>= yesterday') ->size('<= 1K') ->filter(function (\SplFileInfo $file) { return strlen($file->getBasename()) < 9; }) ;
![Page 24: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/24.jpg)
foreach ($finder as $file) { print $file->getRealpath()."\n"; }
$files = iterator_to_array($finder);
$count = iterator_count($finder);
![Page 25: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/25.jpg)
use Symfony\Component\Finder\Finder;
$s3 = new \Zend_Service_Amazon_S3($key, $sct); $s3->registerStreamWrapper("s3");
$finder = new Finder(); $finder ->name('photos*') ->size('< 100K') ->date('since 1 hour ago') ->in('s3://bucket-name') ;
![Page 26: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/26.jpg)
A set of decoupled and cohesive components
Routing
![Page 27: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/27.jpg)
/blog.php?section=symfony&article_id=18475
![Page 28: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/28.jpg)
web/ index.php
![Page 29: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/29.jpg)
/index.php/blog/2010/09/18/Symfony2-in-India
![Page 30: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/30.jpg)
/blog/2010/09/18/Symfony2-in-India
![Page 31: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/31.jpg)
/blog/:year/:month/:day/:slug
![Page 32: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/32.jpg)
post: pattern: /blog/:year/:month/:day/:slug defaults: { _controller: BlogBundle:Post:show }
![Page 33: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/33.jpg)
<routes> <route id="post" pattern="/blog/:year/:month/:day/:slug"> <default key="_controller"> BlogBundle:Post:show </default> </route> </routes>
![Page 34: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/34.jpg)
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route;
$collection = new RouteCollection();
$route = new Route( '/blog/:year/:month/:day/:slug', array('_controller' => 'BlogBundle:Post:show'));
$collection->addRoute('post', $route);
return $collection;
![Page 35: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/35.jpg)
$router ->match('/blog/2010/09/18/Symfony2-in-India')
$router ->generate('post', array('slug' => '...'))
![Page 36: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/36.jpg)
post: pattern: /post/:slug defaults: { _controller: BlogBundle:Post:show }
![Page 37: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/37.jpg)
$router ->generate('post', array('slug' => '...'))
![Page 38: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/38.jpg)
An Object-Oriented abstraction on top of PHP
![Page 39: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/39.jpg)
An Object-Oriented abstraction on top of PHP
Request
![Page 40: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/40.jpg)
use Symfony\Component\HttpFoundation\Request;
$request = new Request();
// get a $_GET parameter $request->query->get('page');
// get a $_POST parameter $request->request->get('page');
// get a $_COOKIE parameter $request->cookies->get('name');
$request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest();
![Page 41: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/41.jpg)
// get a $_FILE parameter $f = $request->files->get('image');
// $f is an instance of // Symfony\Component\HttpFoundation\File\UploadedFile
// guess extension, based on the mime type $n = '/path/to/file'.$file->getDefaultExtension(); $f->move($n);
![Page 42: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/42.jpg)
new Request();
new Request( $_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER );
Request::create('/hello/Fabien', 'GET');
![Page 43: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/43.jpg)
An Object-Oriented abstraction on top of PHP
Session
![Page 44: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/44.jpg)
$session = $request->getSession();
$session->set('foo', 'bar'); $session->get('foo');
$session->setFlash('notice', 'Congratulations!');
![Page 45: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/45.jpg)
An Object-Oriented abstraction on top of PHP
Response
![Page 46: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/46.jpg)
use Symfony\Component\HttpFoundation\Response;
$response = new Response('Hello World', 200, array('Content-Type' => 'text/plain')); $response->send();
$response->setHeader('Content-Type', 'text/plain'); $response->setCookie('foo', 'bar'); $response->setContent('Hello World'); $response->setStatusCode(200);
![Page 47: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/47.jpg)
An Object-Oriented abstraction of the HTTP dialog
![Page 48: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/48.jpg)
A MVC Web Framework
![Page 49: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/49.jpg)
The Symfony2 MVC Philosophy
![Page 50: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/50.jpg)
Be as easy as possible for newcomers and as flexible as possible for advanced users
![Page 51: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/51.jpg)
MVC
![Page 52: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/52.jpg)
http://symfony-reloaded.org/
http://symfony-reloaded.org/downloads/sandbox_2_0_PR3.zip
![Page 53: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/53.jpg)
post: pattern: /hello/:name defaults: { _controller: HelloBundle:Hello:index }
namespace Application\HelloBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller;
class HelloController extends Controller { public function indexAction($name) { return new Response('Hello '.$name); } }
![Page 54: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/54.jpg)
namespace Application\HelloBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller;
class HelloController extends Controller { public function indexAction($name) { // Get things from the Model
return $this->render( 'HelloBundle:Hello:index', array('name' => $name) ); } }
![Page 55: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/55.jpg)
Hello <?php echo $name ?>!
![Page 56: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/56.jpg)
<?php $view->extend('HelloBundle::layout') ?>
Hello <?php echo $name ?>!
![Page 57: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/57.jpg)
<html> <head> <title> <?php $view['slots']->output('title') ?> </title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
![Page 58: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/58.jpg)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
_content
title
layout
slot
slot
![Page 59: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/59.jpg)
{% extends "HelloBundle::layout" %}
{% block content %} Hello {{ name }}! {% endblock %}
![Page 60: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/60.jpg)
<html> <head> <title> {% block title %}{% endblock %} </title> </head> <body> {% block body %}{% endblock %} </body> </html>
![Page 61: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/61.jpg)
~ PAC / HMVC
http://en.wikipedia.org/wiki/Presentation-abstraction-control
![Page 62: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/62.jpg)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
main controller (_content slot)
embedded MVC controller
layout
![Page 63: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/63.jpg)
public function indexAction($name) { $embedded = $this['controller_resolver'] ->render('HelloBundle:Hello:foo', array('name' => $name));
return $this->render( 'HelloBundle:Hello:index', array( 'name' => $name, 'embedded' => $embedded, ) ); }
![Page 64: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/64.jpg)
<?php $view->extend('...:layout') ?>
Lorem ipsum...
<?php echo $view['actions'] ->render('HelloBundle:Hello:foo', array('name' => $name)) ?>
Lorem ipsum...
![Page 65: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/65.jpg)
Bundles
![Page 66: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/66.jpg)
.../ SomeBundle/ Controller/ Entity/ Resources/ config/ views/ SomeBundle.php Tests/
![Page 67: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/67.jpg)
public function registerBundleDirs() { return array( 'Application' => __DIR__.'/../src/Application', 'Bundle' => __DIR__.'/../src/Bundle', 'Symfony\Bundle' => __DIR__.'/../src/vendor/symfony/src/Symfony/Bundle', ); }
![Page 68: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/68.jpg)
$this->render('SomeBundle:Hello:index', $params)
![Page 69: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/69.jpg)
hello: pattern: /hello/:name defaults: { _controller: SomeBundle:Hello:index }
![Page 70: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/70.jpg)
SomeBundle can be any of
Application\SomeBundle Bundle\SomeBundle Symfony\Bundle\SomeBundle
![Page 71: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/71.jpg)
Environments
![Page 72: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/72.jpg)
Developers Customer End Users
Development Environment
Staging Environment
Production Environment
![Page 73: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/73.jpg)
cache cache cache
debug debug debug
logs logs logs
stats stats stats
Development Environment
Staging Environment
Production Environment
![Page 74: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/74.jpg)
# config/config.yml doctrine.dbal: dbname: mydbname user: root password: %doctrine.dbal_password%
swift.mailer: transport: smtp host: localhost
![Page 75: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/75.jpg)
# config/config_dev.yml imports: - { resource: config.yml }
doctrine.dbal: password: null
swift.mailer: transport: gmail username: xxxxxxxx password: xxxxxxxx
![Page 76: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/76.jpg)
# Doctrine Configuration doctrine.dbal: dbname: xxxxxxxx user: xxxxxxxx password: ~
# Swiftmailer Configuration swift.mailer: transport: smtp encryption: ssl auth_mode: login host: smtp.gmail.com username: xxxxxxxx password: xxxxxxxx
![Page 77: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/77.jpg)
<!-- Doctrine Configuration --> <doctrine:dbal dbname="xxxxxxxx" user="xxxxxxxx" password="" />
<!-- Swiftmailer Configuration --> <swift:mailer transport="smtp" encryption="ssl" auth_mode="login" host="smtp.gmail.com" username="xxxxxxxx" password="xxxxxxxx" />
![Page 78: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/78.jpg)
// Doctrine Configuration $container->loadFromExtension('doctrine', 'dbal', array( 'dbname' => 'xxxxxxxx', 'user' => 'xxxxxxxx', 'password' => '', ));
// Swiftmailer Configuration $container->loadFromExtension('swift', 'mailer', array( 'transport' => "smtp", 'encryption' => "ssl", 'auth_mode' => "login", 'host' => "smtp.gmail.com", 'username' => "xxxxxxxx", 'password' => "xxxxxxxx", ));
![Page 79: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/79.jpg)
Dependency Injection Container
![Page 80: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/80.jpg)
Third-party libraries integration Unified Configuration
![Page 81: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/81.jpg)
# Twig Configuration twig.config: auto_reload: true
# Zend Logger Configuration zend.logger: priority: debug path: %kernel.root_dir%/logs/%kernel.environment%.log
![Page 82: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/82.jpg)
Configuration formats XML, YAML, PHP, INI, or Annotations
Parameters management Fast (cached) Inheritance
Sensitive data security …
![Page 83: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/83.jpg)
<doctrine:dbal dbname="sfweb" username="root" password="SuperSecretPasswordThatAnyoneCanSee" />
![Page 84: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/84.jpg)
SetEnv SYMFONY__DOCTRINE__DBAL__PASSWORD "foobar"
in a .htaccess or httpd.conf file
%doctrine.dbal.password%
![Page 85: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/85.jpg)
<doctrine:dbal dbname="sfweb" username="root" password="%doctrine.dbal.password%" />
![Page 86: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/86.jpg)
Developer Tools
![Page 87: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/87.jpg)
INFO: Matched route "blog_home" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'index', '_route' => 'blog_home',))
INFO: Using controller "Bundle\BlogBundle\Controller\PostController::indexAction"
INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ ORDER BY s0_.published_at DESC LIMIT 10 (array ())
![Page 88: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/88.jpg)
INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',))
INFO: Using controller "Bundle\BlogBundle\Controller\PostController::showAction »
INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught Symfony\Components\RequestHandler\Exception\NotFoundHttpException exception)
INFO: Using controller "Symfony\Framework\WebBundle\Controller\ExceptionController::exceptionAction"
![Page 89: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/89.jpg)
DEBUG: Notifying (until) event "core.request" to listener "(Symfony\Framework\WebBundle\Listener\RequestParser, resolve)" INFO: Matched route "blog_post" (parameters: array ( '_bundle' => 'BlogBundle', '_controller' => 'Post', '_action' => 'show', '_format' => 'html', 'id' => '3456', '_route' => 'blog_post',)) DEBUG: Notifying (until) event "core.load_controller" to listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" INFO: Using controller "Bundle\BlogBundle\Controller\PostController::showAction" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" processed the event "core.load_controller" INFO: Trying to get post "3456" from database INFO: SELECT s0_.id AS id0, s0_.title AS title1, s0_.html_body AS html_body2, s0_.excerpt AS excerpt3, s0_.published_at AS published_at4 FROM sf_weblog_post s0_ WHERE s0_.id = ? (array ( 0 => '3456',)) DEBUG: Notifying (until) event "core.exception" to listener "(Symfony\Framework\WebBundle\Listener\ExceptionHandler, handle)" ERR: Post "3456" not found! (No result was found for query although at least one row was expected.) (uncaught Symfony\Components\RequestHandler\Exception\NotFoundHttpException exception) DEBUG: Notifying (until) event "core.request" to listener "(Symfony\Framework\WebBundle\Listener\RequestParser, resolve)" DEBUG: Notifying (until) event "core.load_controller" to listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" INFO: Using controller "Symfony\Framework\WebBundle\Controller\ExceptionController::exceptionAction" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ControllerLoader, resolve)" processed the event "core.load_controller" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Listener\ResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\DataCollector\DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\WebDebugToolbar, handle)" DEBUG: Listener "(Symfony\Framework\WebBundle\Listener\ExceptionHandler, handle)" processed the event "core.exception" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Listener\ResponseFilter, filter)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\DataCollector\DataCollectorManager, handle)" DEBUG: Notifying (filter) event "core.response" to listener "(Symfony\Framework\WebBundle\Debug\WebDebugToolbar, handle)"
![Page 90: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/90.jpg)
![Page 91: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/91.jpg)
![Page 92: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/92.jpg)
![Page 93: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/93.jpg)
![Page 94: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/94.jpg)
![Page 95: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/95.jpg)
![Page 96: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/96.jpg)
![Page 97: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/97.jpg)
![Page 98: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/98.jpg)
Security
XSS / CSRF / SQL Injection
![Page 99: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/99.jpg)
Functional Tests
![Page 100: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/100.jpg)
$client = $this->createClient();
$crawler = $client->request( 'GET', '/hello/Fabien');
$this->assertTrue($crawler->filter( 'html:contains("Hello Fabien")')->count());
![Page 101: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/101.jpg)
$this->assertEquals( 10, $crawler->filter('div.hentry')->count());
$this->assertTrue( $client->getResponse()->isSuccessful());
![Page 102: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/102.jpg)
$crawler = $client->request( 'GET', 'hello/Lucas' );
![Page 103: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/103.jpg)
$link = $crawler->selectLink("Greet Lucas");
$client->click($link);
![Page 104: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/104.jpg)
$form = $crawler->selectButton('submit');
$client->submit($form, array( 'name' => 'Lucas', 'country' => 'France', 'like_symfony' => true, 'photo' => '/path/to/lucas.jpg', ));
![Page 105: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/105.jpg)
$harry = $this->createClient(); $sally = $this->createClient();
$harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages');
$this->assertEquals(201, $harry->getResponse()->getStatusCode());
$this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
![Page 106: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/106.jpg)
$harry = $this->createClient(); $sally = $this->createClient();
$harry->insulate(); $sally->insulate();
$harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages');
$this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
![Page 107: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/107.jpg)
Caching
![Page 108: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/108.jpg)
HTTP Expiration / HTTP Validation
![Page 109: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/109.jpg)
$response->setSharedMaxAge(...); $response->setTtl(...); $response->setMaxAge(...); $response->setClientTtl(...); $response->setExpires(...);
$response->setETag(...); $response->setLastModified(...);
![Page 110: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/110.jpg)
Cache-Control: s-maxage=10
![Page 111: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/111.jpg)
public function showAction() { // ...
$response = $this->render('...', $vars);
$response->setSharedMaxAge(10);
return $response; }
![Page 112: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/112.jpg)
Symfony 2 comes built-in with an HTTP accelerator
![Page 113: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/113.jpg)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
cacheable for 10 seconds cacheable for 5 seconds
main controller
embedded controller
layout
![Page 114: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/114.jpg)
<?php $view->extend('...:layout') ?>
<?php $view['slots']->start('sidebar') ?>
<?php echo $view['actions']->render('...:foo') ?>
<?php $view['slots']->stop() ?>
cacheable for 10 seconds
cacheable for 5 seconds
![Page 115: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/115.jpg)
$view['actions']->render('HelloBundle:Hello:foo', array('name' => $name), array('standalone' => true) )
![Page 116: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/116.jpg)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
![Page 117: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/117.jpg)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vel nulla arcu, vitae cursus nunc. Integer semper turpis et enim por6tor iaculis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris vehicula ves;bulum dictum. Aenean non velit tortor. Nullam adipiscing malesuada aliquam. Mauris dignissim, urna quis iaculis tempus, justo libero por6tor est, nec eleifend est elit vitae ante. Curabitur interdum luctus metus, in pulvinar lectus rutrum sit amet. Duis gravida, metus in dictum eleifend, dolor risus ;ncidunt ligula, non volutpat nulla sapien in elit. Nulla rutrum erat id neque suscipit eu ultricies odio sollicitudin. Aliquam a mi vel eros placerat hendrerit. Phasellus por6tor, augue sit amet vulputate venena;s, dui leo commodo odio, a euismod turpis ligula in elit.
<esi:include src="..." />
![Page 118: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/118.jpg)
ESI… or Edge Side Includes
![Page 119: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/119.jpg)
Symf
ony2
Appli
catio
n
Reve
rse Pr
oxy
Clien
t Lorem ipsum dolor sit amet,
Lorem ipsum dolor
Lorem ipsum dolor sit amet,
Lorem ipsum dolor
1
2
3
4
![Page 120: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/120.jpg)
Symfony2 app
Web Server
Requests
Response
![Page 121: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/121.jpg)
Symfony2 app
Symfony2 HTTP proxy
Web Server
Requests
Response
![Page 122: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/122.jpg)
Symfony2 app
Web Server
Reverse proxy
Requests
Response
![Page 123: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/123.jpg)
Extensibility
![Page 124: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/124.jpg)
Request
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
![Page 125: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/125.jpg)
Request
Response
core.controller
core.response
core.view
core.request
getController()
getArguments()
core.exception
![Page 126: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/126.jpg)
HttpFoundation
HttpKernel
FrameworkBundle
Routing
Console
SwiftmailerBundle
TwigBundle
DependencyInjection
...
...
Components
Bundles
Event Dispatcher
Templating
DoctrineBundle
ZendBundle
![Page 127: Symfony2 - WebExpo 2010](https://reader033.fdocuments.in/reader033/viewer/2022051412/54b7a0ca4a795998738b4680/html5/thumbnails/127.jpg)
Questions?