Top Banner
organizan patrocinan colaboran Jornadas Symfony 5 y 6 de julio 2010 Universitat Jaume I, Castellón http://decharlas.uji.es/symfony
42

34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Nov 13, 2014

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

organizan patrocinan

colaboran

Jornadas Symfony 5 y 6 de julio 2010Universitat Jaume I, Castellón

http://decharlas.uji.es/symfony

Page 2: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

DoctrineNacho Martín

Jornadas Symfony 5 y 6 de julio 2010Universitat Jaume I, Castellón

http://decharlas.uji.es/symfony

Page 3: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

¿Qué es Doctrine?

● Object Relational Mapper hecho para PHP >=5.2.3 (Doctrine 2.0 PHP >5.3)

● Basado en Hibernate (Java)

● ¿Y Propel?

Page 4: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Componentes

Page 5: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Activación//config/ProjectConfiguration.class.phppublic function setup(){ $this->enablePlugins(array('sfDoctrinePlugin')); $this->disablePlugins(array('sfPropelPlugin'));}

#config/databases.ymlall: doctrine: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=midb' username: usuario password: secreto

Page 6: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Una aplicación de ejemplo

● Lista ToDo

● Con items (one-many)

● Y tags (many-many)

Page 7: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

El esquema YAMLTodo: actAs: Timestampable: ~ columns: name: { type: string(255), notnull: true} description: { type: string(1024) } relations: Tags: { class: Tag, refClass: TodoTag, local: todo_id, foreign: tag_id, foreignAlias: Todos}

Item: actAs: Timestampable: ~ columns: name: { type: string(255) } text: { type: string(4000) } todo_id: { type: integer, notnull: true } relations: Todo: { class: Todo, onDelete: CASCADE, local: todo_id, foreign: id, foreignAlias: items } TodoTag: columns: tag_id: { type: integer, primary: true } todo_id: { type: integer, primary: true } relations: Tag: { onDelete: CASCADE, local: tag_id, foreign: id } Todo: { onDelete: CASCADE, local: todo_id, foreign: id }

Tag: columns: name: { type: string(255) }

4

Page 8: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

