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
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