<?php
///////////////////////////////////////////////////////////////////////////////////////////////////
// Classe: Table abstraite
// Auteur: Emilien Dreyfus (hide@address.com)
// Projet: Kobua
//
// Cette classe permet de faire abstraction d'une table de base mysql
// Elle contruit un objet unique ou multiple à partir d'une requete,
// permet d'itérer les éléments et de les sauvegarder.
//
// Utilisation:
//
// -Dériver la classe et surcharger la méthode table_name() qui dois renvoyer le nom de la table
// -Si la clef primaire est différente de id, surcharger la méthode table_primary_key() et
// renvoyer la clef sans fioritures.
//
// -Instancier un objet de la classe dérivée
// -Charger des données: load_from_id($id); // Objet unique
// load_from_where_condition($where); // Clause WHERE mysql
// load_all_order_by($order); // Clause ORDER BY (Pas de where)
// load_all(); // Charge tout les éléments
// ou inserer un élément: set_champ1($c); puis save();
//
// -Si données chargées, afficher ou modifier les données avec get_champ1() et set_champ1($c),
// les méthodes sont crées automatiquement à la volée en fonction de la structure de la table.
//
// -Sauvegarder avec update() si vous avez modifié un élément déja chargé avec set_
// -Itérer avec has_next et next() de cette manière:
//
// while($o->has_next()){
// echo $o->get_id();
// $o->next();
// }
//
abstract class table{
//Cette méthode dois etre surchargée et renvoyer le nom de la table
protected abstract function table_name();
//Cette méthode dois être sur surchargée si la clé primaire est différente de id
protected function table_primary_key(){
return "id";
}
//Flag qui permet d'interdire l'acces a une classe non instanciée
protected $instanciated=false;
//Stockage de la requete en cas d'objet multiligne
private $multi_row_req=null;
//Nombre de ligne effectives
private $multi_row_number=0;
//Compteur pour la ligne courante
private $row_iterator_counter=0;
//Valeurs modifiées par un set (tableau assoc)
private $updated=Array();
//Valeurs accessibles par les get et set
private $values=Array();
//Charge l'objet à partir d'une valeur de clef primaire
public function load_from_id($id){
$sql="SELECT * FROM `{$this->table_name()}` WHERE `{$this->table_primary_key()}`='$id' LIMIT 1";
$req=mysql_query($sql) or die(mysql_error());
if(mysql_error()==""){
$data=mysql_fetch_assoc($req);
$this->multi_row_number=1;
$this->apply_data($data);
return true;
}
return false;
}
function reset_iterator(){
ECHO $this->multi_row_req;
if($this->instanciated){
mysql_data_seek ( $this->multi_row_req , 1 );
$this->row_iterator_counter=0;
}
}
function get_num_rows(){
return $this->multi_row_number;
}
//Charge l'objet avec une condition WHERE (Ex: id='2' ORDER BY date)
public function load_from_where_condition($where_condition){
$sql="SELECT * FROM ".$this->table_name()." WHERE $where_condition";
$req=mysql_query($sql);
if(mysql_error()==""){
$nb=mysql_num_rows($req);
$this->multi_row_number=mysql_num_rows($req);
$this->multi_row_req=$req;
$data=mysql_fetch_assoc($req);
$this->apply_data($data);
return true;
}
return false;
}
function delete_where_condition($where_condition){
$sql="DELETE FROM ".$this->table_name()." WHERE $where_condition";
$req=mysql_query($sql);
}
//Charge l'objet avec tous les éléments dans l'ordre spécifié (Ex: date)
public function load_all_order_by($order){
$sql="SELECT * FROM ".$this->table_name()." WHERE 1 ORDER BY $order";
$req=mysql_query($sql);
if(mysql_error()==""){
$nb=mysql_num_rows($req);
$this->multi_row_number=mysql_num_rows($req);
$this->multi_row_req=$req;
$data=mysql_fetch_assoc($req);
$this->apply_data($data);
return true;
}
return false;
}
//Charge l'objet avec toutes les lignes de la table
public function load_all(){
$sql="SELECT * FROM ".$this->table_name()." WHERE 1";
$req=mysql_query($sql);
if(mysql_error()==""){
$nb=mysql_num_rows($req);
$this->multi_row_number=mysql_num_rows($req);
$this->multi_row_req=$req;
$data=mysql_fetch_assoc($req);
$this->apply_data($data);
return true;
}
return false;
}
//Charge l'objet avec la prochaine ligne
public function next(){
if($this->has_next()){
if(!$this->is_last()){
$data=mysql_fetch_assoc($this->multi_row_req);
$this->apply_data($data);
}
$this->row_iterator_counter++;
return true;
}
}
function is_instanciated(){
return $this->instanciated;
}
function reset(){
$this->instanciated=false;
}
// Permet d'utiliser l'objet comme un itérateur
//
// while($o->has_next()){
// echo $o->get_id();
// $o->next();
// }
//
// Le dernier has_next() retourn true mais le dernier next ne change pas l'objet.
// Bref, utiliser la notation en exemple et ca pose pas de pb.
public function has_next(){
return ($this->instanciated && isset($this->multi_row_req) && $this->row_iterator_counter < $this->multi_row_number);
}
// Permet de savoir si c'est le dernier element
public function is_last(){
return ($this->row_iterator_counter == $this->multi_row_number-1);
}
//Sauvegarde les éléments modifiés de l'objet courant dans la table
public function save(){
if(isset($this->values[$this->table_primary_key()]) && $this->values[$this->table_primary_key()]!=""){
$sql="UPDATE `".$this->table_name()."` SET ";
foreach($this->updated as $k=>$v){
if($v==true){
if($this->values[$k]=="NOW()")
$sql.="`$k`= ".$this->values[$k].",";
else $sql.="`$k`='".$this->values[$k]."',";
$this->updated[$k]=false;
}
}
$sql=substr($sql,0,count($sql)-2);
$sql.=" WHERE `{$this->table_primary_key()}`='{$this->values[$this->table_primary_key()]}'";
mysql_query($sql) or die(mysql_error());
}else if(!$this->instanciated){
$sql="INSERT INTO `".$this->table_name()."` (";
foreach($this->updated as $k=>$v){
if($v==true){
$sql.="`$k`,";
}
}
$sql=substr($sql,0,count($sql)-2);
$sql.=") VALUES (";
foreach($this->values as $k=>$v){
if($this->updated[$k]==true){
if($v=="NOW()")
$sql.=" $v ,";
else
$sql.="'$v',";
$this->updated[$k]=false;
}
}
$sql=substr($sql,0,count($sql)-2);
$sql.=")";
mysql_query($sql);
$this->instanciated=true;
return mysql_error()=="";
}else throw new Exception("Erreur dans save");
}
function insert(){
if(!$this->instanciated){
$sql="INSERT INTO `".$this->table_name()."` (";
foreach($this->updated as $k=>$v){
if($v==true){
$sql.="`$k`,";
}
}
$sql=substr($sql,0,count($sql)-2);
$sql.=") VALUES (";
foreach($this->values as $k=>$v){
if($this->updated[$k]==true){
if($v=="NOW()")
$sql.=" $v ,";
else
$sql.="'$v',";
$this->updated[$k]=false;
}
}
$sql=substr($sql,0,count($sql)-2);
$sql.=")";
mysql_query($sql);
$this->instanciated=true;
return mysql_error()=="";
}else throw new Exception("Erreur dans insert");
}
//Supprime l'objet courant dans la table
public function delete(){
$sql="DELETE FROM`".$this->table_name()."` WHERE `{$this->table_primary_key()}`='{$this->values[$this->table_primary_key()]}' LIMIT 1";
mysql_query($sql) or die($sql." ".mysql_error());
}
// Interception des accesseurs.
public function __call($method, $attrs) {
$prefix = substr($method, 0, 4);
$suffix = substr($method,4,strlen($method)-4);
$cattrs = count($attrs);
if ($prefix == 'set_' && $cattrs == 1) {
$this->updated[$suffix]=true;
return $this->values[$suffix]=$attrs[0];
}
if($this->instanciated){
if ($prefix == 'get_' && $cattrs == 0) {
if(isset($this->values[$suffix]))
return $this->values[$suffix];
else throw new Exception("Champ $suffix inexistant");
}
}else {
return "";
}
throw new Exception("La méthode $method n'existe pas");
}
//Effectue le chargement des données dans la classe (apres requete)
private function apply_data($data){
if(is_array($data)){
foreach($data as $k=>$v){
$this->values[$k]=$v;
$this->updated[$k]=false;
}
$this->instanciated=true;
}
}
}
?>