Citation preview

Frameworks de desarrollo

Symfony Clase 1

Javier Eguíluz [email protected]

Esta obra dispone de una licencia de tipo Creative Commons Reconocimiento‐No comercial‐ Compartir  bajo la misma licencia 3.0 

Se prohíbe explícitamente el uso de este material en  actividades de formación comerciales http://creativecommons.org/licenses/by‐nc‐sa/3.0/es/

This work is licensed under a Creative Commons Attribution‐Noncommercial‐Share Alike 3.0 

The use of these slides in commercial courses or trainings is explicitly prohibited http://creativecommons.org/licenses/by‐nc‐sa/3.0/es/

Capítulo 1

Comenzando el  proyecto

¿Qué es  Symfony?

Framework para el  desarrollo de aplicaciones  web con PHP

• El más profesional • El más documentado • El mejor

PHP      Frameworks Productividad Calidad programación Mantenimiento Rendimiento aplicación

aprendizaje

Curva de aprendizaje  de Symfony

tiempo

¿Qué es Jobeet?

diciembre 2008 1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

La mejor forma de aprender  Symfony 1.2 a través de 24 tutoriales de 1 hora

Un tutorial diferente

• Serio • Profesional • Completo

Prerrequisitos

5.2.4

Instalación de  Symfony

http://www.symfony‐project.org/installation/1_2

symfony‐1.2.4.tgz

check_configuration.php

$ php lib/vendor/symfony/data/bin/symfony

Preparar el  proyecto

frontend

backend

proyecto aplicación

jobeet

frontend

backend

$ symfony generate:project jobeet

apps/

log/

cache/

plugins/

config/

test/

lib/

web/

$ symfony generate:app jobeet ‐‐escaping‐strategy=on ‐‐csrf‐secret=UniqueSecret

frontend

frontend/ config/ lib/ modules/ templates/

‐‐escaping‐strategy

‐‐csrf‐secret

XSS CSRF

config/ProjectConfiguration.class.php

require_once dirname(__FILE__). '/../lib/vendor/'. 'symfony/lib/autoload/'. 'sfCoreAutoload.class.php';

Los entornos

• Entorno de desarrollo (dev) • Entorno de pruebas • Entorno intermedio • Entorno de producción (prod)

Errores en el entorno de desarrollo (dev)

Errores en el entorno de producción (prod)

web/index.php

XML

 



2002‐10‐04     Draw 

2002‐10‐06

White

 

YAML players: Vladimir Kramnik: &kramnik rating: 2700 status: GM Deep Fritz: &fritz rating: 2700 status: Computer David Mertz: &mertz rating: 1400 status: Amateur matches: ‐ Date: 2002‐10‐04 White: *fritz Black: *kramnik Result: Draw ‐ Date: 2002‐10‐06 White: *kramnik Black: *fritz Result: White

El esquema

config/

schema.yml

propel: jobeet_category: id:   ~ name: { type: varchar(255), required: true, index: unique } jobeet_job: id:           ~ category_id:  { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true } type:         { type: varchar(255) } company:      { type: varchar(255), required: true } logo:         { type: varchar(255) } url:          { type: varchar(255) } position:     { type: varchar(255), required: true } location:     { type: varchar(255), required: true } description:  { type: longvarchar, required: true } how_to_apply: { type: longvarchar, required: true } token:        { type: varchar(255), required: true, index: unique } is_public:    { type: boolean, required: true, default: 1 } is_activated: { type: boolean, required: true, default: 0 } email:        { type: varchar(255), required: true } expires_at:   { type: timestamp, required: true } created_at:   ~ updated_at:   ~ jobeet_affiliate: id:         ~ url:        { type: varchar(255), required: true } email:      { type: varchar(255), required: true, index: unique } token:      { type: varchar(255), required: true } is_active:  { type: boolean, required: true, default: 0 } created_at: ~ jobeet_category_affiliate: category_id:  { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true, primaryKey:  true, onDelete: cascade } affiliate_id: { type: integer, foreignTable: jobeet_affiliate, foreignReference: id, required: true, primaryKey:  true, onDelete: cascade }

