Simple storage class.
Storage is a simple class to allow storage of objects into a backend storage, which is for now limited to what PEAR DB supports.
This is a rewrite from ecdTable and ecdIterator, a hacky class I've put together some time ago to ease my work.
Improvements over ecdTable:
Located in /Storable.php (line 79)
Class | Description |
---|---|
Customer | Customer definition |
TimeEntry | A time entry for a project and user |
User | The representation of a user |
User_Customer | |
User_Project | |
StorableTree | An implementation of the TreeInSql pattern |
the internal data structure
a copy of the original data structure, saved before set(). Used to create the WHERE clause in save()
the main database handle
the string to pass to DB to connect to the database.
Initialized to the _DSN constant, but can be overriden in child classes.
if this object's match request exists
the join statement, inserted between the FROM and the WHERE
the match pattern used to find this entry
a cache of the numRows*() functions
the offset and count
intialized in the constructor, used to create the LIMIT part of the SELECT.
What comes after the ORDER BY statement.
the main SELECT result database handle
what rows to SELECT defaults to *
Main constructor
This constructor takes care of most of the initialization of the internal structures. It is how data is "loaded" from the storage, into the internal $_data array. A lookup into the database is made in function of the $match parameter.
Example usage:
- require_once('Storable.php');
- class Users extends Storable {}
- /* list all entries in the 'user' table */
- $u = new User();
- // option 1: current API
- while ($u->next()) {
- print $u->get('name') . '<br />';
- }
- // option 2: if next() was called in the constructor
- for ($u = new User("name LIKE '%oey%'"); $u->exists() ; $u->next()) {
- print "...";
- }
But the most interesting facette about this class is how you can use it to save data back to the storage:
- $u = new User(array('name' => 'joey'));
- if ($u->next()) {
- $u->set('name', 'joe');
- } else {
- print "not found, creating new";
- }
- $u->save();
- // You could also eventually do this, but Storable would then need
- // to DESCRIBE the table and fetch the primary key values to be
- // able to save
- $u = new User("dfjfkldsjfs", null, null, null, "* JOIN `tablename` ON jkflkdsjlsd");
- $u = new User("dfjfkldsjfs", null, null, null, "name,desc");
Note: this constructor doesn't call next() anymore, so the proper way to loop over next() is with a while loop:
While you also have to call next() to load a single object, in opposition with how ecdTable traditionnally worked, but much like how ecdIterator works:
Either:
an associative array where key => value pairs correspond to columns => values. The key and value are equal'd and AND'd in a WHERE request.
$match can also be a string, in which case it is taken verbatim as a WHERE. The programmer is then responsible of properly escaping the request. Also, this can create problems when the WHERE does not match anything and the programmer creates a row from the resulting object: Storable::save() will attempt an INSERT which might fail if the row already exists.
Example:
- $user = new User(Array('firstname' => 'joe', 'lastname' => 'smith'));
is equivalent to:
- $user = new User("`firstname` = 'joe' AND `lastname` = 'smith'");
the SELECT part, * by default. Be *really* careful with what you put here, as Storable relies on the result set to construct a WHERE clause for the INSERT or UPDATE queries, when the object is saved back in the storage.
Example:
backup the data array in $_data_orig for later use, but do not override $_data_orig if it already exists.
Take care of the DB magic to connect to the database
The number of items requested in the constructor.
This is the number of items this request is limited to.
disconnect the database handle
does this object exists in the storage?
Set the values of this object to the keys and values of the array.
Get a given field value.
Behavior when fetching an unknown field is undefined.
Deal with results from PEAR DB queries
Will trigger a fatal (E_USER_ERROR) if DB::isError() returns true, with the error message. The debug info is also printed in a E_USER_NOTICE (so it is not visible by default) to aid debugging.
Cannot be called statically
Load the next row available in this object.
If a row is found matching the parameter, it is loaded into the $_data array and subsequently accessible from get() calls. If more than one row are available, they can be loaded into the object by calling next().
If no row is found, the $match array is loaded in the $_data array, and the object is marked as non-existant (exists() == false). This allows easy object creation:
However, the above code will fail if the object does exist, since Storable is not aware of that until next() is called.
The number of rows matchnig all predicates.
Note: this can be lower or equal (but not higher) than the requested count, if the number of rows matching the predicates is smaller the the requested count.
Number of matches without count() or offset().
The offset requested in the constructor.
Remove record represented by object in database.
The matching row(s) is(are) deleted on the spot, so no save() is necessary.
Sets this object to be new (exists() == false) if row was successfully deleted.
Warning: this will delete *all rows matching $match* if next() is not called to load an object before calling remove().
Example:
Save the object in underlying storage.
If the object exists(), the request done will be an UPDATE, otherwise it will obviously be an INSERT. save() uses some magic from PEAR (autoExect()) to ease the construction of the request.
save() will not try to save an unmodified object (one that hasn't had set() called on it).
save() will happily try to save non-existant fields. It is the duty of the programmer to make sure the fields exist in the underlying storage.
The where_clause() is based on the original result set fetched from the database ($_data_orig pour les intimes), and totally ignores primary keys. This has the advantage of avoiding costly DESCRIBE statement in the constructor, but might create problems with JOINs or custom SELECT statements.
Set given field to the given data.
Warning: setting data in a non-existent field might cause a save() query to fail
Assign the associative array directly to the internal structures.
Construct the SELECT statement and call the actual query.
Construct the proper SELECT with the LIMIT, and do the actual query(), but only if not already done.
This is simply code factored out of next() and num_rows().
What table represents this object. Currently returns the lowercased class name.
Can of course be overriden in child classes.
Generate a valid WHERE clause.
The match array is AND'd. If $match is not an array, it is used verbatim, so it is the duty of the programmer to escape it properly.
cannot be called statically (because of DB::quoteIdentifier())
Documentation generated on Tue, 11 Jan 2005 01:38:28 -0500 by phpDocumentor 1.3.0RC3