Active Record Objects
Net een heel verhaal getypt toen de pagina ging herladen ofzoiets, dus maak het nu kort. Heb het idee uit noodzaak, van internet en van het Prado framework (wat zuigt btw). Het voorbeeld is een superkleine blog met twee tabellen: users en posts. Beide tabellen krijgen een eigen class: User en Post (met prefix ARO). Beide classes worden afgeleid van ActiveRecordObject, waar de meeste logica in staat. De subclasses zijn voor specifieke taken (updatePassword etc) en type specificatie (pk, kolommen, relaties, etc). Het is nog niet af, maar ben benieuwd naar feedback. Er moeten nog minstens 2 dingen in: * DataCenter om dubbele fetches af te vangen (1 pk per type in het DC) * De tweede ben ik even vergeten... Fack! Tips are welcome ofcourse. Voor de voorbeelden gebruik ik deze database: Ik had alle voorbeelden en verschillen heel mooi beschreven, maar daar heb ik nu geen zin meer in. In de code staat commentaar en het voorbeeld en de Db moeten redelijk duidelijk zijn. Vragen beantwoord ik wanneer ik ze zie. De voorbeeldlink gaat niet naar een php pagina, omdat ik alleen het resultaat heb opgeslagen.
De database abstractielaag interface:
<?php #4
interface DB_Generic {
public function __construct( $f_szHost, $f_szUser = '', $f_szPass = '', $f_szDb = '' ); // void
public function saveError(); // void
public function connected(); // bool
public function escape( $v ); // string
public function escapeAndQuote( $v ); // string
public function insert_id(); // int
public function affected_rows(); // int
public function query( $f_szSqlQuery ); // bool / object / resource
public function fetch($f_szSqlQuery); // array
public function select($f_szTable, $f_szWhere = ''); // array
public function fetch_fields($f_szSqlQuery); // array
public function select_one($tbl, $field, $where = ''); // string / null
public function max($tbl, $field, $where = ''); // int
public function min($tbl, $field, $where = ''); // int
public function count($tbl, $where = ''); // int
public function select_by_field($tbl, $field, $where = ''); // assoc array
public function select_fields($tbl, $fields, $where = ''); // array
public function replace_into($tbl, $values); // bool
public function insert($tbl, $values); // bool
public function update($tbl, $update, $where = ''); // bool
public function delete($tbl, $where); // bool
} // END Interface db_generic
?>
De testpagina:
<?php
// db connectie maken
require_once('../../../inc.cls.db_mysqli.php');
$db = new db_mysqli('localhost', 'user', 'pass', 'prutblog'); // extends DB_Generic
function __autoload($class) {
require_once(dirname(__FILE__).'/inc.cls.'.strtolower($class).'.php');
}
// db connectie assignen aan ARO 'DataCenter'
ActiveRecordObject::setDbObject($db);
echo '<pre>';
$kat = AROUser::finder()->findOne('username = \'kat\'');
$kat->bff; // jaap
echo 'User katrien: ';
print_r($kat);
$jaap = AROUser::finder()->byPk(1);
$jaap->bff; // no record found, so empty record stored
echo "\n".'User jaap: ';
print_r($jaap);
$posts = $jaap->posts;
echo "\n".'Jaap\'s posts: ';
print_r($posts);
// OR
$posts = AROPost::finder()->findMany('user_id = '.$jaap->id);
echo "\n".'Nogmaals: ';
print_r($posts);
echo "\n";
echo "\n".'Post [3] met childs: ';
$post3 = AROPost::finder()->byPK(3);
$post3->creator->posts;
print_r($post3);
// Een slecht voorbeeldje van saveAsNew():
$post3->title = 'alleen een andere titel dan';
var_dump($np=$post3->saveAsNew()); // int(7)
AROPost::finder()->byPk($np); // het object
// je gaat natuurlijk geen post letterlijk kopieren, maar je snapt dat het kan
?>
Class AROUser
<?php
class AROUser extends ActiveRecordObject {
protected static $_table = 'users';
protected static $_columns = array(
'username',
// 'password', # there really is no use to update this, so don't list it. It will be fetched though (see * in getQuery())
'name',
'email',
'bff_friend_id',
);
protected static $_pk = 'id';
protected static $_relations = array(
'posts' => array( self::HAS_MANY, 'AROPost', 'user_id'/*, 'id'*/ ), # `id` is default
'bff' => array( self::HAS_ONE, 'AROUser', 'bff_friend_id' ),
);
static public function finder( $class = __CLASS__ ) {
return parent::finder($class);
}
public function getQuery( $clause ) {
$szQuery = 'SELECT * FROM users WHERE 1';
if ( $clause ) {
$szQuery .= ' AND '.$clause;
}
return $szQuery.';';
}
public function updatePassword( $pwd ) {
return $this->getDbObject()->update(
$this->getStaticChildValue('table'), # table
array('password' => md5($this->id.':'.$pwd)), # updates
$this->getStaticChildValue('pk').' = '.$this->id # WHERE clause
);
}
} // END Class AROUser
?>
Class AROPost
<?php
class MyDateTime {
private $utc;
function __construct($utc) {
$this->utc = $utc;
}
function __tostring() {
return (string)$this->utc; # __tostring must always return database format
}
function text() {
return $this->date().' '.$this->time();
}
function date() {
return date('Y-m-d', $this->utc);
}
function time() {
return date('H:i:s', $this->utc);
}
}
class AROPost extends ActiveRecordObject {
protected static $_table = 'posts';
protected static $_columns = array(
'parent_post_id', # FK (NULL)
'user_id', # FK
'title',
'content',
'created', # int
);
protected static $_pk = 'id';
protected static $_relations = array(
'creator' => array( self::HAS_ONE, 'AROUser', 'user_id'/*, 'id'*/ ), # `id` is default
'replies' => array( self::HAS_MANY, 'AROPost', 'parent_post_id', 'id' ),
);
static public function finder( $class = __CLASS__ ) {
return parent::finder($class);
}
public function fill($data) {
parent::fill($data);
$this->created = new MyDateTime($this->created);
}
public function getQuery( $clause ) {
$szQuery = 'SELECT * FROM posts WHERE 1';
if ( $clause ) {
$szQuery .= ' AND '.$clause;
}
return $szQuery.';';
}
} // END Class AROPost
?>
Reacties
0