PHP 5, SQLite in Factory? | aurelian |
| XII. SQLite?
Dupa un timp, am zis sa incerc sa mai creez inca un produs pentru factory-ul descris in postul precedent. Mi-ar fi placut sa am posibilitatea sa logez erorile si mesajele de debug intr-un tabel al unei baze de date. Si cum inca nu am avut posibilitatea sa lucrez cu SQLite, am decis ca acesta sa fie tipul de baza de date pe care o sa il folosesc. Prima concluzie? Daca vreau sa folosesc clientul SQLite din lina de comanda si apoi sa accesez baza de date creata cu acest client din PHP 5.0 trebuie sa folosesc SQLite 2.8.15, nu SQLite 3.0.8. Bazele de date create cu SQLite 3.0.8 vor putea fi accesate din viitorul PHP 5.1, deci mai am de asteptat pana in a doua jumatate a acestui an. Ce este SQLite?
Deci, folosind clientul SQLite, versiune 2.8.15 m-am pus pe treaba, si am creat o baza de date noua:
$ sqlite logger.db
Am aflat ca imi pot scrie sql-ul linistit si apoi il pot importa intr-o baza de date SQLite. dump.sql:
BEGIN TRANSACTION; CREATE TABLE logger (id INTEGER PRIMARY KEY,message TEXT,timeEnter DATE); CREATE TRIGGER insert_logger_timeEnter AFTER INSERT ON logger BEGIN UPDATE logger SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid; END; COMMIT;
Lucruri obisnuite aici: un tabel cu numele logger, ce contine un camp id de tip INTEGER cheie primara, un camp message, unde evident voi tine mesajele si timeEnter in care voi pastra data introducerii unui mesaj nou. In
plus, am creat un TRIGGER, astfel la fiecare insert pe care il voi
face, campul timeEnter se va actualiza singur (nu o sa fie nevoie sa ii
mai zic insert into logger (timeEnter) values DATETIME('NOW'), insert
into logger (message) values ($message) va fi destul pentru a actualiza
cele 3 campuri). Am descoperit astfel si triggeri in SQLite, dupa ce am citit si tutorialul asta.
Am importat fisierul dump.sql cu comanda:
$ sqlite logger.db < dump.sql
Binarul (fisierul .exe pe Windows) ar trebui sa fie in PATH pentru a avea comanda sqlite la prompt.
XIII. Un nou produs, SQLite
Tinand
cont ca va trebui sa implementez metodele interfetei Trace si, urmand
exemplul din FileTrace am scris destul de repede si usor
SQLiteTrace.php:
<?php // merge cu sqlite 2.8.15 pe php 5.0! /* ----------> SQL DUMP BEGIN TRANSACTION; CREATE TABLE logger (id INTEGER PRIMARY KEY,message TEXT,timeEnter DATE); CREATE TRIGGER insert_logger_timeEnter AFTER INSERT ON logger BEGIN UPDATE logger SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid; END; COMMIT; <---------- SQL DUMP */
include_once('ITrace.php'); /** * It logs the trace to a sqlite db * * @todo: implement a custom Exception class * @package test.factory.trace * @access public */ class SQLiteTrace implements Trace {
/** * It`s the db handler * @var handler * @access private */ private $handler;
/** * debug * @var bool * @access private */ private $debug;
/** * The construnctor * it opens the db handler * * @return void * @access public */ public function __construct() { $dbname = 'logger.db'; $this->handler = @sqlite_open($dbname, 0666, $sqliteerror); if($this->handler===false){ throw new Exception($sqliteerror); } }
/** * Sets the debug * @param bool debug * @return void * @access public */ public function setDebug($debug) { $this->debug = $debug; }
/** * It writes a debug message * only if debug is true * @param string message * @return void * @access public */ public function debug($message) { if($this->debug) { // only insert if debug is true sqlite_query($this->handler, "INSERT INTO logger (message) VALUES (' DEBUG >>>> " . $message . "')"); } }
/** * It writes an error message * * @param string message * @return void * @access public */ public function error($message) { // always log errors sqlite_query($this->handler, "INSERT INTO logger (message) VALUES (' ERROR >>>> " . $message . "')"); }
/** * Is the Destructor * just close the handler * @access public * return void */ public function __destruct() { @sqlite_close($this->handler); } }
XIV. Un nou Creator
Am reusit sa rescriu si TraceFactory.php astfel:
<?php /** * Is the factory * * @version 0.3 * @access public * @package test.factory.trace */
class TraceFactory { /** * It trys to get a trace * * @access public * @return object Trace, a trace instance */ public static function &getTrace() { try { include_once('FileTrace.php'); return new FileTrace(); } catch (Exception $ex) { try{ include_once('SQLiteTrace.php'); $t_sqlite = new SQLiteTrace(); $t_sqlite->error("Could not instantiate FileTrace:\n" . $ex->getMessage()); return $t_sqlite; }catch(Exception $sqlite_ex) { include_once('StdoutTrace.php'); $t = new StdoutTrace(); $t->error("Could not instantiate SQLiteTrace:\n" . $sqlite_ex->getMessage()); return $t;
} } } }
Chiar daca nu imi place prea mult blocul:
<?php try {
} catch (Exception $ex) { try{
}catch(Exception $sqlite_ex) { } ?>
Tracerul meu este functional avand 3 metode distincte de a loga mesajele: intr-un fisier, intr-o baza de date sau direct pe consola (nu prea o sa vad lucrul asta prea curand totusi).
XV. Neajunsuri
In momentul de fata, sincer sa fiu, nu imi dau seama unde as putea implementa acest exemplu. As
vrea sa il continui, aducad in discutie un alt procedeu: observer, mai
mult, mi-ar placea sa am mai multe nivele de logare
(debug/info/error/alert/emergency). Metoda getTrace nu mi se pare pre flexibila, cum ar fi daca as vrea sa mai adaug inca un produs acolo? Probabil ar trebui sa o rescriu astfel:
<?php /** * Is the factory * * @version 0.4 * @access public * @package test.factory.trace */
class TraceFactory { /** * It trys to get a trace * * @param string driver, it can be File or SQLite * @access public * @return object Trace, a trace instance */ public static function &getTrace($driver='') { $drivers = array('File','SQLite'); if(!in_array($driver, $drivers)) { include_once('StdoutTrace.php'); return new StdoutTrace(); } try { $rs = $driver . 'Trace'; include_once($rs . '.php'); return new $rs(); } catch (Exception $ex) { include_once('StdoutTrace.php'); $t = new StdoutTrace(); $t->error("Could not instantiate " . $driver . ":\n" . $ex->getMessage()); return $t; } } }
iar testul urmator, runTrace.php
mi-ar loga mesaje in fisierul text in prima parte, in baza de date
SQLite in partea de mijloc si in final as afisa si ceva in consola:
<?php include_once('TraceFactory.php'); $t = &TraceFactory::getTrace('File'); $t->error("O eroare de test!"); $t->setDebug(true); $t->debug("Debug is true"); for($i=1;$i<10;$i++){ $t->debug("Tha lup :: " . $i); } unset($t); $t = &TraceFactory::getTrace('SQLite'); $t->error("Ceva de test!"); $t->setDebug(true); $t->debug("True Debug");
for($i=1;$i<10;$i++){ $t->debug("Za I :: " . $i); } $t->error("FOO IS BAR MUST DIE !!!");
unset($t); $t = &TraceFactory::getTrace('Unknow_driver'); $t->error("Ajunge in consola!"); $t->setDebug(true); $t->debug("True Debug a fos setat");
for($i=1;$i<10;$i++){ $t->debug("I-ul :: " . $i); } $t->error("Fatal!!!");
Ramane
insa de discutat despre diferite niveluri de log si de introducerea
unui observer care sa ma anunte in cazul in care se produce o eroare in
sistem. Pana una-alta, raman cu PEAR::Log, dar o sa continui totusi
acest articol prin introducerea componentelor de mai sus, cea ce
inseamna un sitem de logare a mesajelor cat de cat complet si
utilizabil in productie (chiar daca constat ca SQLite nu este chiar
atat de rapid :) ).
comentarii si sugestii: oancea at gmail dot com. Sus |