Zend Framework 1 + Doctrine 2

Post on 17-May-2015

35,278 views 4 download

Tags:

description

Ralph Schindler (of Zend Framework) and Jon Wage (of Doctrine) presented these slides for a webinar hosted by zend.com (webinar available online).Links are contained within the slides to the demo application that was also used during the webinar.

transcript

Zend Framework 1 + Doctrine 2

Zend Framework 1 + Doctrine 2

Jonathan H. Wage•PHP Developer for over 10 years•Symfony Contributor•Doctrine Contributor•Published Author•Business Owner•Nashville, TN Resident

•http://www.twitter.com/jwage

•http://www.facebook.com/jwage

2

Zend Framework 1 + Doctrine 2

I work at OpenSky

•What is OpenSky?“a social commerce platform”

•Based in New York and is a major open•source software advocate

•http://www.shopopensky.com

3

Zend Framework 1 + Doctrine 2

OpenSky Technologies•PHP 5.3.2•Apache2•Symfony2•Doctrine2•jQuery•mule, stomp, hornetq•MongoDB•nginx•varnish

4

Zend Framework 1 + Doctrine 2

Ralph Schindler•Software Engineer on the Zend Framework team

At Zend for almost 3 yearsBefore that TippingPoint/3Com

•Programming PHP for 12+ years•Live in New Orleans, LA.

Lived in Austin, Tx for 5 years

•Where To Find Me:http://ralphschindler.comhttp://twitter.com/ralphschindlerhttp://github.com/ralphschindlerralphschindler on freenode

5

Zend Framework 1 + Doctrine 2

Guilherme Blanco•Programming Experience

12+ years web development experience 9 years with PHP

•Software Engineer at Yahoo!•Open Source Evangelist

Contributes regularly to the Doctrine Project, Symfony, and Zend Framework

•Where to find me:http://twitter.com/guilhermeblancohttp://github.com/guilhermeblanco

6

The Doctrine Project

Doctrine 2

7

Zend Framework 1 + Doctrine 2

What is Doctrine?• Open Source PHP Project started in 2006

• Specializes in database functionality

Database Abstraction Layer (DBAL) Database Migrations Object Relational Mapper (DBAL) MongoDB Object Document Manager (ODM) CouchDB Object Document Manager (ODM)

8

Zend Framework 1 + Doctrine 2

Who is on the team?

• Roman S. Borschel

• Guilherme Blanco

• Benjamin Eberlei

• Bulat Shakirzyanov

• Jonathan H. Wage

9

Zend Framework 1 + Doctrine 2

Project History• First commit April 13th 2006• First stable version finished and Released September 1st 2008

• One of the first ORM implementations for PHP• 1.0 is First LTS(long term support) release. Maintained until March 1st 2010

• Integrated with many popular frameworks: Symfony, Zend Framework, Code Igniter

10

Zend Framework 1 + Doctrine 2

Doctrine Libraries• Database Abstraction Layer

• Database Migrations• Object Relational Mapper• MongoDB Object Document Manager• CouchDB Object Document Manager

11

Zend Framework 1 + Doctrine 2

DBALDatabase Abstraction Layer

12

Zend Framework 1 + Doctrine 2

Database Abstraction Layer• The Doctrine Database Abstraction

• Layer (DBAL) is a thin layer on top of• PDO, it offers:

select, update, delete, transactions database schema introspection schema management

13

Zend Framework 1 + Doctrine 2

Can be used standalone

14

Zend Framework 1 + Doctrine 2

Evolved fork of PEAR MDB, MDB2, Zend_Db, etc.

15

Zend Framework 1 + Doctrine 2

Download•You can download a standalone

•package to get started using the DBAL:

http://www.doctrine-project.org/projects/dbal/download

16

Zend Framework 1 + Doctrine 2

Autoloader•To use any Doctrine library you must

•register an autoloader:

use Doctrine\Common\ClassLoader;

require '/path/to/doctrine-common/lib/Doctrine/Common/ClassLoader.php';

$classLoader = new ClassLoader('Doctrine\DBAL', '/path/to/doctrine-dbal/lib');$classLoader->register();

17

Zend Framework 1 + Doctrine 2

Create a Connection

