Introduction to Symfony2 for Drupal Developers

download Introduction to Symfony2 for Drupal Developers

If you can't read please download the document

Transcript of Introduction to Symfony2 for Drupal Developers

Introduction to Symfony2

Easing the learning curve for Drupal Devs

Drupal Waterloo Group, 16th May 2013

Tl;Dr: About me

Ex-pat Englishman now living in Southern Ontario.

PHP developer for 5 years, Symfony 1 and 2 user for just over a year.

Senior Developer at MRX Digital Sports Solutions.

Co-organiser of Guelph PHP User Group.

Ex-professional musician.

Drupal times they are a-changin!

Move to using Symfony components brings many changes to Drupal.

This talk aims to ease the learning curve.

Structure:Introduction to Symfony2 architecture

In depth look at the HttpKernel

Introduction to other components that Drupal will be using.

In the beginning...

Introduction to Symfony2

Introduction to Symfony2

Application framework by Fabien Potencier and Sensio Labs.

Heavily inspired by other frameworks, including Rails, Django and Spring.

'Modern', object oriented code base, full test coverage.

Emphasis on caching for speed.

Symfony2 Design Goals

Less MVC, more HTTP.

Don't re-invent the wheel.

De-coupled components:All code must be SOLID

Bundles.

Less MVC, More HTTP

Designed around the HTTP spec.

Purpose: convert a Request object into a Response.

Model and (to a large part) the view layers are left up to the user to implement.

Note that Symfony2 often described as an HTTP framework.Mention how the HttpKernel converts the request to a response.Mention that Symfony has a view component in PHP and that Twig can also be used, but that this can be replaced with any other view that you like.Response doesn't need to be HTML!

Don't Re-invent the Wheel

Symfony uses third party components where possible.

Examples:Twig

Swiftmailer

Monolog

Doctrine/Propel

Assetic

Composer

Mention that this is the opposite of, for example, Zend Framework.A lot of these tools are bundled into the Symfony standard edition but you can use any others that you wish.

De-coupled Components

The whole framework is a collection of de-coupled components.

Each component is (largely) independent of the others.

Code adheres to SOLID principles.

Enables components to be used in isolation in other projects such as Drupal.

Mention design by contract.SOLIDSingle Responsibility Principle

Open/closed principle

Liskov substitution principle.

Interface Segregation principle.

Dependency inversion principle.

Other projects built with Symfony2 components:

Laravel

Silex

React

Bundles

Bundle is a collection of related code, also containing tests, assets, documentation and config for that code.

The Symfony2 framework is a bundle.

Allows code to be easily shared and reused.

Healthy eco-system of shared bundles available on Packagist.

Anatomy of a Symfony Request

How a Request is converted to a Response.

The Front Controller

Symfony2 uses the front controller pattern as single entry point to application.

Steps:Includes cache files.

Creates a Request and AppKernel objects.

AppKernel::handle() method returns a response from the request.

Response::send() is called.

AppKernel::terminate() is then called.

Mention app.php and app_dev.php as entry points to application.Terminate method used as a place to process long running tasks after the response has been sent to the browser for the user. USE WITH CARE.

The HttpKernel

Used to convert the request into a response.

Created and called in the AppKernel.

An event dispatcher and controller resolver are passed to the constructor, the request object is passed to the handle method.

Event driven.

Explain how the event system works here.Observer pattern.

Allows you to create your own observers that are attached and dispatched with events.

Anatomy of HttpKernel

The kernel.request event

Used to initialise the system, add more info to the request, etc.

If this event returns a response the kernel skips directly to the kernel.response event.

Examples:Security listeners are dispatched at this stage.

Router listener.

MRX sport listener for our API.

Mention that attributes can be stored on the request to be used later.Router listener will store a _controller key on the request to use later.

Resolve Controller

The controller resolver is used to get the controller for the request.

Class implementing ControllerResolverInterface is passed to the HttpKernel in the constructor.

Default implementation in Symfony2 will instantiate the controller and, optionally, set the container in it.

The kernel.controller event

Allows you to initialise the controller or change it before the before it's executed.

Can change the controller by setting a new controller on the event object.

Example:SensioFrameworkExtra bundle ParamConverter.

Explain how param converters used.

Getting Controller Arguments

ControllerResolverInterface::getArguments() now called.

Assembles array of arguments to pass to the controller.

Uses reflection.

Default sf2 controller resolver:Will match named arguments in the controller method to attributes stored in the request object.

Will pass the request itself to the controller if it's type hinted.

Calling the controller

Controller method is called with the arguments assembled.

Controller must return a Response object or an array.

If a response is returned, kernels work is pretty much done.

If an array is returned another event is dispatched...

The kernel.view event

Only dispatched if the controller doesn't return a response object.

Job is to convert return data from controller to a response object.

No default listeners in Symfony but examples:SensioFrameworkExtraBundle adds listener for @Template annotations.

FOSRestBundle adds a listener here to render XML, JSON or HTML

The kernel.response event

Called just before the response is returned.

Allows the response to be modified, e.g. setting cookies, headers, etc.

Examples:In the dev environment the WebDebugToolbarListener adds some data to enable the debugging toolbar.

