I've written a PHP5 DB Abstraction framework, and I'm wondering if there are any features you guys think I should add. Here's a general picture of how it works:
I have an abstract class Connection:
Connection
-
protected abstract function Connect($args=array)
-
protected abstract function Disconnect()
-
public final function GetConnectionInfo($item=false)
-
protected $infoConn = array()
All Connections can connect, disconnect, and are supposed to store connection information in $infoConn, where it can be retrieved publicly by GetConnectionInfo.
Database is an abstract class extending Connection:
Database
-
public function __destruct()
-
public abstract function Initialize($args)
-
public final function IsInitialized()
-
protected final function SetInitialized($value)
-
public final function GetQuery($index=false)
-
protected $queries
-
private $initialized
The destructor is empty, Initalize initializes the database with an array $args (so you can re-initialize, or initialize after declaration). IsInitialized returns $initialized, which is (obviously) whether or not the Database has been initialized. GetQuery returns the specified offset of $queries (an array of every query run on the Database), or all of them if no index is specified.
An abstract class DefinableDatabase (for databases that I have implemented DDL for) extends Database:
DefinableDatabase
-
public abstract function CreateDefinition(DataDefinition $def)
-
public abstract function ReadDefinition()
-
public abstract function WriteDefinition(DataDefinition $def,$preserveData=true)
CreateDefinition uses a DataDefinition object (described below) to create a blank database with the defined tables (structure only). ReadDefinition reads the definition from the DefinableDatabase, and WriteDefinition writes it to the DefinableDatabase ($preserveData is whether row ID's should be preserved (true), or columns should be ordered according to the DataDefinition object (false); this issue will be fixed later).
DataDefinition
-
public $Tables=array()
-
public function GetDatabaseName()
-
public function AddTable($name)
-
public function RemoveTable($name)
-
public function FindTable($name)
-
public function FindTableIndex($name)
-
public function LoadXML($file)
-
public function SaveXML($file=false)
-
public function __construct($dbName="", $tables = array())
-
private $dbName
Most of this is pretty obvious. $Tables is an array of DataTable objects. For FindTable, FindTableIndex, AddTable, and RemoveTable, names as strings, or a DataTable object with the name property set (the rest is ignored). LoadXML and SaveXML save or load from files. LoadXML can be passed a string or a file; it automatically determines which. The first argument in the constructor can be an xml file, a string of xml code, or a database name. $tables can be of the format array(array('table1','col1','col2','col3'),array('table2','col1'),new DataTable('table3')). Both Find functions return -1 if it can't be found.
DataTable
-
public $Columns = array()
-
public function AddColumn($name)
-
public function AddColumns($col1,$col2...)
-
public function RemoveColumn($name)
-
public function FindColumn($name)
-
public function FindColumnIndex($name)
-
public function __construct($name)
The only difference from DataDefinition is $Columns is an array of DataColumns, and AddColumns allows you to add more than one column.
DataColumn
Nothing special here.
The ADO class is the first hard, usable database class I have; it properly interprets "SHOW TABLES" and "SHOW COLUMNS IN table", even though these aren't features of ADO (at least, not Access, which is what I'm testing with):
ADO
-
public function GetDatabaseName()
-
public final function GetCreateQuery(DataTable $table)
-
public final function GetAlterQuery(DataTable $table,DataTable $oldTable)
-
public function RS_GetColumnSyntax(Recordset $rs,$column)
-
public function RS_Add(Recordset $rs, $record,$table)
Nothing much interesting here. I left out some unimportant helper functions, which aren't publicly accessible anyways. RS_GetColumnSyntax and RS_Add are overrides on the Recordset class, described below. All Databases return a Recordset class, which has TONS of features.
Recordset
-
public function MoveFirst()
-
public function MoveLast()
-
public function MoveNext()
-
public function MovePrev()
-
public function Move($index)
-
public function IsAtEnd()
-
public function IsAtStart()
-
public function IsAt($index)
-
public function BOF()
-
public function EOF()
-
public function GetColumnName($offset)
-
public function GetColumnNumber($name)
-
public function GetColumnCount()
-
public function GetColumns()
-
public function GetRecord($index=false)
-
public function Get($field,$record=false)
-
public function Count()
-
public function Length()
-
protected function GetColumnSyntax($column)
-
protected function GetTableSyntax($strSQL)
-
protected function ExtractTableFromCommand($strSQL)
-
public function SetDatabase(Database $db)
-
public function SetRecords($records)
-
public function SetRecord($record,$index=false,$ignore=true)
-
public function Set($field,$value)
-
public function Save($requery=true)
-
public function Add($record=array())
-
public function Truncate($table=false)
-
public function Delete($index=false)
-
public function Query($strSQL)
-
public function Requery($strSQL=false)
-
public function Filter($filter,$php=true)
-
public function Sort($field,$order='asc',$flags=array())
-
public function Search($value,$field,$flags=array())
-
public function __construct(Database $db, $strSQL = "", $dbinfo = array(array(),array(),false))
-
private $records, $modified;
-
private $strSQL;
-
private $columns;
-
private $index = 0;
-
private $db;
-
protected final function IsOverridden($method)
-
private function Override($method,$args)
Ow. I'm not gonna go over all of that. Filter(): note $php; if that's true, the filter string is evaluated as PHP code, and filtered internally, without requerying the database. A sample filter command:
$rs->Filter("[ID]==4 and ![locked]");
Field names are inside brackets; you can also put field offsets:
$rs->Filter("[0]==4 and ![1]");
All changes to the recordset seem permanent from the user perspective, but changes aren't sent to the database until $rs->Save() is called. Save() will re-run the SELECT query that produced the recordset if param1 is true; otherwise it'll leave itself in the state it is.
Overrides:
I know that some databases require special steps to accomplish something; Access handles autoincrement fields differently than MySQL, so something needs to be done. Databases can override these methods: GetColumnSyntax, GetTableSyntax, ExtractTableFromCommand, Add.
Sorting:
All sorting is done within PHP; flags include: numeric, string.
$rs->Sort("ID",'asc',array("numeric"));
Search doesn't have any flags ATM; I left room just in case.
Note that all of these classes implement exceptions (quite a bit).
ATM, MySQL is out-of-date (I don't use it much). Eventually, I'll get around to updating it. AFAIK, it's just the DefinableDatabase pieces that need to be stuck on.
So....suggestions, comments, flames?