Custom DataSources
Custom DataSources --
How to write your own DataSource driver.
Introduction
Writing your own DataSource driver is the way to go when none
of the existing driver suit your needs. It is actually pretty easy,
and allows for great flexibility.
Of course, if you're trying to fetch data from an
exotic source, writing your own driver is
required. But, sometimes it's also the best way to achieve the best
optimization, especially (but not only) with
databases.
This document will present you the DataSource interface, and
how to implement it.
Definitions
A DataSource driver is a descendent of
the Structures_DataGrid_DataSource class,
which implements the DataSource interface.
DataSource is a synomym for
DataSource driver.
The DataSource interface consists in a set
of methods that drivers must or may overload and protected properties
that drivers can use, as well as recommended practices.
A DataSource container is a constant or
a variable of any type (string, array, object, etc...) that either
contains data or describes how to retrieve data.
Every DataSource driver is specific to,
and knows how to handle, a given DataSource container
type.
The DataSource interface
Properties available to drivers
array $_options
- Data binding options as an
associative array. You can read the content of this property but you
shouldn't change it directly.
Methods that must or may be implemented in drivers
The constructor must set default options, if any, and call the parent
constructor. This method is optional.
object bind (
mixed container
, array options
)
bind() is reponsible for loading a DataSource
container
into the driver, according to some
binding
options
. This method is optional.
It must return a
PEAR_Error object in case
of failure.
count() must return the total number or records
found in the container. This method is required, and is always called
before
fetch().
It must return a
PEAR_Error object in case of failure.
object sort (
mixed sortSpec
, array sortDir
)
sort() must sort the data according
to
sortSpec
and the optional
sortDir
. This method is required, and is
always called before
fetch(). It must return
a
PEAR_Error object in case of failure.
mixed fetch (
integer offset
, integer len
)
fetch() must return a 2-dimension array of data,
starting from record
offset
, containing
len
records..This method is required
It must return a
PEAR_Error object in case of failure.
Protected methods that drivers can use
void _addDefaultOptions (
array options
)
_addDefaultOptions() is used to declare the
driver-specific options, if any, as well as their default values.
It must be called from the constructor.
void setOptions (
array options
)
setOptions() is a public method used to set
options. If they ever need to change options, drivers should use this
method.
A simple driver
Let's start with a very simple driver. It is rather readable and you
shouldn't have much trouble understanding it. It is not extremely useful
to write a custom driver for a such simple SQL query, but it should get
you started.
A simple SQL adaptor
<?php require 'Structures/DataGrid/DataSource.php'; require_once 'DB.php';
class MyDataSource extends Structures_DataGrid_DataSource { var $db; var $orderBy = ''; function MyDataSource() { $dsn = 'mysql://someuser:apasswd@localhost/thedb'; $this->db =& DB::connect($dsn); }
function count() { $query = "SELECT COUNT(*) FROM animals WHERE species='cat'"; return $this->db->getOne($query); }
function sort($sortSpec, $sortDir = 'ASC') { $this->orderBy = "ORDER BY $sortSpec $sortDir"; }
function fetch($offset = 0, $len = null) { $limit = is_null($len) ? "LIMIT $offset,18446744073709551615" : "LIMIT $offset,$len"; $query = "SELECT * FROM animals WHERE species='cat' "; $query .= $this->_orderBy . " $limit";
return $this->db->getAll($query); } }
?>
|
Testing your driver
Before going live, it is very recommended to test your driver with the
dump() method.
Testing with dump()
<?php $datasource = new MyDataSource();
$count = $datasource->count(); echo "There are $count cats in the farm\n\n";
$datasource->sort('weight');
echo "Here are the 5 lightest ones: \n";
// dump() accepts the same $offset and $len argument as fetch() $datasource->dump(0,5); ?>
|
That should output a nicely formated ascii table like:
There are 23 cats in the farm.
Here are the 5 lightest ones: +---------+---------+-----------+--------+ | name | species | birthDate | weight | +---------+---------+-----------+--------+ | sarge | cat | 20021220 | 1.8 | | etch | cat | 20000509 | 2.5 | | potato | cat | 19980128 | 3.8 | | sid | cat | 20011101 | 4.1 | | woody | cat | 19970712 | 6.0 | +---------+---------+-----------+--------+
|
Using your new driver
Okay, so you have written a driver that's tailored to your needs, and tested
it. It is now time to connect it to
Structures_DataGrid.
For this purpose we're going to use the
bindDataSource()
method.
Binding a custom datasource
<?php
$datagrid =& new Structures_DataGrid();
$datasource = new MyDataSource();
$datagrid->bindDataSource($datasource);
$datagrid->render(); ?>
|
That should output a sortable HTML table.
Of course, the usual features of
Structures_DataGrid are now
available to you: paging, other output formats as XML, MS-Excel,
etc...