Introducing WhiteBoxDB
WhiteBox DB is an active record style database access layer built on four main principles:
- Ease of use, through an active record style
- Security, by building on PDO's prepared statements
- Ease of integration with existing sites built on PDO
- Knowing your limits
Download and try for yourself.
Easy but secure
By querying the DB for meta information the framework can create strictly typed prepared statements to execute its queries, while maintaining an easy to use active record principle.
Ease of integration
The DB class statically wraps around a PDO object which can be obtained using the DB::pdo() method. To 'install' the framework on an existing site you replace the existing pdo connection statement with a WhiteBoxDB connection statement, and then extract the newly created PDO object.
Easy to extend
Anything as versatile as SQL, is as complex as SQL. So instead of adding layer after layer of complexity to the framework, WhiteBoxDB was designed to allow complex queries to happen outside of the framework.
For one thing, any method of PDO is a method of the DB class, allowing you to write DB::query("your SQL here").
Secondly, the Row object has a simple constructor requiring only a table name and an - incomplete! - array of (field, value) pairs. As long as the array contains the primary keys, any values not given will be retrieved from the database when necessary. This means you can do your own custom queries (using joins and whatnot) and then pass the data right back into the framework.
Starting from version 0.8.0 WhiteBoxDB has both MySQL and tentative PostgreSQL support.
More information on the reasoning behind this project can be found in this article
Syntax examples
To get an idea of how it works, check out the syntax examples given below
Getting rows
If you know the primary key, rows can be found using fetch(). For non-existing rows the fetch functions will return null.
<?
// Fetching a row from a table with a single primary key
$row = DB::fetch('user', 12);
// The same, but more verbose
$row = DB::fetch('user', 'id', 12);
// Fetching from tables with a multi-column primary key
$row = DB::fetch('user', 'one', 12, 'two', 48);
// Or, in case you want to automate this
$row = DB::fetchArray('user', array('one'=>12, 'two'=>48));
// If you want a tiny bit less overhead:
$table = DB::getTable('user');
$row1 = $table->fetch(12);
$row2 = $table->fetch(16);
?>
Accessing fields
Accessing fields is done through the magic functions __get and __set.
<?
// Basic get and set
echo $row->name;
$row->name = 'Bob';
// Iterating
foreach($row as $field => $value)
echo "$field : $value";
// Types are handled automatically
$p = $row->someBooleanField;
echo gettype($p); // returns "boolean"
$row->someBooleanField = 12; // Casts 12 to true before storing
// Nulls are handled correctly
$p = $row->someFieldThatsNull;
var_dump($p); // returns "NULL"
?>
Auto-save
Rows are saved automatically on script shutdown*, but to explicitly save a row use
<?
$result = $row->update();
if ($result)
echo "Changes were made and the row was updated!";
else
echo "No changes were made!";
?>
*You can disable this function if you don't like it
Finding rows
Finding rows is done using the find() method. It shares its syntax with the delete method and functions like count() and max()
<?
// Hardcoded example. Bad!
$table->find('size > 10');
// Using question marks. Good!
$table->find('name LIKE ?', 'mi%');
// Longer WHERE clause
$table->find('gender = ? AND name LIKE ?', 'male', 'mi%');
// Using a limit to return only the first 100 results
$table->find('size > ?', 10, 100);
// Returning the second 100 results
$table->find('size > ?', 10, 100, 100);
// Sorting
DB::find('user', 'ORDER BY name');
// Find the first 10 users alphabetically
DB::find('user', 'ORDER BY name', 10);
// Using lists:
DB::find('user', 'name IN ?', array('name1', 'name2', 'name3'));
?>
Getting only selected fields
If you only want to retrieve selected fields, use partialFetch or partialFind. The remaining fields aren't retrieved, but the Row does know they exist. If you decide you want to access them after all the row will automatically fetch them for you.
<?
// Fetch only fieldA and fieldB
$row = $table->partialFetch(array('fieldA', 'fieldB'), 12);
// $row now only contains its primary key and the given fields
// Magic!
echo $row->fieldC;
// $row now contains all its fields
?>
Inserting & deleting
Inserting is handled through the Table or DB insert method. The data to insert is given as an associative array. This array must contain all fields except those that:
- Have a default value (including NULL), or
- Are defined as an
auto_incrementfield in the database
Deleting a single row is as simple as $row->delete(). Bulk deletes can be handled through the DB or Table's delete() method
<?
// Insert a new user
$data = array(
'id' => 1,
'username' => 'Bob',
'password' => sha1(357nbYRQ),
'age' => 256);
$row = DB::insert('user', $data);
// Now delete bob again
$row->delete();
// Poor bob! Let's create him once over
$row1 = DB::insert('user', $data);
// And once more, using the auto_increment id field
unset($data['id']);
$row2 = DB::insert('user', $data);
// Now to delete both Bob's in one go
DB::delete('user', 'username LIKE ?', 'Bob');
?>
Understandable exceptions
By parsing MySQL error codes, WhiteBoxDB is able to throw a few specialized exceptions
- The
ForeignKeyExceptionis thrown when a foreign key restriction fails. Although MySQL doesn't always provide enough information, sometimes you can use this to tell your users what's going on. - The
DuplicateEntryExceptionis thrown when you attempt to insert a non-unique value into a column with a UNIQUE or PRIMARY restriction.
<?php
// Let's assume we've created a UNIQUE restriction on the `username` field.
$row1 = DB::insert('user', array('username' => 'Bob'));
try
{
$row1 = DB::insert('user', array('username' => 'Bob'));
}
catch (\db\DuplicateEntryException $e)
{
echo "Sorry! That name is already taken
}
?>
In the scenario given above, the method $e->getDuplicateEntry() will provide us with the duplicate entry 'Bob', but not, unfortunately, with the name of the field ('username').
Download & install
If all that sounds good to you, or if you want to get some hands-on experience so you can tell me exactly why it sucks so much, please check out the brand new downloads section.
The installation is a three step process: first you need to unzip the downloaded file, then you need to create (or find) a directory with write access where the library can keep its cache file. Once you've done that, create a connection:
<?php
// Using the default path for the cache file
DB::connect('localhost', 'user', 'pass', 'db_name');
// Using a different path
DB::connect('localhost', 'user', 'pass', 'db_name', 'mydir/dbCache.txt');
?>
Have fun!
Jul 15th, 2010
Comments
No comments yet! Feel free to post some using the form below.
If you wish to add code to your comment you can use code tags, like this: <code class="php">yourCodeHere</code>.
Quite a large number of languages are supported, although I can't guarantee it'll be pretty. Inside the code tags you can use any characters except for the string "</code>".