Návrh databázové třídy - díl I: Úvod, cíle

Mon, 8 Mar 2010 20:05:32 +1100

Jaro už je pomalu za dveřmi, je nejvyšší čas pustit se do objektů. Jako učební pomůcku jsem zvolil právě databázový layer, jelikož na jeho návrhu a tvorbě se dá mnohé ukázat i vysvětlit, o využití v praxi nemluvě.

Sám jsem začínal zprvu jednoduchým podnětem: potřebou monitorovat a sčítat provedené SQL dotazy. Skutečný život se ale následně ukázal mnohem složitější, a tak bylo potřeba napsat pokročilou knihovnu, která toho co nejvíce udělá za mě. Proto nyní otevírám miniseriál tak trochu o objektech a tak trochu o návrhových vzorech.

Zadání

Každý úkol by měl mít své zadání, takže nejdříve si specifikujeme body, které se pokusíme splnit. Úkolem třídy bude komunikace s MySQL databází, podchycení nejčastěji prováděných akcí za pomocí metod, které mám kompletně nahradí mysql_ funkce v jazyce PHP. To vše samozřejmě za využití výhod, které nám objektově orientované programování v PHP5 nabízí.

Jaké jsou tedy cíle?

Automatizovat otravných, přesto nutných operací.

Docílení sympatičtějšího zápisu opakovaně volaných funkcí.

Příprava platformy pro snadné připojení k více databázím. Jedna instance bude rovna jednomu otevřenému spojení.

Tvorba prostředí pro ladění SQL dotazů.

A v neposlední řadě se také něco naučit a zlepšit si abstraktní myšlení :o)

Prvotní návrh

Rozhraní, které je vlastně takový to do list, nám definuje všechny veřejné metody, které má výsledná třída obsahovat. Většinu těch soukromých zatím vůbec zmiňovat nebudu, jelikož po jejich implementaci nás stejně přestanou zajímat. V prvním kroku tedy definujeme tři rozhraní, jedno pro každou třídu, která bude ve výsledku existovat.

Rozhraní pro class Db

Kostra databázové třídy napoví, co od ní budeme očekáváme. Jejím úkolem bude mimo jiné uchovávat spojení s databází, ošetřovat veškerý vstup před předáním další třídě a zautomatizovat zdlouhavé psaní dotazů typu INSERT, UPDATE a DELETE. Nakonec ji také rozšíříme o export tabulek.

interface DbModel
{
	public function __construct($key = 'db');

	public function query($query, $pholders = null);
	public function select($query, $pholders = null, $replacePrefix = true);
	public function insert($table, array $items);
	public function update($table, $id, array $items, $col = 'id');
	public function delete($table, array $cond);

	public function replacePrefix($string);
	public function escape($string);
	public function getUniqueColumns($table);
	public function columnExists($table, $col);
	public function tableExists($table);

	public function startTime();
	public function stopTime($start, $format = 6);

	public function dumpAndSave();
	public function dumpAndDownload();
	public function writeToFile($file_name, $content);
	public function addExportCondition($table, $where = null);

	public function getConnection();
	public function getQueries();
	public function numQueries();
	public function getMagicQuotes();

	public function setPrefixChar($char = null);
	public function setBackupFolder($folder);

// 	public function enableLog($user_id = 0);
// 	public function setLogTable($logTable = null);
// 	public function setLogItemsTable($tableItems = null);
// 	public function disableLog();

	public function __destruct();
}

class Query

Syrové informace, které dostane třída Db budou po zpracování odeslány konstruktoru třídy Query. Půjde o znění SQL dotazu plus samozřejmě referenci instanci Db. Jediný konstruktor bude tedy data vkládat, všechny ostatní metody je budou vracet. Rozhraní opět napoví, jaké chování od objektu vyžadujeme.

interface QueryModel
{
	public function __construct(Db $db, $query);
	public function assocList($key = null, $col = null, $pattern = null, $array = array());
	public function result($col = 0, $field = null);
	public function row();
	public function numRows();
	public function insertId();
	public function affectedRows();
	public function countNumRows();
	public function fetch($type = FETCH_ASSOC);
	public function __toString();
	public function __unset($value = null);
	public function __destruct();
}

class DbException

Class DbException bude pouze rozšíření třídy Exception o jednu metodu, které se postará o smysluplný výpis informací o vzniklé chybě. Do konstruktoru budeme předávat vlastní chybové hlášení plus znění ztroskotaného SQL dotazu.

interface DbExceptionModel
{
	public function __construct($msg = null, $errString = null);
	public function show();
}

To by pro úvod zatím stačilo, v pokračování začneme rovnou spojením s databází v metodě Db::__construct a hlavními funkcemi, které využijeme pro výběr, vkládání a mazání dat.