Symfony Components & Friends
Michael Peacock, PHPNE August 2012
About Me
 @michaelpeacock
Head Developer @ Ground Six
  Leading the development team and managing the
  development process
  We are a tech investment company: you bring ideas, we
  partner and build the product
Author
Occasional Speaker
Symfony Components
Routing            YAML
Event dispatcher   Finder
Form               Dependency Injection
Process            HttpFoundation
Security           HttpKernel
Console            Locale
Friends


Pimple: dependency injection container
Twig: templating engine
Silex
Why?

Solve common web application problems
Incredibly well documented
Standalone: use them how you want
[Components] Ideal for:
  Refactoring
Installing
 Create a composer.json file in the root of your project
                    {
                          "require": {
                          	
                          "company/project": "version",
                          }
                    }


 Download Composer

           curl -s https://getcomposer.org/installer | php



 Run Composer

                        php composer.phar install
{



Routing
                                  "require": {
                                      "symfony/routing": "dev-master"
                                  }
                              }




Looks at the users request and converts it into a
Controller::method paid
Request Context: POST|GET|PUT|DELETE
Looks within a list of pre-defined routes
Returns a class name and a method
Defining Routes


YAML
PHP Code (A collection of Routes)
Annotations
comment_story_add:
  pattern: /news/{category}/{date}/{article}
  defaults: { class: 'CommentsController::addComment' }
  requirements:
    date: "[0-9]{2}-[0-9]{2}-[0-9]{4}"
    _method: POST
// look in our routes folder
$locator = new SymfonyComponentConfigFileLocator(array(__DIR__ . '/../../'));
$loader = new SymfonyComponentRoutingLoaderYamlFileLoader($locator);
// the URL the user requested / is visiting
$request = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
// combine it with the request method to create a request context
$requestContext = new SymfonyComponentRoutingRequestContext($request,
$_SERVER['REQUEST_METHOD']);
// Create a router
$router = new SymfonyComponentRoutingRouter($locator, 'routes.yml',
array('cache_dir' => null), $requestContext);


try {
   $requestURL = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
   $requestURL = (strlen($requestURL) > 1) ? rtrim($requestURL, '/') :
   $requestURL;
   $route = $this->router->match($requestURL);
   // explode the resulting route
   $usersRoute = explode('::', $route['class']);
   $controller = new $usersRoute[0]();
   $variables = $route;
   unset($variables['name']);
   unset($variables['class']);
   $action = $controller->$usersRoute[1]($container, $variables);
} catch (SymfonyComponentRoutingExceptionResourceNotFoundException $e) {
   header('HTTP/1.0 404 Not Found');
   die('Page not found.');
}
Event                      {
                               "require": {
                                   "symfony/event-dispatcher": "dev-master"


Dispatcher                 }
                               }




At key points in your application you create an event
Pass this event to the dispatcher
Observers listen for specific events
  Observers can be ordered - some events are observed by
  multiple observers
Example: Displaying a “flash notification”
  Set some sessions containing the notification
  Redirect the user
Event: Notify
 <?php
 namespace ProjectFrameworkEvents;

 class Notify extends RequestRedirection implements NotifiableMessageInterface
 {
     protected $notification;
     protected $class = 'notice';

     public function __construct($url = null, $notification = null, $class = 'notice')
     {
         parent::__construct($url);
         $this->class = $class;
         $this->notification = $notification;
     }

     public function getNotification()
     {
         return $this->notification;
     }

     public function getClass()
     {
         return $this->class;
     }

 }
<?php
namespace ProjectFrameworkEvents;

use SymfonyComponentEventDispatcherEvent;

class RequestRedirection extends Event
{
    protected $url;

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

    public function getURL()
    {
        return $this->url;
    }
}




           <?php
           namespace ProjectFrameworkEvents;

           interface NotifiableMessageInterface
           {
               public function getNotification();
               public function getClass();
           }
Listener: Set Notification
Session
<?php
namespace ProjectFrameworkListeners;

use ProjectFrameworkEvents;
use SymfonyComponentEventDispatcherEvent;

class SetPersistantNotification
{
    public function setNotification( EventsNotifiableMessageInterface $event )
    {
        $_SESSION['system_notification'] = $event->getNotification();
        $_SESSION['system_notification_class'] = $event->getClass();
    }

}
Listener: Redirect
  <?php
  namespace ProjectFrameworkListeners;
  use ProjectFrameworkEvents;
  use SymfonyComponentEventDispatcherEvent;
  class Redirect
  {
      public function redirectUser( EventsRequestRedirection $event )
      {
          header("Location: " . $event->getURL() );
          exit();
      }

  }