ContextListener serializes the current users info into the session.

Almost done...

The response is now returned from the HttpKernel.

Response::send() is called to send the content to the client.

One more event will still be dispatched...

The kernel.terminate event

The only event called after HttpKernel::handle().

Used after the response has been sent to perform some 'heavy' action.

Use with caution!

Example:SwiftmailerBundle with memory spooling.

The kernel.exception event

Called if an uncaught exception is thrown.

Used to handle some kinds of exceptions and to create a response.

Calls a special controller that generates an error page from the exception.

Example:Throwing an exception that implements HttpExceptionInterface allows errors to be converted to the correct HTTP response code.

Mention that sf2 has default templates for different HTTP errors. These can be overridden.

Questions so far?

Time for a breather!

Components being used in Drupal.

HttpFoundation

Collection of classes for working with HTTP requests and responses.

Replaces PHP auto globals with an OOP layer.

Four main 'areas':Request

Response

Session

File

The Request Class

Contains request data (obviously)

Has a series of parameter bags properties containing request data.

These are:Request ($_POST)

Query ($_GET)

Cookies

Attributes (used by the app to store data)

Files ($_FILES

Server ($_SERVER)

Headers (sub-set of $_SERVER)

The Response Class

Actually a collection of classes.

Contains a large collection of setters/getters for manipulating all parts of the response.Many setters for working with the HTTP cache.

From within a controller easiest way to generate a response is to call the Controller::render() method.

Mention that in addition to response there are specialised response classes like JsonResponse, BinaryFileResponse, RedirectResponse, etc.Controllers render method accepts a template name, an array of params and an optional response object.

Session Management

Powerful, OOP wrapper around PHP's native session handling.

Contains a number of methods such as set(), get() and has() for working with session data.

Flash messages.

Various session save handlers for working with different session storage mediums.

Mention what flash messages are and. Explain that the session object stores the flash messages in a 'FlashBag' class.

Routing

Routing consists of three main parts:A RouteCollection of Route objects.

A RequestContext object.

A UrlMatcher object.

The RouteCollection

Container for the routes available in an application.

Each route added to the collection has a name and a Route object.

The Route Object

Contains up to seven parts:A URL route to match (may contain placeholders)

Array of default values to return when the route is matched (i.e. 'controller' => 'foo')

Requirements array, such as constraints for placeholders.

Array of options (not commonly used)

Optional host to match the route against.

Array of schemes (http, https, etc)

Array of valid http methods

The RequestContext

Contains information about the request.

Parameters passed to the constructor of this class.

If using Request object can pass that via the RequestContext::fromRequest() method instead.

The UrlMatcher

Given a route collection and a request context, tries to find a route that matches the request URI.

Can also be used to generate URL's in your controllers or templates.

Mention that URL's are generated by passing the route name and an array of parameters.Very handy if the URL's change as nothing needs to change in the controllers or views.

The Event Dispatcher Component

Implementation of the Observer pattern.

Central to the HttpKernel.

Allows listeners to be notified in order when an event is dispatched.

Three main parts:The event dispatcher.

Listeners to events.

Event obects.

Explain how you might want to use events:Separation of concerns.

Extension points for applications.

Easy code reusability.

Bad point: makes it harder to find/see what's going on.

The Event Dispatcher

The addListener() method is used to add a listener to an event.

Up to three arguments:The name of the event.

A PHP callable to be dispatched.

An optional priority.

Mention that higher priority means dispatched first.Priority defaults to 0.If two callbacks have the same priority then dispatched in order they're added.

The Event Listener

Nothing special here!

Each callable is passed the event object when called.

If you want to create an object that subscribes to multiple events use the EventSubscriberInterface.

Mention that the EventSubscriberInterface notifies the dispatcher what events it listens to.Call addSubscriber() method on the dispatcher to add a subscriber.

The Event Object

Basic event object has 2 methods:isPropagationStopped()

stopPropagation()

Designed to be extended by you!

After each listener is called the dispatcher checks if propagation has been stopped.

Mention that the event object is available in the scope after being dispatched. Therefore it can hold the results of the event dispatch.

The Dependency Injection Container

A bit of background...

DI is one of the SOLID guidelines.

Helps to ensure that code is loosely coupled.

Also enables the Liskov substitution principle.

Makes unit testing much easier.

In general, if your class has '$foo = new Bar' you're doing it wrong.

How do all of these objects get made?

Enter the DI Container

An object that knows how to make other objects.

Objects made as needed.

Fetching an object is as simple as calling Container::get('name')

Call pass arguments to methods.

Service Locator or DI Container?

Configuring the Container

ParametersValues to be passed to other objects.

Easily reusable

ServicesObjects managed by the container

Registered by name

Allows constructor injection, setter injection and setting public properties on the service.

Can pass other services as arguments to methods.

Note that the name of a service is what it is referred to when you want to fetch an instance.

Tagged Services

Services can be tagged with meta data.

Doesn't alter service definition but the container can retrieve services by tag name.

Example:Tagging a service with the name of an event, an event name and a method to call. Allows it to be called with the event dispatcher.

Questions?

Feel free to contact me with any questions or comments:[email protected]

@JCook21

http://jeremycook.ca

Thanks for listening.