Overview
A good ORM package must address the mapping of relationships among objects. EZPDO makes object relationships mapping simple.
One major strength EZPDO has is, unlike other ORM packages, it handles 1:N and M:N relationships automatically. By “automatically”, we mean that EZPDO does the relationship mapping without asking you to create any auxiliary association tables and totally frees you from maintaining them later on.
Besides inheritance, two other important types of relationships are supported: aggregation and composition. We will explain what they mean shortly. (You may also want to take a look at the terms at phpPatterns (which, by the way, is a great source for applying design patterns in PHP).
Object relationships
Aggregation
Aggregation is when a class A object $a has access to a class B objects $b, object $b perhaps having been instantiated outside object $a. If object $a “dies”, object $b will continue to “live”.
[EZPDO translation] Deleting object $a will not remove object $b in datastore.
Composition
Composition happens when a class A object ($a) instantiates another object, object ($b) of another class B, object $b dies when object $a dies. In other words the class A object ($a) controls the whole of the class B object ($b).
[EZPDO translation] Deleting $a will also delete $b from datastore.
Tags for relationships
So how do we specify object relationship in EZPDO? There are two tags for this purpose:
- Aggregation:
@orm has [one|many] Class_X [inverse[(var)]]
- Composition:
@orm composed_of [one|many] Class_Y [inverse[(var)]]
As you may have noticed, the optional keyword after has or composed_of can be either “one” or “many”. If you don’t specify, “one” is assumed. If “many” is used, the corresponding variable is called a many-valued relational variable; otherwise a single-valued variable.
You may have noticed the keyword inverse in the @orm tags. We will describe it soon in Inverse of a relationship var.
Modeling 1:1, 1:N, N:1 and M:N
The @orm has/composed_of [one|many] tags give you enough ammunition to knock out any object relationships, be it 1:1 (one-to-one), 1:N (one-to-many), N:1 (many-to-one), or M:N (many-to-many).
Example 1:1
Let’s start with the simplest: a book has only one author.
/** * @orm mysql://dbuser:secret@localhost/ezpdo */ class Author { // ...... } /** * @orm mysql://dbuser:secret@localhost/ezpdo */ class Book { /** * @orm has one Author */ public $author; }
Example 1:N
An author may have written many books.
/** * @orm mysql://dbuser:secret@localhost/ezpdo */ class Author { /** * An author may write more than one book * @orm has many Book */ public $books; } /** * @orm mysql://dbuser:secret@localhost/ezpdo */ class Book { /** * Let's assume a book has only one author * @orm has one Author */ public $author; }
Note that this example forms a two-way reference, while Example 1:1 is a one-way reference. EZPDO handles one-way and two-way automatically.
Example M:N
Let’s model two facts:
- A book makes references to many other books.
- Writers may co-author one book.
/** * @orm mysql://dbuser:secret@localhost/ezpdo */ class Author { /** * An author may write more than one book * @orm has many Book */ public $books; } /** * @orm mysql://dbuser:secret@localhost/ezpdo */ class Book { /** * A book may be co-authored by more than one author * @orm has many Author */ public $authors; /** * A book may reference many other books * @orm has many Book */ public $ref_books; }
Note that the above example shows you EZPDO can model relationships within the same class ($ref_books) and relationships among different classes ($authors).
Inverse of a relationship var
A relationship variable can have a variable as its inverse in its related class. When two variables are specified as inverses of one another, they can be used to form bidirectional links. An update to one variable will automatically trigger a corresponding update to the other variable, maintaining consistency between the fields.
One or both variables can be many-valued, or both can be single-valued.
Using inverse() in the var @orm tag, you can make a pair of variables in two classes as inverses to each other. For example,
// class A class classA { // @orm has one classB inverse(as) public $b; } // class B class classB { // @orm has many ClassA inverse(b) public $as; }
Variables classA::$b and classB::$a form a bidirectional link. Assigning one object to another will also install the relationship on the other direction. So
$a->b = $b;
is equivalent to
$a->b = $b; $b->as[] = $a;
if A::$b and B::$as are not specified as inverses.
Specify object relationships
With EZPDO, making associations among objects is as easy as
assignement (
. What makes it even nicer is all these associations
made in memory are persisted into your database automatically. As an
EZPDO user, you are also totally(!) free from maintaining them in
later object updating or deletion, all of which are taken care of by the
EZPDO core.
See this example in the tutorial on how to specify object relationships at runtime.