Dispatcher
        Create an event dispatcher

        Create instance of listener

        Add the listener

           Event name

           Callable: e.g. Object > Method array combo, Closure (event is passed)

           Priority: for multiple listeners listening for the same event

$dispatcher = new EventDispatcher();

// Notification (Success, Warning, Error)
$setPersistantNotification = new ListenersSetPersistantNotification();
$dispatcher->addListener('notify', array($setPersistantNotification, 'setNotification'), 10);

// Redirect
$redirectUser = new ListenersRedirect();
$dispatcher->addListener('notifiy', array($redirectUser, 'redirectUser'), 0);
Raise and Dispatch Event

 $url = $baseUrl . 'account';
 $message = 'Your password was changed successfuly.';
 $event = new EventsRedirectableNotification($url, $message, 'success');
 $dispatcher->dispatch('notify', $event);
{



Forms
                                       "require": {
                                           "symfony/form": "dev-master"
                                       }
                                   }



A little fiddly to get running in a stand-alone mode
  READ: I didn’t have time to figure it out for this talk :-(
Supports:
  Creating forms programmatically
  Processing form submissions
  Uploading Files
  Validating submissions with the Validator
Creating a form: with Silex
$data = array();
$data['a_hidden_field'] = 'the value';
$form = $app['form.factory']->createBuilder('form', $data)
	 ->add('image', 'file')
	 ->add('name')
	 ->add('a_hidden_field', 'hidden')
	 ->getform();
return $app['twig']->render('form.twig', array('form' => $form->createView()));




            <form action="/" method="post" {{ form_enctype(form) }}>
                {{ form_widget(form) }}

                <input type="submit" name="submit" />
            </form>
Process form submission


    if(   'POST' == $request->getMethod()) {
    	 	    $form->bindRequest($request);
    	 	    if($form->isValid()) {
    	 	    	 $data = $form->getData();
    	 	    }
    	 }
File upload


    $uploadedFile = $form['image']->getData();
    	 	 	 	
    $path = $uploadedFile->getPath();
    $originalName = $uploadedFile->getOriginalName();
    $mimeType = $uploadedFile->getMimeType();
    	 	 	 	
    $uploadedFile->move( '/var/www/uploads/upload.png');
{



Validator
                                     "require": {
                                         "symfony/validator": "dev-master"
                                     }
                                 }




 Takes a series of constraints
 Checks an input against these constraints
 Returns a collection of violations
Validation Constraints
 Constraints define the rule that an input must satisfy
 Examples:
   Min/Max Length
   Email
   Regex
   Date
   Min / Max / Null / NotNull / Empty / Not Empty
Documentation Example
  <?php
  use SymfonyComponentValidatorValidation;
  use SymfonyComponentValidatorConstraints as Assert;

  $validator = Validation::createValidator();

  $constraint = new AssertCollection(array(
      'name' => new AssertCollection(array(
          'first_name' => new AssertMinLength(101),
          'last_name' => new AssertMinLength(1),
      )),
      'email'    => new AssertEmail(),
      'simple'   => new AssertMinLength(102),
      'gender'   => new AssertChoice(array(3, 4)),
      'file'     => new AssertFile(),
      'password' => new AssertMinLength(60),
  ));

  $violations = $validator->validateValue($input, $constraint);
{



Security
                                  "require": {
                                      "symfony/security": "dev-master"
                                  }
                              }




 Provides a framework for:
   Authentication
   Authorisation
     Firewall: who can access which areas e.g. “edit”
     Access Control: what data the user can
     manipulate e.g. edit home page
HTTP                   {
                           "require": {
                               "symfony/http-foundation": "dev-master"


Foundation
                           }
                       }




Abstracts core HTTP functions
  Request: Super Globals ($_POST, $_GET, etc)
  Response: Status Codes, Cache, Cookies, Sessions
HTTPFoundation: Request
Object-Oriented wrapper for SuperGloabls
          use SymfonyComponentHttpFoundationRequest;
          $request = Request::createFromGlobals();


                      Property          Purpose

                       request        store $_POST

                        query         store $_GET

                       cookies      store $_COOKIE

                      attributes   Application specific

                        files             $_FILE

                       server          $_SERVER

                      headers      subset of $_SERVER
ParameterBag
Request properties are all ParameterBag or sub-classes
Provides special methods to manage contents, including:
  all
  keys
  add
  get
  set
  has
  remove

 $value = $request->query->get(‘my_get_parameter’);
Response
use SymfonyComponentHttpFoundationResponse;

$response = new Response();
$response->setContent('Hello PHPNE');
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/plain');

// alternatively...
$response = new Response('Hello PHPNE', 200, array('content-type', 'text/plain'));

$response->prepare();

// send the response to the user
$response->send();
Pimple
                    {
                        "require": {
                            "pimple/pimple": "dev-master"
                        }
                    }




   Dependency Injection Container
     Use it to store and pass objects, and other things
     your code depends on
   What is dependency injection?
                public function __construct()
                {
Not injected      $this->database = new mysqli();
                }

                public function __construct($database)
                {
    Injected      $this->database = $database;
                }
Pimple: Lazy Loading
        We can use anonymous functions to prevent
        (dependent) objects being instantiated until they are
        needed
$container['database'] = $container->share(function($container) {
    try {
         $db = new
         PDO("mysql:host={$container['database_host']};port={$container['database_port']};dbname={$container['d
         atabase_name']}", $container['database_user'], $container['database_pass'], array(PDO::ATTR_PERSISTENT
         => true, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",PDO::MYSQL_ATTR_USE_BUFFERED_QUERY =>
         true));

          $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

          return $db;
      }
      catch (PDOException $e) {
          echo $e->getMessage();
          exit();
      }
});
Parameters


          $container['my_parameter'] = 'Some Value';




 Objects