config/

schema.yml

propel: jobeet_category: id:   ~ name: { type: varchar(255), required: true, index: unique }

config/

schema.yml

jobeet_job: id:           ~ category_id:  { type: integer, foreignTable: jobeet_category,  foreignReference: id, required: true } type:         { type: varchar(255) } company:      { type: varchar(255), required: true } logo:         { type: varchar(255) } url:          { type: varchar(255) } position:     { type: varchar(255), required: true } location:     { type: varchar(255), required: true } description:  { type: longvarchar, required: true } how_to_apply: { type: longvarchar, required: true } token:        { type: varchar(255), required: true, index:  unique } is_public:    { type: boolean, required: true, default: 1 } is_activated: { type: boolean, required: true, default: 0 } email:        { type: varchar(255), required: true } expires_at:   { type: timestamp, required: true } created_at:   ~ updated_at:   ~

config/

schema.yml

jobeet_affiliate: id:         ~ url:        { type: varchar(255), required: true } email:      { type: varchar(255), required: true, index: unique } token:      { type: varchar(255), required: true } is_active:  { type: boolean, required: true, default: 0 } created_at: ~

config/ jobeet_category_affiliate: category_id:  { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true, primaryKey: true, onDelete: cascade } affiliate_id: { type: integer, foreignTable: jobeet_affiliate, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }

schema.yml

config/



schema.yml

type: boolean, tinyint, smallint, integer, bigint, double, float,  real, decimal, char, varchar(size), longvarchar, date, time,  timestamp, blob, clob



required: true, false



index: true, false



primaryKey: true, false



foreignKey, foreignReference

La base de datos

$ mysqladmin ‐uroot ‐p create jobeet $ symfony configure:database “mysql:host=localhost;dbname=jobeet” root ConTraSenA config/databases.yml

El ORM

$ symfony propel:build‐sql data/sql/ $ symfony propel:insert‐sql ‐‐no‐confirmation $ symfony propel:build‐model lib/model/

• • • •

extends

JobeetJob BaseJobeetJob JobeetJobPeer BaseJobeetJobPeer

extends

$job = new JobeetJob(); $job‐>setPosition('Web developer'); $job‐>save(); echo $job‐>getPosition(); $job‐>delete();

$category = new JobeetCategory();  $category‐>setName('Programming'); $job = new JobeetJob(); $job‐>setCategory($category);

$ symfony propel:build‐all ‐‐no‐confirmation

+

$ symfony propel:build‐sql $ symfony propel:insert‐sql $ symfony propel:build‐model $ symfony propel:build‐forms $ symfony propel:build‐filters

$ symfony propel:build‐all

$ symfony cc Borra la caché de Symfony • Ejecutar siempre que añades  clases (autoload) • La solución de casi todos los  errores de los principiantes •

$ symfony cache:clear $ symfony cache:cl $ symfony ca:c $ symfony cc

Los datos iniciales

data/fixtures/

• • •

Datos iniciales Datos de prueba Datos de usuarios

data/fixtures/

010_categories.yml

JobeetCategory: design:        { name: Design } programming:   { name: Programming } manager:       { name: Manager } administrator: { name: Administrator }

data/fixtures/

020_jobs.yml

JobeetJob: job_sensio_labs: category_id:  programming type:         full‐time company:      Sensio Labs logo:         sensio‐labs.gif url:          http://www.sensiolabs.com/ position:     Web Developer location:     Paris, France description:  | You have already developed websites with symfony and you want to work with Open‐Source technologies. You have a minimum of  3 years experience in web development with PHP or Java and you wish to participate to development of Web 2.0 sites using the best frameworks available. how_to_apply: | Send your resume to fabien.potencier [at] sensio.com is_public:    true is_activated: true token:        job_sensio_labs email:        [email protected] expires_at:   2010‐10‐10

