Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Doctrine in FLOW3

Doctrine in FLOW3

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

Karsten Dambekalns

April 01, 2012
Tweet

More Decks by Karsten Dambekalns

Other Decks in Technology

Transcript

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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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
    * @ORM\ManyToMany(targetEntity="Example\Product")
    */
    protected $products;
    }
    8

    View full-size slide

  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
    * @ORM\ManyToMany(targetEntity="Example\Product")
    */
    protected $products;
    }
    Doctrine 2 in FLOW3
    9

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  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\Example\FrontendUserGroup>
    * @ORM\ManyToMany(mappedBy="users")
    * @ORM\JoinTable(name="user_groups_mm", …)
    */
    protected $groups;
    23

    View full-size slide

  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

    View full-size slide

  25. Persistence in FLOW3 with Doctrine 2
    Questions?
    25

    View full-size slide

  26. Thank You!
    • These slides can be found at:
    http://speakerdeck.com/u/kdambekalns | http://slideshare.net/kfish
    • Give me feedback:
    [email protected] | [email protected]
    • Download FLOW3: http://flow3.typo3.org
    • Follow me on twitter: @kdambekalns
    • Support me using
    26

    View full-size slide