$container['my_object'] = function($container){
	 //will return this each and every time $container['my_object'] is accessed
	 return new MyObject();
};
Sharing Objects
    $container['my_object'] = $container->share(function($container){
    	 // will return a new instance first time accessed
    	 // same object returned every other time
    	 return new MyObject();
    });



Protecting Parameters

$container['my_object'] = $container->protect(function($container){
	 // lets you return the result of an anonymous function as a parameter	
	 return some_function();
});




A warning: You can’t modify a parameter
Twig
                     {
                         "require": {
                             "twig/twig": "dev-master"
                         }
                     }




Lightweight template engine
Really easy to extend and use

    // create a twig filesystem loader so it can access templates
    $loader = new Twig_Loader_Filesystem('templates');
    // create a new twig environment and pass it the loader
    $twig = Twig_Environment($loader);
    // load the template
    $twig->loadTemplate('index.twig');
    // render it
    $twig->render(array('title' => 'variable'));
Twig Template Syntax

      {{ some_variable }}

      {# some comment #}

      {% set list_of_items = variable.getItems() %}

      {%   for item in list_of_items %}
      	    <li>{{loop.index}}: {{item.name}}</li>
      {%   else %}
      	    <li>Empty :-(</li>
      {%   endfor %}
Silex
                 {
                     "require": {
                         "silex/silex": "dev-master"
                     }
                 }




 A “micro-framework” based off some of these
 components and pimple
 Designed for single-page PHP apps
Silex: A note on closures

 Anonymous function: created without a name
 Can accept parameters
 Can use variables from compile time scope if defined


         $objectToInject = new stdClass();
         $test = function($parameter) use ($objectToInject){
         	 // here we can use $parameter and $objectToInject
         };
Setup

        require_once '../vendor/autoload.php';

        use SymfonyComponentHttpFoundationRequest;
        use SymfonyComponentHttpFoundationResponse;

        use SymfonyComponentProcessProcess;

        $app = new SilexApplication();
        // Enable debugging.
        $app['debug'] = true;
Silex: Before running

$app->before(function () use ($app)
{
    $app->register(new SilexProviderTranslationServiceProvider(), array(
        'locale_fallback' => 'en',
        ));
    $app->register(new SilexProviderFormServiceProvider());
    $app->register(new SilexProviderTwigServiceProvider(), array(
                 'twig.path' => __DIR__.'/views',
     ));
     $app['conn'] = new mysqli('localhost', 'root', '', 'app');
});
Silex: Routes
     $app->get('image.{format}', function( $format ) use ($app)
     {
         $form = $app['form.factory']->createBuilder('form', array())
                     ->add('image', 'file')
                     ->getform();
         return $app['twig']->render("upload.{$format}.twig",
     array('title' => 'Upload image', 'form' => $form->createView()));
     })->assert('format', 'json|html' );




$app->post('/image.{format}', function( $format, Request $request) use ($app)
{
    return $app['twig']->render("image.{$format}.twig", array));
})->assert( 'format', 'json|html');
Silex: Run



        $app->run();
Silex & Components

Silex has a number of “providers” which allow certain
components to be plugged in
Silex knows nothing about the component
The component knows nothing about Silex
The provider bridges the gap
Silex Providers:
 Doctrine: ORM
                     URL Generator
 Monolog: Sessions
                     Validator
 SwiftMailer
                     HTTP Cache
 Session
                     Form
 Twig
                     Any that you create
 Translation
Conclusion

Lots of components
Solve lots of problems
Easy to use
Why reinvent the wheel? Use a Symfony Component or
one of their friends
Cheers!

Thanks for listening!


mkpeacock@gmail.com
@michaelpeacock

Phpne august-2012-symfony-components-friends

  • 1.
    Symfony Components &Friends Michael Peacock, PHPNE August 2012
  • 2.
    About Me @michaelpeacock HeadDeveloper @ Ground Six Leading the development team and managing the development process We are a tech investment company: you bring ideas, we partner and build the product Author Occasional Speaker
  • 3.
    Symfony Components Routing YAML Event dispatcher Finder Form Dependency Injection Process HttpFoundation Security HttpKernel Console Locale
  • 4.
    Friends Pimple: dependency injectioncontainer Twig: templating engine Silex
  • 5.
    Why? Solve common webapplication problems Incredibly well documented Standalone: use them how you want [Components] Ideal for: Refactoring
  • 6.
    Installing Create acomposer.json file in the root of your project { "require": { "company/project": "version", } } Download Composer curl -s https://getcomposer.org/installer | php Run Composer php composer.phar install
  • 7.
    { Routing "require": { "symfony/routing": "dev-master" } } Looks at the users request and converts it into a Controller::method paid Request Context: POST|GET|PUT|DELETE Looks within a list of pre-defined routes Returns a class name and a method
  • 8.
    Defining Routes YAML PHP Code(A collection of Routes) Annotations
  • 9.
    comment_story_add: pattern:/news/{category}/{date}/{article} defaults: { class: 'CommentsController::addComment' } requirements: date: "[0-9]{2}-[0-9]{2}-[0-9]{4}" _method: POST
  • 10.
    // look inour routes folder $locator = new SymfonyComponentConfigFileLocator(array(__DIR__ . '/../../')); $loader = new SymfonyComponentRoutingLoaderYamlFileLoader($locator); // the URL the user requested / is visiting $request = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; // combine it with the request method to create a request context $requestContext = new SymfonyComponentRoutingRequestContext($request, $_SERVER['REQUEST_METHOD']); // Create a router $router = new SymfonyComponentRoutingRouter($locator, 'routes.yml', array('cache_dir' => null), $requestContext); try { $requestURL = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; $requestURL = (strlen($requestURL) > 1) ? rtrim($requestURL, '/') : $requestURL; $route = $this->router->match($requestURL); // explode the resulting route $usersRoute = explode('::', $route['class']); $controller = new $usersRoute[0](); $variables = $route; unset($variables['name']); unset($variables['class']); $action = $controller->$usersRoute[1]($container, $variables); } catch (SymfonyComponentRoutingExceptionResourceNotFoundException $e) { header('HTTP/1.0 404 Not Found'); die('Page not found.'); }
  • 11.
    Event { "require": { "symfony/event-dispatcher": "dev-master" Dispatcher } } At key points in your application you create an event Pass this event to the dispatcher Observers listen for specific events Observers can be ordered - some events are observed by multiple observers Example: Displaying a “flash notification” Set some sessions containing the notification Redirect the user
  • 12.
    Event: Notify <?php namespace ProjectFrameworkEvents; class Notify extends RequestRedirection implements NotifiableMessageInterface { protected $notification; protected $class = 'notice'; public function __construct($url = null, $notification = null, $class = 'notice') { parent::__construct($url); $this->class = $class; $this->notification = $notification; } public function getNotification() { return $this->notification; } public function getClass() { return $this->class; } }
  • 13.
    <?php namespace ProjectFrameworkEvents; use SymfonyComponentEventDispatcherEvent; classRequestRedirection extends Event { protected $url; public function __construct($url = null) { $this->url = $url; } public function getURL() { return $this->url; } } <?php namespace ProjectFrameworkEvents; interface NotifiableMessageInterface { public function getNotification(); public function getClass(); }
  • 14.
    Listener: Set Notification Session <?php namespaceProjectFrameworkListeners; use ProjectFrameworkEvents; use SymfonyComponentEventDispatcherEvent; class SetPersistantNotification { public function setNotification( EventsNotifiableMessageInterface $event ) { $_SESSION['system_notification'] = $event->getNotification(); $_SESSION['system_notification_class'] = $event->getClass(); } }
  • 15.
    Listener: Redirect <?php namespace ProjectFrameworkListeners; use ProjectFrameworkEvents; use SymfonyComponentEventDispatcherEvent; class Redirect { public function redirectUser( EventsRequestRedirection $event ) { header("Location: " . $event->getURL() ); exit(); } }
  • 16.
    Dispatcher Create an event dispatcher Create instance of listener Add the listener Event name Callable: e.g. Object > Method array combo, Closure (event is passed) Priority: for multiple listeners listening for the same event $dispatcher = new EventDispatcher(); // Notification (Success, Warning, Error) $setPersistantNotification = new ListenersSetPersistantNotification(); $dispatcher->addListener('notify', array($setPersistantNotification, 'setNotification'), 10); // Redirect $redirectUser = new ListenersRedirect(); $dispatcher->addListener('notifiy', array($redirectUser, 'redirectUser'), 0);
  • 17.
    Raise and DispatchEvent $url = $baseUrl . 'account'; $message = 'Your password was changed successfuly.'; $event = new EventsRedirectableNotification($url, $message, 'success'); $dispatcher->dispatch('notify', $event);
  • 18.
    { Forms "require": { "symfony/form": "dev-master" } } A little fiddly to get running in a stand-alone mode READ: I didn’t have time to figure it out for this talk :-( Supports: Creating forms programmatically Processing form submissions Uploading Files Validating submissions with the Validator
  • 19.
    Creating a form:with Silex $data = array(); $data['a_hidden_field'] = 'the value'; $form = $app['form.factory']->createBuilder('form', $data) ->add('image', 'file') ->add('name') ->add('a_hidden_field', 'hidden') ->getform(); return $app['twig']->render('form.twig', array('form' => $form->createView())); <form action="/" method="post" {{ form_enctype(form) }}> {{ form_widget(form) }} <input type="submit" name="submit" /> </form>
  • 20.
    Process form submission if( 'POST' == $request->getMethod()) { $form->bindRequest($request); if($form->isValid()) { $data = $form->getData(); } }
  • 21.
    File upload $uploadedFile = $form['image']->getData(); $path = $uploadedFile->getPath(); $originalName = $uploadedFile->getOriginalName(); $mimeType = $uploadedFile->getMimeType(); $uploadedFile->move( '/var/www/uploads/upload.png');
  • 22.
    { Validator "require": { "symfony/validator": "dev-master" } } Takes a series of constraints Checks an input against these constraints Returns a collection of violations
  • 23.
    Validation Constraints Constraintsdefine the rule that an input must satisfy Examples: Min/Max Length Email Regex Date Min / Max / Null / NotNull / Empty / Not Empty
  • 24.
    Documentation Example <?php use SymfonyComponentValidatorValidation; use SymfonyComponentValidatorConstraints as Assert; $validator = Validation::createValidator(); $constraint = new AssertCollection(array( 'name' => new AssertCollection(array( 'first_name' => new AssertMinLength(101), 'last_name' => new AssertMinLength(1), )), 'email' => new AssertEmail(), 'simple' => new AssertMinLength(102), 'gender' => new AssertChoice(array(3, 4)), 'file' => new AssertFile(), 'password' => new AssertMinLength(60), )); $violations = $validator->validateValue($input, $constraint);
  • 25.
    { Security "require": { "symfony/security": "dev-master" } } Provides a framework for: Authentication Authorisation Firewall: who can access which areas e.g. “edit” Access Control: what data the user can manipulate e.g. edit home page
  • 26.
    HTTP { "require": { "symfony/http-foundation": "dev-master" Foundation } } Abstracts core HTTP functions Request: Super Globals ($_POST, $_GET, etc) Response: Status Codes, Cache, Cookies, Sessions
  • 27.
    HTTPFoundation: Request Object-Oriented wrapperfor SuperGloabls use SymfonyComponentHttpFoundationRequest; $request = Request::createFromGlobals(); Property Purpose request store $_POST query store $_GET cookies store $_COOKIE attributes Application specific files $_FILE server $_SERVER headers subset of $_SERVER
  • 28.
    ParameterBag Request properties areall ParameterBag or sub-classes Provides special methods to manage contents, including: all keys add get set has remove $value = $request->query->get(‘my_get_parameter’);
  • 29.
    Response use SymfonyComponentHttpFoundationResponse; $response =new Response(); $response->setContent('Hello PHPNE'); $response->setStatusCode(200); $response->headers->set('Content-Type', 'text/plain'); // alternatively... $response = new Response('Hello PHPNE', 200, array('content-type', 'text/plain')); $response->prepare(); // send the response to the user $response->send();
  • 30.
    Pimple { "require": { "pimple/pimple": "dev-master" } } Dependency Injection Container Use it to store and pass objects, and other things your code depends on What is dependency injection? public function __construct() { Not injected $this->database = new mysqli(); } public function __construct($database) { Injected $this->database = $database; }
  • 31.
    Pimple: Lazy Loading We can use anonymous functions to prevent (dependent) objects being instantiated until they are needed $container['database'] = $container->share(function($container) { try { $db = new PDO("mysql:host={$container['database_host']};port={$container['database_port']};dbname={$container['d atabase_name']}", $container['database_user'], $container['database_pass'], array(PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true)); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $db; } catch (PDOException $e) { echo $e->getMessage(); exit(); } });
  • 32.
    Parameters $container['my_parameter'] = 'Some Value'; Objects $container['my_object'] = function($container){ //will return this each and every time $container['my_object'] is accessed return new MyObject(); };
  • 33.
    Sharing Objects $container['my_object'] = $container->share(function($container){ // will return a new instance first time accessed // same object returned every other time return new MyObject(); }); Protecting Parameters $container['my_object'] = $container->protect(function($container){ // lets you return the result of an anonymous function as a parameter return some_function(); }); A warning: You can’t modify a parameter
  • 34.
    Twig { "require": { "twig/twig": "dev-master" } } Lightweight template engine Really easy to extend and use // create a twig filesystem loader so it can access templates $loader = new Twig_Loader_Filesystem('templates'); // create a new twig environment and pass it the loader $twig = Twig_Environment($loader); // load the template $twig->loadTemplate('index.twig'); // render it $twig->render(array('title' => 'variable'));
  • 35.
    Twig Template Syntax {{ some_variable }} {# some comment #} {% set list_of_items = variable.getItems() %} {% for item in list_of_items %} <li>{{loop.index}}: {{item.name}}</li> {% else %} <li>Empty :-(</li> {% endfor %}
  • 36.
    Silex { "require": { "silex/silex": "dev-master" } } A “micro-framework” based off some of these components and pimple Designed for single-page PHP apps
  • 37.
    Silex: A noteon closures Anonymous function: created without a name Can accept parameters Can use variables from compile time scope if defined $objectToInject = new stdClass(); $test = function($parameter) use ($objectToInject){ // here we can use $parameter and $objectToInject };
  • 38.
    Setup require_once '../vendor/autoload.php'; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentProcessProcess; $app = new SilexApplication(); // Enable debugging. $app['debug'] = true;
  • 39.
    Silex: Before running $app->before(function() use ($app) { $app->register(new SilexProviderTranslationServiceProvider(), array( 'locale_fallback' => 'en', )); $app->register(new SilexProviderFormServiceProvider()); $app->register(new SilexProviderTwigServiceProvider(), array( 'twig.path' => __DIR__.'/views', )); $app['conn'] = new mysqli('localhost', 'root', '', 'app'); });
  • 40.
    Silex: Routes $app->get('image.{format}', function( $format ) use ($app) { $form = $app['form.factory']->createBuilder('form', array()) ->add('image', 'file') ->getform(); return $app['twig']->render("upload.{$format}.twig", array('title' => 'Upload image', 'form' => $form->createView())); })->assert('format', 'json|html' ); $app->post('/image.{format}', function( $format, Request $request) use ($app) { return $app['twig']->render("image.{$format}.twig", array)); })->assert( 'format', 'json|html');
  • 41.
    Silex: Run $app->run();
  • 42.
    Silex & Components Silexhas a number of “providers” which allow certain components to be plugged in Silex knows nothing about the component The component knows nothing about Silex The provider bridges the gap
  • 43.
    Silex Providers: Doctrine:ORM URL Generator Monolog: Sessions Validator SwiftMailer HTTP Cache Session Form Twig Any that you create Translation
  • 44.
    Conclusion Lots of components Solvelots of problems Easy to use Why reinvent the wheel? Use a Symfony Component or one of their friends
  • 45.

Editor's Notes