ipc2010se doctrine2 enterprise persistence layer for php

79
Doctrine 2 Enterprise Persistence Layer for PHP Guilherme Blanco, Yahoo! quarta-feira, 2 de junho de 2010

Upload: guilherme-blanco

Post on 08-May-2015

6.200 views

Category:

Technology


4 download

DESCRIPTION

Talk given at IPC 2010 Spring Edition at Berlim, Germany

TRANSCRIPT

Page 1: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine 2

Enterprise Persistence Layer for PHP

Guilherme Blanco, Yahoo!

quarta-feira, 2 de junho de 2010

Page 2: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Who am I?

10+ years web developer

Open Source evangelist

Works for Yahoo!

Contributes to... ...Doctrine ...Zend Framework ...Symfony ...PHP etc

Likes to sing and also fish on spare time! =)

quarta-feira, 2 de junho de 2010

Page 3: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Who am I?

http://www.twitter.com/guilhermeblanco

http://www.facebook.com/guilhermeblanco

quarta-feira, 2 de junho de 2010

Page 4: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine 2

quarta-feira, 2 de junho de 2010

Page 5: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine 2

PHP 5.3+

100% code rewritten

Fully namespaced code

quarta-feira, 2 de junho de 2010

Page 6: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine 2

Tools used: phpUnit Unit testing Phing Packaging and distribution Symfony Components

YAMLConsole

Sismo Continuous Integration GIT Source version control JIRA Issue tracking and management Trac Timeline, source code & changeset viewer

quarta-feira, 2 de junho de 2010

Page 7: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine 2

Three main packages: Common

DBAL

ORM

quarta-feira, 2 de junho de 2010

Page 8: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common

[email protected]:doctrine/common.git

Cache Drivers

quarta-feira, 2 de junho de 2010

Page 9: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Cache

Supported Drivers: APCCache

$cacheDriver = new \Doctrine\Common\Cache\ApcCache();

MemcacheCache$memcache = new \Memcache();$memcache->addServer('memcache_host', 11211);

$cacheDriver = new \Doctrine\Common\Cache\MemcacheCache();$cacheDriver->setMemcache($memcache);

XcacheCache$cacheDriver = new \Doctrine\Common\Cache\XcacheCache();

quarta-feira, 2 de junho de 2010

Page 10: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Cache

Cache Drivers Interface:

interface \Doctrine\Common\Cache\Cache {function setNamespace($namespace);function getIds();

function fetch($id);

function contains($id);

function save($id, $data, $lifeTime = 0);

function delete($id);function deleteAll();

function deleteByRegex($regex);function deleteByPrefix($prefix);function deleteBySuffix($suffix);

}

quarta-feira, 2 de junho de 2010

Page 11: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common

[email protected]:doctrine/common.git

Cache Drivers

Class Loader

quarta-feira, 2 de junho de 2010

Page 12: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\ClassLoader

Implements PSR #0 PSR = PHP Standards Recommendation

Technical Interoperability between libraries Symfony, Zend Framework, Doctrine, Agavi, PEAR2/Pyrus,

Lithium, Flow3, Solar, etc

Possible merge in PHP core: SplClassLoader http://wiki.php.net/rfc/splclassloader

quarta-feira, 2 de junho de 2010

Page 13: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\ClassLoader

Usage:

require_once '/path/to/lib/Doctrine/Common/ClassLoader.php';

$doctrineClassLoader = new \Doctrine\Common\ClassLoader( 'Doctrine', '/path/to/lib/Doctrine');

$doctrineClassLoader->register();

quarta-feira, 2 de junho de 2010

Page 14: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common

[email protected]:doctrine/common.git

Cache Drivers

Class Loader

Collections

quarta-feira, 2 de junho de 2010

Page 15: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Collections

Solution inspired in java.util.Collection interface

Plain PHP arrays are hard to manipulate

..but custom array implementations are not compatible with array_* functions

Heavily usage of Closures

User-land SplArray Where are the PHP devs?

