Your SlideShare is downloading. ×
0
Symfony Components & FriendsMichael Peacock, PHPNE August 2012
About Me @michaelpeacockHead Developer @ Ground Six  Leading the development team and managing the  development process  W...
Symfony ComponentsRouting            YAMLEvent dispatcher   FinderForm               Dependency InjectionProcess          ...
FriendsPimple: dependency injection containerTwig: templating engineSilex
Why?Solve common web application problemsIncredibly well documentedStandalone: use them how you want[Components] Ideal for...
Installing Create a composer.json file in the root of your project                    {                          "require":...
{Routing                                  "require": {                                      "symfony/routing": "dev-master...
Defining RoutesYAMLPHP Code (A collection of Routes)Annotations
comment_story_add:  pattern: /news/{category}/{date}/{article}  defaults: { class: CommentsController::addComment }  requi...
// look in our routes folder$locator = new SymfonyComponentConfigFileLocator(array(__DIR__ . /../../));$loader = new Symfo...
Event                      {                               "require": {                                   "symfony/event-d...
Event: Notify <?php namespace ProjectFrameworkEvents; class Notify extends RequestRedirection implements NotifiableMessage...
<?phpnamespace ProjectFrameworkEvents;use SymfonyComponentEventDispatcherEvent;class RequestRedirection extends Event{    ...
Listener: Set NotificationSession<?phpnamespace ProjectFrameworkListeners;use ProjectFrameworkEvents;use SymfonyComponentEv...
Listener: Redirect  <?php  namespace ProjectFrameworkListeners;  use ProjectFrameworkEvents;  use SymfonyComponentEventDis...
Dispatcher        Create an event dispatcher        Create instance of listener        Add the listener           Event na...
Raise and Dispatch Event $url = $baseUrl . account; $message = Your password was changed successfuly.; $event = new Events...
{Forms                                       "require": {                                           "symfony/form": "dev-m...
Creating a form: with Silex$data = array();$data[a_hidden_field] = the value;$form = $app[form.factory]->createBuilder(for...
Process form submission    if(   POST == $request->getMethod()) {    	 	    $form->bindRequest($request);    	 	    if($fo...
File upload    $uploadedFile = $form[image]->getData();    	 	 	 	    $path = $uploadedFile->getPath();    $originalName =...
{Validator                                     "require": {                                         "symfony/validator": "...
Validation Constraints Constraints define the rule that an input must satisfy Examples:   Min/Max Length   Email   Regex   ...
Documentation Example  <?php  use SymfonyComponentValidatorValidation;  use SymfonyComponentValidatorConstraints as Assert...
{Security                                  "require": {                                      "symfony/security": "dev-mast...
HTTP                   {                           "require": {                               "symfony/http-foundation": "...
HTTPFoundation: RequestObject-Oriented wrapper for SuperGloabls          use SymfonyComponentHttpFoundationRequest;       ...
ParameterBagRequest properties are all ParameterBag or sub-classesProvides special methods to manage contents, including: ...
Responseuse SymfonyComponentHttpFoundationResponse;$response = new Response();$response->setContent(Hello PHPNE);$response...
Pimple                    {                        "require": {                            "pimple/pimple": "dev-master"  ...
Pimple: Lazy Loading        We can use anonymous functions to prevent        (dependent) objects being instantiated until ...
Parameters          $container[my_parameter] = Some Value; Objects$container[my_object] = function($container){	 //will re...
Sharing Objects    $container[my_object] = $container->share(function($container){    	 // will return a new instance firs...
Twig                     {                         "require": {                             "twig/twig": "dev-master"     ...
Twig Template Syntax      {{ some_variable }}      {# some comment #}      {% set list_of_items = variable.getItems() %}  ...
Silex                 {                     "require": {                         "silex/silex": "dev-master"              ...
Silex: A note on closures Anonymous function: created without a name Can accept parameters Can use variables from compile ...
Setup        require_once ../vendor/autoload.php;        use SymfonyComponentHttpFoundationRequest;        use SymfonyComp...
Silex: Before running$app->before(function () use ($app){    $app->register(new SilexProviderTranslationServiceProvider(),...
Silex: Routes     $app->get(image.{format}, function( $format ) use ($app)     {         $form = $app[form.factory]->creat...
Silex: Run        $app->run();
Silex & ComponentsSilex has a number of “providers” which allow certaincomponents to be plugged inSilex knows nothing abou...
Silex Providers: Doctrine: ORM                     URL Generator Monolog: Sessions                     Validator SwiftMail...
ConclusionLots of componentsSolve lots of problemsEasy to useWhy reinvent the wheel? Use a Symfony Component orone of thei...
Cheers!Thanks for listening!mkpeacock@gmail.com@michaelpeacock
Upcoming SlideShare
Loading in...5
×

Phpne august-2012-symfony-components-friends

2,064

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
2,064
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
15
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \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
  • Transcript of "Phpne august-2012-symfony-components-friends"

    1. 1. Symfony Components & FriendsMichael Peacock, PHPNE August 2012
    2. 2. 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
    3. 3. Symfony ComponentsRouting YAMLEvent dispatcher FinderForm Dependency InjectionProcess HttpFoundationSecurity HttpKernelConsole Locale
    4. 4. FriendsPimple: dependency injection containerTwig: templating engineSilex
    5. 5. Why?Solve common web application problemsIncredibly well documentedStandalone: use them how you want[Components] Ideal for: Refactoring
    6. 6. 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
    7. 7. {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
    8. 8. Defining RoutesYAMLPHP Code (A collection of Routes)Annotations
    9. 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. 10. // 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.);}
    11. 11. 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
    12. 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. 13. <?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(); }
    14. 14. 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(); }}
    15. 15. Listener: Redirect <?php namespace ProjectFrameworkListeners; use ProjectFrameworkEvents; use SymfonyComponentEventDispatcherEvent; class Redirect { public function redirectUser( EventsRequestRedirection $event ) { header("Location: " . $event->getURL() ); exit(); } }
    16. 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. 17. Raise and Dispatch Event $url = $baseUrl . account; $message = Your password was changed successfuly.; $event = new EventsRedirectableNotification($url, $message, success); $dispatcher->dispatch(notify, $event);
    18. 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. 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. 20. Process form submission if( POST == $request->getMethod()) { $form->bindRequest($request); if($form->isValid()) { $data = $form->getData(); } }
    21. 21. File upload $uploadedFile = $form[image]->getData(); $path = $uploadedFile->getPath(); $originalName = $uploadedFile->getOriginalName(); $mimeType = $uploadedFile->getMimeType(); $uploadedFile->move( /var/www/uploads/upload.png);
    22. 22. {Validator "require": { "symfony/validator": "dev-master" } } Takes a series of constraints Checks an input against these constraints Returns a collection of violations
    23. 23. 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
    24. 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. 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. 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. 27. 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
    28. 28. 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’);
    29. 29. 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();
    30. 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. 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. 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. 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. 34. 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));
    35. 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. 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. 37. 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 };
    38. 38. Setup require_once ../vendor/autoload.php; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentProcessProcess; $app = new SilexApplication(); // Enable debugging. $app[debug] = true;
    39. 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. 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. 41. Silex: Run $app->run();
    42. 42. 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
    43. 43. Silex Providers: Doctrine: ORM URL Generator Monolog: Sessions Validator SwiftMailer HTTP Cache Session Form Twig Any that you create Translation
    44. 44. ConclusionLots of componentsSolve lots of problemsEasy to useWhy reinvent the wheel? Use a Symfony Component orone of their friends
    45. 45. Cheers!Thanks for listening!mkpeacock@gmail.com@michaelpeacock
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×