Save 37% off PRO during our Black Friday Sale! »

Doctrine in FLOW3

Doctrine in FLOW3

Presentation given at F3X 2012 on the integration of Doctrine 2 into the PHP framework FLOW3.

Ecfb276920529fc9b924ad4a0877d9ce?s=128

Karsten Dambekalns

April 01, 2012
Tweet

Transcript

  1. Karsten Dambekalns Persistence in FLOW3 with Doctrine 2 FLOW3 Experience

    2012 1
  2. co-lead of TYPO3 5.0 and FLOW3 34 years old lives

    in Lübeck, Germany 1 wife, 3 sons, 1 espresso machine likes canoeing and climbing Karsten Dambekalns 2
  3. Persistence in FLOW3 with Doctrine 2 Object Persistence in the

    Flow • Based on Doctrine 2 • Seamless integration into FLOW3 • Provides the great Doctrine 2 features • Uses UUIDs • Our low-level persistence API • Allows for own, custom persistence backends (instead of Doctrine 2) • CouchDB is supported natively 3
  4. Basic Object Persistence // Create a new customer and persist

    it: $customer = new Customer("Robert"); $this->customerRepository->add($customer); // Update a customer: $customer->setName("I, Robot"); $this->customerRepository->update($customer); // Find an existing customer: $otherCustomer = $this->customerRepository->findByFirstName("Karsten"); // … and delete it: $this->customerRepository->remove($otherCustomer); • Get your repository injected conveniently • Handle your objects (almost) like you had no framework 4
  5. Persistence in FLOW3 with Doctrine 2 Differences to plain Doctrine

    2 in modeling • Identifier properties are added transparently • FLOW3 does autodetection for • repository class names, column types, referenced column names • target entity types, cascade attributes • All Doctrine annotations work as usual • Whatever you specify wins over automation • Allows for full flexibility 5
  6. Purely Doctrine 2 use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="BugRepository")

    */ class Bug { /** * @var integer * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue */ protected $id; /** * @var string * @ORM\Column(type="string") */ protected $description; /** * @var \DateTime * @ORM\Column(type="datetime") */ 6
  7. use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="BugRepository") */ class Bug

    { /** * @var integer * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue */ protected $id; /** * @var string * @ORM\Column(type="string") */ protected $description; /** * @var \DateTime * @ORM\Column(type="datetime") */ Doctrine 2 in FLOW3 7
  8. Purely Doctrine 2 /** * @var \DateTime * @ORM\Column(type="datetime") */

    protected $created; /** * @var Example\User * @ORM\ManyToOne(targetEntity="Example\User", inversedBy="assignedBugs") */ protected $engineer; /** * @var \Doctrine\Common\Collections\Collection<Example\Product> * @ORM\ManyToMany(targetEntity="Example\Product") */ protected $products; } 8
  9. /** * @var \DateTime * @ORM\Column(type="datetime") */ protected $created; /**

    * @var Example\User * @ORM\ManyToOne(targetEntity="Example\User", inversedBy="assignedBugs") */ protected $engineer; /** * @var \Doctrine\Common\Collections\Collection<Example\Product> * @ORM\ManyToMany(targetEntity="Example\Product") */ protected $products; } Doctrine 2 in FLOW3 9
  10. Using Repositories Choose between the generic base repository to support

    any backend or the Doctrine base repository to access advanced Doctrine functionality. Extending the base repositories of FLOW3 • Provides basic methods like: findAll(), countAll(), remove(), removeAll() • Provides automatic finder methods to retrieve by property: findByPropertyName($value), findOneByPropertyName($value) Add specialized finder methods to your own repository. 10
  11. Advanced Queries using the QOM class PostRepository extends \FLOW3\Persistence\Repository {

    /** * Finds most recent posts excluding the given post * * @param \TYPO3\Blog\Domain\Model\Post $post Post to exclude from result * @param integer $limit The number of posts to return at max * @return array All posts of the $post's blog except for $post */ public function findRecentExceptThis(\TYPO3\Blog\Domain\Model\Post $post, $limit = 20) { $query = $this->createQuery(); $posts = $query->matching($query->equals('blog', $post->getBlog())) ->setOrderings(array( 'date' => \TYPO3\FLOW3\Persistence\QueryInterface::ORDER_DESCENDING )) ->setLimit($limit) ->execute() ->toArray(); unset($posts[array_search($post, $posts)]); return $posts; } } PostRepository.php 11
  12. Advanced Queries using DQL class PostRepository extends \FLOW3\Persistence\Doctrine\Repository { /**

    * Finds most recent posts excluding the given post * * @param \TYPO3\Blog\Domain\Model\Post $post Post to exclude from result * @param integer $limit The number of posts to return at max * @return array All posts of the $post's blog except for $post */ public function findRecentExceptThis(\TYPO3\Blog\Domain\Model\Post $post, $limit = 20) { // this is an alternative way of doing this when extending the Doctrine 2 // specific repository and using DQL. $query = $this->entityManager->createQuery( 'SELECT p FROM \TYPO3\Blog\Domain\Model\Post p WHERE p.blog = :blog AND NOT p = :excludedPost ORDER BY p.date DESC' ); return $query ->setMaxResults($limit) ->execute(array('blog' => $post->getBlog(), 'excludedPost' => $post)); } } PostRepository.php 12
  13. Modeling Associations • Modeling associations is hard for many people

    • Start with the model, not the data • Read the Doctrine documentation on associations • Put a printed list of possible association on your wall • Always remember: The owning side of a relationship determines the updates to the relationship in the database 13
  14. Modeling Associations How FLOW3 helps you with associations • Cascade

    attributes are managed by FLOW3 • based on aggregate boundaries • Target entity can be left out • Join columns and tables have automagic defaults • No, not only if your identifier column is named id • Check your mapping with flow3 doctrine:validate All magic can be overridden by using annotations! 14
  15. Schema Management Doctrine 2 Migrations • Migrations allow schema versioning

    and change deployment • Migrations are the recommended way for schema updates • Can also be used to deploy predefined and update existing data • Tools to create and deploy migrations are integrated with FLOW3 15
  16. Schema Management Migrations Workflow • Develop until your model is

    ready for a first “freeze” • Create a migration and move / check / customize it • Migrate to create the tables $ ./flow3 doctrine:migrationgenerate Generated new migration class! Next Steps: - Move /…/DoctrineMigrations/Version20120328152041.php to YourPackage/Migrations/Mysql/ - Review and adjust the generated migration. - (optional) execute the migration using ./flow3 doctrine:migrate $ ./flow3 doctrine:migrate 16
  17. Schema Management /** * Rename FLOW3 tables to follow FQCN

    */ class Version20110824124835 extends AbstractMigration { /** * @param Schema $schema * @return void */ public function up(Schema $schema) { $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); $this->addSql("RENAME TABLE flow3_policy_role TO typo3_flow3_security_policy_role"); $this->addSql("RENAME TABLE flow3_resource_resource TO typo3_flow3_resource_resource"); $this->addSql("RENAME TABLE flow3_resource_resourcepointer TO typo3_flow3_resource_resourcepointer"); $this->addSql("RENAME TABLE flow3_resource_securitypublishingconfiguration TO typo3_flow3_security_authorization_resource_securitypublis_6180a"); $this->addSql("RENAME TABLE flow3_security_account TO typo3_flow3_security_account"); } Migration files are usually very simple code 17
  18. Schema Management $ ./flow3 doctrine:migrationstatus == Configuration >> Name: Doctrine

    Database Migrations >> Database Driver: pdo_mysql >> Database Name: blog >> Configuration Source: manually configured >> Version Table Name: flow3_doctrine_migrationstatus >> Migrations Namespace: TYPO3\FLOW3\Persistence\Doctrine\Migrations >> Migrations Directory: /…/Configuration/Doctrine/Migrations >> Current Version: 2011-06-08 07:43:24 (20110608074324) >> Latest Version: 2011-06-08 07:43:24 (20110608074324) >> Executed Migrations: 1 >> Available Migrations: 1 >> New Migrations: 0 == Migration Versions >> 2011-06-08 07:43:24 (20110608074324) migrated Checking the migration status on the console 18
  19. Schema Management Migrations Workflow • Rinse and repeat: from now

    on create a new migration whenever you changed your model classes • Generated migrations most probably need to be adjusted: • Renaming a model means renaming a table, not dropping and creating • Data migration might need to be added • Sometimes the generated changes are useless Good migrations make your user’s day 19
  20. Schema Management Manual database updates • For simple situations this

    can be good enough: • Useful when • You need to use an existing database dump • No migrations exist for your database of choice (send patches!) • Using SQLite (due to limited schema change functionality) $ ./flow3 doctrine:create $ ./flow3 doctrine:update 20
  21. Integrating existing database tables Use existing data from TYPO3 or

    other applications Two principal approaches • Accessing raw data in a specialized repository • Use your own database connection and SQL • Does not use the default persistence layer • Creating a clean model mapped to the existing structure • FLOW3 will use the same database as the existing application • Uses the default persistence layer 21
  22. Mapping fe_users to a model /** * @FLOW3\Entity * @ORM\Table(name=”fe_users”)

    */ class FrontendUser { /** * @var integer * @ORM\Id * @ORM\Column(name="uid") * @ORM\GeneratedValue */ protected $identifier; /** * @var string */ protected $username; 22
  23. Mapping fe_users to a model /** * @var string */

    protected $username; /** * @var string * @ORM\Column(name="first_name") */ protected $firstName; /** * @var \Doctrine\Common\Collections\Collection<My \Example\FrontendUserGroup> * @ORM\ManyToMany(mappedBy="users") * @ORM\JoinTable(name="user_groups_mm", …) */ protected $groups; 23
  24. Integrating existing database tables Pitfalls • Migrations will try to

    drop existing tables and columns! • Data type mismatches break FK constraints • integer vs. unsigned integer • Real data can be bad data • No FK constraints on legacy data • Missing entries break associations • Watch out for specifics like deleted and hidden flags 24
  25. Persistence in FLOW3 with Doctrine 2 Questions? 25

  26. Thank You! • These slides can be found at: http://speakerdeck.com/u/kdambekalns

    | http://slideshare.net/kfish • Give me feedback: karsten@typo3.org | karsten@dambekalns.de • Download FLOW3: http://flow3.typo3.org • Follow me on twitter: @kdambekalns • Support me using 26