symfony en drupal 8 - drupalcamp spain

Post on 08-Dec-2014

2.615 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Presentación sobre los componentes de Symfony utilizados en Drupal 8. DrupalCamp Spain

TRANSCRIPT

Symfony en Drupal 8 Raul Fraile

Raúl Fraile (@raulfraile)

PHP/Symfony2 dev @

PHP 5.3 Zend Certified Engineer

Symfony Certified Developer

LadybugPHP

Sobre mi

Drupal Island

Drupal Island

Durante años, Drupal ha sido la envidia de muchos CMS/frameworks: Comunidad activa, robustez, extensibilidad…

Drupal Island

https://www.flickr.com/photos/peterlozano/14020046267/

Drupal Island

En los últimos años, PHP ha mejorado en muchos aspectos, y no sólo como lenguaje.

Ésta mejora “obliga” a Drupal a cambiar para dirigirse a un mercado más empresarial/profesional.

Drupal Island

5.3+

Mejoras en OO

Namespaces

Closures

Traits

Funciones generadoras

Composer

function drupal_http_request($url, array $options = array()) { // Allow an alternate HTTP client library to replace Drupal's default // implementation. $override_function = variable_get('drupal_http_request_function', FALSE); if (!empty($override_function) && function_exists($override_function)) { return $override_function($url, $options); } ! $result = new stdClass(); ! // Parse the URL and make sure we can handle the schema. $uri = @parse_url($url); ! if ($uri == FALSE) { $result->error = 'unable to parse URL'; $result->code = -1001; return $result; } ! if (!isset($uri['scheme'])) { $result->error = 'missing schema'; $result->code = -1002; return $result; } ! timer_start(__FUNCTION__); ! // Merge the default options. $options += array( 'headers' => array(), 'method' => 'GET',

Drupal Islanddrupal_http_request()

} break; default: $result->error = $status_message; } ! return $result; }

Drupal Islanddrupal_http_request()

} break; default: $result->error = $status_message; } ! return $result; }

Drupal Island

LOC: 304

Complejidad ciclomática: 41

N-Path: 25.303.344.960

drupal_http_request()

Drupal Island

N-Path ≈ Núm. caminos ≈ Tests

2 TB de tests

412 DVDs de tests

670K Drupals de tests

drupal_http_request()

Drupal Island

slideshare.net/ircmaxell/development-by-the-numbers

Anthony Ferrara

Drupal Island

Dificultad para mantener el código.

Código antiguo, compatibilidad con PHP 4.

Orientación a objetos testimonial.

Reinventando la rueda.

Drupal Island

Drupal Island

Drupal Island

Drupal Island

NIHNot Invented Here

Drupal Island

NIHNot Invented Here

PIEProudly Found Elsewhere

Drupal Island

ClassLoader DependencyInjection

EventDispatcher HttpFoundation

HttpKernel Routing Serializer Validator

Yaml

Twig Doctrine Common

Doctrine Annotations Guzzle Assetic

SymfonyCMF Routing EasyRDF PHPUnit

Zend Feed

Drupal Island

50% de las dependencias de

Drupal 8 son componentes de

Symfony

Drupal Island

¿Por qué Symfony?

Proyecto maduro y de calidad.

Basado en componentes. “Líder” de la revolución contra los frameworks monolíticos.

Comunidad grande y activa.

¿Por qué Symfony?

Componentes de Symfony2

Conjunto de librerías desacopladas e independientes.

Implementan funcionalidad común para sitios/apps web.

Bloques con los que se construye el full-stack framework.

Componentes de Symfony2

HttpFoundation

Abstracción del protocolo HTTP.

El origen de la colaboración entre

Symfony y Drupal.

HttpFoundation

HttpFoundation GET /index.php HTTP/1.1 Host: test.com Accept-Language:en;q=0.8 Accept-Encoding:gzip User-Agent: Mozilla/5.0

HttpFoundation

$_GET $_POST $_COOKIE $_FILES $_SERVER

GET /index.php HTTP/1.1 Host: test.com Accept-Language:en;q=0.8 Accept-Encoding:gzip User-Agent: Mozilla/5.0

query request cookies files server headers

getScheme getHost

getClientIp getMethod

getContentType getPreferredLanguage

HttpFoundation

$_GET $_POST $_COOKIE $_FILES $_SERVER

GET /index.php HTTP/1.1 Host: test.com Accept-Language:en;q=0.8 Accept-Encoding:gzip User-Agent: Mozilla/5.0

HttpFoundation

use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; !$request = Request::createFromGlobals(); !$html = sprintf( '<h1>Hola %s!</h1>', $request->query->get('name', 'Raul')); !$response = new Response($html); $response ->headers->set("content-type", "text/html"); $response->send();

HttpFoundation

use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; !$request = Request::createFromGlobals(); !$html = sprintf( '<h1>Hola %s!</h1>', $request->query->get('name', 'Raul')); !$response = new Response($html); $response ->headers->set("content-type", "text/html"); $response->send();

HttpFoundation

