This chapter describes typical usage of the Persistent Object package with a
single persistent class using MySQL as the persistence storage.
We want to make a simple class, representing a person, persistent using
persistent object. It is a simple class with only a few members:
- <?php
- class Person
- {
- private id = null;
- public name = null;
- public age = null;
-
- public function getState()
- {
- $result = array();
- $result['id'] = $this->id;
- $result['name'] = $this->name;
- $result['age'] = $this->age;
- return $result;
- }
-
- public function setState( array $properties )
- {
- foreach( $state as $key => $value )
- {
- $this->$key = $value;
- }
- }
- }
- ?>
The id member will map to the required persistent identifier. It has to default
to null. This is not required for any of the other mapped members. The id field
is a required unique identifier for this persistent object. It is generated by
the identifier generator and usually maps to an auto increment column in the
database.
For simplicity we have made the name and age members of the Person class
public. However, this is not required and in a real application you can use
any access method you like e.g access methods or properties or even having the
data completely private.
All persistent objects must implement the getState() and setState()
methods. They are used to retrieve the state of the object when saving it and
to set it when loading it. The getState() method should always return the
complete state of the object while the setState() method should be prepared to
only set one member at the time.
We are going to map the Person class onto the following SQL table:
CREATE TABLE persons
(
id integer unsigned not null auto_increment,
full_name varchar(255),
age integer,
PRIMARY KEY (id)
) TYPE=InnoDB;
The fields map one to one to the members of the Person class. Using the
InnoDB type is not required. We strongly recommend it however, since it
supports transactions. The id column is of the type auto_increment. This is
required for the id generator that we will use. Other id generators may have
other requirements to work as expected.
In order for Persistent Object to be able to store objects of the Person class
into the persons table we need to tell it how the columns are mapped to class
members. We will use the ezcPersistentCodeManager to fetch the definitions when
required.
ezcPersistentCodeManager requires us to define the mapping using the
ezcPersistentObjectDefinition, ezcPersistentObjectIdProperty and
ezcPersistentObjectProperty classes:
- <?php
- $def = new ezcPersistentObjectDefinition();
- $def->table = "persons";
- $def->class = "Person";
-
- $def->idProperty = new ezcPersistentObjectIdProperty;
- $def->idProperty->columnName = 'id';
- $def->idProperty->propertyName = 'id';
- $def->idProperty->generator = new ezcPersistentGeneratorDefinition( 'ezcPersistentSequenceGenerator' );
-
- $def->properties['name'] = new ezcPersistentObjectProperty;
- $def->properties['name']->columnName = 'full_name';
- $def->properties['name']->propertyName = 'name';
- $def->properties['name']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_STRING;
-
- $def->properties['age'] = new ezcPersistentObjectProperty;
- $def->properties['age']->columnName = 'age';
- $def->properties['age']->propertyName = 'age';
- $def->properties['age']->propertyType = ezcPersistentObjectProperty::PHP_TYPE_INT;
-
- return $def;
- ?>
The first block of code creates the definition object and sets the database
table and the name of the class to map. The second block defines the mapping of
the identifier member and the algorithm that should be used to create
identifiers for new objects. We will use the ezcPersistentSequenceGenerator
which simply retrieves the new identifier generated by auto_increment.
The next two code blocks define the mapping between the database columns and
the class members. It is possible to use the same name in the class and the
database for a field.
The members must be inserted into the properties member, which is an
associative array, using the name of the member as the key name.
If you look at the API of ezcPersistentObjectDefinition
it also has a property named 'columns' which is the same array as the
'properties' except it is mapped on the column names instead of the property
names. This reverse mapping is set up by the ezcPersistentCodeManager.
Finally we return the complete definition. Your definition will not work unless
you return it to the manager.
To make the definition work with the ezcPersistentCodeManager it must be put in
a separate PHP file and given the name of the class in lowercase letters. In
our example it should be put in a file named person.php.
The session object is in charge of the actual loading and saving of persistent
objects. A session can be created simply by instantiating it:
- <?php
- $session = new ezcPersistentSession(
- ezcDbInstance::get(),
- new ezcPersistentCodeManager( "path/to/definitions" )
- );
- ?>
The session takes two arguments: a pointer to the database instance to use and
the manager it should use to retrieve persistent object definitions. We are
using the ezcPersistentCodeManager which loads the definitions directly from
file. You should point it to the location where you saved the person.php file.
While it is possible to create a new session each time you want to manipulate a
persistent object you will probably want to use the same session each
time. This functionality can be achieved by wrapping the session in a singleton
class.
Creating a new Person object and making it persistent is straight forward:
- <?php
- $object = new Person();
- $object->name = "Guybrush Threepwood";
- $object->age = 31;
-
- $session->save( $object );
- ?>
This code saves our newly created object to the database and generates an id
for it. The id is set to the id property of the object. Since Guybrush is our
first person he will get the identifier 1.
Of course, the age of Guybrush Threepwood is the source of much debate and most
probably he is younger than 31. To make the change simply edit the object and
tell the session to update it.
- <?php
- $object->age = 25;
- $session->update( $object );
- ?>
Note that we used update() to store the object this time. This is because we
want to trigger an UPDATE query instead of an INSERT query.
There are several ways to retrieve persistent objects from the database. The
simplest is to fetch one object by its identifier.
- <?php
- $object = $session->load( 'Person', 1 );
- ?>
This code retrieves the Guybrush object created above.
If you have stored a lot of persistent objects to the database and you want to retrieve a
list you can use the find method. The find method requires a query parameter which you
can retrieve from the session first.
- <?php
- $q = $session->createFindQuery( 'Person' );
- $q->where( $q->expr->gt( 'age', 15 ) )
- ->orderBy( 'full_name' )
- ->limit( 10 );
- $objects = $session->find( $q, 'Person' );
- ?>
This code will fill fetch a maximum of 10 Person objects older than 15 years
sorted by their names.
The find() method will fetch the complete result set and instantiate it for
you. This is not desirable if you are fetching large numbers of objects and you
want it to be fast and efficient. For this you can use the fetchIterator()
method:
- <?php
- $q = $session->createFindQuery( 'Person' );
- $q->where( $q->expr->gt( 'age', 15 ) )
- ->orderBy( 'name' )
- ->limit( 10 );
- $objects = $session->findIterator( $q, 'Person' );
-
- foreach( $objects as $object )
- {
- // ...
- }
- ?>
This code will produce the same result as the first find() example. However,
only one object will be instantiated and the data will be transfered from the
database only when it is needed.
The easiest way to delete persistent objects is to use the delete method() on
the session:
- <?php
- $object = $session->load( 'Person', 1 );
- $session->delete( $object );
- ?>
Of course, you can only delete instantiated objects this way. If you want to
delete an object or a whole series of objects that are not instantiated you can
use the deleteFromQuery() method:
- <?php
- $q = $session->createDeleteQuery( 'Person' );
- $q->where( $q->expr->gt( 'age', 15 ) );
- $session->deleteFromQuery( $q );
- ?>
When executed the above code will remove all persons older than 15 years old
from the database.
All persistent objects are required to have an identifier field. The identifier
generation algorithm defines how the system will generate IDs for new
objects. This chapter describes the available generators.
The sequence generator relies on the PDO::lastInsertId() method to retrieve the
IDs for newly created persistent objects.
It is recommended to use auto_increment id columns for databases supporting
it. This includes MySQL and SQLite. Other databases need to use a sequence. E.g
for PostgreSQL the person table definition should look like:
CREATE TABLE persons
(
id integer unsigned not null,
full_name varchar(255),
age integer,
PRIMARY KEY (id)
);
CREATE SEQUENCE person_seq START 1;
If your database requires you to use a sequence this parameter should be
provided to the ezcPersistentSequenceGenerator in the mapping definition.
- <?php
- $def->idProperty->generator = new ezcPersistentGeneratorDefinition(
- 'ezcPersistentSequenceGenerator',
- array( 'sequence' => 'person_sequence' )
- );
- ?>
The session object needs to be able to fetch the persistent object
definitions in order to function properly. The task of fetching the definitions
is performed by a definition loader which is provided to the session when it is
instantiated.
This is currently the only manager available. It simply reads the definition
from a file named the same as the class from the specified directory. It does
not perform any error checking on the definition and simply assumes that it is
correct.
It is very easy to create your own definition loader. Simply extend the
ezcPersistentDefinitionManager abstract class and implement the fetchDefinition
method:
- <?php
- class ezcPersistentCodeManager extends ezcPersistentDefinitionManager
- {
- public function fetchDefinition( $class )
- {
- }
- }
- ?>
The fetchDefinition() method should create the definition structure for the
requested class or throw an exception