$ symfony propel:data‐load

+

$ symfony propel:build‐sql $ symfony propel:insert‐sql $ symfony propel:build‐model $ symfony propel:build‐forms $ symfony propel:build‐filters $ symfony propel:data‐load

$ symfony propel:build‐all‐load

Probando la  aplicación en el  navegador

proyecto aplicación módulo

jobeet

frontend

job

backend

$ symfony propel:generate‐module ‐‐with‐show ‐‐non‐verbose‐templates

frontend job JobeetJob

frontend/modules/job actions/ templates/

frontend/modules/job/actions/actions.class.php

index

edit

show

update

new

delete

create

http://jobeet.localhost/frontend_dev.php/job

frontend _dev job

Objeto

Categoría

Representación  textual

_ _toString()

lib/model/

JobeetCategory.php

class JobeetCategory extends BaseJobeetCategory { public function __toString() { return $this‐>getName(); } }

lib/model/

class JobeetJob extends BaseJobeetJob { public function __toString() { return sprintf( '%s at %s (%s)', $this‐>getPosition(), $this‐>getCompany(), $this‐>getLocation() ); } }

JobeetJob.php

lib/model/

JobeetAffiliate.php

class JobeetAffiliate extends BaseJobeetAffiliate { public function __toString() { return $this‐>getUrl(); } }

http://jobeet.localhost/frontend_dev.php/job

Capítulo 4

El controlador y  la vista

La arquitectura MVC

¿Cómo se programaba con PHP en  el siglo pasado?

1 página del  sitio web

=

1 archivo PHP  diferente

¿Cómo se programaba con PHP en  el siglo pasado? inicialización y  configuración lógica de  negocio acceso a BBDD generar  código HTML pagina.php

Modelo Vista Controlador

Modelo Directorio /lib/model Vista Directorios templates/ Controlador Archivos index.php y frontend_dev.php Archivos actions.class.php

El layout

patrón de diseño decorator

apps/frontend/templates/layout.php

apps/frontend/templates/

layout.php



Jobeet ‐ Your best job board



...





Plantillas Symfony • Archivos PHP 

normales • Existe un plugin 

para Smarty • Symfony 2.0 podría 

incluir plantillas

Las hojas de estilos,  imágenes y archivos  JavaScript

helpers

...

apps/frontend/config/ default: http_metas: content‐type: text/html metas: #title: symfony project #description: symfony project #keywords: symfony, project #language: en #robots: index, follow stylesheets: [main.css] javascripts: [] has_layout: on layout: layout

view.yml

apps/frontend/config/

view.yml

default: ...

stylesheets:  [main.css, jobs.css, job.css] ...



apps/frontend/config/

view.yml

default: ...

stylesheets:  [main.css, jobs.css, job] ...



apps/frontend/config/

view.yml

default: ...

stylesheets:  [main.css, /css/v2/jobs.css] ...



apps/frontend/config/

view.yml

default: ...

stylesheets: [main.css, jobs: { media: print } ] ...



metas: title: El título 1

Symfony

metas: title: El título 2

Proyecto

metas: title: El título 3

Aplicación

metas: title: El título 4

Módulo

view.yml

Symfony lib/vendor/symfony/lib/config/config/view.yml Proyecto config/view.yml Aplicación apps/frontend/config/view.yml Módulo apps/frontend/modules/job/config/view.yml

metas: stylesheets: [job]

view.yml

plantilla plantilla

La portada del módulo  de las ofertas de  trabajo

apps/ frontend/ modules/ job/ actions/ actions.class.php templates/ indexSuccess.php

acción

=

+ plantilla

http://jobeet.localhost/frontend_dev.php/job/index

frontend (aplicación) _dev (entorno) job (módulo) index (acción executeIndex y  plantilla indexSuccess)

apps/frontend/modules/job/actions/

actions.class.php

class jobActions extends sfActions { public function executeIndex(sfWebRequest $request) { $this‐>jobeet_job_list = JobeetJobPeer::doSelect(new Criteria()); } // ... }

SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]]

