One of the more powerful features of the Ruby On Rails framework is the implementation of the ActiveRecord pattern. It provides the basic database operations (CRUD, Create Read Update Delete) in order to have fun in programming and not writing all the same boring SQL queries.

ActiveRecord implementation is quite complex in RubyOnRails. Let’s see an “easier” implementation in PHP. We should come to a very powerful version in some episodes.So stay tuned!

The basic concept about ActiveRecord is that every record of a table is an object. Primarly we have to define a base class to provide database access. For the sake of semplicity we user the PEAR::MDB2 class in order to give basic database access.
[ATTENTION: the following part of my article is written in Italian, I will translate it to English versi soon.]
[The italian version of this article can be found at Ciarpame.com]

require 'MDB2.php';
abstract class ActiveRecordBase {
protected $__db; // Dichiariamo un oggetto "protected" per l'accesso al DB
protected $__primary_key = "id"; // Definiamo una chiave primaria per la tabella. Può essere poi
// modificata per ogni singola classe che estende questa.
protected $__fields; // In questo attributo di tipo array andremo a salvare i campi della nostra tabella (escluso il campo primary key)
protected $__table; // In questo attributo salviamo il nome della tabella
/**
* Il costruttore istanzia una connessione con il db e se sono presenti dei dati
* li salva nell'oggetto (non nel database!)
*/
public function __construct($data=array()){
$this->db = &MDB2::connect(DB_DSN);  // DB_DSN è una stringa che contiene di dati accesso al DB
$this->__table = strtolower(get_class($this));
if (!empty($data)) foreach ($data as $key => $value){ $this->$key = $value; $this->fields[] = $key;}
}
 
/**
* Definiamo un metodo per create un nuovo Record.
* Esso è privato perché verrà utilizzato dal metodo save()
*/
private function create(){
// Creaimo l'istruzione SQL a partire dai campi disponibili
$sql = "INSERT INTO ".$this->__db->quoteIdentifier($this->table)." (";
$first = true;
$data = array();
foreach ($this->__fields as $field){
if (!$first) $sql.=",";
$sql.= $this->__db->quoteIdentifier($field);
$data[] = $this->$field;
$first = false;
}
$sql.= ") VALUES (";
for ($i = 0; $i < count($fields); $i++) if ($i=0) $sql.="?" else $sql.=",?";
$sql:=");";
$prep = $this->__db->prepare($sql);
$res =  $prep->execute($data);
$pkey_field = $this->__primary_key;
if ($res) $this->$pkey_field = $this->__db->lastInsertID($this->__table);
return $res;
}
 
private function update(){
$sql = "UPDATE ".$this->__db->quoteIdentifier($this->__table)." SET ";
$first = true;
$data = array();
foreach ($this->__fields as $field){
if (!$first) $sql.=",";
$sql = "$field = ?";
$data[] = $this->$field;
$first = false;
}
$pkey_field = $this->__primary_key;
$sql = "WHERE ".$this->db->quoteIdentifier($pkey_field)." = ".$this->db->quote($this->$pkey_field);
$prep = $this->__db->prepare($sql);
return $prep->execute($data);
}
 
private function delete(){
$pkey_field = $this->__primary_key;
$sql = "DELETE FROM ".$this->__db->quoteIdentifier($this->__table).
" WHERE ".$this->db->quoteIdentifier($pkey_field)." = ".$this->db->quote($this->$pkey_field);
return $this->__db->query($sql);
}
 
public function save(){
$pkey_field = $this->__primary_key;
if (!isset($this->$pkey_field)) return $this->create();
else return $this->update();
}
 
public function destroy(){
$pkey_field = $this->__primary_key;
if (isset($this->$pkey_field)) return $this->delete();
else return false;
}
 
}

In questa implementazione, ancora in stato “embrionale”, è possibile creare un nuovo record.
Un uso molto semplice potrebbe essere creare una classe che estenda la base e istanziarne un oggetto:

require 'ActiveRecordBase.class.php'
class Dog extends ActiveRecordBase {}
$dog = new Dog(array('name' => 'Pluto', 'age' => '7'));
$dog->save();

Il precedente script inserisce un nuovo record in una tabella ‘dog’ (stessa nome della classe che estende ActiveRecordBase) assegnando gli attributi ‘name’ e ‘age’.
La primary key viene implicitamente impostata come “id” (ovviamente se il campo ha l’attributo auto_increment) e il valore inserito automaticamente.
Il tutto in 3 righe di codice, molto molto semplici…non è una bella comodità?
Più avanti vedremo come effettuare ricerche, e quindi come implementare il metodo “find” e migliorare ulteriormente la classe base in modo da gestire meglio errori, validazioni e chiavi esterne.