Doctrine 2 - Introduction


Published on

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Doctrine 2 - Introduction

  1. 1. Introduction to ORM Doctrine 2
  2. 2. Object-relational mapping (ORM, O/RM, and O/R mapping) in computer software is a programming technique for converting data between incompatible type systems in object-oriented programming languages. This creates, in effect, a "virtual object database" that can be used from within the programming language. There are both free and commercial packages available that perform object-relational mapping, although some programmers opt to create their own ORM tools.
  3. 3. Loose coupling: Given two lines of code, A and B, they are coupled when B must change behavior only because A changed. Content coupling (high) is when one module modifies or relies on the internal workings of another module (e.g. accessing local data of another module). Therefore changing the way the second module produces data (location, type, timing) will lead to changing the dependent module. High cohesion: They are cohesive when a change to A allows B to change so that both add new value. Functional cohesion (best) is when parts of a module are grouped because they all contribute to a single well-defined task of the module Loose coupling and High Coupling
  4. 4. Ways to deal with data coming from Relational DB's: <ul><li>Advantages: </li></ul><ul><li>Quick (initialy). </li></ul><ul><li>Can use fully all the SQL features, (vendor specific as well) </li></ul><ul><li>Don't require developers with OO experience. </li></ul><ul><li>Disadvantages: </li></ul><ul><li>Vendor dependance. </li></ul><ul><li>The data can come from a webservice, (no comun interface) </li></ul><ul><li>Dificult to maintain, for large systems. </li></ul><ul><li>Change in a table will repercute trought the whole code (high coupling) </li></ul><ul><li>Dificult to implement proper cahcing (when something change in the db, we </li></ul><ul><li>don't know which cache element are affected.) </li></ul>Direct SQL:
  5. 5. Ways to achive “Low Cohesion” and “High coupling” Classes.... first approach class Orders { public function __construct($orderId) { $sql = “select o.order_id,.... from order o inner join o.order_product op on... Inner join op.product p on... inner join o.customers c on. where o.order_id = $orderId. } } class Customer { public function getFullName(){} public function getRating(){} } Class Product { public function getPrice(){} }
  6. 6. <ul><li>Disadvantage: </li></ul><ul><li>Inflexible, we don't need always all that data, we could implelemnt loads criteria, but this make it more and more complex. </li></ul><ul><li>Very Low Cohesion and high coupling, order holds data, and logic for order_products, customer,etc </li></ul><ul><li>if something change in OrderProduct class and/or order_product table is unlikley to break Order class. </li></ul><ul><li>Classes start to be blotted. </li></ul><ul><li>No clear responsabilities for each class. </li></ul><ul><li>Dificult to implement proper caching (when something is updated in db, what queries are affected). </li></ul><ul><li>Advantage: </li></ul><ul><li>Good for small systems. </li></ul><ul><li>Efficent Sql. </li></ul>Ways to achive “Low Cohesion” and “High coupling”
  7. 7. class Order { public function __construct($orderId) { $sql = “select o.order_id,.... from order o where o.order_id = $orderId” } public function getOrderProducts() { $sql = “select op.order_product_id,.... from order_product op where order_id = $this->orderId” } public function getCustomer() { $sql = “select c.customer_id,.... from customer c where c.customer_id = $this->customerId” } } Ways to achive “Low Cohesion” and “High coupling”
  8. 8. class Order { public function __construct($orderId) { $sql = “select o.order_id,.... from order o where o.order_id = $orderId” } public function getOrderProducts() { $this->_orderProducts = new OrderProductCollection($this->orderId); } public function getCustomer() { $this->_customer = new Customer($this->customerId); } } Or even better... Ways to achive “Low Cohesion” and “High coupling”
  9. 9. <ul><li>Now the order class only is concern about the order data and logic, and delegate to OrderProduct, Customer, etc. </li></ul><ul><li>High Cohestion, low coupling, (if something change in OrderProduct class and/or order_product table is unlikley to break Order class) </li></ul><ul><li>. </li></ul><ul><li>We are in controll of what is loaded. </li></ul><ul><li>Very ineficent queries: </li></ul><ul><li>forach( $orderCollection as $order) </li></ul><ul><li>{ </li></ul><ul><li>$order->getCustomer() </li></ul><ul><li>$order->getOrderProducts() </li></ul><ul><li>} </li></ul><ul><li>SELECT ... FROM order </li></ul><ul><li>SELECT … FROM customer </li></ul><ul><li>SELECT … FROM order_product </li></ul>Ways to achive “Low Cohesion” and “High coupling”
  10. 10. $queryBuilder = $em ->createQueryBuilder(); ->select('o') ->from('EntitiesOrders', 'o') ->innerJoin('o.ordersProducts', 'op') ->innerJoin('o.customers', 'c') ->where($queryBuilder->expr()->in('o.ordersId', '?1')) ->setMaxResults(1) ->setParameter(1, '5030492') ->getQuery(); $order = $query->getSingleResult(); This will generate an efficent code: SELECT ..... FROM orders o0_ INNER JOIN orders_products o1_ ON o0_.orders_id = o1_.orders_id INNER JOIN customers c2_ ON o0_.customers_id = c2_.customers_id WHERE o0_.orders_id IN (?) LIMIT 1 Ways to achive “Low Cohesion” and “High coupling” Welcome to Doctrine 2: DQL language
  11. 11. <ul><li>Efficent SQL: The entity manager map the obejcts to the sql tables, and knows how they are realted (trought the metadata), and generate a efficent sql query. </li></ul><ul><li>Don't break choesion: Doctrine create and injects (hydratete) the data into the obejcts (Order, OrderProduct, Customer, etc). </li></ul><ul><li>Flexible, we get what we want: We tell doctrine trought 'DQL language' (pseudo SQL) which obejct we want. </li></ul><ul><li>Database independant. </li></ul>Doctrine 2
  12. 12. How to access the data: echo $order->getCustomer()->getFirstName(); echo $order->getCustomer()->getFullName(); echo $order->getAddressDeliveryStreet(); foreach( $order->getOrdersProducts() as $orderProduct ) { echo $orderProduct->getOrdersProductsId(); echo $orderProduct->getProductName(); } Doctrine create and inject (Hydrate) the data into $order, $customer $orderProducts (collection). We still have decouple and choesive objects Doctrine 2
  13. 13. We sill can do: $queryBuilder = $em ->createQueryBuilder(); ->select('o') ->from('EntitiesOrders', 'o'); And access, but sql no as efficent...: “ SELECT o0.... FROM orders o0_ WHERE o0_.orders_id IN (?) LIMIT 1” echo $order->getCustomer()->getFirstName(); “ SELECT t0.... FROM customers t0 WHERE t0.customers_id = ?” echo $order->getCustomer()->getFullName(); echo $order->getAddressDeliveryStreet(); $orderProducts = $order->getOrdersProducts(); “ SELECT t0... FROM orders_products t0 WHERE orders_id = ?” foreach( $orderProducts as $orderProduct) { echo $orderProduct->getOrdersProductsId(); echo $orderProduct->getProductName(); } Doctrine 2
  14. 14. Also we have magic finder methods throw the repositories: $em->getRepository(“EntitiesOrder”)->find() Or ->findByCustomerId() Doctrine 2
  15. 15. We meet the Doctrin Entities... <?php namespace Entities; /** * @Entity @Table(name=&quot;orders&quot;) */ class Orders { /** * @Id @Column(type=&quot;integer&quot;, name=&quot;orders_id&quot;) * @GeneratedValue(strategy=&quot;AUTO&quot;) */ private $ordersId; /** * @Column(type=&quot;integer&quot;, name=&quot;customers_id&quot;) */ private $customersId; /** * @ManyToOne(targetEntity=&quot;Customers&quot;) * @JoinColumn(name=&quot;customers_id&quot;, referencedColumnName=&quot;customers_id&quot;) */ private $customers; public function getOrdersId() { return $this->ordersId; } public function setOrderId($orderId) { $this->ordersId = $ordersId; } Doctrine 2
  16. 16. They don't follow the Active Record pattern like Zend_Table or Doctrine: “ Active record is an approach to accessing data in a database. A database table or view is wrapped into a class. Thus, an object instance is tied to a single row in the table. After creation of an object, a new row is added to the table upon save. Any object loaded gets its information from the database. When an object is updated the corresponding row in the table is also updated. The wrapper class implements accessor methods or properties for each column in the table or view.”
  17. 17. Data Mapper The Data Mapper is a layer of software that separates the in-memory objects from the database. Its responsibility is to transfer data between the two and also to isolate them from each other. With Data Mapper the in-memory objects needn't know even that there's a database present; they need no SQL interface code, and certainly no knowledge of the database schema. (The database schema is always ignorant of the objects that use it.) Since it's a form of Mapper (473), Data Mapper itself is even unknown to the domain layer $order = new Order; $order->setCustomerId(3); $order->setDeliveryAddress('....'); $em->persist($order); $em->flush();
  18. 18. <ul><li>Entities Metadata, ono-to one, one-to many, may-to many relations </li></ul><ul><li>Custom Repositories </li></ul><ul><li>Query Builder </li></ul><ul><li>Extension </li></ul><ul><li>Listeners </li></ul>Next Session....