Understanding the Components

Lenard Palko

Development Manager @ PITECH+PLUS

Symfony Certified Developer

lenard.palko@gmail.com

@lenardpalko

Drupal 8

Symfony

Agenda

A little bit of Symfony

Symfony - the components

Symfony Project

Framework

Components

+1,000

code contributors

+300,000

Symfony developers

+1,000,000

Monthly downloads

www.symfony.com

Symfony - the Framework​

full-stack web framework

works out-of-the box

easy to install

easy to extend

https://www.flickr.com/photos/wonderlane/3909074244/

Symfony - the Framework​


$ sudo curl -LsS http://symfony.com/installer -o /usr/local/bin/symfony
$ sudo chmod a+x /usr/local/bin/symfony
$ symfony new my_project 2.6.0

symfony installer

or

composer


$ composer create-project symfony/framework-standard-edition my_project_name "2.6.*"

Symfony - the Framework​

https://www.flickr.com/photos/ogimogi/2253657555

a set of reusable, decoupled PHP components "glued" togheter

they resolve individual isolated problems of web development 

Components

Symfony Components are a set of decoupled and reusable PHP libraries. They are becoming the standard foundation on which the best PHP applications are built on. You can use any of these components in your own applications independently from the Symfony Framework.

www.symfony.com

Components

The Symfony Components provide the low-level building blocks that you need to build a web product so that YOU can focus on what matters most for Drupal.

Components

why this is good

easy to understand /easy to maintain

not tied to any framework

components can evolve individually

can be easily replaced

Components

Components

ClassLoader

The ClassLoader component provides tools to autoload your classes and cache their locations for performance.

www.symfony.com

ClassLoader

autoloading

manually include all files that contain the classes

 

vs

 

just using a class

ClassLoader

wow

...

but how does it find the file for a class ?

ClassLoader

Standards

PHP Framework Interop Group

ClassLoader

Standards

results in PSR

PHP Standard Recommendation

 

PSR-0 -> Autoloading Standard

PSR-1 -> Basic Coding Standard

PSR-2 -> Coding Style Guide

PSR-3 ->Logger Interface

PSR-4 -> Improved Autoloading 

ClassLoader

PSR-4

user-code : hey @php, I want to create a new Vendor\Package\Class object 

php : oups ... I don't have it, @autoloader, could you load it

autoloader : I know that class files are in 'src' folder

autoloader : so I'll try to include src/Vendor/Package/Class.php

autoloader : ok ... found it ... you can use it now

ClassLoader

PSR-4


use Vendor\Package\Class;

$class = new Class();

src/
    Vendor/
        Package/
            Class.php
require __DIR__.'/lib/ClassLoader/Psr4ClassLoader.php';

$loader = new Psr4ClassLoader();
$loader->addPrefix('Vendor\\Package\\', 'src');
$loader->register(); // register the autoloader

Composer

  • Dependency Manager for PHP
  • packagist.org
  • PEAR on steroids

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

Composer

