SlideShare una empresa de Scribd logo
Silex
  desarrollo web ágil y
  profesional con PHP

BILBOSTACK          JAVIER EGUILUZ
26 ENERO 2013
Gracias a la organización.



Asier   Fran     Ibon    Vicenç
Agenda
 1. Introducción
 2. Programando aplicaciones
 3. DEMO
 4. Buenas prácticas
 5. Puntos débiles
Introducción
¿Por qué?
En el mundo de los negocios...
1. Rápido
2. Barato
3. Bueno
En el mundo de los negocios...
1. Rápido              ELIGE DOS

2. Barato
3. Bueno
En el mundo de la programación...
1. Bien hecho
2. Terminado a tiempo
3. Barato
En el mundo de la programación...
1. Bien hecho     ELIGE UNA

2. Terminado a tiempo
3. Barato
En el mundo de la programación...
✔ Bien
1.     hecho
✔ Terminado a tiempo
2.
✔ Barato
3.
   Con Silex puedes
   tenerlo todo
¡no tengo
¡quiero hacerlo bien!    tiempo!
¿Qué es
 Silex?
Foto: Wikipedia
Curiosity (2012)




                  Sojourner (2007)
Foto: Wikipedia
Sojourner   Curiosity
                (2007)      (2012)

Masa            11 kg      900 kg
Coste ($)      150 M      1.800 M
Memoria RAM     64 KB      256 MB
CPU             2 MHz     200 MHz
Es importante tener en cuenta que...
• El grande jamás podrá ser tan ágil
  como el pequeño.
• El pequeño jamás podrá competir
  en potencia y funcionalidad con el
  grande.
Silex
The PHP micro-framework
based on the Symfony2
Components

                           el logo
                          de Silex
los dos son frameworks y usan los mismos componentes, pero...
...Symfony es un framework muy grande y Silex es un framework muy pequeño
Silex   Symfony2
Peso               5 MB      8 MB
Archivos           3.366    6.578
Nivel dificultad

Flexibilidad
Los creadores de Silex




Igor Wiedler     Fabien Potencier
@igorw           @fabpot
+ fácil     + calidad
- calidad   - facil
+ fácil     + calidad
- calidad   - facil
Programando
 aplicaciones
Funciones anónimas
         y closures
Función normal
function suma($a, $b) {
  return $a + $b;
}
Función anónima
function ($a, $b) {
  return $a + $b;
}
Usando una función anónima
$app->get('...', function ($a, $b) {
   return $a + $b;
});
Closure
$a = 3;
function ($b) {
  return $a + $b;
}
Closure
$a = 3;             NO FUNCIONA
function ($b) {
  return $a + $b;
}
Closure
$a = 3;
function ($b) use ($a) {
  return $a + $b;
}
El código más común de Silex
$app->get('...', function ($var) use ($app) {
   // ...
});
El primer
 ejemplo
Hola
mundo.
http://bilbostack.com/hola
Hola Mundo en Silex
require_once __DIR__.'/../vendor/autoload.php';

$app = new SilexApplication();

$app->get('/hola', function() {
   return 'Hola mundo';
});

$app->run();
Cargar clases automáticamente
require_once __DIR__.'/../vendor/autoload.php';

$app = new SilexApplication();

$app->get('/hola', function() {
   return 'Hola mundo';
});

$app->run();
Crear la aplicación Silex
require_once __DIR__.'/../vendor/autoload.php';

$app = new SilexApplication();

$app->get('/hola', function() {
   return 'Hola mundo';
});

$app->run();
Ejecutar código para una URL
require_once __DIR__.'/../vendor/autoload.php';

$app = new SilexApplication();

$app->get('/hola', function() {
   return 'Hola mundo';
});

$app->run();
Arrancar la aplicación
require_once __DIR__.'/../vendor/autoload.php';

$app = new SilexApplication();

$app->get('/hola', function() {
   return 'Hola mundo';
});

$app->run();
Hola Mundo en Silex
require_once __DIR__.'/../vendor/autoload.php';

$app = new SilexApplication();

$app->get('/hola', function() {
   return 'Hola mundo';
});

$app->run();
Sinatra / Ruby

require 'sinatra'

get '/hola' do
 "Hola mundo."
end
node.js / JavaScript

var http = require('http');

http.createServer(function (request, response) {
   response.writeHead(
      200, { 'Content-Type': 'text/plain' }
   );
   response.end('Hola mundon');
}).listen(80);
Un ejemplo
       real
Silex, desarrollo web ágil y profesional con PHP
Fo
                     rk
                          m
                           eo
                              n
