Skip to content
David Moises Paz Reyes edited this page Mar 6, 2012 · 1 revision

Tutorial

So you have followed the simple example and you want to do more with EZPDO.

In this tutorial, we are going to use a simple book-author example to show you some more features EZPDO has, especially its capability of handling object relationships.

##Download and install

The example in this tutorial is included in the EZPDO package. If you have not installed the package, grab the latest release and install now.

Once you have installed the package, go to the examples/book directory.

cd /path/to/install/ezpdo
cd examples/books

##The config file

The directory structure for this example looks like this.

books  
|  
+-- classes  
|  
+-- compiled  

We put all our class files under directory classes and compiled information under compiled. You need to make sure that the compiled directory is writable to the user who runs the scirpts. In the case of SQLite, you also need to make sure the directory to hold your database is writeable (books in this example).

Please note that this example is configured to use SQLite (which, by default, is a built-in extension in PHP 5) and should be able to run without any customization (except that you need to make sure the directories, books and books/compiled are writable to the user who runs the scripts).

All customization can be done in the EZPDO config file.

Let us make sure we have set up our configuration right. We will need to have an EZPDO config file. It normally sits in the directory the scripts live (which is also the default directory that EZPDO will look for the config file), but its totally up to you - you can put it anywhere youd like. If this is the case, make sure you load it explicitly (1).

The configuration file for the tutorial looks like this.

One thing worth mentioning is that the auto_flush and auto_compile options are enabled in the config file.

  • auto_flush: EZPDO saves all objects it creates before quitting the script (except example objects used in
  • auto_compile: EZPDO compiles a new class for mapping information on the fly when you persist its objects for the first time.

For this tutorial, unless you want to customize, you can safely skip database setup and go directly to the data model section.

##Database setup

In case you want your objects to be stored in a different database than the pre-configured one, you only need to change the default_dsn tag in the config file.

Suppose the DSN to the database you like to use is

mysql://username:password@localhost/mydb

Edit config.xml and put the above DSN between <default_dsn> and </default_dsn>.

<default_dsn>mysql://username:password@localhost/mydb</default_dsn>

Once this is done, EZPDO will generate tables for you automatically in the database you specified. If you would like to set up your database from scratch and do more customization, check out this guide.

##The data model

In this example, we have two classes, Author and Book.

  1. An author can write more than one book.
  2. A book can have more than one authors.

So this is an M:N (many-to-many) association. As described in Object relationships, EZPDO handles object relationship automatically, which you will see below.

##The Base class

The classes Author and Book are based off class Base. The Base class does not do anything other than providing a tracking id, which could be used by, say, a bookstore, to easily track books and authors. Note that the var $trackId is simply a regular var that will be persisted in the database. Please dont confuse it with the object identifier (OID) that EZPDO maintains internally. Using this superclass for Author and Book, we want to show you how EZPDO handles inheritance(2).

class Base {
    
    /**
     * tracking id (used by bookstore)
     * @var string
     * @orm char(64)
     */
    public $trackId;
    
    /**
     * Constructor
     */
    public function __construct() { 
        $this->trackId = uniqid('track-'); 
    } 
}

The @orm tag says variable $trackId is mapped to a 64-char column.

##The Author class

An author has a name ($name) and a collection (array) of books ($books) s/he has written.

class Author extends Base {
    /**
     * Name of the author
     * @var string
     * @orm char(64)
     */
    public $name;
    
    /**
     * Books written by the author
     * @var array of Book
     * @orm has many Book
     */
    public $books = array();
    
    /**
     * Constructor
     * @param string $name author name
     */
    public function __construct($name = '') { 
        parent::__construct();
        $this->name = $name;
    }
 
    // the rest of the code in the class omitted... 
 
}

Notice the @orm tag above for the variable $books. It uses

@orm has many Book

which indicates that the variable is a relationship field, of which its associated class is Book and it can have many Book objects.

##The Book class

A book has a title ($title) and page number. A book can have more than one authors.

class Book extends Base {
    
    /**
     * Bool title
     * @var string
     * @orm title char(80)
     */
    public $title;
    
    /**
     * Number of pages
     * @var integer
     * @orm integer
     */
    public $pages = -1;
    
    /**
     * Book author (assuming many co-authors)
     * @var Author
     * @orm has many Author
     */
    public $authors = array();
 
    /**
     * Constructor
     * @param string
     */
    public function __construct($title = '') { 
    parent::__construct();
        $this->title = $title;
    }
 
    // the rest of the code in the class omitted... 
}

Notice above the @orm tag for the variable $authors. It uses

@orm has many Author

which indicates that the variable is a relationship field, of which its associated class is Author and it can have many Author objects.

##Create objects (and associations)

This following snippets show you how to add authors and books using EZPDO. Check out the source file examples/books/add.php.

###Include runtime API

You need to include the EZPDO runtime API and get the persistence manager before you persist any objects.

// need EZPDO runtime API
include_once(dirname(__FILE__) . '/../../ezpdo_runtime.php');
 
// load config.xml (optional: not needed if in currrent dir)
//epLoadConfig('/path/to/your/config.xml');
 
// get the persistence manager (a singleton)
$m = epManager::instance();

###Create authors

Now let us call the manager to work to create authors.

// create authors
$a1 = $m->create('Author');
$a1->name = 'Erich Gamma';
 
$a2 = $m->create('Author');
$a2->name = 'Richard Helm';
 
$a3 = $m->create('Author');
$a3->name = 'Ralph Johnson';
 
$a4 = $m->create('Author');
$a4->name = 'John Vlissides';

Just in case you are a getter/setter lover, you can always do

// setter 
$a1->setName('Erich Gamma');
// getter
echo $a1->getName();

You dont have to define them in the class. The getter/setter methods all come free. The EZPDO core is responsible for setting them up.

You can also access an EZPDO object as an array and its variables as array keys. (You think I am crazy, dont you? :) Example,

$a1['name'] = 'Erich Gamma';
echo $a1['name'];

The magic is that all EZPDO objects have the ArrayAccess interface implemented.

Every road goes to Rome. You choose whichever way you like to play with your objects. :)