{
  "name": "drupal/core",
  "description": "Drupal is an open source ...",
  "type": "drupal-core",
  "license": "GPL-2.0+",
  "require": {
    "php": ">=5.4.5",
    "sdboyer/gliph": "0.1.*",
    "symfony/class-loader": "2.6.*",
    "symfony/css-selector": "2.6.*",
    "symfony/dependency-injection": "2.6.*",
    "symfony/event-dispatcher": "2.6.*",
    "symfony/http-foundation": "2.6.*",
...
  "autoload": {
    "psr-4": {
      "Drupal\\Core\\": "lib/Drupal/Core",
      "Drupal\\Component\\": "lib/Drupal/Component",
      "Drupal\\Driver\\": "../drivers/lib/Drupal/Driver"
    },
...  
}

if you have a composer.json

Composer

$ composer install

then after

composer.lock

DependencyInjection

The DependencyInjection component allows you to standardize and centralize the way objects are constructed in your application.

www.symfony.com

DependencyInjection

implementation of a powerful design pattern "Dependency Injection"

code follows "I" principle from SOLID

DependencyInjection

hmmm ... what does "I" stand for ?

Inversion of Control

decoupling dependencies

DependencyInjection

Example

You have an application in which the user can edit some configuration values.

And you want to save them "somewhere".

DependencyInjection

Example


class ConfigSaver 
{
    protected $storage;

    public function __construct()
    {
        $this->storage = new FileStorage();
    }

    public function set($name, $value)
    {
        $this->storage->save($name, $value);
    }
}

$configSaver = new ConfigSaver();

???

DependencyInjection

Example


class ConfigSaver
{
    protected $storage;

    public function __construct(StorageInterface $storage)
    {
        $this->storage = $storage;
    }

    public function set($name, $value)
    {
        $this->storage->save($name, $value);
    }
}

$storage = new FileStorage(); // or DbStorage() or SessionStorage() or mock
$configSaver = new ConfigSaver($storage);

DependencyInjection

Basically, you are using Dependency Injection pattern when your object receives it's dependencies

constructor (contructor injection)

method (setter injection)

field (property injection)

 

DependencyInjection

BUT why do I need this component ?

you say ... OK

DependencyInjection

Dependency Injection Container

 

or

 

Service Container

DependencyInjection

Service Container

controller : hey @container, could you give me the config saver service 

container : oups ... I don't have it, let me build it

container : it has a storage dependency, let me check the configuration

container : it is a FileStorage, let me build that too

container : it's ready you can use the service now

controller : thanks

DependencyInjection

Dependency Injection Container

can inject services and parameters

based on configuration files that can be written in YML, XML, PHP

..and this get's even better :)

DependencyInjection

Performance

The service container can be "compiled" (dumped) to plain PHP

CompilerPass

Modify already registered services

DependencyInjection

Where can you see it Drupal ?

  • Drupal\Core\DependencyInjection\Container
  • core.services.yml
  • modules/*/*.services.yml

services:
  cache_factory:
    class: Drupal\Core\Cache\CacheFactory
    arguments: ['@settings']
    calls:
      - [setContainer, ['@service_container']]
  cache_contexts:
    class: Drupal\Core\Cache\CacheContexts
    arguments: ['@service_container', '%cache_contexts%' ]
...
  exception.default:
    class: Drupal\Core\EventSubscriber\DefaultExceptionSubscriber
    tags:
      - { name: event_subscriber }
    arguments: ['@config.factory', '@bare_html_page_renderer']

DependencyInjection

core.services.yml

HttpFoundation

  • Request
  • Response

www.symfony.com

The HttpFoundation component defines an object-oriented layer for the HTTP specification.

HttpFoundation

Request

Server

Response

user

browser

HttpFoundation

Request

simple OO representation of HTTP request message

holds information about the client request

wraps existing global PHP parameters in "bags"

HttpFoundation

Request


$input = $_POST['input'];
$method = $_SERVER['REQUEST_METHOD'];
$cookie = $_COOKIE['cookie'];


use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();

$input = $request->get('input');
$method = $request->getMethod();
$cookie = $request->cookies->get('cookie');

$request->isSecure();
$request->getClientIp();

HttpFoundation

Response

simple OO representation of HTTP response message

holds the information to be sent back

status, headers, content

HttpFoundation

Response


header("HTTP/1.0 404 Not Found");

header("Cache-Control: max-age=600");

setcookie('cookie', 'value');

echo 'Lorem ipsum...';

use Symfony\Component\HttpFoundation\Response;

$response = new Response('Not Found!', 404);
$response->setMaxAge(600);

$response->setContent('Lorem ipsum...');

use Symfony\Component\HttpFoundation\Cookie;
$response->headers->setCookie(new Cookie('cookie', 'value'));

HttpFoundation

other services

RequestStack

Session

UploadedFile

EventDispatcher

The EventDispatcher component provides tools that allow your application components to communicate with each other by dispatching events and listening to them.

www.symfony.com

EventDispatcher

mediator pattern

http://sourcemaking.com/files/v2/content/patterns/Mediator_example-2x.png

EventDispatcher

decoupled system

event based communication

listeners are independent

removing listener doesn't affect the system

 

EventDispatcher

Two types of consumers :

listeners

subscribers

EventDispatcher


// dispatching an event
$this->dispatcher->dispatch(BlockEvents::ADMINISTRATIVE_CONTEXT, new BlockContextEvent();

// setting up a subscriber implements EventSubscriberInterface
public static function getSubscribedEvents() {
    $events[BlockEvents::ACTIVE_CONTEXT][] = 'onBlockActiveContext';
    $events[BlockEvents::ADMINISTRATIVE_CONTEXT][] = 'onBlockAdministrativeContext';
    return $events;
}

Routing

www.symfony.com

The Routing component maps a HTTP request to a set of configuration variables.

Routing

Kernel

Routing

kernel.request

Request

_controller

Routing

listens on kernel.request

matches route config

sets _controller on request

Routing

SymfonyCMF routing

http://cmf.symfony.com/

DynamicRouter

+ enhancers

Routing


block.admin_demo:
  path: '/admin/structure/block/demo/{theme}'
  defaults:
    _controller: '\Drupal\block\Controller\BlockController::demo'
    _title_callback: 'theme_handler:getName'
  requirements:
    _access_theme: 'TRUE'
    _permission: 'administer blocks'
  options:
    _admin_route: FALSE

HttpKernel

The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher.

www.symfony.com

HttpKernel


$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$response = $kernel
    ->handle($request);
      

HttpKernelInterface

HttpKernel

  • Symfony\Component\HttpKernel\KernelEvents
    • kernel.request
    • kernel.controller
    • kernel.response
    • kernel.view
    • kernel.finish_request
    • kernel.terminate
    • kernel.exception

HttpKernel

Workflow

Validator

http://www.vanseodesign.com/blog/wp-content/uploads/2011/01/validate.jpg

Generic class validation component

Validator

add validation to any PHP object

configuration based

translatable error messages

Validator


$object = new Object();
$errors = $validator->validate($object);

Acme\OneBundle\Onjectr:
    properties:
        email:
            - Email: ~

validation.yml

Serializer

The Serializer component is meant to be used to turn objects into a specific format (XML, JSON, YAML, ...) and the other way around.

www.symfony.com

Serializer

www.symfony.com

Yaml

www.symfony.com

The Yaml component loads and dumps YAML files.

Yaml


use Symfony\Component\Yaml\Parser;

$yaml = new Parser();

$value = $yaml->parse(file_get_contents('/path/to/file.yml'));

fast

easy to use

Configuration Management Initiative

Your own framework


$routes = new RouteCollection();
$routes->add('hello', new Route('/hello', array('_controller' =>
    function (Request $request) {
        return new Response(sprintf("Hello %s", $request->get('name')));
    }    
)));

$request = Request::createFromGlobals();

$matcher = new UrlMatcher($routes, new RequestContext());

$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new RouterListener($matcher));

$resolver = new ControllerResolver();
$kernel = new HttpKernel($dispatcher, $resolver);
$kernel->handle($request)->send();

https://speakerdeck.com/fabpot/symfony2-meets-drupal-8

QUESTIONS ?

THANK YOU

References

 

http://symfony.com/components

https://speakerdeck.com/fabpot/symfony2-meets-drupal-8

https://cipix.nl/understanding-drupal-8-part-1-general-structure-framework

http://www.sitepoint.com/drupal-8-hooks-symfony-event-dispatcher

http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1

Understanding the Components

By lenardpalko

Understanding the Components

  • 1,663