github.com/                       Gi
                                    tH
                                      ub

javiereguiluz/bilbostack
Enrutamiento
Ruta de la portada
$app->get('/', function () use ($app) {
   // ...
});
Ruta básica
$app->get('/agenda', function () use ($app) {
   // ...
});
Ruta con partes variables
$app->get('/speakers/{slug}', function ()
                              use ($app) {
   // ...
});
Ruta con partes variables
$app->get('/speakers/{slug}', function ()
                              use ($app) {
   // ...
});
Ruta con partes variables
$app->get('/speakers/{slug}', function ()
                              use ($app) {
   // ...
});

/speakers/pablo-garaizar
/speakers/carlos-sanchez
/speakers/esto-esta-mal
Otros métodos HTTP
$app->post('/registro', function () use ($app) {
   // ...
});
Otros métodos HTTP
$app->post('/registro', function () use ($app) {
   // ...
});

$app->put( );
$app->delete( );
Ruta para todos los métodos HTTP
$app->match('/registro', function () use ($app) {
   // ...
});
Ruta para algunos métodos HTTP
$app->match('/registro', function () use ($app) {
   // ...
})
->method('GET|POST');
Rutas con variables
$app->get('/speakers/{slug}', function ($slug) {
   // ...
});
Rutas con variables
$app->get('/speakers/{track}/{slug}',
         function ($track, $slug) use ($app) {
   // ...
});
Variables especiales
use SymfonyComponentHttpFoundationRequest;

$app->get('/speakers/{slug}',
         function (Request $request, $slug) {
   // ...
});
Variables especiales
use SymfonyComponentHttpFoundationRequest;

$app->get('/speakers/{slug}',
         function (Request $request, $slug) {
   // ...
});
Variables especiales
use SymfonyComponentHttpFoundationRequest;

$app->get('/speakers/{slug}',
         function (Request $request, $slug) {
   // ...
});

$request->server->get('HTTP_USER_AGENT')
$request->get('slug')
Modificando las variables de la ruta
$app->get('/schedule/{slug}',
         function ($slug) use ($app) {
   // ...
})->convert('slug', function ($slug) {
   return strtolower($slug);
});
Modificando las variables de la ruta
$app->get('/schedule/{slug}',
         function ($slug) use ($app) {
   // ...
})->convert('slug', function ($slug) {
   return str_replace('-', '_', $slug);
});
Restringiendo las variables de la ruta
$app->get('/schedule/{track}', function ($track)
{
  // ...
})->assert('track', 'd+');
Restringiendo las variables de la ruta
$app->get('/schedule/{track}', function ($track)
{
  // ...
})->assert('track', 'trackd+');
Restringiendo las variables de la ruta
$app->get('/schedule/{track}', function ($track)
{
  // ...
})->assert('track', '1|2');
Valores por defecto
$app->get('/schedule/{track}', function ($track)
{
  // ...
})->value('track', '1');
Valores por defecto
$app->get('/schedule/{track}', function ($track)
{
  // ...
})->value('track', '1');

/schedule
/schedule/1
Rutas con nombre
$app->get('/', function () use ($app) {
  // ...
})->bind('portada');
Controladores
Controlador básico
$app->get('/donde-comer', function ()
                             use ($app) {
   return $app['twig']->render('comer.twig');
})
->bind('comer');
Controlador típico
$app->get('/', function () use ($app) {
  $ponentes = $app['ponentes'];

  return $app['twig']->render('portada.twig',
         array('ponentes' => $ponentes)
  );
})->bind('portada');
Controlador típico
$app->get('/', function () use ($app) {
  $ponentes = $app['ponentes'];

  return $app['twig']->render('portada.twig',
         array('ponentes' => $ponentes)
  );
})->bind('portada');
Gestión de errores
$app->get('/speakers/{slug}',
      function ($slug) use ($app) {
  if (...) {
      $app->abort(404, "No existe el ponente.");
  }

  // ...

  return $app['twig']->render('ponente.twig',...);
})->bind('ponente');
Gestión de errores
$app->get('/speakers/{slug}',
      function ($slug) use ($app) {
  if (...) {
      $app->abort(404, "No existe el ponente.");
  }

  // ...

  return $app['twig']->render('ponente.twig',...);
})->bind('ponente');
Controlador especial para errores
$app->error(function (Exception $e, $code)
            use ($app) {

  // ...

});
Controlador especial para errores
$app->error(function (Exception $e, $code)
            use ($app) {

  // ...

});
Esqueleto de una aplicación Silex
$app->get('/', ...)->bind('portada');

$app->get('/agenda', ...)->bind('agenda');

