I am using Codeigniter and it's ActiveRecord.
I had this idea for a base class that provided a generic getter/setter for doing simple queries on a database. I have a lot of database objects that could benefit from not having to duplicate the basic query patterns.
Instead of writing functions whose sole purpose were to chain a few active record queries and return the result, I could instead do it with a generic $parameters
array and providing the table name via the function call.
<?php
class ORMModel extends CI_Model {
public function __call($name, $args) {
$method = strtolower(substr($name, 0, 3));
$object = substr($name, 3);
// Parsing arguments
$params = (isset($args[0])) ? $args[0] : array();
$single = (isset($args[1])) ? $args[1] : false;
$count = (isset($args[2])) ? $args[2] : false;
$page = (isset($args[3])) ? $args[3] : '';
$per_page = (isset($args[4])) ? $args[4] : '';
if ($method === 'get') {
$this->db->from($object);
} elseif ($method !== 'set') {
throw new Exception('Unsupported method ' . $name);
}
if (method_exists($this, $name)) {
$this->{$name}($params);
} elseif ($method === 'get') {
$this->__getter($params);
} else {
$this->__setter($params);
};
if ($method === 'set') {
// Insert on duplicate method, for both insert/updates, this way the SET can act as the WHERE as well
return $this->db->on_duplicate($object);
}
$this->db->limit($per_page, $page);
$result = $this->db->get();
if (!$result) {
throw new Exception('No result from ' . $name);
}
if ($count) {
return $result->num_rows;
}
if ($single) {
return $result->row_array();
} else {
return $result->result_array();
}
}
private function __getter($params) {
foreach ($params as $field => $value) {
if (method_exists($this, $field)) {
$this->where{$field}($value);
}
$this->db->where_in($field, $value);
}
}
private function __setter($params) {
foreach ($params as $field => $value) {
$this->db->set($field, $value);
}
}
}
Example usage:
// Returns all orders
$this->ORMModel->getOrder()
// Returns order ID 3
$this->ORMModel->getOrder(array('id' => 3))
// Returns orders before a certain date
function orderWhereDateBefore() {
$this->db->where('date <=', $value);
}
$this->ORMModel->getOrder(array('dateBefore' => '2012-01-01'))
// Huge search query (from a form)
$params = array(
'status' => 'Paid',
'dateBefore' => '2012-01-01',
'name' => 'Some Guy',
...
);
$this->ORMModel->getOrder($params);
// Set an order
$params = array(
'status' => 'Paid',
'dateBefore' => '2012-01-01',
'name' => 'Some Guy',
...
);
$this->ORMModel->setOrder($params);
The additional arguments also provide more flexibility for standard display of results, such as pagination and full count of the result set.
However, I am concerned whether its reusability can trump the concerns of readability, usability and debuggability (for lack of a better word)Maintainability, and if so, can it be improved on?