What Is Doctrine?

8,012 views
7,816 views

Published on

Beginner presentation introducing the Doctrine ORM and the basic operations. Also talks a bit about some upcoming versions 1.2 and 2.0.

Published in: Technology
0 Comments
9 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
8,012
On SlideShare
0
From Embeds
0
Number of Embeds
314
Actions
Shares
0
Downloads
220
Comments
0
Likes
9
Embeds 0
No embeds

No notes for slide

What Is Doctrine?

  1. 1. Nashville LAMP What is Doctrine? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  2. 2. Nashville LAMP Doctrine is a ORM written in PHP What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  3. 3. Nashville LAMP What is an ORM? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  4. 4. Nashville LAMP ORM stands for Object Relational Mapper What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  5. 5. Nashville LAMP Manipulate RDBMS as a set of PHP objects What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  6. 6. Nashville LAMP Easy to get started What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  7. 7. Nashville LAMP Doctrine Sandbox What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  8. 8. Nashville LAMP Doctrine Sandbox $ svn co http://svn.doctrine-project.org/branches/1.1 lamp_doctrine $ cd lamp_doctrine/tools/sandbox $ php doctrine.php Command Line What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  9. 9. Nashville LAMP User: Test Schema columns: first_name: lamp_doctrine/tools/sandbox/schema/schema.yml type: string(255) notnull: true Phonenumber: last_name: columns: type: string(255) phonenumber: notnull: true type: string(55) username: notnull: true type: string(255) user_id: unique: true type: integer notnull: true notnull: true password: relations: type: string(255) User: notnull: true foreignAlias: Phonenumbers email_address: onDelete: CASCADE type: string(255) notnull: true email: true unique: true What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  10. 10. Nashville LAMP Test Data lamp_doctrine/tools/sandbox/data/fixtures/data.yml User: jwage: first_name: Jonathan last_name: Wage username: jwage password: changeme email_address: jonathan.wage@sensio.com Phonenumbers: cell: phonenumber: 6155139185 office: phonenumber: 4159925468 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  11. 11. Nashville LAMP Build All Reload $ php doctrine.php build-all-reload What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  12. 12. Nashville LAMP Running Tests • First DQL Query • Working with objects • Writing DQL Queries – SELECT queries – UPDATE queries – DELETE queries • Custom Accessors/Mutators • Using Migrations What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  13. 13. Nashville LAMP First DQL Query $ php doctrine.php dql quot;FROM User u, u.Phonenumbers pquot; What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  14. 14. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Insert new User $user = new User(); $user->first_name = 'Fabien'; $user->last_name = 'Potencier'; $user->username = 'fabpot'; $user->password = 'changeme'; $user->email_address = 'fabien.potencier@sensio.com'; $user->save(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  15. 15. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Edit existing User $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('jwage'); $user->password = 'newpassword'; $user->save(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  16. 16. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Adding Phonenumbers $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('fabpot'); $user->Phonenumbers[]->phonenumber = '1233451234'; $user->Phonenumbers[]->phonenumber = '9875674543'; $user->save(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  17. 17. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Deleting Objects $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('fabpot'); $user->Phonenumbers[0]->delete(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  18. 18. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Deleting Collections $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('fabpot'); $user->Phonenumbers->delete(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  19. 19. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php SELECT Queries $q = Doctrine::getTable('User') ->createQuery('u'); $users = $q->execute(); print_r($users->toArray()); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  20. 20. Nashville LAMP Writing DQL Queries Array ( [0] => Array ( [id] => 1 [first_name] => Jonathan [last_name] => Wage [username] => jwage [password] => changeme [email_address] => jonathan.wage@sensio.com ) [1] => Array ( [id] => 2 [first_name] => Fabien [last_name] => Potencier [username] => fabpot [password] => changeme [email_address] => fabien.potencier@sensio.com ) ) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  21. 21. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php SELECT Queries $q = Doctrine::getTable('User') ->createQuery('u') ->leftJoin('u.Phonenumbers p') ->andWhere('u.username = ?', 'jwage'); $users = $q->execute(); print_r($users->toArray(true)); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  22. 22. Nashville LAMP Writing DQL Queries Array ( [0] => Array ( [id] => 1 [first_name] => Jonathan [last_name] => Wage [username] => jwage [password] => changeme [email_address] => jonathan.wage@sensio.com [Phonenumbers] => Array ( [0] => Array ( [id] => 1 [phonenumber] => 6155139185 [user_id] => 1 [User] => ) [1] => Array ( [id] => 2 [phonenumber] => 4159925468 [user_id] => 1 [User] => ) ) ) ) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  23. 23. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php UPDATE Queries $q = Doctrine::getTable('User') ->createQuery('u') ->update() ->set('email_address', '?', 'jonwage@gmail.com') ->andWhere('username = ?', 'jwage'); $affectedRows = $q->execute(); echo $affectedRows; // 1 $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  24. 24. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php DELETE Queries $q = Doctrine::getTable('User') ->createQuery('u') ->delete() ->andWhere('username = ?', 'jwage'); $affectedRows = $q->execute(); echo $affectedRows; // 1 $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  25. 25. Nashville LAMP Custom Accessors Enable Auto Accessor Override lamp_doctrine/tools/sandbox/config.php // ... $manager = Doctrine_Manager::getInstance(); $manager->setAttribute('auto_accessor_override', true); What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  26. 26. Nashville LAMP Custom Accessors Custom `name` accessor What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  27. 27. Nashville LAMP Custom Accessors lamp_doctrine/tools/sandbox/models/User.php class User extends BaseUser { public function getName() { return trim($this->first_name.' '.$this->last_name); } } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  28. 28. Nashville LAMP Custom Accessors lamp_doctrine/tools/sandbox/index.php $q = Doctrine::getTable('User') ->createQuery('u') ->andWhere('username = ?', 'jwage'); $user = $q->fetchOne(); echo $user->name; // Jonathan Wage $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  29. 29. Nashville LAMP Custom Mutator MD5 encrypt passwords class User extends BaseUser { // ... public function setPassword($password) { $this->_set('password', md5($password)); } } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  30. 30. Nashville LAMP Custom Mutator MD5 encrypt passwords $q = Doctrine::getTable('User') ->createQuery('u') ->andWhere('username = ?', 'jwage'); $user = $q->fetchOne(); $user->password = 'changeme'; $user->save(); echo $user->password; // 4cb9c8a8048fd02294477fcb1a41191a What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  31. 31. Nashville LAMP Accessor/Mutator Syntax Object property, function, array access echo $user->name; echo $user->get('name'); echo $user['name']; What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  32. 32. Nashville LAMP Database Migrations What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  33. 33. Nashville LAMP Deploy schema changes What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  34. 34. Nashville LAMP Maintain production data What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  35. 35. Nashville LAMP Programmatic interface for issuing DDL statements What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  36. 36. Nashville LAMP Versions your database What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  37. 37. Nashville LAMP Upgrade your database to new versions Downgrade to previous versions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  38. 38. Nashville LAMP Database Migrations Add new status column to users What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  39. 39. Nashville LAMP Database Migrations User: columns: # ... status: type: enum values: [Pending, Active, Inactive] What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  40. 40. Nashville LAMP Database Migrations Generate migration class $ php doctrine generate-migrations-diff What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  41. 41. Nashville LAMP Database Migrations Generate migration class class Version1 extends Doctrine_Migration_Base { public function up() { $this->addColumn('user', 'status', 'enum', '', array('values' => array(0 => 'Pending', 1 => 'Active', 2 => 'Inactive'))); } public function down() { $this->removeColumn('user', 'status'); } } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  42. 42. Nashville LAMP Database Migrations Customize migration class class Version1 extends Doctrine_Migration_Base { public function postUp() { Doctrine::loadModels(realpath(dirname(__FILE__).'/../models')); Doctrine::getTable('User') ->createQuery('u') ->update() ->set('status', '?', 'Active') ->execute(); } // ... } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  43. 43. Nashville LAMP Database Migrations Executing migration $ php doctrine migrate migrate - migrated successfully to version #1 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  44. 44. Nashville LAMP Database Migrations Update models from YAML $ php doctrine generate-models-yaml What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  45. 45. Nashville LAMP Database Migrations Inspect migration was successful or not New status column exists Default `Active` value What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  46. 46. Nashville LAMP Future of Doctrine? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  47. 47. Nashville LAMP New Versions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  48. 48. Nashville LAMP Doctrine 1.2 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  49. 49. Nashville LAMP Continued evolution of the 1.x codebase What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  50. 50. Nashville LAMP Doctrine 2.0 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  51. 51. Nashville LAMP Almost complete re-rewrite What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  52. 52. Nashville LAMP Major version What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  53. 53. Nashville LAMP Requires PHP 5.3 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  54. 54. Nashville LAMP Performance increases from 5.3 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  55. 55. Nashville LAMP Test suite runs 20% faster What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  56. 56. Nashville LAMP And uses 30% less memory What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  57. 57. Nashville LAMP Hydration performance improvements What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  58. 58. Nashville LAMP Hydration Performance Doctrine 1.1 4.3435637950897 for 5000 records Doctrine 2.0 1.4314442552312 for 5000 records Doctrine 2.0 3.4690098762512 for 10000 records What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  59. 59. Nashville LAMP Removed Major Limitation No need to extend a base class /** class User extends Doctrine_Record * @DoctrineEntity { * @DoctrineTable(name=quot;userquot;) public function setTableDefinition() */ { class User $this->hasColumn('id', 'integer', null, array( { 'primary' => true, /** 'auto_increment' => true * @DoctrineId )); * @DoctrineColumn(type=quot;integerquot;) * @DoctrineGeneratedValue(strategy=quot;autoquot;) $this->hasColumn('username', 'string', 255); */ } public $id; } /** * @DoctrineColumn(type=quot;varcharquot;, length=255) */ public $username; } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  60. 60. Nashville LAMP No more crazy cyclic references What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  61. 61. Nashville LAMP print_r() your objects $user = new User(); $user->username = 'jwage'; print_r($user); User Object ( [id] => [username] => jwage ) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  62. 62. Nashville LAMP Positive effects of removing the base class all around What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  63. 63. Nashville LAMP General Improvements What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  64. 64. Nashville LAMP Code de-coupled What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  65. 65. Nashville LAMP 3 Main Packages What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  66. 66. Nashville LAMP Common What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  67. 67. Nashville LAMP DBAL What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  68. 68. Nashville LAMP ORM What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  69. 69. Nashville LAMP Use Doctrine DBAL separate from the ORM What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  70. 70. Nashville LAMP Easier to extend and override things What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  71. 71. Nashville LAMP Better support for multiple databases What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  72. 72. Nashville LAMP Sequences, schemas and catalogs What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  73. 73. Nashville LAMP Simplified connection information $config = new DoctrineORMConfiguration(); $eventManager = new DoctrineCommonEventManager(); $connectionOptions = array( 'driver' => 'pdo_sqlite', 'path' => 'database.sqlite' ); $em = DoctrineORMEntityManager::create($connectionOptions, $config, $eventManager); What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  74. 74. Nashville LAMP No more DSN nightmares What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  75. 75. Nashville LAMP Connection information specified as arrays What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  76. 76. Nashville LAMP Removed old attribute system What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  77. 77. Nashville LAMP Replaced with simpler string based system What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  78. 78. Nashville LAMP Real Native SQL support What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  79. 79. Nashville LAMP Driver Based Meta Data What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  80. 80. Nashville LAMP PHP Annotations /** * @DoctrineEntity * @DoctrineTable(name=quot;userquot;) */ class User { /** * @DoctrineId * @DoctrineColumn(type=quot;integerquot;) * @DoctrineGeneratedValue(strategy=quot;autoquot;) */ public $id; /** * @DoctrineColumn(type=quot;varcharquot;, length=255) */ public $username; } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  81. 81. Nashville LAMP PHP Code class User { public $id, $username; } $metadata = new ClassMetadata('User'); $metadata->mapField(array( 'fieldName' => 'id', 'type' => 'integer', 'id' => true )); $metadata->setIdGeneratorType('auto'); $metadata->mapField(array( 'fieldName' => 'username', 'type' => 'varchar', 'length' => 255 )); What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  82. 82. Nashville LAMP YAML class User { public $id, $username; } User: properties: id: id: true type: integer idGenerator: auto username: type: varchar length: 255 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  83. 83. Nashville LAMP Write your own driver What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  84. 84. Nashville LAMP Cache What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  85. 85. Nashville LAMP Query Cache Cache final SQL that is parsed from DQL What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  86. 86. Nashville LAMP Metadata Cache Cache the parsing of meta data What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  87. 87. Nashville LAMP Result Cache Cache the results of your queries What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  88. 88. Nashville LAMP Inheritance Mapping What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  89. 89. Nashville LAMP Single Table One table per hierarchy What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  90. 90. Nashville LAMP Class Table One table per class What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  91. 91. Nashville LAMP Concrete Table One table per concrete class What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  92. 92. Nashville LAMP Testing What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  93. 93. Nashville LAMP Switched to phpUnit What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  94. 94. Nashville LAMP Better mock testing What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  95. 95. Nashville LAMP Easy to run tests against multiple DBMS What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  96. 96. Nashville LAMP Code de-coupled so it is easier to test What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  97. 97. Nashville LAMP New Features What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  98. 98. Nashville LAMP New DQL Parser What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  99. 99. Nashville LAMP Hand written What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  100. 100. Nashville LAMP Recursive-descent parser What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  101. 101. Nashville LAMP Constructs AST What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  102. 102. Nashville LAMP PHP Class names directly represent DQL language What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  103. 103. Nashville LAMP Every DQL feature has a class to handle parsing What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  104. 104. Nashville LAMP Easy to maintain Easy to add new features Easy to use What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  105. 105. Nashville LAMP Performance? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  106. 106. Nashville LAMP Final SQL can be easily and effectively cached What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  107. 107. Nashville LAMP Not practical to parse every time What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  108. 108. Nashville LAMP Custom Column Types What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  109. 109. Nashville LAMP Add your own data types What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  110. 110. Nashville LAMP Types are OOP classes What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  111. 111. Nashville LAMP Easy to extend or add new types What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  112. 112. Nashville LAMP Extend DQL What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  113. 113. Nashville LAMP DQL parser can be extended What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  114. 114. Nashville LAMP Add your own DQL functions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  115. 115. Nashville LAMP When? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  116. 116. Nashville LAMP First release in September 09` What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  117. 117. Nashville LAMP ALPHA What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  118. 118. Nashville LAMP BETA What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  119. 119. Nashville LAMP RC What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  120. 120. Nashville LAMP Stable - 2010’ ? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  121. 121. Nashville LAMP What is next? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  122. 122. Nashville LAMP Publishing of first Doctrine book What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  123. 123. Nashville LAMP Write more documentation What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  124. 124. Nashville LAMP Publish more books What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  125. 125. Nashville LAMP Doctrine community extension repository Symfony has Plugins and Doctrine has Extensions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  126. 126. Nashville LAMP Default DBAL and ORM in PEAR2? De-facto standard? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  127. 127. Nashville LAMP It is up to you! :) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  128. 128. Nashville LAMP Questions? Jonathan H. Wage jonathan.wage@sensio.com +1 415 992 5468 sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com You can contact Jonathan about Doctrine and Open-Source or for training, consulting, application development, or business related questions at jonathan.wage@sensio.com What is Doctrine? www.doctrine-project.org www.sensiolabs.com

×