$app->get('/speakers/{slug}', ...)
->bind('ponente');

$app->get('/schedule/{slug}', ...)
->bind('ponencia');
1 aplicación = 1 archivo
$app->get('/', ...)->bind('portada');

$app->get('/agenda', ...)-
>bind('agenda');

$app->get('/speakers/{slug}', ...)
->bind('ponente');

$app->get('/schedule/{slug}', ...)
->bind('ponencia');




                 controllers.php
1 aplicación = 1 archivo

                                        EL ORDEN
$app->get('/', ...)->bind('portada');

$app->get('/agenda', ...)-
>bind('agenda');                         IMPORTA
$app->get('/speakers/{slug}', ...)
->bind('ponente');

$app->get('/schedule/{slug}', ...)
->bind('ponencia');




                 controllers.php
Middlewares
     (filtros)
Petición HTTP           Objeto Request



                    Silex



                            Tu aplicación




Página HTML         Silex
                            Objeto Response
Petición HTTP           Objeto Request

                                     !
                    Silex



                            Tu aplicación

         !                            !

Página HTML         Silex
                            Objeto Response
Filtro before
$app->before(function (Request $request) {
   // ...
});
Secuencia de ejecución
• Buscar la ruta que pide el usuario.
• Comprobar la seguridad.
• Ejecutar filtro before()
• Ejecutar controlador de la ruta
Ejemplo de filtro before
$app->before(function (Request $request) {
   if (...) {
       return new RedirectResponse('/login');
   }
});
Filtro after
$app->after(function (Request $request,
                      Response $response) {
   // ...
});
Secuencia de ejecución
• Buscar la ruta que pide el usuario.
• Comprobar la seguridad.
• Ejecutar filtro before( )
• Ejecutar controlador de la ruta.
• Ejecutar filtro after( )
• Enviar respuesta al usuario.
Ejemplo de filtro after
$app->after(function (Request $request) {
   log('...');
});
Ejemplo de filtro after
$app->after(function (Request $request) {
   log('...');
});

                 ¿Dónde está mi
                   respuesta?
Filtro finish
$app->finish(function (Request $request,
                       Response $response) {
   // ...
});
Cada ruta con su filtro
$app->get('/', ...)->bind('portada')->before(...);

$app->get('/agenda', ...)->bind('agenda')
->before(...)->after(...);

$app->get('/speakers/{slug}', ...)
->bind('ponente')->before(...);

$app->get('/schedule/{slug}', ...)
->bind('ponencia')->before(...);
Proveedores de
      servicios
Bases de datos


           Formularios

Núcleo     Plantillas

de Silex   Caché HTTP


           Envío de emails

             proveedores
Bases de datos


                        Formularios

Núcleo     Plantillas

de Silex                Caché HTTP


                        Envío de emails

                          proveedores
Bases de datos


           Formularios

Núcleo                   Plantillas

de Silex                 Caché HTTP


                      Envío de emails

                            proveedores
Bases de datos


           Formularios

Núcleo     Plantillas

de Silex   Caché HTTP


           Envío de emails
Bases de datos   Serializador   Seguridad


Formularios      Logger         Sesiones


Validación       Emails         Plantillas


Caché HTTP       URL
Usar formularios de Symfony2
use SilexProviderFormServiceProvider;

// ...

$app->register(new FormServiceProvider());
Acceder a BBDD con Doctrine2
use SilexProviderDoctrineServiceProvider;

// ...

$app->register(new DoctrineServiceProvider());
Utilizar las plantillas de Twig
use SilexProviderTwigServiceProvider;

// ...

$app->register(new TwigServiceProvider(), array(
  'twig.path' => array(__DIR__.'/../templates'),
  'twig.options' => array('...'),
));
DEMO
github.com/javiereguiluz/bilbostack




                                                ub
                                          G itH
                                   e on
                                k m
                            F or
Instalación
Descargar archivo comprimido

   silex.sensiolabs.org
Descargar archivo comprimido
Descargar archivo comprimido
Descargar archivo comprimido
Instalación via composer.json
{
  "require": {
     "silex/silex": "1.0.*"
  },
  "minimum-stability": "dev"
}
Instalación via composer.json
{
  "require": {
     "fabpot/silex-skeleton": "*"
  },
  "minimum-stability": "dev"
}
Instalación recomendada
$ composer
  create-project
  fabpot/silex-skeleton
  --stability=dev
Silex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHP
web/        src/      src/
index.php   app.php   controllers.php
web/        src/      src/
index.php   app.php   controllers.php




No tocar
web/        src/        src/
index.php   app.php     controllers.php




No tocar     Activas
            servicios