$config = new \Doctrine\DBAL\Configuration();//..$connectionParams = array( 'dbname' => 'mydb', 'user' => 'user', 'password' => 'secret', 'host' => 'localhost', 'driver' => 'pdo_mysql',);$conn = DriverManager::getConnection($connectionParams);

18

Zend Framework 1 + Doctrine 2

Data API• prepare($sql) - Prepare a given sql statement and return the \Doctrine\DBAL\Driver\Statement

instance.

• executeUpdate($sql, array $params) - Executes a prepared statement with the given sql and parameters and returns the affected rows count.

• execute($sql, array $params) - Creates a prepared statement for the given sql and passes the parameters to the execute method, then returning the statement.

• fetchAll($sql, array $params) - Execute the query and fetch all results into an array.

• fetchArray($sql, array $params) - Numeric index retrieval of first result row of the given query.

• fetchBoth($sql, array $params) - Both numeric and assoc column name retrieval of the first result row.

• fetchColumn($sql, array $params, $colnum) - Retrieve only the given column of the first result row.

• fetchRow($sql, array $params) - Retrieve assoc row of the first result row.

• select($sql, $limit, $offset) - Modify the given query with a limit clause.

• delete($tableName, array $identifier) - Delete all rows of a table matching the given identifier, where keys are column names.

• insert($tableName, array $data) - Insert a row into the given table name using the key value pairs of data.

19

Zend Framework 1 + Doctrine 2

Very Similar to PDO

$users = $conn->fetchAll('SELECT * FROM users');

20

Zend Framework 1 + Doctrine 2

Schema Manager•Learn about and modify your database

•through the SchemaManager:

$sm = $conn->getSchemaManager();

21

Zend Framework 1 + Doctrine 2

Introspection API•listDatabases()•listFunctions()•listSequences()•listTableColumns($tableName)•listTableConstraints($tableName)•listTableDetails($tableName)•listTableForeignKeys($tableName)•listTableIndexes($tableName)•listTables()

22

Zend Framework 1 + Doctrine 2

Introspection API

