You are on page 1of 66

DOCTRINE 2 & ZF2 +

MARCO PIVETTA
Doctrine core team Zf2 contributor Modules developer time waster @Ocramius - Ocramius

MAIN LIBRARIES
BjyAuthorize , AssetManager , ZeffMu , ZfrRest , OcraDiCompiler , OcraServiceManager , OcraCachedViewResolver , DoctrineModule , DoctrineORMModule , DoctrineMongoODMModule , VersionEyeModule

DOCTRINE PROJECT
An incubator for persistence-oriented libraries

WHAT IS DOCTRINE ORM?


Doctrine ORM is an Object Relational Mapper It is inspired by Hibernate and the JPA (JSR-317) It is based on a DBAL (DataBase Abstraction Layer) Allows developers to save and load POPO with SQL

An ORM gives you the impression that you are working with a "virtual" database (graph) composed by objects

FORGET THE DATABASE!

Simple put:

THE MODULES!
DoctrineModule basic common functionality DoctrineORMModule ORM/SQL Connection DoctrineMongoODMModule ODM/MongoDB Connection

INSTALLATION!

p h pc o m p o s e r . p h a rr e q u i r ed o c t r i n e / d o c t r i n e o r m m o d u l e : 0 . 7 . *

p h pc o m p o s e r . p h a rr e q u i r ez e n d f r a m e w o r k / z e n d d e v e l o p e r t o o l s : d e v m a s t e r

c pv e n d o r / z e n d f r a m e w o r k / z e n d d e v e l o p e r t o o l s / c o n f i g / z e n d d e v e l o p e r t o o l s . l o c a l . p h p . d i s tc o n f i g / a u t o l o a d / z d t . l o c a l . p h p

ENABLING THE MODULES


c o n f i g / a p p l i c a t i o n . c o n f i g . p h p r e t u r na r r a y ( ' m o d u l e s '= >a r r a y ( ' Z e n d D e v e l o p e r T o o l s ' , ' A p p l i c a t i o n ' , ' D o c t r i n e M o d u l e ' , ' D o c t r i n e O R M M o d u l e ' , ) , / /[ . . . ] ) ;

You should see:

WRITE YOUR FIRST ENTITY


m o d u l e / A p p l i c a t i o n / s r c / A p p l i c a t i o n / E n t i t y / U s e r n a m e s p a c eA p p l i c a t i o n \ E n t i t y ; u s eD o c t r i n e \ O R M \ M a p p i n ga sO R M ; / * *@ O R M \ E n t i t y* / c l a s sU s e r{ / * * *@ O R M \ I d *@ O R M \ G e n e r a t e d V a l u e ( s t r a t e g y = " A U T O " ) *@ O R M \ C o l u m n ( t y p e = " i n t e g e r " ) * / p r o t e c t e d$ i d ; / * *@ O R M \ C o l u m n ( t y p e = " s t r i n g " )* / p r o t e c t e d$ f u l l N a m e ; / /g e t t e r s / s e t t e r s }