quarta-feira, 2 de junho de 2010

Page 16: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common

[email protected]:doctrine/common.git

Cache Drivers

Class Loader

Collections

Lexer

Annotations Parser

quarta-feira, 2 de junho de 2010

Page 17: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Annotations

Java like Annotations

Define metadata information in classes

Reusable and highly extendable

Suppress missing PHP functionality Again, where are the PHP devs? RFC already written: http://wiki.php.net/rfc/annotations

quarta-feira, 2 de junho de 2010

Page 18: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\AnnotationsAnnotations ::= Annotation {[ "*" ]* [Annotation]}*Annotation ::= "@" AnnotationName ["(" [Values] ")"]AnnotationName ::= QualifiedName | SimpleName | AliasedNameQualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleNameAliasedName ::= Alias ":" SimpleNameNameSpacePart ::= identifierSimpleName ::= identifierAlias ::= identifierValues ::= Array | Value {"," Value}*Value ::= PlainValue | FieldAssignmentPlainValue ::= integer | string | float | boolean | Array | AnnotationFieldAssignment ::= FieldName "=" PlainValueFieldName ::= identifierArray ::= "{" ArrayEntry {"," ArrayEntry}* "}"ArrayEntry ::= Value | KeyValuePairKeyValuePair ::= Key "=" PlainValueKey ::= string | integer

quarta-feira, 2 de junho de 2010

Page 19: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Annotations

Creating Annotations classes:

final class \Doctrine\ORM\Mapping\Entity extends \Doctrine\Common\Annotations\Annotation { public $repositoryClass;}

Using Annotations:

namespace MyProject\Entity;