$tables = $sm->listTables();foreach ($tables as $table) { $columns = $sm->listTableColumns($table); // ...}

23

Zend Framework 1 + Doctrine 2

DDL Statements•Progromatically issue DDL statements:

$columns = array( 'id' => array( 'type' => \Doctrine\DBAL\Type::getType('integer'), 'autoincrement' => true, 'primary' => true, 'notnull' => true ), 'test' => array( 'type' => \Doctrine\DBAL\Type::getType('string'), 'length' => 255 ));

$options = array();

$sm->createTable('new_table', $columns, $options);

24

Zend Framework 1 + Doctrine 2

DDL Statements

•Progromatically issue DDL statements:

$definition = array( 'name' => 'user_id_fk', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user');$sm->createForeignKey('profile', $definition);

25

Zend Framework 1 + Doctrine 2

Try a Method•You can try a method and return true if

•the operation was successful:

if ($sm->tryMethod('createTable', 'new_table', $columns, $options)) { // do something}

26

Zend Framework 1 + Doctrine 2

Drop and Create Database

try { $sm->dropDatabase('test_db');} catch (Exception $e) {}

$sm->createDatabase('test_db');

27

Zend Framework 1 + Doctrine 2

Drop and Create Database•A little better! Every drop and create

•functionality in the API has a method•that follows the dropAndCreate pattern:

$sm->dropAndCreateDatabase('test_db');

28

Zend Framework 1 + Doctrine 2

Schema Representation

$platform = $em->getConnection()->getDatabasePlatform();

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

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

Array( [0] => CREATE TABLE my_table (id INTEGER NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY("id")))

29

Zend Framework 1 + Doctrine 2

Schema Representation

Array( [0] => DROP TABLE my_table)

Returns the reverse SQL of what toSql() returns

// ......

// get queries to safely delete this schema.$dropSchema = $schema->toDropSql($platform);

Array( [0] => DROP TABLE my_table)

30

Zend Framework 1 + Doctrine 2

Comparing Schemas$fromSchema = new \Doctrine\DBAL\Schema\Schema();$myTable = $fromSchema->createTable("my_table");$myTable->addColumn("id", "integer", array("unsigned" => true));$myTable->addColumn("username", "string", array("length" => 32));$myTable->setPrimaryKey(array("id"));

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

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

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

print_r($queries);

ALTER TABLE my_table ADD email VARCHAR(255) NOT NULL

31

Zend Framework 1 + Doctrine 2

ORMObject Relational Mapper

32

Zend Framework 1 + Doctrine 2

What is ORM?

•“Technique for converting data between incompatible type systems in object-oriented programming languages.”

http://en.wikipedia.org/wiki/Object-relational_mapping

33

Zend Framework 1 + Doctrine 2

The ORM is built on top of Common and DBAL

34

Zend Framework 1 + Doctrine 2

ORM Goals

• Maintain transparency• Keep domain and persistence layer separated• Performance• Consistent and decoupled API• Well defined semantics

35

http://www.doctrine-project.org/projects/orm/download

Zend Framework 1 + Doctrine 2

Download

36

Zend Framework 1 + Doctrine 2

Architecture•Entities• Lightweight persistent domain object• Regular PHP class• Does not extend any base Doctrine class• Cannot be final or contain final methods

• Any two entities in a hierarchy of classes must not have a mapped property with the same name

• Supports inheritance, polymorphic associations and polymorphic queries.

• Both abstract and concrete classes can be entities• Entities may extend non-entity classes as well as entity classes, and non-entity classes may extend entity classes

37

Zend Framework 1 + Doctrine 2

Architecture• No more base class required

• Values stored in object properties• Persistence is done transparently

namespace Entities;

class User{ private $id; private $name;}

38

Zend Framework 1 + Doctrine 2

Architecture

• The EntityManager• Central access point to the ORM functionality provided by Doctrine 2. API is used to manage the persistence of your objects and to query for persistent objects.

• Employes transactional write behind strategy that delays the execution of SQL statements in order to execute them in the most efficient way

• Execute at end of transaction so that all write locks are quickly releases

• Internally an EntityManager uses a UnitOfWork to keep track of your objects

39

Zend Framework 1 + Doctrine 2

Create EntityManager• Create a new EntityManager instance:

$config = new \Doctrine\ORM\Configuration();$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities"));$config->setMetadataDriverImpl($driverImpl);

$config->setProxyDir(__DIR__ . '/Proxies');$config->setProxyNamespace('Proxies');

$em = \Doctrine\ORM\EntityManager::create($conn, $config);

40

Zend Framework 1 + Doctrine 2

Map entities to RDBMS tables

• Entities are just regular PHP objects

namespace Entities;

class User{ private $id; private $name;}

41

Zend Framework 1 + Doctrine 2

Map entities to RDBMS tables• Entities are just regular PHP objects

Mapped By:•Annotations

namespace Entities;

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

/** @Column(length=50) */ private $name;}

42

Zend Framework 1 + Doctrine 2

• Entities are just regular PHP objects:Mapped By:

•Annotations

•YAMLEntities\User: type: entity table: users id: id: type: integer generator: strategy: AUTO fields: name: type: string length: 255

43

Map entities to RDBMS tables

Zend Framework 1 + Doctrine 2

• Entities are just regular PHP objects:Mapped By:

•Annotations

•YAML

•XML<?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-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<entity name="Entities\User" table="users"> <id name="id" type="integer"> <generator strategy="AUTO"/> </id> <field name="name" type="string" length="50"/> </entity>

</doctrine-mapping>

44

Map entities to RDBMS tables

Zend Framework 1 + Doctrine 2

Mapping Performance• Only parsed once

• Cached using configured cache driver• Subsequent requests pull mapping information from configured cache driver

45

Zend Framework 1 + Doctrine 2

Working with Objects• Use the $em to manage the persistence of your entities:

$user = new User;$user->setName('Jonathan H. Wage');

$em->persist($user);$em->flush();

46

Zend Framework 1 + Doctrine 2

Working with Objects• Updating an object:

$user = $em->getRepository('User') ->find(array('name' => 'jwage'));

// modify the already managed object$user->setPassword('changed');$em->flush(); // issues update

47

Zend Framework 1 + Doctrine 2

Working with Objects• Removing an object:

$user = $em->getRepository('User') ->find(array('name' => 'jwage'));

// schedule for deletion$em->remove($user);$em->flush(); // issues delete

48

Zend Framework 1 + Doctrine 2

Transactions• Implicit:

•EntityManager#flush() will begin and commit/rollback a transaction

$user = new User;$user->setName('George');$em->persist($user);$em->flush();

49

Zend Framework 1 + Doctrine 2

Transactions• Explicit:

// $em instanceof EntityManager$em->getConnection()->beginTransaction(); // suspend auto-committry { //... do some work $user = new User; $user->setName('George'); $em->persist($user); $em->flush(); $em->getConnection()->commit();} catch (Exception $e) { $em->getConnection()->rollback(); $em->close(); throw $e;}

50

Zend Framework 1 + Doctrine 2

Transactions• A more convenient explicit transaction:

// $em instanceof EntityManager$em->transactional(function($em) { //... do some work $user = new User; $user->setName('George'); $em->persist($user);});

51

Zend Framework 1 + Doctrine 2

Transactions and Performance

for ($i = 0; $i < 20; ++$i) { $user = new User; $user->name = 'Jonathan H. Wage'; $em->persist($user);}

$s = microtime(true);$em->flush();$e = microtime(true);echo $e - $s;

52

Zend Framework 1 + Doctrine 2

Transactions and Performance• How you use transactions can greatly affect performance. Here is the same thing using raw PHP code:

$s = microtime(true);for ($i = 0; $i < 20; ++$i) { mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')", $link);}$e = microtime(true);echo $e - $s;

53

Zend Framework 1 + Doctrine 2

Which is faster?• The one using no ORM, and no abstraction at all?

• Or the one using the Doctrine ORM?

54

Zend Framework 1 + Doctrine 2

Which is faster?

• The one using no ORM, and no abstraction at all?

• Or the one using the Doctrine ORM?

• Doctrine2 wins! How?

Doctrine2 0.0094 seconds

mysql_query 0.0165 seconds

55

Zend Framework 1 + Doctrine 2

Not Faster• Doctrine just automatically performed the inserts inside one transaction. Here is the code updated to use transactions:

$s = microtime(true);mysql_query('START TRANSACTION', $link);for ($i = 0; $i < 20; ++$i) { mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')", $link);}mysql_query('COMMIT', $link);$e = microtime(true);echo $e - $s;

56

Zend Framework 1 + Doctrine 2

Much Faster• Transactions matter and can affect performance greater than any code optimization!

Doctrine2 0.0094 seconds

mysql_query 0.0165 seconds0.0028

57

Zend Framework 1 + Doctrine 2

Locking Support• Optimistic locking with integer:

class User{ // ... /** @Version @Column(type="integer") */ private $version; // ...}

58

Zend Framework 1 + Doctrine 2

Locking Support• Optimistic locking with timestamp:

class User{ // ... /** @Version @Column(type="datetime") */ private $version; // ...}

59

Zend Framework 1 + Doctrine 2

Locking Support• Verify version when finding:

use Doctrine\DBAL\LockMode;use Doctrine\ORM\OptimisticLockException;

$theEntityId = 1;$expectedVersion = 184;

try { $entity = $em->find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion);

// do the work

$em->flush();} catch(OptimisticLockException $e) { echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";}

60

Zend Framework 1 + Doctrine 2

Locking Support• Example implementation:

$post = $em->find('BlogPost', 123456);

echo '<input type="hidden" name="id" value="' . $post->getId() . '" />';echo '<input type="hidden" name="version" value="' . $post->getCurrentVersion() . '" />';

$postId = (int) $_GET['id'];$postVersion = (int) $_GET['version'];

$post = $em->find('BlogPost', $postId, \Doctrine\DBAL\LockMode::OPTIMISTIC, $postVersion);

61

Zend Framework 1 + Doctrine 2

DQLDoctrine Query Language

62

Zend Framework 1 + Doctrine 2

DQL• DQL stands for Doctrine Query Language and is an Object Query Language derivate that is very similar to the Hibernate Query Language (HQL) or the Java Persistence Query Language (JPQL).

• DQL provides powerful querying capabilities over your object model. Imagine all your objects lying around in some storage (like an object database). When writing DQL queries, think about querying that storage to find a certain subset of your objects.

63

Zend Framework 1 + Doctrine 2

DQL Parser• Parser completely re-written from scratch

• Parsed by top down recursive descent lexer parser that constructs an AST(Abstract Syntax Tree)

• Platform specific SQL is generated from AST

64

Zend Framework 1 + Doctrine 2

Doctrine Query Language

$q = $em->createQuery('SELECT u FROM User u');$users = $q->execute();

65

Zend Framework 1 + Doctrine 2

Query Builder

• Same query built using the QueryBuilder

$qb = $em->createQueryBuilder() ->select('u') ->from('User', 'u');

$q = $qb->getQuery();$users = $q->execute();

66

Zend Framework 1 + Doctrine 2

More Examples

$query = $em->createQuery( 'SELECT u, g, FROM User u ' . 'LEFT JOIN u.Groups g ' . 'ORDER BY u.name ASC, g.name ASC');$users = $query->execute();

$qb = $em->createQueryBuilder() ->select('u, g') ->from('User', 'u') ->leftJoin('u.Groups', 'g') ->orderBy('u.name', 'ASC') ->addOrderBy('g.name', 'ASC');

$query = $qb->getQuery();

67

Zend Framework 1 + Doctrine 2

Executing Queries• Executing and getting results

$users = $query->execute();

foreach ($users as $user) { // ... foreach ($user->getGroups() as $group) { // ... }}

68

Zend Framework 1 + Doctrine 2

Executing Queries• Execute query and iterate over results keeping memory usage low:

foreach ($query->iterate() as $user) { // ... foreach ($user->getGroups() as $group) { // ... }}

69

Zend Framework 1 + Doctrine 2

Result Cache• Optionally cache the results of your queries in your driver of choice:

$cacheDriver = new \Doctrine\Common\Cache\ApcCache();$config->setResultCacheImpl($cacheDriver);

$query = $em->createQuery('select u from Entities\User u');$query->useResultCache(true, 3600, 'my_query_name');

$users = $query->execute();

$users = $query->execute(); // 2nd time pulls from cache

70

Zend Framework 1 + Doctrine 2

Inheritance• Doctrine supports mapping entities that use inheritance with the following strategies:

Mapped Superclass Single Table Inheritance Class Table Inheritance

71

Zend Framework 1 + Doctrine 2

Mapped Superclasses

/** @MappedSuperclass */abstract class MappedSuperclassBase{ /** @Column(type="integer") */ private $mapped1; /** @Column(type="string") */ private $mapped2; /** * @OneToOne(targetEntity="MappedSuperclassRelated1") * @JoinColumn(name="related1_id", referencedColumnName="id") */ private $mappedRelated1;

// ... more fields and methods}

/** @Entity */class EntitySubClass extends MappedSuperclassBase{ /** @Id @Column(type="integer") */ private $id; /** @Column(type="string") */ private $name;

// ... more fields and methods}

72

Zend Framework 1 + Doctrine 2

Single Table Inheritance

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

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

73

Zend Framework 1 + Doctrine 2

Single Table Inheritance• All entities share one table.

• To distinguish which row represents which type in the hierarchy a so-called discriminator column is used.

74

Zend Framework 1 + Doctrine 2

Class Table Inheritance

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

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

75

Zend Framework 1 + Doctrine 2

Class Table Inheritance• Each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes.

• The table of a child class is linked to the table of a parent class through a foreign key constraint.

• A discriminator column is used in the topmost table of the hierarchy because this is the easiest way to achieve polymorphic queries.

76

Zend Framework 1 + Doctrine 2

Bulk Inserts with Domain• Insert 10000 objects batches of 20:

$batchSize = 20;for ($i = 1; $i <= 10000; ++$i) { $user = new User; $user->setStatus('user'); $user->setUsername('user' . $i); $user->setName('Mr.Smith-' . $i); $em->persist($user); if ($i % $batchSize == 0) { $em->flush(); $em->clear(); // Detaches all objects from Doctrine! }}

77

Zend Framework 1 + Doctrine 2

Bulk Update with DQL

$q = $em->createQuery('update Manager m set m.salary = m.salary * 0.9');$numUpdated = $q->execute();

78

Zend Framework 1 + Doctrine 2

Bulk Update with Domain

• Update objects in batches of 20:

$batchSize = 20;$i = 0;$q = $em->createQuery('select u from User u');$iterableResult = $q->iterate();foreach($iterableResult AS $row) { $user = $row[0]; $user->increaseCredit(); $user->calculateNewBonuses(); if (($i % $batchSize) == 0) { $em->flush(); // Executes all updates. $em->clear(); // Detaches all objects from Doctrine! } ++$i;}

79

Zend Framework 1 + Doctrine 2

Bulk Delete with DQL

$q = $em->createQuery('delete from Manager m where m.salary > 100000');$numDeleted = $q->execute();

80

Zend Framework 1 + Doctrine 2

Bulk Delete with Domain

$batchSize = 20;$i = 0;$q = $em->createQuery('select u from User u');$iterableResult = $q->iterate();while (($row = $iterableResult->next()) !== false) { $em->remove($row[0]); if (($i % $batchSize) == 0) { $em->flush(); // Executes all deletions. $em->clear(); // Detaches all objects from Doctrine! } ++$i;}

81

Zend Framework 1 + Doctrine 2

Events•Doctrine triggers events throughout the

•lifecycle of objects it manages: preRemove postRemove prePersist postPersist preUpdate postUpdate preLoad postLoad

82

Zend Framework 1 + Doctrine 2

Example

/** * @Entity * @HasLifecycleCallbacks */class BlogPost{ // ...

/** @PreUpdate */ public function prePersist() { $this->createdAt = new DateTime(); }

/** @PreUpdate */ public function preUpdate() { $this->updatedAt = new DateTime(); }}

83

Zend Framework 1 + Doctrine 2

Using Raw SQL• Write a raw SQL string

• Map the result set of the SQL query using a ResultSetMapping instance

84

Zend Framework 1 + Doctrine 2

Using Raw SQL

$sql = 'SELECT id, name FROM users WHERE username = ?';

$rsm = new ResultSetMapping;$rsm->addEntityResult('User', 'u');$rsm->addFieldResult('u', 'id', 'id');$rsm->addFieldResult('u', 'name', 'name');

$query = $this->_em->createNativeQuery($sql, $rsm);$query->setParameter(1, 'jwage');

$users = $query->getResult();

85

Zend Framework 1 + Doctrine 2

Why use an object mapper?

86

Zend Framework 1 + Doctrine 2

Encapsulate your domain in an object oriented interface

Encapsulation

87

Zend Framework 1 + Doctrine 2

The organization of your domain logic in an OO way improved maintainability

Maintainability

88

Zend Framework 1 + Doctrine 2

Keeping a clean OO domain model makes your business logic easily testable for improved stability

Testability

89

Zend Framework 1 + Doctrine 2

Write portable and thin application controller code and fat models.

Portability

90

The Doctrine Project

Demo Time

91

Zend Framework 1 + Doctrine 2

What we are going to accomplish•Start with a vanilla Zend Framework Project

•Ensure all dependencies are met•Configure out application to utilize Doctrine•Create an Entity (in our library) with Annotations•Generate the Database

•Generate Proxies + Repositories•Create a Controller for basic crud•Talk about what would happen next

92

Zend Framework 1 + Doctrine 2

Where To Get The Code•http://github.com/ralphschindler/NOLASnowball

Self contained ProjectBranches:

•master - Clean ZF Project, with ZF embedded in library/ folder

•non-model-artifacts - Authentication service, Login form

•doctrine2-managed– Has following libraries: Doctrine2, Symfony (Copied into library), Bisna (ZF1 +

Doctrine2 Integration library)

– Has the following entity created: NOLASnowball\Entity\Stand

– Has the proper application.ini settings

– Has scripts/doctrine.php setup for easy use

•doctrine2-managed-crud– Created Stand Controller, actions are complete, view scripts complete

– Proxies & Repositories are generated

– Assumes you’ve generated the SQL (locally would need to change db credentials)

93

Zend Framework 1 + Doctrine 2

Lets look at code!•Demo time

94

Zend Framework 1 + Doctrine 2

Exercises and Things To Implement•flush() could be a postDispatch() function call

•All interaction with Entities could be moved into a Service LayerOnce such implementation: https://github.com/guilhermeblanco/ZF1-Doctrine2-ServiceLayer

•Add relationships, and alter forms accordingly

95

Zend Framework 1 + Doctrine 2

Recommended Reading•Doctrine Website & Manual (Also has download)

http://www.doctrine-project.org/

•Zend Framework Web & Manual (With download)http://framework.zend.com/

•Ralph Schindler’s Sample Applicationhttps://github.com/ralphschindler/NOLASnowball

•Guilherme Blanco’s ZF1 + D2 Integration codehttps://github.com/guilhermeblanco/ZendFramework1-Doctrine2

96

Zend Framework 1 + Doctrine 2

Questions?•Q & A Time

97