web/        src/        src/
index.php   app.php     controllers.php




No tocar     Activas       $app
            servicios   ->get('/', ...});
Buenas
prácticas
Organizando
los controladores
$app->get('/', ...);

                         // ...


                                  controllers.php

$app->get('/', ...);     $app->get('/', ...);



              blog.php              backend.php
Importando controladores
$app->mount('/blog', include 'blog.php');
$app->mount('/admin', include 'backend.php');
Importando controladores
$app->mount('/blog', include 'blog.php');
$app->mount('/admin', include 'backend.php');
Importando controladores
$app->mount('/blog', include 'blog.php');
$app->mount('/admin', include 'backend.php');


PORTADA: /
PORTADA DE BLOG: /blog/
PORTADA DE BACKEND: /admin/
1 aplicación = 1 archivo
$app->get('/', ...)->bind('portada');

$app->get('/agenda', ...)-
>bind('agenda');

$app->get('/speakers/{slug}', ...)
->bind('ponente');

$app->get('/schedule/{slug}', ...)
->bind('ponencia');




                 controllers.php
1 aplicación pequeña = 1 archivo
$app->get('/', ...)->bind('portada');

$app->get('/agenda', ...)-
>bind('agenda');

$app->get('/speakers/{slug}', ...)
->bind('ponente');

$app->get('/schedule/{slug}', ...)
->bind('ponencia');




                 controllers.php
1 aplicación mediana = N archivos
$app->get('/', ...)->bind('portada');   $app->get('/', ...);

$app->get('/agenda', ...)-              $app->get('/ver', ...);
>bind('agenda');
                                        $app->get('/listar', ...);
$app->get('/speakers/{slug}', ...)
->bind('ponente');
                                                                     blog.php
$app->get('/schedule/{slug}', ...)
->bind('ponencia');



                                        $app->get('/', ...);




                 controllers.php                               backend.php
Escalando una
aplicación Silex
Controladores como clases
namespace IgorwShopController;

use SilexApplication;
use SymfonyComponentHttpFoundationRequest;

class ShopController
{
   public function indexAction(Request $request, Application $app)
   {
     ...
   }
}
Controladores como clases
$app->get('/', controller('shop/index'));
$app->match('/login', controller('shop/login'));
$app->get('/product', controller('shop/
product'));
http://igor.io/2012/11/09/scaling-silex.html
Puntos
débiles
i18n   Depuración

ORM    Documentación

ESI
i18n (internacionalización)
• Fácil traducir contenidos
  {{ "Hola Mundo"|trans }}
• No es cómodo traducir rutas y
  contenidos de la base de datos.
ORM
• No hay soporte oficial del ORM
 completo (Doctrine2).
• No hay ORM alternativos ligeros.
• Si tu aplicación necesita un ORM,
 puede ser demasiado grande para
 Silex.
Depuración
// activar el modo debug
$app['debug'] = true;

// activar el log
use SilexProviderMonologServiceProvider;

$app->register(new MonologServiceProvider(),
array(
    'monolog.logfile' => __DIR__.'/../logs/dev.log',
));
Mensajes de error
Silex, desarrollo web ágil y profesional con PHP
ESI
• Silex incluye soporte de ESI.
• Su uso es bastante incómodo
  (comparado con Symfony2).
Documentación
• Todas las características de Silex
  están documentadas.
• No es tan abundante como la de
  Symfony2.
Documentación
• Oficial
  silex.sensiolabs.org/documentation
• Traducción
  librosweb.es/silex
Conclusiones
Conclusiones
• Silex es un microframework, pero no es
  un juguete.
Conclusiones
• Silex es un microframework, pero no es
  un juguete.
• Silex sirve para cualquier aplicación
  web que no sea enorme.
Conclusiones
• Silex es un microframework, pero no es
  un juguete.
• Silex sirve para cualquier aplicación
  web que no sea enorme.
• Silex reduce a “horas” el tiempo de
  desarrollo de aplicaciones enteras.
Conclusiones
• Silex es un microframework, pero no es
  un juguete.
• Silex sirve para cualquier aplicación
  web que no sea enorme.
• Silex reduce a “horas” el tiempo de
  desarrollo de aplicaciones enteras.
• Silex combina la agilidad de PHP con la
  profesionalidad de Symfony.
GRACIAS.
Contacto
         • javier.eguiluz@gmail.com
         • twitter.com/javiereguiluz
         • github.com/javiereguiluz
         • linkedin.com/in/javiereguiluz



domingo, 27 de enero de 13

Más contenido relacionado

Silex, desarrollo web ágil y profesional con PHP