Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A little Object Relational Mapper in PHP
<?php
/**
* A little Object Relational Mapper in PHP
* @author dennis.hotson@gmail.com
*/
class Post
{
public $title;
public $content;
}
class Comment
{
public $post_id;
public $name;
public $content;
}
$db = new Db('blog.db', array('Post', 'Comment'));
$p1 = new Post();
$p1->title = 'Welcome to my Blog!';
$p1->content = 'This is my first post.. cool';
$db->save($p1);
$p2 = new Post();
$p2->title = 'My 2nd post';
$p2->content = '2nd post.. Rad!';
$db->save($p2);
$comment = new Comment();
$comment->post = $p2;
$comment->name = 'Franklin';
$comment->content = 'Cool blog dude...';
$db->save($comment);
$p1->title = 'Welcome to my blaargh!';
$db->save($p1);
$posts = $db->table('Post')->all();
foreach ($posts as $post)
echo "Post #$post->id : $post->title > $post->content\n";
// ----------
class Db
{
const primary_key = 'INTEGER PRIMARY KEY';
const integer = 'INTEGER';
const string = 'STRING';
private $_db;
/**
* @param $file The sqlite database file to load
* @param $classes The classes to create tables for
*/
public function __construct($file, $classes = array())
{
$this->_db = new SQLiteDatabase($file);
foreach ($classes as $class)
$this->_createTable($class);
}
public function table($class)
{
return new Finder($this->_db, $class);
}
public function save($obj)
{
$class = get_class($obj);
$values = array();
foreach (get_class_vars($class) as $field => $_)
{
if (preg_match('#(.*)_id$#', $field, $matches))
{
$f = $matches[1];
if (isset($obj->$f) && isset($obj->$f->id))
$obj->$field = $obj->$f->id;
}
$values[$field] = $obj->$field;
}
if (!isset($obj->id)) // insert
{
foreach ($values as $field => $v)
$values[$field] = "'".sqlite_escape_string($v)."'";
$sql = sprintf("INSERT INTO %s (%s) VALUES (%s)",
$class,
implode(array_keys($values), ', '),
implode($values, ", ")
);
$this->_db->queryExec($sql);
$obj->id = $this->_db->lastInsertRowid();
}
else // update
{
foreach ($values as $field => $v)
$values[$field] = sprintf(
"%s = '%s'",
$field,
sqlite_escape_string($obj->$field)
);
$sql = sprintf('UPDATE %s SET %s WHERE id = %d',
$class,
implode($values, ', '),
$obj->id
);
$this->_db->queryExec($sql);
}
}
private function _createTable($class)
{
$fields = array(
'id' => array('type' => self::primary_key),
);
foreach (get_class_vars($class) as $name => $default)
{
if (preg_match('#_id$#', $name)) // foreign keys end in '_id'
$type = self::integer;
elseif(is_integer($default))
$type = self::integer;
else
$type = self::string;
$fields[$name] = array(
'type' => $type,
'default' => $default
);
}
$columndefs = array();
foreach ($fields as $name => $field)
{
$columndefs []= sprintf('%s %s%s',
$name,
$field['type'],
isset($field['default'])
? " DEFAULT '".sqlite_escape_string($field['default'])."'"
: ''
);
}
$this->_db->queryExec(sprintf('DROP TABLE %s', $class));
$this->_db->queryExec(sprintf('CREATE TABLE %s (%s)',
$class,
implode($columndefs, ', ')
));
}
}
class Finder
{
private $_db;
private $_class;
public function __construct($db, $class)
{
$this->_db = $db;
$this->_class = $class;
}
public function all()
{
$set = $this->_db->arrayQuery(
sprintf('SELECT * FROM %s', $this->_class),
SQLITE_ASSOC);
$result = array();
foreach ($set as $record)
$result []= $this->_newModel($record);
return $result;
}
public function findById($id)
{
$set = $this->_db->arrayQuery(
sprintf('SELECT * FROM %s WHERE id = %d', $this->_class, $id),
SQLITE_ASSOC);
return count($set) > 0
? $this->_newModel($set[0])
: null;
}
private function _newModel($record)
{
$obj = new $this->_class;
foreach ($record as $field => $value)
$obj->$field = $value;
return $obj;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.