/** * @Entity(repositoryClass="Repository\UserRepository") */class User { // ... }

quarta-feira, 2 de junho de 2010

Page 20: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Annotations

Reading Annotations:

$reader = new \Doctrine\Common\Annotations\AnnotationReader( new \Doctrine\Common\Cache\ArrayCache());$reader->setDefaultAnnotationNamespace( 'Doctrine\ORM\Mapping\\'); $class = new \ReflectionClass('MyProject\Entity\User');$classAnnotations = $reader->getClassAnnotations($class);

echo $classAnnotations['Doctrine\ORM\Mapping\Entity'] ->repositoryClass;

quarta-feira, 2 de junho de 2010

Page 21: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\Common\Annotationsinterface \Doctrine\Common\Annotations\AnnotationReader { function setDefaultAnnotationNamespace($defaultNamespace);

function setAnnotationNamespaceAlias($namespace, $alias);

function getClassAnnotations(\ReflectionClass $class);

function getClassAnnotation(\ReflectionClass $class, $annot);

function getPropertyAnnotations(\ReflectionProperty $property);

function getPropertyAnnotation( \ReflectionProperty $property, $annot );

function getMethodAnnotations(\ReflectionMethod $method);

function getMethodAnnotation(\ReflectionMethod $method, $annot);}

quarta-feira, 2 de junho de 2010

Page 22: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

[email protected]:doctrine/dbal.git

Database Abstraction Layer built at the top of PDO and proprietary drivers

Supported drivers: DB2 Microsoft SQL Server (pdo_sqlsrv & sqlsrv) MySQL PostgreSQL Oracle SQLite

quarta-feira, 2 de junho de 2010

Page 23: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

Improved API for Database introspection and schema management

Hopefully it can be a defacto standard DBAL for PHP 5.3 in the future, like MDB2 for PEAR1

Inspired in ezcDatabase, MDB2 and Zend_Db

Maybe we can make this happen for PEAR2

quarta-feira, 2 de junho de 2010

Page 24: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBALinterface \Doctrine\DBAL\Connection { // Data manipulation API

/* Executes an SQL DELETE statement on a table. */ function delete($tableName, array $identifier);

/* Executes an SQL UPDATE statement on a table. */ function update($tableName, array $data, array $identifier);

/* Inserts a table row with specified data. */ function insert($tableName, array $data);

/* Prepares an SQL statement. Returns a DBAL\Statement */ function prepare($statement);

/* Applies a SQL statement and return # of affected rows. */ function exec($statement);

// ...

quarta-feira, 2 de junho de 2010

Page 25: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL // Transaction API

/* Returns the current transaction nesting level. */ function getTransactionNestingLevel();

/* Executes a function in a transaction. */ function transactional(\Closure $func);

/* Starts a transaction by suspending auto-commit mode. */ function beginTransaction();

/* Commits the current transaction. */ function commit();

/* Cancel any database changes done during current transaction. */ function rollback();

/* Check if current transaction is marked for rollback only. */ function isRollbackOnly();

// ...

quarta-feira, 2 de junho de 2010

Page 26: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL // Data fetching API

/* Executes a SQL query and returns first row as an assoc array. */ function fetchAssoc($statement, array $params = array());

/* Executes a SQL query and returns first row as a numeric array. */ function fetchArray($statement, array $params = array());

/* Executes a SQL query and returns first column value of result. */ function fetchColumn( $statement, array $params = array(), $colnum = 0 );

/* Executes a SQL query and returns the result as an assoc array. */ function fetchAll($sql, array $params = array());}

quarta-feira, 2 de junho de 2010

Page 27: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL\Types

Centralized point to convert values From Database to PHP From PHP to Database

Database agnostic

Accessing specific DB dialect called Platform

Extendable

quarta-feira, 2 de junho de 2010

Page 28: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL\Types

New DataType is just implement an abstract class:interface \Doctrine\DBAL\Types\Type { function convertToDatabaseValue( $value, AbstractPlatform $platform );

function convertToPHPValue( $value, AbstractPlatform $platform );

function getSqlDeclaration( array $fieldDeclaration, AbstractPlatform $platform ); function getName();

function getBindingType();}

quarta-feira, 2 de junho de 2010

Page 29: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBALclass \MyProject\DataTypes\MyObjectType extends \Doctrine\DBAL\Types\Type{ public function getSqlDeclaration( array $fieldDeclaration, AbstractPlatform $platform ) { return $platform->getClobTypeDeclarationSQL($fieldDeclaration); }

public function convertToDatabaseValue( $value, AbstractPlatform $platform ) { return serialize($value); }

public function convertToPHPValue($value, AbstractPlatform $platform) { $value = (is_resource($value)) ? stream_get_contents($value) : $value; return unserialize($value); }

public function getName() { return "my-object"; }}

quarta-feira, 2 de junho de 2010

Page 30: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL\Types

Finally, make Doctrine know about your DataType:\Doctrine\DBAL\Types\Type::addType( "my-object", "\MyProject\DataTypes\MyObjectType");

Then you can use it in your Entities!/** * @Entity * @Table(name="files") */class File { // ...

/** * @Column(type="my-object") */ protected $content;}

quarta-feira, 2 de junho de 2010

Page 31: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

Creating a schema:$platform = $em->getConnection()->getDatabasePlatform();

$schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("users"); $table->addColumn("id", "integer", array("unsigned" => true));$table->addColumn("name", "string", array("length" => 32));$table->setPrimaryKey(array("id"));

// get queries to create this schema.$queries = $schema->toSql($platform);

Array( 0 => 'CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR(32) NOT NULL, PRIMARY KEY("id") )')

quarta-feira, 2 de junho de 2010

Page 32: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

Deleting a schema:// get queries to safely delete the schema.$queries = $schema->toDropSql($platform);

Array( 0 => 'DROP TABLE users')

It does the reverse of what ->toSql() does

quarta-feira, 2 de junho de 2010

Page 33: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

Comparing schemas:$platform = $em->getConnection()->getDatabasePlatform();

$fromSchema = new \Doctrine\DBAL\Schema\Schema();$table = $fromSchema->createTable("users"); $table->addColumn("id", "integer", array("unsigned" => true));$table->addColumn("name", "string", array("length" => 32));$table->setPrimaryKey(array("id"));

quarta-feira, 2 de junho de 2010

Page 34: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

Comparing schemas:$platform = $em->getConnection()->getDatabasePlatform();

$toSchema = new \Doctrine\DBAL\Schema\Schema(); $table = $toSchema->createTable("users"); $table->addColumn("id", "integer", array("unsigned" => true));$table->addColumn("name", "string", array("length" => 32));$table->addColumn("email", "string", array("length" => 255));$table->setPrimaryKey(array("id"));

quarta-feira, 2 de junho de 2010

Page 35: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\DBAL

Comparing schemas:$platform = $em->getConnection()->getDatabasePlatform();

$comparator = new \Doctrine\DBAL\Schema\Comparator(); $schemaDiff = $comparator->compare($fromSchema, $toSchema);

// queries to get from one to another schema.$queries = $schemaDiff->toSql($platform);

Array( 0 => 'ALTER TABLE users ADD email VARCHAR(255) NOT NULL')

quarta-feira, 2 de junho de 2010

Page 36: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Insert Performance

Inserting 20 entries with Doctrine 2:for ($i = 0; $i < 20; $i++) { $user = new User(); $user->name = 'Guilherme Blanco'; $em->persist($user);}

$start = microtime(0);$em->flush();$end = microtime(0);

echo $end - $start;

quarta-feira, 2 de junho de 2010

Page 37: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Insert Performance

Inserting 20 entries with raw PHP code:$start = microtime(0);

for ($i = 0; $i < 20; $i++) { mysql_query( "INSERT INTO users (name) VALUES ('Guilherme Blanco')", $db_link );}

$end = microtime(0);

echo $end - $start;

quarta-feira, 2 de junho de 2010

Page 38: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Insert Performance

We are not kidding here! =PWhich one do you think it is faster? Doctrine 2

Took: 0.0094 seconds PHP code

Took: 0.0165 seconds

WTH?!?! Doctrine 2 is faster than raw PHP? It does a lot less, provides no features, no abstraction! Answer is TRANSACTIONS!

Doctrine 2 manages our transactions and efficiently executes all inserts in a single.

quarta-feira, 2 de junho de 2010

Page 39: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Insert Performance

Doctrine 2 *IS NOT* faster than raw PHP code

Simple developers oversights can cause significant performance problems!

quarta-feira, 2 de junho de 2010

Page 40: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Insert Performance

Inserting 20 entries with raw PHP code (revisited):$start = microtime(0);

mysql_query("START TRANSACTION", $db_link);

for ($i = 0; $i < 20; $i++) { mysql_query( "INSERT INTO users (name) VALUES ('Guilherme Blanco')", $db_link );}

mysql_query("COMMIT", $db_link);

$end = microtime(0);

echo $end - $start;

quarta-feira, 2 de junho de 2010

Page 41: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Insert Performance

Final performance information... Doctrine 2

Took: 0.0094 seconds PHP code

Took: 0.0165 seconds PHP code (revisited)

Took: 0.0028 seconds

You can read more about this on Doctrine Blog http://www.doctrine-project.org/blog/transactions-and-performance

quarta-feira, 2 de junho de 2010

Page 42: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

What have we learned from Doctrine 1? Persistence Layer != Domain Model Focus on our key purpose, the Persistence Layer “You’re doing it wrong!” Kill magic

quarta-feira, 2 de junho de 2010

Page 43: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Performance comparison Hydrating 5000 records

Doctrine 1.2: 4.3 seconds Doctrine 2.0-DEV: 1.4 seconds

Hydrating 10000 records Doctrine 2.0-DEV: 3.5 seconds

Twice records and still faster than Doctrine 1!

quarta-feira, 2 de junho de 2010

Page 44: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Why is it faster? PHP 5.3 optimizations!

30% less resources usage, 20% faster 5.3-DEV (lazy bucket alloc, interned strings, runtime cache),

Doctrine 2 can run 50% faster! Better Hydration algorithm Topological Sorting Slim Entities Killed magic aspects of Doctrine 1

quarta-feira, 2 de junho de 2010

Page 45: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Why kill magic? Eliminate the WTF/minute (WTF factor)

Hard to debug Edge cases are hard to fix Edge cases are hard to workaround

Everything works until you go outside the box

...and magic is slow! I can prove it! __set is ~87% slower than normal set __get is ~150% slower than normal get

quarta-feira, 2 de junho de 2010

Page 46: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

How we kill magic? We call it OOP!

Object Composition Inheritance Aggregation Containment Encapsulation etc

quarta-feira, 2 de junho de 2010

Page 47: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

DataMapper instead of ActiveRecord

Heavily inspired by JSR-317, a.k.a. JPA v2.0

Java... WHAT?!?! #$@&*! PHP still lacks of standards PHP Standards Group can rescue us?!

Final 2.0.0 version expected for September 1st

quarta-feira, 2 de junho de 2010

Page 48: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Entities Regular PHP class Lightweight persistent domain object Do not extend any base class! Cannot be final or contain final methods Two entities in a hierarchy of classes can not map

property with the same name Abstract and concrete classes can be Entities Entities may extend non-entity classes as well as entity

classes Non-entity classes may also extend entity classes

quarta-feira, 2 de junho de 2010

Page 49: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORMnamespace Entity;

/** * @Entity * @Table(name="users") */class User { /** * @Id @GeneratedValue * @Column(type="integer") */ protected $id;

/** * @Column(type="string", length=32) */ protected $name;

// ... getters and setters}

quarta-feira, 2 de junho de 2010

Page 50: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORMEntity\User: type: entity table: users id: id: type: integer generator: strategy: AUTO fields: name: type: string length: 32

quarta-feira, 2 de junho de 2010

Page 51: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM<?xml version="1.0" encoding="UTF-8"?><doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mappinghttp://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> <entity name="Entity\User" table="users"> <id name="id" type="integer"> <generator strategy="AUTO"/> </id> <field name="name" type="string" length="50"/> </entity></doctrine-mapping>

quarta-feira, 2 de junho de 2010

Page 52: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Column mapping type length scale, precision nullable unique name (DB) options columnDefinition

/** * @Column(type="string", length=32, unique=true) */protected $foo;

quarta-feira, 2 de junho de 2010

Page 53: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Identifier fields Supports different strategies:

AUTO SEQUENCE TABLE NONE

/** * @Id @GeneratedValue(strategy="AUTO") * @Column(type="integer") */protected $id;

quarta-feira, 2 de junho de 2010

Page 54: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Association fields OneToOne

/** @OneToOne(targetEntity="Shipping") */private $shipping;

OneToMany ManyToOne ManyToMany

/** * @ManyToMany(targetEntity="Group") * @JoinTable(name="users_groups", joinColumns={ * @JoinColumn(name="user_id", referencedColumnName="id") * }, inverseJoinColumns={ * @JoinColumn(name="group_id", referencedColumnName="id") * }) */private $groups;

quarta-feira, 2 de junho de 2010

Page 55: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Inheritance Concrete Table Inheritance

No irrelevant columns No locking problems

Difficult to deal with Primary Keys No relations in base class Search on superclass means search in all tables (too much

queries or a weird join) Refactoring of fields means update a few or all table

quarta-feira, 2 de junho de 2010

Page 56: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM/** @MappedSuperclass */class MappedSuperclassBase { /** @Column(type="string") */ protected $mapped;

/** * @OneToOne(targetEntity="MappedSuperclassRelated") * @JoinColumn(name="related_id", referencedColumnName="id") */ protected $related;}

/** @Entity @Table(name="users") */class User extends MappedSuperclassBase { /** @Id @Column(type="integer") */ protected $id;

/** @Column(type="string", length=32) */ protected $name;}

quarta-feira, 2 de junho de 2010

Page 57: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORMCREATE TABLE users ( mapped TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related_id INTEGER DEFAULT NULL, PRIMARY KEY(id));

quarta-feira, 2 de junho de 2010

Page 58: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Inheritance Single Table Inheritance

Only one table on database No joins Refactoring of fields do not change DB schema

Waste of space on database Too many locks due to many accesses No duplicated name of fields with different meaning

quarta-feira, 2 de junho de 2010

Page 59: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORMnamespace MyProject\Entity;

/** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "user" = "User", "employee" = "Employee" * }) */class User { // ...}

/** @Entity */class Employee extends User { // ...}

quarta-feira, 2 de junho de 2010

Page 60: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Inheritance Class Table Inheritance

Easy to understand DB space is optimized due to normalization Direct relationship between Domain Model and database

Too many joins Refactoring of fields need a database schema update Supertype table accessed a lot, may be in lock mode

quarta-feira, 2 de junho de 2010

Page 61: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORMnamespace MyProject\Entity;

/** * @Entity * @InheritanceType("JOINED") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "user" = "User", "employee" = "Employee" * }) */class User { // ...}

/** @Entity */class Employee extends User { // ...}

quarta-feira, 2 de junho de 2010

Page 62: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Proxies Lazy-load Entity data Provide the possibility to get an Entity reference

without database access Can be generated on-the-fly (during script execution)

or via a Console tool

$proxyUser = $em->getReference("User", 1);

quarta-feira, 2 de junho de 2010

Page 63: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

EntityManager Central point of ORM functionality Employes Transaction Write Behind strategy that

delays executions of SQL statements ...this means, efficiency! ...and also means that write locks are quickly released!

Internally, it uses a UnitOfWork to keep track of your objects state

quarta-feira, 2 de junho de 2010

Page 64: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORMinterface \Doctrine\ORM\EntityManager { // Transaction API

/* Starts a transaction on the underlying database connection. */ function beginTransaction();

/* Commits a transaction on underlying database connection. */ function commit();

/* Flushes all changes to queued objects to the database. */ function flush();

/* Performs a rollback on the underlying database connection. */ function rollback();

/* Executes a function in a transaction. */ function transactional(\Closure $func);

// ...

quarta-feira, 2 de junho de 2010

Page 65: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM // Query API

/* Creates a new Query object. */ function createQuery($dql);

/* Creates a native SQL query. */ function createNativeQuery( $sql, \Doctrine\ORM\Query\ResultSetMapping $rsm );

/* Create a QueryBuilder instance. */ function createQueryBuilder();

/* Finds an Entity by its identifier. */ function find($entityName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null);

/* Gets a reference to the entity identified by the given type and identifier without actually loading it. */ function getReference($entityName, $identifier);

// ...quarta-feira, 2 de junho de 2010

Page 66: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM // Object Manipulation API

/* Tells EntityManager to make instance managed and persistent. */ function persist($entity);

/* Removes an entity instance. */ function remove($entity);

/* Refresh state of entity from database, overrides changes. */ function refresh($entity);

/* Detaches an entity from the EntityManager. */ function detach($entity);

/* Merges state of detached entity into persistence context. */ function merge($entity);

// ...

quarta-feira, 2 de junho de 2010

Page 67: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM // Repository, Configuration, EventManager, etc

/* Gets the EventManager used by the EntityManager. */ function getEventManager();

/* Gets the Configuration used by the EntityManager. */ function getConfiguration();

/* Gets the repository for an entity class. */ function getRepository($entityName);

/* Returns the metadata for a class. */ function getClassMetadata($className);

/* Gets database connection object used by the EntityManager. */ function getConnection();}

quarta-feira, 2 de junho de 2010

Page 68: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Working with Entities in EntityManager Creating an EntityManager

$config = new \Doctrine\ORM\Configuration();

$config->setMetadataCacheImpl($cacheDriver);$config->setQueryCacheImpl($cacheDriver);

$config->setProxyDir("/path/to/MyProject/Proxies");$config->setProxyNamespace("MyProject\Proxies");

$connectionOptions = array( "driver" => "pdo_sqlite", "path" => "database.sqlite");

// Creating the EntityManager$em = \Doctrine\ORM\EntityManager::create( $connectionOptions, $config);

quarta-feira, 2 de junho de 2010

Page 69: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Working with Entities in EntityManager Persisting Entities

try { $em->transactional(function ($em) { $user = new \MyProject\Entity\User(); $user->name = "Guilherme Blanco";

$em->persist($user); });} catch (\Exception $e) { // ...}

quarta-feira, 2 de junho de 2010

Page 70: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Working with Entities in EntityManager Updating Entities

try { $em->transactional(function ($em) { $user = $em->find("MyProject\Entity\User", 1); $user->name = "Benjamin Eberlei";

$em->persist($user); });} catch (\Exception $e) { // ...}

quarta-feira, 2 de junho de 2010

Page 71: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Working with Entities in EntityManager Deleting Entities

try { $em->transactional(function ($em) { $user = $em->getReference("MyProject\Entity\User", 1); $em->remove($user); });} catch (\Exception $e) { // ...}

quarta-feira, 2 de junho de 2010

Page 72: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Doctrine Query Language (DQL) Implementation of an OQL Heavily influenced by Hibernate QL Parsed by a top-down recursive descent parser LL(*),

constructing an abstract syntax tree (AST) AST is then used to generate vendor dependent SQL

$query = $em->createQuery( "SELECT u FROM MyProject\Entity\User u");$users = $query->execute();

quarta-feira, 2 de junho de 2010

Page 73: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Native Query Allow you the possibility to fallback to the power of

SQL without losing the ability to hydrate the data to your Entities

$rsm = new \Doctrine\ORM\Query\ResultSetMapping();$rsm->addEntityResult("MyProject\Entity\User", "u");$rsm->addFieldResult("u", "id", "id");$rsm->addFieldResult("u", "name", "name");

$query = $em->createNativeQuery( "SELECT id, name FROM users WHERE username = ?", $rsm);$query->setParameter(1, "guilhermeblanco");

$users = $query->getResult();

quarta-feira, 2 de junho de 2010

Page 74: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

QueryBuilder Builder implementation Building and execution are separated QueryBuilder cannot be executed; instead, get the

Query instance from it and execute

$qb = $em->createQueryBuilder() ->select("u") ->from("MyProject\Entity\User", "u");$users = $qb->getQuery()->execute();

quarta-feira, 2 de junho de 2010

Page 75: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Doctrine supports different cache levels Metadata cache

$config->setMetadataCacheImpl($cacheDriver);

Query cache$config->setQueryCacheImpl($cacheDriver);

Result cache$config->setResultCacheImpl($cacheDriver);

$query = $em->createQuery( "SELECT u FROM MyProject\Entity\User u");$query->useResultCache(true, 3600, "my_custom_name");

quarta-feira, 2 de junho de 2010

Page 76: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Console Uses Symfony 2 Console component Help developing with Doctrine Tasks available in all packages

$helperSet = $cli->getHelperSet();$helperSet->set( new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper( $em->getConnection() ), 'db');$helperSet->set( new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper( $em ), 'em');

$cli->addCommands(array(...));

quarta-feira, 2 de junho de 2010

Page 77: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Doctrine\ORM

Available Commands: \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand \Doctrine\DBAL\Tools\Console\Command\ImportCommand \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand \Doctrine\ORM\Tools\Console\Command\RunDqlCommand

quarta-feira, 2 de junho de 2010

Page 78: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Future

DBAL QueryBuilder Finish MSSQL Server driver

DQL Support for TYPE() Add multiple FROM Entities support Embedded Values

ODM Extract DocumentManager interface Stabilize the MongoDB driver Implement other drivers (CouchDB, SimpleDB, ...)

quarta-feira, 2 de junho de 2010

Page 79: IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

Questions?

Guilherme Blanco Contact Info:

@guilhermeblanco

[email protected]

http://www.facebook.com/guilhermeblanco

+55 16 9215.8480

THANK YOU FOR YOUR PATIENCE!!! =)

quarta-feira, 2 de junho de 2010