use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; !$request = Request::createFromGlobals(); !$html = sprintf( '<h1>Hola %s!</h1>', $request->query->get('name', 'Raul')); !$response = new Response($html); $response ->headers->set("content-type", "text/html"); $response->send();

HttpFoundation

use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; !$request = Request::createFromGlobals(); !$html = sprintf( '<h1>Hola %s!</h1>', $request->query->get('name', 'Raul')); !$response = new Response($html); $response ->headers->set("content-type", "text/html"); $response->send();

HttpKernel

El componente HttpKernel define

un proceso abstracto para convertir

un objeto Request en un Response:

HttpKernelInterface

HttpKernel

HttpKernel

HttpKernelInterface

HttpKernel

Request HttpKernelInterface

HttpKernel

Request ResponseHttpKernelInterface

HttpKernel

Request ResponseHttpKernelInterface

HttpKernel

Request ResponseHttpKernelInterface

HttpKernel

Request ResponseHttpKernelInterface

HttpKernel

Request ResponseHttpKernelInterface

HttpKernel

Aplicación

Caché

HttpKernel

Aplicación

Negociación

Caché

HttpKernel

Aplicación

Negociación

Caché

HttpKernel

Aplicación

Middleware

El componente dispone de una implementación concreta de HttpKernelInterface.

Diseñada para ser muy flexible, con eventos “estándar”.

HttpKernel

ClassLoader

El componente ClassLoader permite realizar autoload de clases en PHP.

Un único require/include por aplicación.

Permite cachear las rutas para ganar rendimiento.

Dispone de 2 autoloaders: PSR-0 y MapClass.

ClassLoader

Cada vez que se utiliza una clase que no ha sido incluida previamente, PHP utiliza el mecanismo de autoload.

FQN + reglas/map = require(archivo)

ClassLoader

ClassLoader

new MyClass()

ClassMap PSR-0/4

ClassLoader

new MyClass()

ClassMap PSR-0/4

ClassLoader

new MyClass()

ClassMap PSR-0/4

Path

require_once( )

ClassLoader

new MyClass()

ClassMap PSR-0/4

Path

ClassLoader

new MyClass()

ClassMap PSR-0/4

require_once( )

ClassLoader

new MyClass()

ClassMap PSR-0/4

Path

require_once( )

ClassLoader

new MyClass()

ClassMap PSR-0/4

Path

ClassLoaderPHP Framework Interop Group

The idea behind the group is for project r e p re s en t a t i v e s t o t a l k a bou t t h e commonalities between our projects and find ways we can work together. Our main audience is each other, but we’re very aware that the rest of the PHP community is watching. If other folks want to adopt what we’re doing they are welcome to do so, but that is not the aim.

ClassLoaderPHP Framework Interop Group

PSR-0 Autoloading Standard

PSR-1 Basic Coding Standard

PSR-2 Coding Style Guide

PSR-3 Logger Interface

PSR-4 Improved Autoloading

Routing

RoutingCMF

El componente Symfony/Routing relaciona peticiones HTTP con un conjunto de variables.

CMF/Routing lo extiende para permitir rutas dinámicas:

URLs definidas por usuarios

Multiidioma

Routing

Routing

Request

Controller

ChainRouter

Routing

Request

Controller

ChainRouter

R1 R2 R3

R4 R5 R6

Routing

Request

Controller

ChainRouter

R1 R2 R3

R4 R5 R6

RouterInterface

Routing

Request

Controller

ChainRouter

R1 R2 R3

R4 R5 R6

RouterInterface

EventDispatcher

El componente EventDispatcher implementa el patrón Mediador (Mediator Pattern), permitiendo desacoplar nuestro código.

Alternativa OO a los clásicos hooks de Drupal.

EventDispatcher

EventDispatcher

Productor

Consumidor

Consumidor

Consumidor

Consumidor

Med

iado

r

EventDispatcher

Productor

Consumidor

Consumidor

Consumidor

Consumidor

Med

iado

r

EventDispatcheruse Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); // add listeners $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Updating RSS feed' . PHP_EOL; }); $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Sending emails' . PHP_EOL; }); // save the post // … !// dispatch the event $event = new BlogPostEvent($blogPost); $dispatcher->dispatch('blog.post.saved', $event);

EventDispatcheruse Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); // add listeners $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Updating RSS feed' . PHP_EOL; }); $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Sending emails' . PHP_EOL; }); // save the post // … !// dispatch the event $event = new BlogPostEvent($blogPost); $dispatcher->dispatch('blog.post.saved', $event);

EventDispatcheruse Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); // add listeners $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Updating RSS feed' . PHP_EOL; }); $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Sending emails' . PHP_EOL; }); // save the post // … !// dispatch the event $event = new BlogPostEvent($blogPost); $dispatcher->dispatch('blog.post.saved', $event);

EventDispatcheruse Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; $dispatcher = new EventDispatcher(); // add listeners $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Updating RSS feed' . PHP_EOL; }); $dispatcher->addListener('blog.post.saved', function (BlogPostEvent $event) { echo 'Sending emails' . PHP_EOL; }); // save the post // … !// dispatch the event $event = new BlogPostEvent($blogPost); $dispatcher->dispatch('blog.post.saved', $event);

