doctrine 2 - introduction

18
Introduction to ORM Doctrine 2

Upload: diego-lewin

Post on 27-Jan-2015

105 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Doctrine 2 - Introduction

Introduction to ORM

Doctrine 2

Page 2: Doctrine 2 - Introduction

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.

Page 3: Doctrine 2 - Introduction

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

Page 4: Doctrine 2 - Introduction

Ways to deal with data coming from Relational DB's:

Advantages:

Quick (initialy).

Can use fully all the SQL features, (vendor specific as well)

Don't require developers with OO experience.

Disadvantages:

Vendor dependance.

The data can come from a webservice, (no comun interface)

Dificult to maintain, for large systems.

Change in a table will repercute trought the whole code (high coupling)

Dificult to implement proper cahcing (when something change in the db, we don't know which cache element are affected.)

Direct SQL:

Page 5: Doctrine 2 - Introduction

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(){}}

Page 6: Doctrine 2 - Introduction

Disadvantage:

Inflexible, we don't need always all that data, we could implelemnt loads criteria, but this make it more and more complex.

Very Low Cohesion and high coupling, order holds data, and logic for order_products, customer,etc

if something change in OrderProduct class and/or order_product table is unlikley to break Order class.

Classes start to be blotted.

No clear responsabilities for each class.

Dificult to implement proper caching (when something is updated in db, what queries are affected).

Advantage:

Good for small systems.

Efficent Sql.

Ways to achive “Low Cohesion” and “High coupling”

Page 7: Doctrine 2 - Introduction

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”

Page 8: Doctrine 2 - Introduction

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”

Page 9: Doctrine 2 - Introduction

Now the order class only is concern about the order data and logic, and delegate to OrderProduct, Customer, etc.

High Cohestion, low coupling, (if something change in OrderProduct class and/or order_product table is unlikley to break Order class). We are in controll of what is loaded.

Very ineficent queries:

forach( $orderCollection as $order){ $order->getCustomer() $order->getOrderProducts()

}

SELECT ... FROM order SELECT … FROM customer SELECT … FROM order_product

Ways to achive “Low Cohesion” and “High coupling”

Page 10: Doctrine 2 - Introduction

$queryBuilder = $em ->createQueryBuilder(); ->select('o') ->from('Entities\Orders', '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

Page 11: Doctrine 2 - Introduction

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.

Don't break choesion: Doctrine create and injects (hydratete) the data into the obejcts (Order, OrderProduct, Customer, etc).

Flexible, we get what we want: We tell doctrine trought 'DQL language' (pseudo SQL) which obejct we want.

Database independant.

Doctrine 2

Page 12: Doctrine 2 - Introduction

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

Page 13: Doctrine 2 - Introduction

We sill can do:

$queryBuilder = $em ->createQueryBuilder(); ->select('o') ->from('Entities\Orders', '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

Page 14: Doctrine 2 - Introduction

Also we have magic finder methods throw the repositories:

$em->getRepository(“Entities\Order”)->find()Or->findByCustomerId()

Doctrine 2

Page 15: Doctrine 2 - Introduction

We meet the Doctrin Entities...

<?phpnamespace Entities;

/** * @Entity @Table(name="orders") */class Orders{ /** * @Id @Column(type="integer", name="orders_id") * @GeneratedValue(strategy="AUTO") */ private $ordersId;

/** * @Column(type="integer", name="customers_id") */ private $customersId;

/** * @ManyToOne(targetEntity="Customers") * @JoinColumn(name="customers_id", referencedColumnName="customers_id") */ private $customers;

public function getOrdersId() { return $this->ordersId; }

public function setOrderId($orderId) { $this->ordersId = $ordersId; }

Doctrine 2

Page 16: Doctrine 2 - Introduction

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.”

Page 17: Doctrine 2 - Introduction

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();

Page 18: Doctrine 2 - Introduction

Entities Metadata, ono-to one, one-to many, may-to many relations

Custom Repositories

Query Builder

Extension

Listeners

Next Session....