CONFIGURE MAPPINGS
m o d u l e / A p p l i c a t i o n / c o n f i g / m o d u l e . c o n f i g . p h p r e t u r na r r a y ( ' d o c t r i n e '= >a r r a y ( ' d r i v e r '= >a r r a y ( ' a p p l i c a t i o n _ e n t i t i e s '= >a r r a y ( ' c l a s s '= > ' D o c t r i n e \ O R M \ M a p p i n g \ D r i v e r \ A n n o t a t i o n D r i v e r ' ' c a c h e '= >' a r r a y ' ' p a t h s '= >a r r a y ( _ _ D I R _ _.' / . . / s r c / A p p l i c a t i o n / E n t i t y ' ) ) , ' o r m _ d e f a u l t '= >a r r a y ( ' d r i v e r s '= >a r r a y ( ' A p p l i c a t i o n \ E n t i t y '= >' a p p l i c a t i o n _ e n t i t i e s ' ) ) ) ) ,/ /[ . . . ]

You should see:

CONFIGURE THE CONNECTION


c o n f i g / a u t o l o a d / d o c t r i n e . l o c a l . p h p r e t u r na r r a y ( ' d o c t r i n e '= >a r r a y ( ' c o n n e c t i o n '= >a r r a y ( ' o r m _ d e f a u l t '= >a r r a y ( ' d r i v e r C l a s s '= > ' D o c t r i n e \ D B A L \ D r i v e r \ P D O M y S q l \ D r i v e r ' , ' p a r a m s '= >a r r a y ( ' h o s t ' = >' l o c a l h o s t ' , ' p o r t ' = >' 3 3 0 6 ' , ' u s e r ' = >' u s e r n a m e ' , ' p a s s w o r d '= >' p a s s w o r d ' , ' d b n a m e ' = >' d a t a b a s e ' , ) ) ) ) ) ;

VALIDATE MAPPINGS
. / v e n d o r / b i n / d o c t r i n e m o d u l eo r m : v a l i d a t e s c h e m a

GENERATE THE DATABASE

. / v e n d o r / b i n / d o c t r i n e m o d u l eo r m : s c h e m a t o o l : c r e a t e

TEST IT!
m o d u l e / A p p l i c a t i o n / s r c / A p p l i c a t i o n / C o n t r o l l e r / I n d e x C o n t r o l l e r . p h p p u b l i cf u n c t i o ni n d e x A c t i o n ( ){ $ o b j e c t M a n a g e r=$ t h i s > g e t S e r v i c e L o c a t o r ( ) > g e t ( ' D o c t r i n e \ O R M \ E n t i t y M a n a g e r ' ) ; $ u s e r=n e w\ A p p l i c a t i o n \ E n t i t y \ U s e r ( ) ; $ u s e r > s e t F u l l N a m e ( ' M a r c oP i v e t t a ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ u s e r ) ; $ o b j e c t M a n a g e r > f l u s h ( ) ; d i e ( v a r _ d u m p ( $ u s e r > g e t I d ( ) ) ) ;/ /y e s ,I ' ml a z y }

EXAMPLES

PERSISTING AN OBJECT
$ u s e r=n e wU s e r ( ) ; $ u s e r > s e t F u l l N a m e ( ' M a r c oP i v e t t a ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ u s e r ) ;/ /$ u s e r 1i sn o w" m a n a g e d " $ o b j e c t M a n a g e r > f l u s h ( ) ;/ /c o m m i tc h a n g e st od b v a r _ d u m p ( $ u s e r 1 > g e t I d ( ) ) ;/ /1

PERSISTING MULTIPLE OBJECTS


$ u s e r 1=n e wU s e r ( ) ; $ u s e r 1 > s e t F u l l N a m e ( ' M a r c oP i v e t t a ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ u s e r 1 ) ; $ u s e r 2=n e wU s e r ( ) ; $ u s e r 2 > s e t F u l l N a m e ( ' M i c h a lG a l l e g o ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ u s e r 2 ) ; $ u s e r 3=n e wU s e r ( ) ; $ u s e r 3 > s e t F u l l N a m e ( ' K y l eS p r a g g s ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ u s e r 3 ) ; $ o b j e c t M a n a g e r > f l u s h ( ) ;

RETRIEVING AN OBJECT
$ u s e r 1=$ o b j e c t M a n a g e r > f i n d ( ' U s e r ' ,1 ) ; v a r _ d u m p ( $ u s e r 1 > g e t F u l l N a m e ( ) ) ;/ /M a r c oP i v e t t a $ u s e r 2=$ o b j e c t M a n a g e r > g e t R e p o s i t o r y ( ' U s e r ' ) > f i n d O n e B y ( a r r a y ( ' f u l l N a m e '= >' M i c h a lG a l l e g o ' ) ) ; v a r _ d u m p ( $ u s e r 2 > g e t F u l l N a m e ( ) ) ;/ /M i c h a lG a l l e g o

UPDATING AN OBJECT
$ u s e r=$ o b j e c t M a n a g e r > f i n d ( ' U s e r ' ,1 ) ; $ u s e r > s e t F u l l N a m e ( ' G u i l h e r m eB l a n c o ' ) ; $ o b j e c t M a n a g e r > f l u s h ( ) ;

DELETING AN OBJECT
$ u s e r=$ o b j e c t M a n a g e r > f i n d ( ' U s e r ' ,1 ) ; $ o b j e c t M a n a g e r > r e m o v e ( $ u s e r ) ; $ o b j e c t M a n a g e r > f l u s h ( ) ;

ASSOCIATIONS - USER
/ * *@ O R M \ E n t i t y* / c l a s sU s e r{ / /l i k eb e f o r e / * *@ O R M \ M a n y T o O n e ( t a r g e t E n t i t y = " A d d r e s s " )* / p r o t e c t e d$ a d d r e s s ; / * *@ O R M \ M a n y T o M a n y ( t a r g e t E n t i t y = " P r o j e c t s " )* / p r o t e c t e d$ p r o j e c t s ; p u b l i cf u n c t i o n_ _ c o n s t r u c t ( ) { $ t h i s > p r o j e c t s=n e wA r r a y C o l l e c t i o n ( ) ; } / /g e t t e r s / s e t t e r s }

ASSOCIATIONS - ADDRESS
/ * *@ O R M \ E n t i t y* / c l a s sA d d r e s s{ / *@ O R M \ I d@ O R M \ C o l u m n ( t y p e = " i n t e g e r " )@ O R M \ G e n e r a t e d V a l u e ( s t r a t e g y = " A U T O " )* / p r o t e c t e d$ i d ; / * *@ O R M \ C o l u m n ( t y p e = " s t r i n g " )* / p r o t e c t e d$ c i t y ; / * *@ O R M \ C o l u m n ( t y p e = " s t r i n g " )* / p r o t e c t e d$ c o u n t r y ; / /g e t t e r s / s e t t e r se t c . }

ASSOCIATIONS - PROJECTS
/ * *@ O R M \ E n t i t y* / c l a s sP r o j e c t{ / *@ O R M \ I d@ O R M \ C o l u m n ( t y p e = " i n t e g e r " )@ O R M \ G e n e r a t e d V a l u e ( s t r a t e g y = " A U T O " )* / p r o t e c t e d$ i d ; / * *@ O R M \ C o l u m n ( t y p e = " s t r i n g " )* / p r o t e c t e d$ n a m e ; / /g e t t e r s / s e t t e r s }

ASSOCIATIONS - PERSISTING ASSOCIATIONS


$ u s e r=n e wU s e r ( ) ; $ u s e r > s e t F u l l N a m e ( ' M a r c oP i v e t t a ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ u s e r ) ; $ a d d r e s s=n e wA d d r e s s ( ) ; $ a d d r e s s > s e t C i t y ( ' F r a n k f u r t ' ) $ a d d r e s s > s e t C o u n t r y ( ' G e r m a n y ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ a d d r e s s ) ; $ p r o j e c t=n e wP r o j e c t ( ) ; $ p r o j e c t > s e t N a m e ( ' D o c t r i n eO R M ' ) ; $ o b j e c t M a n a g e r > p e r s i s t ( $ p r o j e c t ) ; $ u s e r > s e t A d d r e s s ( $ a d d r e s s ) ; $ u s e r > g e t P r o j e c t s ( ) > a d d ( $ p r o j e c t ) ; $ o b j e c t M a n a g e r > f l u s h ( ) ;

ASSOCIATIONS - RETRIEVING ASSOCIATIONS


$ u s e r=$ o b j e c t M a n a g e r > f i n d ( ' U s e r ' ,1 ) ; v a r _ d u m p ( $ u s e r > g e t A d d r e s s ( ) > g e t C i t y ( ) ) ;/ /F r a n k f u r t v a r _ d u m p ( $ u s e r > g e t P r o j e c t s ( ) > f i r s t ( ) > g e t N a m e ( ) )/ /D o c t r i n eO R M

More tutorials at http://marco-pivetta.com/doctrine2-orm-tutorial

DOCTRINEMODULE GOODIES

EER UML MODEL


See what your entities look like in a graph:

PAGINATOR ADAPTER
u s eD o c t r i n e \ C o m m o n \ C o l l e c t i o n s \ A r r a y C o l l e c t i o n ; u s eD o c t r i n e M o d u l e \ P a g i n a t o r \ A d a p t e r \ C o l l e c t i o na sA d a p t e r ; u s eZ e n d \ P a g i n a t o r \ P a g i n a t o r ; / /C r e a t eaD o c t r i n eC o l l e c t i o n $ c o l l e c t i o n=n e wA r r a y C o l l e c t i o n ( r a n g e ( 1 ,1 0 1 ) ) ; / /C r e a t et h ep a g i n a t o ri t s e l f $ p a g i n a t o r=n e wP a g i n a t o r ( n e wA d a p t e r ( $ c o l l e c t i o n ) ) ; $ p a g i n a t o r > s e t C u r r e n t P a g e N u m b e r ( 1 ) > s e t I t e m C o u n t P e r P a g e ( 5 ) ;

PAGINATOR ADAPTER (ORM)


u s eD o c t r i n e O R M M o d u l e \ P a g i n a t o r \ A d a p t e r \ D o c t r i n e P a g i n a t o r ; u s eD o c t r i n e \ O R M \ T o o l s \ P a g i n a t i o n \ P a g i n a t o ra sO R M P a g i n a t o r ; u s eZ e n d \ P a g i n a t o r \ P a g i n a t o r ; / /C r e a t eaD o c t r i n eC o l l e c t i o n $ q u e r y=$ e m > c r e a t e Q u e r y ( ' S E L E C TfF R O MF o ofJ O I Nf . b a rb ' ) ; / /C r e a t et h ep a g i n a t o ri t s e l f $ p a g i n a t o r=n e wP a g i n a t o r ( n e wD o c t r i n e P a g i n a t o r ( n e wO R M P a g i n a t o r ( $ q u e r y ) ) ) ; $ p a g i n a t o r > s e t C u r r e n t P a g e N u m b e r ( 1 ) > s e t I t e m C o u n t P e r P a g e ( 5 ) ;

OBJECT-EXISTS VALIDATOR
$ r e p o s i t o r y=$ o b j e c t M a n a g e r > g e t R e p o s i t o r y ( ' A p p l i c a t i o n \ E n t i t y \ U s e r ' ) ; $ v a l i d a t o r=n e w\ D o c t r i n e M o d u l e \ V a l i d a t o r \ O b j e c t E x i s t s ( a r r a y ( ' o b j e c t _ r e p o s i t o r y '= >$ r e p o s i t o r y , ' f i e l d s '= >a r r a y ( ' e m a i l ' ) ) ) ; v a r _ d u m p ( $ v a l i d a t o r > i s V a l i d ( ' t e s t @ e x a m p l e . c o m ' ) ) ; v a r _ d u m p ( $ v a l i d a t o r > i s V a l i d ( a r r a y ( ' e m a i l '= >' t e s t @ e x a m p l e . c o m ' ) ) ) ;

CACHE ADAPTERS
$ z e n d C a c h e=n e w\ Z e n d \ C a c h e \ S t o r a g e \ A d a p t e r \ M e m o r y ( ) ; $ c a c h e=n e w\ D o c t r i n e M o d u l e \ C a c h e \ Z e n d S t o r a g e C a c h e ( $ z e n d C a c h e ) ; $ d o c t r i n e C a c h e=n e w\ D o c t r i n e \ C o m m o n \ C a c h e \ A r r a y C a c h e ( ) ; $ o p t i o n s=n e w\ Z e n d \ C a c h e \ S t o r a g e \ A d a p t e r \ A d a p t e r O p t i o n s ( ) ; $ c a c h e=n e w\ D o c t r i n e M o d u l e \ C a c h e \ D o c t r i n e C a c h e S t o r a g e ( $ o p t i o n s , $ d o c t r i n e C a c h e ) ;

HYDRATOR
u s eD o c t r i n e M o d u l e \ S t d l i b \ H y d r a t o r \ D o c t r i n e O b j e c t ; $ h y d r a t o r=n e wD o c t r i n e O b j e c t ( $ o b j e c t M a n a g e r , ' A p p l i c a t i o n \ E n t i t y \ C i t y ' ) ; $ c i t y=n e wC i t y ( ) ; $ d a t a=a r r a y ( ' n a m e '= >' F r a n k f u r t ' ) ; $ c i t y=$ h y d r a t o r > h y d r a t e ( $ d a t a ,$ c i t y ) ; e c h o$ c i t y > g e t N a m e ( ) ;/ /p r i n t s" F r a n k f u r t " $ d a t a A r r a y=$ h y d r a t o r > e x t r a c t ( $ c i t y ) ; e c h o$ d a t a A r r a y [ ' n a m e ' ] ;/ /p r i n t s" F r a n k f u r t "

HYDRATOR (2)
u s eD o c t r i n e M o d u l e \ S t d l i b \ H y d r a t o r \ D o c t r i n e O b j e c t ; $ h y d r a t o r=n e wD o c t r i n e O b j e c t ( $ o b j e c t M a n a g e r , ' A p p l i c a t i o n \ E n t i t y \ C i t y ' ) ; $ c i t y=n e wC i t y ( ) ; $ d a t a=a r r a y ( ' c o u n t r y '= >1 2 3 ) ; $ c i t y=$ h y d r a t o r > h y d r a t e ( $ d a t a ,$ c i t y ) ; v a r _ d u m p ( $ c i t y > g e t C o u n t r y ( ) ) ; / /p r i n t sc l a s sC o u n t r y # 1( 1 ){ / / p r o t e c t e d$ n a m e= >s t r i n g ( 5 )" G e r m a n y " / /}

FORM ELEMENT
$ f o r m > a d d ( a r r a y ( ' t y p e '= >' D o c t r i n e M o d u l e \ F o r m \ E l e m e n t \ O b j e c t S e l e c t ' , ' n a m e '= >' u s e r ' , ' o p t i o n s '= >a r r a y ( ' o b j e c t _ m a n a g e r '= >$ o b j e c t M a n a g e r , ' t a r g e t _ c l a s s ' = >' M o d u l e \ E n t i t y \ U s e r ' , ' p r o p e r t y ' = >' f u l l N a m e ' , ' i s _ m e t h o d ' = >t r u e , ' f i n d _ m e t h o d ' = >a r r a y ( ' n a m e ' = >' f i n d B y ' , ' p a r a m s '= >a r r a y ( ' c r i t e r i a '= >a r r a y ( ' a c t i v e '= >1 ) , ' o r d e r B y ' = >a r r a y ( ' l a s N a m e '= >' A S C ' ) , ) , ) , ) , ) ) ;

MORE STUFF!
Everything works with MongoDB ODM too! CouchDB ODM/PHPCR ODM/OrientDB ODM

GOOD PRACTICES

KEEP ENTITIES SIMPLE


Think of entities as value-objects Don't add logic to entities (hard to change later!) Keep entities aware only of themselves + relations

USE DOCTRINE/COMMON API


If you stick with using only doctrine/common API, users of your modules can switch between ORM/ MongoDB ODM/CouchDB ODM/ PHPCR ODM/OrientDB ODM

USE DOCTRINE/COMMON API


Prefer
D o c t r i n e \ C o m m o n \ P e r s i s t e n c e \ O b j e c t M a n a g e r

over
D o c t r i n e \ O R M \ E n t i t y M a n a g e r

USE DOCTRINE/COMMON API


Prefer
D o c t r i n e \ C o m m o n \ P e r s i s t e n c e \ O b j e c t R e p o s i t o r y

over
D o c t r i n e \ O R M \ E n t i t y R e p o s i t o r y

USE COLLECTIONS EXTENSIVELY


Doctrine comes with a powerful collections API OOP API for array-like data structures

USE THE CRITERIA API


Collections provide a Criteria API Allows you to filter virtually any kind of data structure

CRITERIA API EXAMPLE


u s eD o c t r i n e \ C o m m o n \ C o l l e c t i o n s \ C r i t e r i a ; u s eD o c t r i n e \ C o m m o n \ C o l l e c t i o n s \ A r r a y C o l l e c t i o n ; $ c o l l e c t i o n=n e wA r r a y C o l l e c t i o n ( a r r a y ( $ u s e r 1 ,$ u s e r 2 ,$ u s e r 3 ) ) ; $ c r i t e r i a =n e wC r i t e r i a ( ) ; $ c r i t e r i a > a n d W h e r e ( $ c r i t e r i a > e x p r ( ) > g t ( ' l a s t L o g i n ' , n e w\ D a t e T i m e ( ' 1d a y ' ) ) ) ; $ r e c e n t V i s i t o r s=$ c o l l e c t i o n > m a t c h i n g ( $ c r i t e r i a ) ; $ r e c e n t V i s i t o r s=$ e m > g e t R e p o s i t o r y ( ' A p p l i c a t i o n \ E n t i t y \ U s e r s ' ) > m a t c h i n g ( $ c r i t e r i a ) ;

CRITERIA API ADVANTAGES


Works in ORM Repositories, Collections, etc... Abstracts the problem of "searching" Same criteria for different storages (ORM, ODM, Memory, ElasticSearch, cache...) Allows you to define your own R e c e n t U s e r s C r i t e r i a or I n a c t i v e U s e r s C r i t e r i a ...

INJECT THE OBJECT MANAGER


If you fetch the entity manager from within your services, replacing it will become very hard: Inject it instead!

INJECT THE OBJECT MANAGER


' f a c t o r i e s '= >a r r a y ( ' m y _ s e r v i c e '= >f u n c t i o n( $ s l ){ $ o b j e c t M a n a g e r=$ s l > g e t ( ' D o c t r i n e \ O R M \ E n t i t y M a n a g e r ' ) ; r e t u r nn e wM y S e r v i c e ( $ o b j e c t M a n a g e r ) ; } ) , c l a s sM y S e r v i c e { p u b l i cf u n c t i o n_ _ c o n s t r u c t ( O b j e c t M a n a g e r$ o b j e c t M a n a g e r ) { / /[ . . . ] } }

KEEP OBJECT MANAGER OUT OF CONTROLLERS

DON'T USE PERSISTENCE TO SOLVE APPLICATION PROBLEMS


Filtering data when saved to DB Validating data when saved to DB Saving files when records are saved to DB Using DB-level errors to check input validity

KEEP YOUR OBJECT GRAPH CONSISTENT


An ObjectManager works under the assumption that managed objects are valid! Assign values to your entities only when data is valid!

QUESTIONS?

FORK IT!
You can find these slides on GitHub at https://github.com/Ocramius/doctrine-orm-zf2tutorial

THANKS FOR WATCHING!

You might also like