Pro Yearly is on sale from $80 to $50! »

Doctrine, Object Persistence, and You

Doctrine, Object Persistence, and You

Presented May 9, 2014 at OpenWest: https://joind.in/talk/view/11190

Presented March 16, 2014 at Midwest PHP: http://joind.in/talk/view/10561

Presented February 8, 2014 at Sunshine PHP: http://joind.in/talk/view/10530

Presented January 17, 2014 at Ski PHP: http://joind.in/talk/view/10427

Presented October 9, 2013 at ZendCon: https://joind.in/talk/view/9085

Reveal.js presentation published at: http://jmikola.github.io/slides/doctrine_object_persistence/

F23700b51dc0c196c1dc02f84aeeecdf?s=128

Jeremy Mikola

May 09, 2014
Tweet

Transcript

  1. DOCTRINE, OBJECT PERSISTENCE, AND YOU Jeremy Mikola jmikola

  2. Agenda Design Patterns Object Persistence Behind the Persistence

  3. None
  4. None
  5. None
  6. PEAR DB Metabase PEAR MDB PEAR MDB2 Zend_Db Doctrine ORM

    1.x Doctrine ORM 2.x Doctrine DBAL
  7. Design Patterns

  8. None
  9. Who needs design patterns?

  10. Selecting Data from a Table $ c o n =

    m y s q l i _ c o n n e c t ( " e x a m p l e . c o m " , " p e t e r " , " a b c 1 2 3 " , " m y _ d b " ) ; i f ( m y s q l i _ c o n n e c t _ e r r n o ( ) ) { e c h o " F a i l e d t o c o n n e c t t o M y S Q L : " . m y s q l i _ c o n n e c t _ e r r o r ( ) ; } $ r e s u l t = m y s q l i _ q u e r y ( $ c o n , " S E L E C T * F R O M P e r s o n s " ) ; w h i l e ( $ r o w = m y s q l i _ f e t c h _ a r r a y ( $ r e s u l t ) ) { e c h o $ r o w [ ' F i r s t N a m e ' ] . " " . $ r o w [ ' L a s t N a m e ' ] ; e c h o " < b r > " ; } m y s q l i _ c l o s e ( $ c o n ) ; http://www.w3schools.com/php/php_mysql_select.asp
  11. Inserting Form Data into a Database $ c o n

    = m y s q l i _ c o n n e c t ( " e x a m p l e . c o m " , " p e t e r " , " a b c 1 2 3 " , " m y _ d b " ) ; i f ( m y s q l i _ c o n n e c t _ e r r n o ( ) ) { e c h o " F a i l e d t o c o n n e c t t o M y S Q L : " . m y s q l i _ c o n n e c t _ e r r o r ( ) ; } $ s q l = " I N S E R T I N T O P e r s o n s ( F i r s t N a m e , L a s t N a m e , A g e ) V A L U E S ( ' $ _ P O S T [ f i r s t n a m e ] ' , ' $ _ P O S T [ l a s t n a m e ] ' , ' $ _ P O S T [ a g e ] ' ) " ; i f ( ! m y s q l i _ q u e r y ( $ c o n , $ s q l ) ) { d i e ( ' E r r o r : ' . m y s q l i _ e r r o r ( $ c o n ) ) ; } m y s q l i _ c l o s e ( $ c o n ) ; http://www.w3schools.com/php/php_mysql_insert.asp
  12. None
  13. Data Source Architectural Patterns Table data gateway Row data gateway

    Active record Data mapper
  14. Gateway Patterns

  15. An object that encapsulates access to an external system or

    resource. “ — Martin Fowler in PoEAA
  16. Table Data Gateway e.g. Zend\Db\TableGateway

  17. An object that acts as a Gateway to a database

    table. One instance handles all the rows in the table. “ — Martin Fowler in PoEAA
  18. Table Data Gateway

  19. What this looks like in PHP n a m e

    s p a c e Z e n d \ D b \ T a b l e G a t e w a y ; i n t e r f a c e T a b l e G a t e w a y I n t e r f a c e { p u b l i c f u n c t i o n g e t T a b l e ( ) ; p u b l i c f u n c t i o n s e l e c t ( $ w h e r e = n u l l ) ; p u b l i c f u n c t i o n i n s e r t ( $ s e t ) ; p u b l i c f u n c t i o n u p d a t e ( $ s e t , $ w h e r e = n u l l ) ; p u b l i c f u n c t i o n d e l e t e ( $ w h e r e ) ; }
  20. Row Data Gateway e.g. Zend\Db\RowGateway

  21. Row Data Gateway

  22. What’s the problem? Gateways are thin abstractions Data model not

    included Hydration and persistence?
  23. Active Record e.g. Doctrine ORM 1.x

  24. None
  25. An object that wraps a row in a database table

    or view, encapsulates the database access, and adds domain logic on that data. “ — Martin Fowler in PoEAA
  26. Active Record

  27. Active Record Sits on top of our domain model Row

    data gateway + business logic
  28. Domain Model Data encapsulation Business logic Relationships Validation?

  29. Active Record adds… Factory method for new objects Hydration for

    fetched objects Persistence logic Common queries CRUD methods
  30. What this looks like in PHP / / c r

    e a t e T i t o $ u s e r = U s e r : : c r e a t e ( [ ' n a m e ' = > ' T i t o ' , ' s t a t e ' = > ' V A ' ] ) ; / / r e a d T i t o $ u s e r = U s e r : : f i n d _ b y _ n a m e ( ' T i t o ' ) ; / / u p d a t e T i t o $ u s e r - > n a m e = ' T i t o J r ' ; $ u s e r - > s a v e ( ) ; / / d e l e t e T i t o $ u s e r - > d e l e t e ( ) ; http://phpactiverecord.org/projects/main/wiki/Quick_Start
  31. What’s the problem? Testability Single Responsibility Principle

  32. ONE DOES NOT SIMPLY MOCK OUT ACTIVERECORD

  33. What’s the problem? Testability Scalability and performance Single Responsibility Principle

    Multitenancy
  34. Scalability and Performance Fat models eat memory

  35. An Elephant Never Forgets

  36. Data Mapper e.g. Doctrine ORM 2.x, ODMs

  37. A layer of Mappers that moves data between objects and

    a database while keeping them independent of each other and the mapper itself. “ — Martin Fowler in PoEAA
  38. Data Mapper

  39. Data Mapper Complements the domain model, instead of augmenting it

    Manages hydration and persistence
  40. The Data Mapper is a layer of software that separates

    the in-memory objects from the database. “ — Martin Fowler in PoEAA
  41. ☑ Separation of concerns

  42. With Data Mapper the in-memory objects needn’t know even that

    there’s a database present. “ — Martin Fowler in PoEAA
  43. ☑ Testability

  44. None
  45. None
  46. What this looks like in PHP / / c r

    e a t e J o n $ u s e r = n e w U s e r ( ) ; $ u s e r - > s e t N a m e ( ' J o n ' ) ; $ u s e r - > s e t S t a t e ( ' T N ' ) ; $ m a n a g e r - > p e r s i s t ( $ u s e r ) ; $ m a n a g e r - > f l u s h ( ) ; / / r e a d J o n $ u s e r = $ 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 ( [ ' n a m e ' = > ' J o n ' ] ) ; / / u p d a t e J o n $ u s e r - > s e t N a m e ( ' J o n W a g e ' ) ; $ m a n a g e r - > f l u s h ( ) ; / / d e l e t e J o n $ m a n a g e r - > r e m o v e ( $ u s e r ) ; $ m a n a g e r - > f l u s h ( ) ; http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html
  47. Data Mapper Simple models Manager handles persistence Repository holds queries

  48. ☑ Multitenancy

  49. ☑ Scalability and performance

  50. Object Persistence in Doctrine ORM 2.x, ODMs Inspired by and

    Hibernate JPA 2.0
  51. Architecture EventManager Metadata Hydrator Persister UnitOfWork ObjectManager Repository Query

  52. Metadata / * * * @ E n t i

    t y * @ T a b l e ( n a m e = " p r o d u c t s " ) * / c l a s s P r o d u c t { / * * * @ I d * @ C o l u m n ( t y p e = " i n t e g e r " ) * @ G e n e r a t e d V a l u e * / p r o t e c t e d $ i d ; / * * @ 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 ; / / . . . }
  53. Hydrator

  54. Persister

  55. Unit of Work

  56. A Unit of Work keeps track of everything you do

    during a business transaction that can affect the database. “ — Martin Fowler in PoEAA
  57. When you’re done, it figures out everything that needs to

    be done to alter the database as a result of your work. “ — Martin Fowler in PoEAA
  58. Unit of Work: Object States New Managed Removed Detached

  59. What this looks like in PHP $ u s e

    r = n e w U s e r ( ) ; $ u s e r - > s e t N a m e ( ' J o n ' ) ; / / $ u s e r i s N E W $ m a n a g e r - > p e r s i s t ( $ u s e r ) ; / / $ u s e r i s M A N A G E D $ m a n a g e r - > f l u s h ( ) ; $ m a n a g e r - > r e m o v e ( $ u s e r ) ; / / $ u s e r i s R E M O V E D $ m a n a g e r - > f l u s h ( ) ;
  60. Unit of Work: Identity Map

  61. What this looks like in PHP $ u s e

    r A = $ 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 ( [ ' i d ' = > 1 ] ) ; $ u s e r B = $ 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 ( [ ' i d ' = > 1 ] ) ; $ u s e r A = = = $ u s e r B ; / / t r u e
  62. Doctrine\Common\Persistence\ ObjectManager f i n d ( $ c l

    a s s , $ i d ) p e r s i s t ( $ o b j e c t ) r e m o v e ( $ o b j e c t ) f l u s h ( ) c l e a r ( ) d e t a c h ( $ o b j e c t ) m e r g e ( $ o b j e c t ) r e f r e s h ( $ o b j e c t )
  63. Lifecycle Events Remove Persist Update Load Flush Clear

  64. Event Notification

  65. Doctrine\Common\ EventManager d i s p a t c h

    E v e n t ( $ e v e n t , $ a r g s ) g e t L i s t e n e r s ( $ e v e n t ) h a s L i s t e n e r s ( $ e v e n t ) a d d E v e n t L i s t e n e r ( $ e v e n t , $ l i s t e n e r ) r e m o v e E v e n t L i s t e n e r ( $ e v e n t , $ l i s t e n e r ) a d d E v e n t S u b s c r i b e r ( $ s u b s c r i b e r ) r e m o v e E v e n t S u b s c r i b e r ( $ s u b s c r i b e r )
  66. Doctrine\Common\Persistence\ ObjectRepository f i n d ( $ i d

    ) f i n d A l l ( ) f i n d B y ( $ c r i t e r i a , … ) f i n d O n e B y ( $ c r i t e r i a ) g e t C l a s s N a m e ( )
  67. Query Abstracts database query API Fluent builder interface Filter classes

    ORM/ODM behavior e.g. hydration, fetch mode
  68. What this looks like in PHP / / $ q

    b i s a D o c t r i n e \ O R M \ Q u e r y B u i l d e r $ q b - > s e l e c t ( ' u ' ) - > f r o m ( ' U s e r ' , ' u ' ) - > w h e r e ( ' u . n a m e = : n a m e O R u . n i c k n a m e = : n a m e ' ) - > o r d e r B y ( ' u . a g e ' , ' D E S C ' ) - > s e t P a r a m e t e r s ( [ ' n a m e ' = > ' J o n ' ] ) - > g e t Q u e r y ( ) - > g e t R e s u l t ( )
  69. What this looks like in PHP / / $ q

    b i s a D o c t r i n e \ O R M \ Q u e r y B u i l d e r $ q b - > s e l e c t ( ' u ' ) - > f r o m ( ' U s e r ' , ' u ' ) - > w h e r e ( $ q b - > e x p r ( ) - > o r X ( $ q b - > e x p r ( ) - > e q ( ' u . n a m e ' , ' : n a m e ' ) , $ q b - > e x p r ( ) - > l i k e ( ' u . n i c k n a m e ' , ' : n a m e ' ) ) ) - > o r d e r B y ( ' u . a g e ' , ' D E S C ' ) - > s e t P a r a m e t e r s ( [ ' n a m e ' = > ' J o n ' ] ) - > g e t Q u e r y ( ) - > g e t R e s u l t ( ) ;
  70. None
  71. None
  72. Performance and Tunability Caching results, queries, etc. Change tracking policies

    Proxy objects, fetch modes Code generation
  73. Behind the Persistence

  74. Packages Cache Annotations Lexer Collections Inflector Common DBAL MongoDB CouchDB

    ORM MongoDB ODM CouchDB ODM PHPCR ODM
  75. packagist.org/packages/doctrine/

  76. Doctrine\Common\ Cache Supports over a dozen backends Namespaces and versioning

    Very simple API
  77. Doctrine\Common\ Annotations DocBlock annotation parsing Utilizes the lexer component Cache

    integration
  78. Doctrine\Common\ Collections Object-oriented collection interface ArrayCollection implementation ORM/ODM persistent collections

    Java-inspired Criteria API
  79. Doctrine\ DBAL Thin layer atop PDO SQL database abstraction Type

    mapping Query builder
  80. Doctrine\ MongoDB MongoDB driver abstraction Error handling, recovery Syntactic sugar

    Query builder
  81. But wait, there’s more! CouchDB client and ODM PHP Content

    Repository ODM OrientDB ODM Database migrations
  82. Wrapping Up

  83. Essentially the ORM can handle about 80- 90% of the

    mapping problems, but that last chunk always needs careful work by somebody who really understands how a relational database works. “ — Martin Fowler in OrmHate
  84. Pertinent Resources http://github.com/doctrine http://doctrine-project.org/ http://doctrine-project.org/jira

  85. Freenode IRC #doctrine #doctrine-dev

  86. THANKS! Questions?

  87. Image Credits by http://xkcd.com/327/ http://hqwallbase.com/images/big/Trees-Wallpaper-3008x2000.jpg http://www.angryarchitect.com/wp-content/uploads/2010/04/FowlerFront.jpg https://raw.github.com/paulirish/w3fools/master/images/pity.jpg http://b-i.forbesimg.com/danschawbel/files/2013/03/david.heinemeier.hansson.jpg http://icons8.com http://www.visualpharm.com/