###Create books

Now let us create the books.

// create books 
$b1 = $m->create('Book');
$b1->title = 'Design Patterns';
$b1->pages = 395;
 
$b2 = $m->create('Book');
$b2->title = 'Contributing to Eclipse: Principles, Patterns, and Plugins';
$b2->pages = 320;
 
// add more books...
// ......

###Associate authors and books

If you have come this far, you know what we are getting into. Object relationships!

With EZPDO, make 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. You are also totally (and I mean totally! :) free from maintaining them in later updating or deleting, all of which are taken care of by the EZPDO core.

// add authors to books 
$b1->authors = array($a1, $a2, $a3, $a4);
$b2->authors = array($a1);
$b3->authors = array($a2);
$b4->authors = array($a3);
$b5->authors = array($a4);
 
// add books to authors 
$a1->books = array($b1, $b2);
$a2->books = array($b1, $b3);
$a3->books = array($b1, $b4);
$a4->books = array($b1, $b5);

Or you might prefer adding objects to a many-valued relationship field one by one, then you can do

// add authors to books  
$b1->authors[] = $a1;
$b1->authors[] = $a2;
$b1->authors[] = $a3;
$b1->authors[] = $a4;

Simply array operations!

###Commit and auto_flush

Since we have enabled auto_flush in config.xml, we dont even need to commit. Upon quitting the script, all objects are commited to database.

In case you dont want to use the auto_flush feature, you need to commit objects explicitly. You can either commit objects individually

$m->commit($b1);

or flush them all at once

$m->flush();

or flush only objects of a certain class

$m->flush('Book');

Once you have an EZPDO object, you can call commit() or delete() directly through the object without bothering the manager. For example,

// commit an object
$o->commit();
 
// delete an object
$o->delete();

##Object operations

###Check stored objects

Go to the example/books directory and type

php add.php

All the objects you have created will be stored in the database. Now its time to check stored objects.

In case you are curious about how EZPDO maps classes into database tables, you may take a look at the database yourself. You may use tools such as phpMyAdmin to help you visualize the database tables.

In this example, we have a script, print.php, to print out all objects stored. It reads all objects into memory and print them out. Code snippet:

// get the persistence manager
$m = epManager::instance();
 
// get all authors and books 
$authors = $m->get('Author');
$books = $m->get('Book');
    
// loop through authors/books 
// ......

So type

php print.php

and you should see something like this:

author {
  trackId: track-421dbcad4b12e
  name: Erich Gamma
  books:
    1. Contributing to Eclipse: Principles, Patterns, and Plugins
    2. Design Patterns
}

###Find objects

Say you want to find all books written by Eric Gamma, do the following:

// get the persistence manager
$m = epManager::instance();
 
// create the example object
$ea = $m->create('Author');
 
// set name to search
$ea->name = 'Erich Gamma'; 
 
// null variable is ignored in searching
// !!!important if the class constructor set non-null values!!!
$ea->trackId = null;
$ea->books = null;
 
// use the example object to find
if (!($as = $m->find($ea))) {
    echo "Cannot find author [" . $ea->name . "]\n";
    exit();
}
 
// go through each author and print
foreach($as as $a) {
    echo $a; echo "\n";
}

You need to create an example object for the search using the same API method create(), then you call find() with the example object (3). Objects found are put into an array.

You can now also use EZOQL to do object query with more flexibility. The following code does the same thing you just did.

// ...
 
// use EZOQL to find objects
$as = $m->query("from Author as author where author.name = 'Erich Gamma'");
if (!$as) {
    echo "Cannot find author [Erich Gamma]\n";
    exit();
}
 
// ...

###Delete objects

You can delete objects individually

$m->delete($o);

or delete all objects of a class

$m->deleteAll('Book');

Keep in mind that when you delete an object, all associations from and to this object are also removed from the storage. There is no (absolutely no!) need for you to maintain associations for consistency. EZPDO does it all.

For our example in this tutorial, we have a script delete.php in the directory. Type

php delete.php

and all books and authors along with their associations are deleted from the database. Type php print.php to check if objects are deleted.

##What's next?

Congratulations! You have just finished the EZPDO quickstart tutorial! I am sure you have had enough clue and desire to explore more.

It is a good idea to take a moment to skim through the minimalistic runtime API first. And then copy an example directory and start to mess around with it.

You may also want to see what EZOQL (the mini object query language) can do for you. You will be surprised! :)

Dont forget to help us improve this tutorial.

Have fun!


##Notes:

(1) In case the script you run is in a different directory from the one your config.xml is in, you need to use function epLoadConfig() to load your config.xml after including ezpdo_runtime.php, for example,

include_once('/path/to/ezpdo/ezpdo_runtime.php');
epLoadConfig('/path/to/your/config.ini'); // .ini
//epLoadConfig('/path/to/your/config.xml'); // .xml

(2) To learn more on how EZPDO handles inheritance mapping, please refer to Inheritance. Persistence for more complex inheritance can also be found in the composite example under /examples/composite in the package. The example implements the Composite design pattern, in which each object can have a parent object and a set of child objects.

(1) Please note that if an object is used as an example object to find other objects, it’s instantly marked as an uncommitable object. you need to explicitly reset the flag, eo->epSetCommittable(true); for it to be committable. Especially when you choose to auto-flush all uncommited objects including the example objects before quiting the script, make sure you have flagged all of them committable.

Clone this wiki locally