apps/frontend/modules/job/templates/

indexSuccess.php

...

...  

La plantilla de la página  de una oferta de  trabajo

Slots

Jobeet

layout

plantilla

             

layout

Título de la página

plantilla

apps/frontend/templates/

layout.php



apps/frontend/modules/job/templates/

indexSuccess.php

   

La acción de la página  de una oferta de  trabajo

apps/frontend/modules/job/actions/

actions.class.php

public function executeShow(sfWebRequest $request) { $this‐>job = JobeetJobPeer::retrieveByPk( $request‐>getParameter('id') ); $this‐>forward404Unless($this‐>job); }

La petición y la  respuesta

objeto sfWebRequest class jobActions extends sfActions { public function executeShow(sfWebRequest { $peticion = $request; $origen = $peticion‐>getReferer(); $metodo = $peticion‐>getMethod(); } // ... }

$request)

Nombre del método

Equivalente de PHP

getMethod()

$_SERVER['REQUEST_METHOD']

getUri()

$_SERVER['REQUEST_URI']

getReferer()

$_SERVER['HTTP_REFERER']

getHost()

$_SERVER['HTTP_HOST']

getLanguages()

$_SERVER['HTTP_ACCEPT_LANGUAGE']

getCharsets()

$_SERVER['HTTP_ACCEPT_CHARSET']

isXmlHttpRequest()

$_SERVER['X_REQUESTD_WITH'] == 'XMLHttpRequest'

getHttpHeader()

$_SERVER

getCookie()

$_COOKIE

isSecure()

$_SERVER['HTTPS']

getFiles()

$_FILES

getGetParameter()

$_GET

getPostParameter()

$_POST

getUrlParameter()

$_SERVER['PATH_INFO']

getRemoteAddress()

$_SERVER['REMOTE_ADDR']

public function executeShow(sfWebRequest $request) { ... $request‐>getParameter('id'); ... }

/ruta1/ruta2/ruta3?id=3&clave1= valor1&clave2=valor2

objeto sfWebResponse class jobActions extends sfActions { public function executeShow(sfWebRequest $request) { $respuesta = $this‐>getResponse(); $respuesta‐>setStatusCode(404); $respuesta‐>addStyleSheet('/css/job.css'); $respuesta‐>setTitle('Título de la página'); } // ... }

archivo de configuración metas: stylesheets: [job]

plantilla

acción $this‐>getResponse()‐> addStyleSheet('/css/job.css');

Capítulo 5

El sistema de  enrutamiento

URL

internet

symfony

URL

URI

sistema de  enrutamiento

URI 'job/show?id='.$job‐>getId()

url_for() URL

job/show/id/1

URI modulo/accion?clave1= valor1&clave2=valor2& ...

Configurando el  enrutamiento

apps/frontend/config/

routing.yml

homepage: url: / param: { module: default, action: index } default_index: url: /:module param: { action: index } default: url: /:module/:action/*

nombre patrón default_index: url: /:module param: { action: index } parámetros

homepage: url: / param: { module: default, action: index } default_index: url: /:module param: { action: index } default: url: /:module/:action/* 

/job

/frontend_dev.php/job

1

entorno

aplicación

¿módulo? 2

???

¿acción?

apps/frontend/config/routing.yml

/job

default_index: url: /:module param: { action: index }

:module = job = módulo

3

apps/frontend/config/routing.yml

default_index: url: /:module param: { action: index }

4

acción = index

/frontend_dev.php/job

aplicación = frontend entorno = dev

módulo = job acción = index

URI

url_for()

URL

url_for('job/show?id='.$job‐>getId()) /job/show/id/1

URI

url_for()

URL

url_for('@default?id='.$job‐>getId())

Personalizando el  enrutamiento

apps/frontend/config/

routing.yml

homepage: url: / param: { module: job, action: index } default_index: url: /:module param: { action: index } default: url: /:module/:action/*