refactoring to symfony components
DESCRIPTION
TRANSCRIPT
![Page 1: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/1.jpg)
REFACTORING TOSYMFONY COMPONENTS
...AND THEIR FRIENDSMichael Peacock
![Page 2: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/2.jpg)
@MICHAELPEACOCKHead Developer @ Ground SixTechnical authorOccasional conference speaker
![Page 3: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/3.jpg)
THE COMPONENTShttp://symfony.com/components
![Page 4: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/4.jpg)
WHY USE COMPONENTSSolve common web application problemsIncredibly well documented(relatively) Standalone: use them how you likeIdeal for refactoring
![Page 5: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/5.jpg)
INSTALLATIONComposer: the knight in shining armour
Download it
Create a composer.json file
Run composer
curl -s https://getcomposer.org/installer | php
{ "require": { "symfony/the-project-name": "dev-master", }}
php composer.phar install
![Page 6: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/6.jpg)
THEIR FRIENDS
![Page 7: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/7.jpg)
WHAT'S IN STOREAutoloading classes with ClassLoaderRouting requests with RoutingListening for events with the EventDispatcherParsing YAML files with the YAML componentHTTP Requests and responses with HTTPFoundationInjecting dependencies with PimpleTemplates with Twig
![Page 8: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/8.jpg)
OUR REFACTORING TALESPEED UP DEVELOPMENT & MODERNISE LEGACY CODEBASE
![Page 9: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/9.jpg)
OUR JOURNEYMessy structure, some procedural code: ClassLoaderGlobals, singletons and crazy objects: PimpleScattered routing logic, long if/else conditions: RoutingHardcoded configurations: YAMLDuplicated logic: EventDispatcherPHP & HTML mixed together: TwigDuplicate form logic, spagetti code: Validator (Fuel)Other improvements: Mailer, HTTPFoundation,Translation & Validator
![Page 10: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/10.jpg)
MESSY STRUCTURE & PROCEDURAL CODE
![Page 11: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/11.jpg)
CLASS LOADER
![Page 12: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/12.jpg)
LAYING THE FOUNDATIONSControllersPSR-0
Namespace the codeRestructure into a better directory heirarchyComponent based structure for our own code too
![Page 13: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/13.jpg)
USAGE$namespaces = array( 'VendorName\\Namespace' => __DIR__ .'/', 'VendorName\\AnotherNamespace' => __DIR__ .'/');
$loader = new \Symfony\Component\ClassLoader\UniversalClassLoader();$loader->register();$loader->registerNamespaces($namespaces);
![Page 14: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/14.jpg)
CACHINGSupport for APC available, just needs to be enabled
![Page 15: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/15.jpg)
GLOBALS, SINGLETONS AND CRAZY OBJECTS
![Page 16: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/16.jpg)
PIMPLE
Pimple is a dependency injection container which lets useasily manage and inject our dependencies into our projects.
We put the dependencies into a container, and then we injectthis container into our code which uses it.
![Page 17: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/17.jpg)
REFACTORING TO USE A CONTAINER<?phpclass SomeModel{ public function __construct() { $sql = ""; $query = Database::query($sql); } }before
<?phpclass SomeModel{ public function __construct($container=array()) { // TODO: further refactor once d.i.c. in place $sql = ""; $query = Database::query($sql); }}after
![Page 18: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/18.jpg)
LAZY LOADINGBy utilising closures, code isn't run until it is first requested /called; i.e. database connection is established only when you
first try and use the connection$container['db'] = function($c) { return new \PDO("...", $c['db_user'], $c['db_pwd']);};
![Page 19: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/19.jpg)
SHARING OBJECTS$container['db'] = $container->share(function($c) { return new \PDO("...", $c['db_user'], $c['db_pwd']);});
![Page 20: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/20.jpg)
FURTHER REFACTORING<?phpclass SomeModel{ public function __construct($container=array()) { $sql = ""; $query = $container['db']->query($sql); }}
![Page 21: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/21.jpg)
CREATING YOUR OWN CONTAINERParticularly useful for re-use and different use-cases (cli vs
web)<?phpnamespace Project\Framework\Container;
class MyContainer extends \Pimple{ public function __construct(array $values = array()) { parent::__construct($values); // add things to the container here }}
![Page 22: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/22.jpg)
CONTROLLER REFACTORING (BEFORE)<?phpclass SomeController{ // ... public function someAction() { $model = new SomeModel($this->container); }}
![Page 23: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/23.jpg)
REDUCING NEW...CONTAINERS WITHINCONTAINERS
<?phpnamespace Faceifi\Framework\Container;
class DataAccessObjects extends \Pimple{ public function __construct(array $values = array()) { parent::__construct($values);
$this['user'] = $this->share(function($c) { return new UserDao($c['container']); }); }}
![Page 24: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/24.jpg)
CONTROLLER REFACTORING (AFTER)<?phpclass SomeController { // ... public function someAction() { $model = $this->container['factories']['some_model']->newModel(); } }
![Page 25: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/25.jpg)
HARDCODED CONFIGURATIONS
![Page 26: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/26.jpg)
YAML
![Page 27: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/27.jpg)
A YAML FILEdb_mysql: host: 'localhost' user: 'root' pass: '' name: 'db' port: 3306 auto_patch: true
general: production: false skin: 'release' site_url: 'http://localhost:4567/'
![Page 28: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/28.jpg)
PARSING A YAML FILE$yaml = new Symfony\Component\Yaml\Parser();
$parsed_settings = $yaml->parse(file_get_contents(__DIR__.'/config.yml'));
![Page 29: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/29.jpg)
CACHING:-(
![Page 30: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/30.jpg)
SCATTERED ROUTING LOGIC, LONG IF/ELSECONDITIONS
![Page 31: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/31.jpg)
ROUTING
![Page 32: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/32.jpg)
REFACTORING FOUNDATIONSMostly taken care of when we ensured all controllers were
objects and that the new structure followed PSR-0.Controllers refactored like so:
public function __construct($container){ $this->container = $container;}
public function anOldAction($date, $some_id)
public function aNewAction($url_params=array())
![Page 33: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/33.jpg)
SETTING IT UPAlias some of the namespaces
Prepare dependencies
Construct
use Symfony\Component\Config\FileLocator;use Symfony\Component\Routing\RequestContext;use Symfony\Component\Routing;
$locator = new FileLocator(array(FRAMEWORK_PATH));$request = (isset($_SERVER['REQUEST_URI']))? $_SERVER['REQUEST_URI']:'';$context = new RequestContext($request, $_SERVER['REQUEST_METHOD']);
$router = new Routing\Router(new YamlFileLoader($locator), 'routes.yml', array(), $context);
![Page 34: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/34.jpg)
ROUTES FILEindex: pattern: / defaults: { class: 'Project\Static\Controller', method: 'homePage' } requirements: _method: GET
![Page 35: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/35.jpg)
ROUTINGtry { $url = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : ''; // get rid of the trailing slash $url = (strlen($requestURL) > 1) ? rtrim($requestURL, '/') : $url;
$route = $router->match($url); $controller = new $route['class']($container); $action = $controller->$route['method']();}catch (Routing\Exception\ResourceNotFoundException $e) { // todo: 404}
![Page 36: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/36.jpg)
ROUTE VARIABLEScomment_story_add: pattern: /news/{category}/{date}/{article} defaults: { class: 'Comments\Controller::addComment' } requirements: date: "[0-9]{2}-[0-9]{2}-[0-9]{4}" _method: POST
$route = $router->match($url); $controller = new $route['class']($container); $variables = $route; unset($variables['name'], $variables['class'], $variables['method']); $action = $controller->$route['method']();
![Page 37: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/37.jpg)
AUTHENTICATION CONTROLaccount: pattern: /account defaults: { class: 'Project\Account\Controller', method: 'manage', logged_in: true } requirements: _method: GET
if (isset($route['logged_in'])) { if (is_null($container['user'])) { // User is trying to access logged in only content - redirect to login and store redirect $_SESSION['redirect'] = $_SERVER['REQUEST_URI']; $event = new Events\RequestRedirection($container['settings']['base_url'] . 'login/'); $this->container['dispatcher']->dispatch('redirect', $event); }}
![Page 38: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/38.jpg)
ROUTE CACHING$router = new Routing\Router(new YamlFileLoader($locator), 'routes.yml', array('cache_dir' => '/var/www/cache/'), $context);
![Page 39: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/39.jpg)
UTM DATA, ETC
http://forums.phpfreaks.com/topic/257622-remove-utm-tags-from-url-regex/
$url = preg_replace('/&?utm_(.*?)\=[̂&]+/', '', $url);$url = (substr($url, -1) == '?') ? rtrim($url, '?') : $url;
![Page 40: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/40.jpg)
DUPLICATED LOGIC
![Page 41: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/41.jpg)
EVENT DISPATCHER
![Page 42: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/42.jpg)
WHY?
![Page 43: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/43.jpg)
USE CASESRedirecting the user / flash notificationsSending transactional emailsAdding a product to a basketHooking into other features to share other features e.g.tweet on content creation
![Page 44: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/44.jpg)
REDIRECTION & "FLASH" NOTIFICATIONS1. Raise an event2. Listen for notification events, and log the notification in-
session3. Listen for a redirect event, and redirect
Ordering is important here as we don't want to redirectbefore setting the session!
![Page 45: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/45.jpg)
APPROACHNotifiableMessageInterfaceRequestRedirection eventRedirectableNotification event (extends and implementsthe above)Events must extend the symfony event
![Page 46: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/46.jpg)
NOTIFIABLE MESSAGE INTERFACE<?phpnamespace Project\Framework\Events;
interface NotifiableMessageInterface{ public function getNotification(); // the html class to be applied public function getClass();}
![Page 47: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/47.jpg)
REQUEST REDIRECTION EVENT<?phpnamespace Project\Framework\Events;use Symfony\Component\EventDispatcher\Event;class RequestRedirection extends Event{ protected $url;
public function __construct($url = null) { $this->url = $url; }
public function getURL() { return $this->url; }}
![Page 48: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/48.jpg)
LISTENER<?phpnamespace Project\Framework\Listeners;
use Project\Framework\Events;use Symfony\Component\EventDispatcher\Event;
class SetPersistantNotification{ public function setNotification( Events\NotifiableMessageInterface $event ) { $_SESSION['system_notification'] = $event->getNotification(); $_SESSION['system_notification_class'] = $event->getClass(); }
}
![Page 49: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/49.jpg)
ANOTHER LISTENER<?phpnamespace Project\Framework\Listeners;
use Project\Framework\Events;use Symfony\Component\EventDispatcher\Event;
class Redirect{ public function redirectUser( Events\RequestRedirection $event ) { // TODO: utilise httpframework header("Location: " . $event->getURL() ); exit(); }
}
![Page 50: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/50.jpg)
LISTEN UP...Create an event dispatcherCreate instance of listenerAdd the listener
Event nameA callable e.g. Object/Method array combo, Closure, etcPriority: for multiple listeners listening for the sameevent
![Page 51: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/51.jpg)
LISTEN UP$dispatcher = new EventDispatcher();
// Notification (Success, Warning, Error)$setPersistantNotification = new Listeners\SetPersistantNotification();$dispatcher->addListener('notify', array($setPersistantNotification, 'setNotification'), 10);
// Redirect$redirectUser = new Listeners\Redirect();$dispatcher->addListener('notifiy', array($redirectUser, 'redirectUser'), 0);
![Page 52: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/52.jpg)
DISPATCH$url = $base_url . 'account';$message = 'Your password was changed successfuly.';$event = new Events\RedirectableNotification($url, $message, 'success');$dispatcher->dispatch('notify', $event);
![Page 53: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/53.jpg)
GOTCHASget/set Name
![Page 54: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/54.jpg)
STANDARD EVENTWe tend to use our own event object which extends the
symfony one. This holds a payload which is our event relatedobject.
<?php
namespace Project\Framework\Events;
class Event extends \Symfony\Component\EventDispatcher\Event{ protected $payLoad;
public function setPayLoad($payload) { $this->payLoad = $payload; }
public function getPayLoad() { return $this->payLoad; }}
![Page 55: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/55.jpg)
QUEUEABLEInterface to define an event as something that can bequeuedListener to queue the event e.g. in beanstalk<?phpnamespace Project\Framework\Events;
interface QueueableInterface{ public function getId();}
![Page 56: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/56.jpg)
QUEUE AN EVENT IN YOUR LISTENERpublic function checkEvent(Events\Event $event){ if ($event->getPayLoad() instanceof QueueableInterface) { $tubes_map = array('new.user' => 'tweet'); $id = $event->getPayLoad()->getId(); $tube = $tubes_map[$event->getName()]; $this->container['q']->useTube($tube)->put($id)) }}
![Page 57: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/57.jpg)
PHP & HTML MIXED TOGETHER
![Page 58: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/58.jpg)
TWIG
![Page 59: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/59.jpg)
SETUP AND LOAD
Load and render template
// 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'));
![Page 60: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/60.jpg)
REFACTORING TO TWIGA place to prepare twig and also perform any non-twigpresentation logic. Keeps the data de-coupled from the
workings of the template engineabstract class View{ public function __construct($container) { $loader = new \Twig_Loader_FileSystem('templates'); $this->templateEngine = new \Twig_Environment($loader); } public function generate($model=null); public function render($template_file) { $this->templateEngine->loadTemplate($template_file); echo $twig->render($this->container->templateVariables); exit; }}
![Page 61: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/61.jpg)
PIMPLE ISSUE / ADD GLOBAL
![Page 62: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/62.jpg)
TWIG TEMPLATES{{ 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 %}
![Page 63: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/63.jpg)
TEMPLATE CACHINGThis caches compiled templates not output
$this->twig = new \Twig_Environment($loader, array( 'cache' => '/var/www/cache/templates/, ));
![Page 64: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/64.jpg)
OUTPUT CACHING
![Page 65: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/65.jpg)
SETUP OUTPUT CACHINGuse Desarrolla2\Cache\Cache;use Desarrolla2\Cache\Adapter\File;
$adapter = new File();$adapter->setOption('ttl', (int) $container['misc_config']->cache->ttl);try { $adapter->setOption('cacheDir', '/var/www/cache/pages/');}catch (\Exception $e) { // temporarily let the application use the /tmp folder?}
$cache = new Cache($adapter);
![Page 66: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/66.jpg)
INTEGRATING OUTPUT CACHING$cache_key = md5($url);if ($cache_enabled && $route['cachable']) { if(is_null($this->container['user'] && $cache->has($cache_key)) { echo $cache->get($cache_key); exit; }}
![Page 67: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/67.jpg)
VALIDATOR (FUEL)There is a symfony component which does this, though we
opted for the Fuel validation component.
![Page 68: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/68.jpg)
HTTPFOUNDATIONAbstracting superglobals, the HTTP request and the HTTP
response
![Page 69: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/69.jpg)
REQUEST
Provides a parameter bag of properties
PropertyProperty PurposePurposerequest store $_POSTquery store $_GETcookies store $_COOKIEattributes application specificfiles $_FILEserver $_SERVERheaders subset of $_SERVER
use Symfony\Component\HttpFoundation\Request;$request = Request::createFromGlobals();
![Page 70: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/70.jpg)
A PARAMETER BAG?Request properties are all ParameterBag or sub-classes
Provides special methods to manage contents, including:
allkeysgetaddsethasremove
![Page 71: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/71.jpg)
RESPONSEuse Symfony\Component\HttpFoundation\Response;
$response = new Response();$response->setContent('Hello PHPUK');$response->setStatusCode(200);$response->headers->set('Content-Type', 'text/plain');
// alternatively...$response = new Response('Hello PHPUK', 200, array('content-type', 'text/plain'));
$response->prepare();
// send the response to the user$response->send();
![Page 72: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/72.jpg)
TRANSLATIONWorth a mention
![Page 73: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/73.jpg)
SWIFT MAILER
![Page 74: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/74.jpg)
SMTP TRANSPORT$transport = \Swift_SmtpTransport::newInstance($container['settings']['smtp']['host'], 25) ->setUsername($container['settings']['smtp']['user']) ->setPassword($container['settings']['smtp']['pass']);
![Page 75: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/75.jpg)
CREATE THE MESSAGE$this->message = \Swift_Message::newInstance($subject) ->setFrom(array($from => $from_name)) ->setTo(array($recipient => $recipient_name)) ->setBody($body, $content_type);
![Page 76: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/76.jpg)
SEND THE MESSAGE$mailer = \Swift_Mailer::newInstance($transport);
return $mailer->send($message);
![Page 77: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/77.jpg)
THANKS!@MICHAELPEACOCK
WWW.MICHAELPEACOCK.CO.UKHTTPS://JOIND.IN/8046
![Page 78: Refactoring to symfony components](https://reader033.vdocuments.mx/reader033/viewer/2022051209/547cfd55b37959492b8b514c/html5/thumbnails/78.jpg)
IMAGE CREDITShttp://www.flickr.com/photos/oskay/275142789/http://www.flickr.com/photos/martin_bircher/5287769680/http://www.flickr.com/photos/tronixstuff/5122815499/http://www.flickr.com/photos/tronixstuff/4581416773/http://www.flickr.com/photos/oskay/437339684/http://www.flickr.com/photos/oskay/437342078/http://www.flickr.com/photos/laughingsquid/2885196845/