• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
ORM Doctrine
 

ORM Doctrine

on

  • 2,771 views

 

Statistics

Views

Total Views
2,771
Views on SlideShare
2,769
Embed Views
2

Actions

Likes
1
Downloads
101
Comments
0

1 Embed 2

http://www.sfexception.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    ORM Doctrine ORM Doctrine Presentation Transcript

    • Jornadas Symfony 5 y 6 de julio 2010 Universitat Jaume I, Castellón http://decharlas.uji.es/symfony organizan patrocinan colaboran
    • Doctrine Nacho Martín 5 y 6 de julio 2010 Jornadas Symfony Universitat Jaume I, Castellón 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? Jornadas Symfony http://decharlas.uji.es/symfony
    • Componentes Jornadas Symfony http://decharlas.uji.es/symfony
    • Activación //config/ProjectConfiguration.class.php public function setup() { $this->enablePlugins(array('sfDoctrinePlugin')); $this->disablePlugins(array('sfPropelPlugin')); } #config/databases.yml all: doctrine: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=midb' username: usuario password: secreto Jornadas Symfony http://decharlas.uji.es/symfony
    • Una aplicación de ejemplo ● Lista ToDo ● Con items (one-many) ● Y tags (many-many) Jornadas Symfony http://decharlas.uji.es/symfony
    • El esquema YAML Todo: 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) } 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', )); } 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); } } 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] Jornadas Symfony http://decharlas.uji.es/symfony
    • DQL ● Simplifica SQL y es portable ● Incorpora POO a SQL Jornadas Symfony http://decharlas.uji.es/symfony
    • DQL $q = Doctrine_Query::create() ->select('l.*, i.name, t.name') ->from('Todo l') ->innerJoin('l.Items i') ->leftJoin('l.Tags t'); echo $q->getSqlQuery(); 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 Jornadas Symfony http://decharlas.uji.es/symfony
    • Objetos Métodos de acceso y manipulación $list = new Todo(); //Manipulación 1 $list->name = "Cosas que hacer en Denver"; 2 $list['name'] = "Cosas que hacer en Denver"; 3 $list->set('name', "Cosas que hacer en Denver"); //Acceso 1 echo $list->name; 2 echo $list['name']; //Recomendado (hidratación) 3 echo $list->get('name'); 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! 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']; Jornadas Symfony http://decharlas.uji.es/symfony
    • Hidratación (II) Array $q = Doctrine_Query::create() ( ->from('Todo l') [0] => Array ( ->innerJoin('l.Items i'); [id] => 1 [name] => Cosas que hacer en Denver $lists = $q->execute(); //Record [description] => Cuando hayamos muerto echo $lists[0]['name']; [created_at] => 2010-06-22 23:55:02 [updated_at] => 2010-06-22 23:55:02 [Items] => Array $lists = $q->fetchArray(); //Array ( echo $lists[0]['name']; [0] => Array //O bien $q->execute(array(), ( Doctrine::HYDRATE_ARRAY); [id] => 1 [name] => Comer gambas print_r($lists); [text] => [todo_id] => 1 [created_at] => 2010-06-22 23:55:02 [updated_at] => 2010-06-22 23:55:02 ) [1] => Array (…) ) ) ) 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() Jornadas Symfony http://decharlas.uji.es/symfony
    • Definiendo setters/getters class 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))); } } 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() ● Las relaciones son $item = new Item(); intuitivas $item['name'] = "La broma infinita"; $item->link('Todo',array($list['id'])); ● Siempre podemos recurrir $item->save(); a DQL //Borrar $list->Items[0]->delete(); ● Pero en DQL no se //Siempre nos quedará DQL ejecutarán preDelete(), $q = Doctrine_Query::create() postDelete()... (!) ->delete('Item') ->addWhere('todo_id = ?', $list['id']) ->whereIn('name', array($item['name'], 'otro nombre')); $q->execute(); Jornadas Symfony http://decharlas.uji.es/symfony
    • Many to many Array $q = Doctrine_Query::create() ( [0] => Array ->from('Todo l') ( ->leftJoin('l.TodoTag tt') [id] => 27 ->leftJoin('tt.Tag t'); [name] => Cosas que hacer en Denver print_r($q->fetchArray()); [description] => Cuando hayamos muerto [created_at] => 2010-06-23 20:35:41 //Equivalente [updated_at] => 2010-06-23 20:35:41 $q = Doctrine_Query::create() [TodoTag] => Array ->from('Todo l') ( ->leftJoin('l.Tags t'); [0] => Array print_r($q->fetchArray()); ( [tag_id] => 2 [todo_id] => 27 ● Podemos “olvidarnos” [Tag] => Array ( de la tabla intermedia [id] => 2 [name] => Turismo ) ) ) ) ) Jornadas Symfony http://decharlas.uji.es/symfony
    • Mucha tela que cortar ● Behaviours ● Validadores ● Migraciones ● Herencia ● Caché ● Event listeners ● … Jornadas Symfony http://decharlas.uji.es/symfony
    • Mucha tela que cortar ● Behaviours ● Validadores ● Migraciones ● Herencia ● Caché ● Event listeners ● … ¿Pero y Doctrine2? Veamos Doctrine2 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 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 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); } } } 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 ;) Jornadas Symfony http://decharlas.uji.es/symfony
    • Fixtures $em = $this->getEntityManager(); $user1 = new ModelsUsuario(); $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 Jornadas Symfony http://decharlas.uji.es/symfony
    • persist() y flush() $user = new EntitiesUsuario; $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 Jornadas Symfony http://decharlas.uji.es/symfony
    • Rendimiento (I) for ($i=0; $i<1000; $i++){ $user = new EntitiesUsuario; $user->setNombre('Nacho'); $em->persist($user); } $inicio = microtime(true); $em->flush(); $final = microtime(true); echo $final-$inicio."n"; 0.377s ////////////////////////// $inicio = microtime(true); for ($i=0; $i<1000; $i++){ mysql_query("INSERT INTO usuarios (nombre) VALUES ('Nacho')", $link); } 41.4s $final = microtime(true); echo $final-$inicio."n"; 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 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'; } 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"); } } 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 Ejemplos: http://github.com/guilhermeblanco/Doctrine2-Sluggable-Functional-Behavior http://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior http://www.doctrine-project.org/blog/doctrine2-versionable Jornadas Symfony http://decharlas.uji.es/symfony
    • Migraciones (I) Hacen el esquema versionable BD (antes) BD (después) Esquema Fichero de migración Jornadas Symfony http://decharlas.uji.es/symfony
    • Migraciones (I) Hacen el esquema versionable BD (antes) BD (después) Comparar Esquema Fichero de migración Jornadas Symfony http://decharlas.uji.es/symfony
    • Migraciones (I) Hacen el esquema versionable BD (antes) BD (después) Comparar Generar Esquema Fichero de migración Jornadas Symfony http://decharlas.uji.es/symfony
    • Migraciones (I) Hacen el esquema versionable BD (antes) BD (después) Comparar Generar Esquema Fichero de migración Jornadas Symfony http://decharlas.uji.es/symfony
    • Migraciones (I) Hacen el esquema versionable Migrar BD (antes) BD (después) Comparar Generar Esquema Fichero de migración 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'); } } 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 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 ;) Jornadas Symfony http://decharlas.uji.es/symfony
    • ¿Preguntas? Si surgen más tarde ;) : nitram.ohcan@gmail.com twitter:@nacmartin http://nacho-martin.com Jornadas Symfony http://decharlas.uji.es/symfony