Upload
raul-fraile
View
2.634
Download
1
Embed Size (px)
DESCRIPTION
Presentación sobre los componentes de Symfony utilizados en Drupal 8. DrupalCamp Spain
Citation preview
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
blog.servergrove.com/tag/symfony2-components
Gràcies!
@raulfraile
VPS100-700: 15% mes: 'DPSpain15' VPS100-700: 20% mes: 'DPSpain20'