El modelo (columnas)abstract class BaseTodo extends sfDoctrineRecord{ public function setTableDefinition() { $this->setTableName('todo'); $this->hasColumn('name', 'string', 255, array( 'type' => 'string', 'notnull' => true, 'length' => '255', )); $this->hasColumn('description', 'string', 1024, array( 'type' => 'string', 'length' => '1024', )); }

Page 9: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

El modelo (relaciones) public function setUp() { parent::setUp(); $this->hasMany('Tag as Tags', array( 'refClass' => 'TodoTag', 'local' => 'todo_id', 'foreign' => 'tag_id'));

$this->hasMany('Item as items', array( 'local' => 'id', 'foreign' => 'todo_id'));

$this->hasMany('TodoTag', array( 'local' => 'id', 'foreign' => 'tag_id'));

//Behaviour $timestampable0 = new Doctrine_Template_Timestampable(); $this->actAs($timestampable0); }}

Page 10: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Fixtures (Doctrine 1)Todo: denver: name: Cosas que hacer en Denver description: Cuando hayamos muerto

Item: gambas: name: Comer gambas Todo: denver gangsters: name: Cosas de gangsters Todo: denver

Tag: turismo: name: Turismo gangsteril Todos: [denver]

Page 11: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

DQL

● Simplifica SQL y es portable

● Incorpora POO a SQL

Page 12: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

DQL

SELECT t.id AS t__id, t.name AS t__name, t.description AS t__description, t.created_at AS t__created_at, t.updated_at AS t__updated_at, i.id AS i__id, i.name AS i__name, t2.id AS t2__id, t2.name AS t2__name FROM todo t INNER JOIN item i ON t.id = i.todo_id LEFT JOIN todo_tag t3 ON (t.id = t3.todo_id) LEFT JOIN tag t2 ON t2.id = t3.tag_id

$q = Doctrine_Query::create() ->select('l.*, i.name, t.name') ->from('Todo l') ->innerJoin('l.Items i') ->leftJoin('l.Tags t');echo $q->getSqlQuery();

Page 13: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Objetos

$list = new Todo();

//Manipulación$list->name = "Cosas que hacer en Denver";$list['name'] = "Cosas que hacer en Denver";$list->set('name', "Cosas que hacer en Denver");

//Accesoecho $list->name;echo $list['name']; //Recomendado (hidratación)echo $list->get('name');

Métodos de acceso y manipulación

123

123

Page 14: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Hidratación (I)

● En objetos● En arrays (más rápido)● Scalar● Single Scalar● Bajo demanda● …

¿No es suficiente?¡Escribe el tuyo!

Page 15: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Hidratación (II) $q = Doctrine_Query::create() ->from('Todo l') ->innerJoin('l.Items i');

$lists = $q->execute(); //Record echo $lists[0]['name'];

Page 16: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Hidratación (II)Array( [0] => Array ( [id] => 1 [name] => Cosas que hacer en Denver [description] => Cuando hayamos muerto [created_at] => 2010-06-22 23:55:02 [updated_at] => 2010-06-22 23:55:02 [Items] => Array ( [0] => Array ( [id] => 1 [name] => Comer gambas [text] => [todo_id] => 1 [created_at] => 2010-06-22 23:55:02 [updated_at] => 2010-06-22 23:55:02 )

[1] => Array ( … ) ) ))

$q = Doctrine_Query::create() ->from('Todo l') ->innerJoin('l.Items i');

$lists = $q->execute(); //Record echo $lists[0]['name']; $lists = $q->fetchArray(); //Array echo $lists[0]['name']; //O bien $q->execute(array(), Doctrine::HYDRATE_ARRAY); print_r($lists);

Page 17: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Hidratación (III)

● El acceso por arrays funciona en los dos métodos de hidratación● La hidratación por arrays es más eficiente si solo queremos consultar datos directos de la BD● fetchArray() es un alias de execute() con la hidratación por array● Uso de foreach, count(), isset(), unset()

Page 18: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Definiendo setters/gettersclass Todo extends BaseTodo{ //Nuevo getter public function getDescriptionHtml() { return Markdown::parse(htmlspecialchars( $this->description)); }

//Sobrecarga del setter public function setDescription($description) { return $this->_set('description', Markdown::parse(htmlspecialchars($description))); }}

Page 19: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Relaciones $list = new Todo(); $list['name'] = "Libros para este verano"; $list->Items[]->name = "Hablemos de Langostas"; $list->save();

//Usando link() $item = new Item(); $item['name'] = "La broma infinita"; $item->link('Todo',array($list['id'])); $item->save(); //Borrar $list->Items[0]->delete(); //Siempre nos quedará DQL $q = Doctrine_Query::create() ->delete('Item') ->addWhere('todo_id = ?', $list['id']) ->whereIn('name', array($item['name'], 'otro nombre')); $q->execute();

●Las relaciones son intuitivas

●Siempre podemos recurrir a DQL

●Pero en DQL no se ejecutarán preDelete(), postDelete()... (!)

Page 20: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Many to many$q = Doctrine_Query::create() ->from('Todo l') ->leftJoin('l.TodoTag tt') ->leftJoin('tt.Tag t');print_r($q->fetchArray());

//Equivalente$q = Doctrine_Query::create() ->from('Todo l') ->leftJoin('l.Tags t');print_r($q->fetchArray());

Array( [0] => Array ( [id] => 27 [name] => Cosas que hacer en Denver [description] => Cuando hayamos muerto [created_at] => 2010-06-23 20:35:41 [updated_at] => 2010-06-23 20:35:41 [TodoTag] => Array ( [0] => Array ( [tag_id] => 2 [todo_id] => 27 [Tag] => Array ( [id] => 2 [name] => Turismo ) ) ) ))

● Podemos olvidarnos “ ”de la tabla intermedia

Page 21: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Mucha tela que cortar● Behaviours● Validadores● Migraciones● Herencia● Caché● Event listeners● …

Page 22: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Mucha tela que cortar● Behaviours● Validadores● Migraciones● Herencia● Caché● Event listeners● …

Mucha tela que cortar

¿Pero y Doctrine2?Veamos Doctrine2

Page 23: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Doctrine2

● Reescritura completa del código para PHP 5.3● Mejoras importantes de rendimiento● Menos magia● Caché mejorada● Entidades

Page 24: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Entidades (I)<?php

namespace Entities;

/** @Entity @Table(name="usuarios") */class Usuario{ /** * @Id @Column(type="integer") * @GeneratedValue(strategy="AUTO") */ private $id; /** @Column(type="string", length=50) */ private $nombre; /** * @OneToOne(targetEntity="Direccion") * @JoinColumn(name="direccion_id", referencedColumnName="id") */ private $direccion;

DocBlock Annotations

Page 25: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Entidades (II) public function getId() { return $this->id; }

public function getNombre() { return $this->nombre; }

public function setNombre($nombre) { $this->nombre = $nombre; }

public function getDireccion() { return $this->direccion; }

public function setDireccion(Direccion $direccion) { if ($this->direccion !== $direccion) { $this->direccion = $direccion; $direccion->setUsuario($this); } }}

Page 26: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Entidades (III)● No descienden de ninguna clase, están separadas del ORM, aunque mapeadas “ ”

por él● Menos magia. Es más fácil entender qué está pasando● Más rápidas● Herencia● Gestionadas por el Entity Manager● Sí, se pueden escribir en YAML y XML ;)

Page 27: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Fixtures$em = $this->getEntityManager(); $user1 = new \Models\Usuario();$user1->nombre = 'Nacho';

● Adiós al YAML. Se escriben en PHP● ¿Por qué?

● Es más rápido cargarlas● El código para tratar fixtures en YAML introdujo muchos bugs en el pasado

Page 28: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

persist() y flush()$user = new \Entities\Usuario;$user->setNombre('Nacho');$entitymanager->persist($user);$entitymanager->flush();

● Atención al uso de espacios de nombre● Persist marca el objeto para guardar“ ”● Flush ejecuta la unidad de trabajo

Page 29: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Rendimiento (I)for ($i=0; $i<1000; $i++){ $user = new \Entities\Usuario; $user->setNombre('Nacho'); $em->persist($user);}$inicio = microtime(true);$em->flush();$final = microtime(true);echo $final-$inicio."\n";

//////////////////////////$inicio = microtime(true);for ($i=0; $i<1000; $i++){ mysql_query("INSERT INTO usuarios (nombre) VALUES ('Nacho')", $link);}$final = microtime(true);echo $final-$inicio."\n";

0.377s

41.4s

Page 30: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Rendimiento (II)● Doctrine2 gestiona las transacciones por nosotros● Así que es más rápido que código PHP+SQL mal optimizado● (Por supuesto usar transacciones en PHP+SQL es más rápido que Doctrine2)● También podemos controlar las transacciones nosotros

Page 31: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Eventos Lifecycle● pre/postRemove● pre/postPersist● pre/postUpdate● postLoad : carga desde BD● loadClassMetadata : carga desde metadatos (annotations, yaml, xml)● onFlush

/** @Entity @HasLifecycleCallbacks */class Usuario{ //(...) /** @PostPersist */ public function doAlgoOnPostPersist() { $this->nombre = 'Me han cambiado en el postpersist'; }

Page 32: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Behaviours (I)En Doctrine2 son código normal de PHP que

extiende la funcionalidad base de las entidades/** @HasLifecycleCallbacks */class BlogPost{ //(...) public function __construct() { $this->created = $this->updated = new DateTime("now"); }

/** * @PreUpdate */ public function updated() { $this->updated = new DateTime("now"); }}

Page 33: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Behaviours (II)¿Pero cómo hacer el código reutilizable entre

entidades?Usando interfaces, eventos y código PHP

orientado a objetos

http://github.com/guilhermeblanco/Doctrine2-Sluggable-Functional-Behavior

http://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior http://www.doctrine-project.org/blog/doctrine2-versionable

Ejemplos:

Page 34: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (I)Hacen el esquema versionable

BD (antes) BD (después)

Esquema Fichero demigración

Page 35: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (I)Hacen el esquema versionable

BD (antes) BD (después)

Esquema

Comparar

Fichero demigración

Page 36: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (I)Hacen el esquema versionable

BD (antes) BD (después)

Esquema

Comparar

Fichero demigración

Generar

Page 37: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (I)Hacen el esquema versionable

BD (antes) BD (después)

Esquema

Comparar

Fichero demigración

Generar

Page 38: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (I)Hacen el esquema versionable

BD (antes) BD (después)

Esquema

Comparar

Fichero demigración

Generar

Migrar

Page 39: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (II)Aspecto de un fichero de migración

class Version20100416130401 extends AbstractMigration{ public function up(Schema $schema) { $table = $schema->createTable('users'); $table->addColumn('username', 'string'); $table->addColumn('password', 'string'); }

public function down(Schema $schema) { $schema->dropTable('users'); }}

Page 40: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

Migraciones (III)Gestionadas desde la consola:

● Diff: tras cambiar una entidad, genera la migración necesaria para cambiar la BD● Dry-run: muestra el SQL para cerciorarnos de que es lo que esperamos● Status: muestra en qué estado (versión, migraciones posibles, fecha...) estamos● Migrate: ejecuta la migración (hacia adelante o hacia atrás revertir)→● Write-sql: en lugar de migrar, escribe el SQL a un fichero

Page 41: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

MongoDB (ODM)

● El ODM tiene el mismo aspecto que el ORM (métodos parecidos, Entidad → Documento, EntityManager → DocumentManager,...)

● Mañana hay una charla sobre MongoDB y Symfony ;)

Page 42: 34063724 Doctrine Nacho Martin Jornadas Symfony en Castellon Julio 2010

Jornadas Symfony http://decharlas.uji.es/symfony

¿Preguntas?

Si surgen más tarde ;) :[email protected]

twitter:@nacmartinhttp://nacho-martin.com