• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Phpne august-2012-symfony-components-friends
 

Phpne august-2012-symfony-components-friends

on

  • 2,126 views

 

Statistics

Views

Total Views
2,126
Views on SlideShare
1,846
Embed Views
280

Actions

Likes
0
Downloads
13
Comments
0

3 Embeds 280

http://www.michaelpeacock.co.uk 253
http://lanyrd.com 25
http://www.linkedin.com 2

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Problem with not using an event for this is that code is littered with SESSION setting and Header Redirects. What if we change how this needs to work? Lots of find and replaces\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Dot syntax is very special. It can be used to access object properties, object methods, array elements, and even object getter methods. Templates can also be extended to chain multiple templates together.\n
  • \n
  • \n
  • \n
  • \n
  • Request parameter is optional, the Type Hint is used to work out if its used or not\n
  • \n
  • \n
  • \n
  • \n
  • \n

Phpne august-2012-symfony-components-friends Phpne august-2012-symfony-components-friends Presentation Transcript

  • Symfony Components & FriendsMichael Peacock, PHPNE August 2012
  • About Me @michaelpeacockHead 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 productAuthorOccasional Speaker
  • Symfony ComponentsRouting YAMLEvent dispatcher FinderForm Dependency InjectionProcess HttpFoundationSecurity HttpKernelConsole Locale
  • FriendsPimple: dependency injection containerTwig: templating engineSilex
  • Why?Solve common web application problemsIncredibly well documentedStandalone: 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 aController::method paidRequest Context: POST|GET|PUT|DELETELooks within a list of pre-defined routesReturns a class name and a method
  • Defining RoutesYAMLPHP 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 eventPass this event to the dispatcherObservers listen for specific events Observers can be ordered - some events are observed by multiple observersExample: 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; } }
  • <?phpnamespace 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 NotificationSession<?phpnamespace 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: RequestObject-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
  • ParameterBagRequest properties are all ParameterBag or sub-classesProvides special methods to manage contents, including: all keys add get set has remove $value = $request->query->get(‘my_get_parameter’);
  • Responseuse 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 engineReally 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 & ComponentsSilex has a number of “providers” which allow certaincomponents to be plugged inSilex knows nothing about the componentThe component knows nothing about SilexThe provider bridges the gap
  • Silex Providers: Doctrine: ORM URL Generator Monolog: Sessions Validator SwiftMailer HTTP Cache Session Form Twig Any that you create Translation
  • ConclusionLots of componentsSolve lots of problemsEasy to useWhy reinvent the wheel? Use a Symfony Component orone of their friends
  • Cheers!Thanks for listening!mkpeacock@gmail.com@michaelpeacock