DependencyInjection

El componente DependencyInjection permite centralizar la construcción de objetos de la aplicación.

La inyección de dependencias es un patrón de diseño de software.

Las dependencias no se crean (no new), se inyectan.

Más flexibilidad y reusabilidad.

DependencyInjection

DependencyInjectionclass Blog { protected $mailer; protected $posts; ! function __construct() { $this->mailer = new MyMailer(); } ! function addPost(Post $post) { $this->posts[] = $post; $this->sendMail($post); } ! function sendMail(Post $post) { $this->mailer->send(/* ... */); } }

DependencyInjectionclass Blog { protected $mailer; protected $posts; ! function __construct() { $this->mailer = new MyMailer(); } ! function addPost(Post $post) { $this->posts[] = $post; $this->sendMail($post); } ! function sendMail(Post $post) { $this->mailer->send(/* ... */); } }

DependencyInjectionclass Blog { protected $mailer; protected $posts; ! function __construct() { $this->mailer = new MyMailer(); } ! function addPost(Post $post) { $this->posts[] = $post; $this->sendMail($post); } ! function sendMail(Post $post) { $this->mailer->send(/* ... */); } }

DependencyInjectionclass Blog { protected $mailer; protected $posts; ! function __construct(MailerInterface $mailer) { $this->mailer = $mailer; } ! function addPost(Post $post) { $this->posts[] = $post; $this->sendMail($post); } ! function sendMail(Post $post) { $this->mailer->send(/* ... */); } }

DependencyInjection

DIC

SMTP …

Mailer

DependencyInjection

DIC

SMTP …

$container->get(“Mailer”)

Mailer

DependencyInjection

DIC

$container->get(“Mailer”)

Mailer

DependencyInjection

DIC

$container->get(“Mailer”)

Mailer

DependencyInjection

leanpub.com/a-year-with-symfony

Matthias Noback

Validator

El componente Validator permite validar información de entrada a nuestra aplicación.

Basado en la especificación JSR 303.

Se divide en constraints y validators.

Validator

Validator

use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Constraints\Range; $validator = Validation::createValidator(); $constraint = new Range(array( 'min' => 1, 'max' => 10 )); $violations = $validator->validateValue( 15, $constraint );

Validator

use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Constraints\Range; $validator = Validation::createValidator(); $constraint = new Range(array( 'min' => 1, 'max' => 10 )); $violations = $validator->validateValue( 15, $constraint );

Validator

use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Constraints\Range; $validator = Validation::createValidator(); $constraint = new Range(array( 'min' => 1, 'max' => 10 )); $violations = $validator->validateValue( 15, $constraint );

Validator

use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Constraints\Range; $validator = Validation::createValidator(); $constraint = new Range(array( 'min' => 1, 'max' => 10 )); $violations = $validator->validateValue( 15, $constraint );

Validator

use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Constraints\Range; $validator = Validation::createValidator(); $constraint = new Range(array( 'min' => 1, 'max' => 10 )); $violations = $validator->validateValue( 15, $constraint );

Validator

NotBlank Ip DateTime CardScheme

Blank Range Time Currency

NotNull EqualTo Choice Luhn

Null NotEqualTo Collection Iban

True IdenticalTo Count Isbn

False NotIdenticalTo UniqueEntity Issn

Type LessThan Language Callback

Email LessThanOrEqual Locale Expression

Length GreaterThan Country All

Url GreaterThanOrEqual File UserPassword

Regex Date Image Valid

Serializer

El componente Serializer convierte objetos PHP en otros formatos (p.ej. JSON) y viceversa.

Está diseñado para que pueda ser extensible.

Serializer

Serializer

Objeto FormatoArray

Serialización

Deserialización

Yaml

El componente Yaml parsea y serializa archivos en formato YAML (YAML Ain't Markup Language).

YAML es un formato de serialización de datos amigable para humanos.

Soporte para múltiples lenguajes de programación.

Yaml

Yaml

talks: 0: title: "Symfony en Drupal 8" speaker: "Raúl Fraile" description: "La versión 8 de Drupal…” datetime: 2014-05-18T10:00:00+02:00

Yaml

talks: 0: title: "Symfony en Drupal 8" speaker: "Raúl Fraile" description: "La versión 8 de Drupal…” datetime: 2014-05-18T10:00:00+02:00

array (1) · [talks]: array (1) · · [0]: array (4) · · · [title]: string (19) "Symfony en Drupal 8" · · · [speaker]: string (11) "Raúl Fraile" · · · [description]: string (464) "La versión 8 de Drupal…” · · · [datetime]: int 1400400000

Yaml

use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Dumper; !$parser = new Parser(); $data = $parser->parse( file_get_contents(‘data.yml') ); !$dumper = new Dumper(); $yaml = $dumper->dump($data); file_put_contents('data2.yml', $yaml);

Recursos

Recursos

symfony.es/libro

Javier Eguiluz

Recursos

blog.servergrove.com/tag/symfony2-components

Gràcies!

@raulfraile

VPS100-700: 15% mes: 'DPSpain15' VPS100-700: 20% mes: 'DPSpain20'

top related