Skip to content

Instantly share code, notes, and snippets.

@kiurchv
Last active December 16, 2020 03:52
Show Gist options
  • Save kiurchv/5555313 to your computer and use it in GitHub Desktop.
Save kiurchv/5555313 to your computer and use it in GitHub Desktop.
ORM implementation
<?php
/**
* ORM implementation.
*
* BaseModel realizes all logic for managing database connections and
* work with entities which stored in database as plain PHP objects.
*
* This implementation supports object relations:
*
* * one to one
* * many to one
*
* Not realized:
*
* * model validations(use database constraints)
* * many to many object relation
*
* @author Miroslav Kyurchev <[email protected]>
* @copyright 2013 Miroslav Kyurchev
* @depends Inflector
* @license MIT
* @since 0.1
* @version 0.1
*/
class BaseModel
{
private static $db;
protected $attributes = array();
/**
* Connects to database.
*
* @access public
* @static
* @return PDO Object representing a connection to a database
*/
static function db()
{
if (!isset(self::$db)) {
if (isset($_ENV["DATABASE_URL"])) {
extract(parse_url($_ENV["DATABASE_URL"]));
$dsn = "pgsql:host=$host;dbname=".substr($path, 1).";user=$user;password=$pass";
} else {
$dsn = "pgsql:host=localhost;dbname=wt_lab2_test;user=postgres;password=postgres";
}
self::$db = new PDO($dsn);
}
return self::$db;
}
/**
* Returns name of table corresponding current model.
* @access public
* @static
* @return string Name of the table corresponding current model
*/
static function table_name()
{
return Inflector::tableize(get_called_class());
}
/**
* Gets all records.
* @access public
* @static
* @return array Objects corresponiding table records
*/
static function all()
{
$query = 'SELECT * FROM '.self::table_name();
$reflection = new ReflectionClass(get_called_class());
$sth = self::db()->prepare($query);
$sth->setFetchMode(PDO::FETCH_INTO, $reflection->newInstance());
$sth->execute();
return $sth->fetchAll(PDO::FETCH_INTO);
}
/**
* Finds record by given column.
* @access public
* @static
* @param int $name Name of column to find by
* @param int $value Column value to find
* @return object Object corresponding record with given id
*/
static function find_by($name, $value)
{
$query = 'SELECT * FROM '.self::table_name().' WHERE '.$name.'=?';
$reflection = new ReflectionClass(get_called_class());
$sth = self::db()->prepare($query);
$sth->setFetchMode(PDO::FETCH_INTO, $reflection->newInstance());
$sth->execute(array($value));
return $sth->fetch(PDO::FETCH_INTO);
}
/**
* Finds record by id.
* @access public
* @static
* @param int $id Id of record to find
* @return object Object corresponding record with given id
*/
static function find($id)
{
return self::find_by('id', $id);
}
/**
* Constructs object and saves it to database.
* @access public
* @static
* @param array $attributes Attributes to save in databse
* @return object Object corresponding database record
*/
static function create($attributes)
{
$attributes = array_filter($attributes);
unset($attributes['id']);
$columns = array_keys($attributes);
$placeholders = array_map(function ($elem) {
return ":$elem";
}, $columns);
$query = 'INSERT INTO '.self::table_name().' ('.join(', ', $columns).') values ('.join(', ', $placeholders).')';
$sth = self::db()->prepare($query);
if ($sth->execute($attributes))
{
$reflection = new ReflectionClass(get_called_class());
return $reflection->newInstance($attributes);
} else {
return false;
}
}
/**
* Deletes record with given id from table
* @access public
* @static
* @param int $id Id of record to delete
* @return bool Result of executing query
*/
static function delete($id)
{
$query = 'DELETE FROM '.self::table_name().' WHERE id=?';
$sth = self::db()->prepare($query);
return $sth->execute(array($id));
}
/**
* Finds all objects of the given model which are associated with current
* @access public
* @param string $class_name Name of the model to find
* @return array Objects which are associated with current
*/
function find_assoc($class_name)
{
$table_name = Inflector::tableize($class_name);
$column_name = Inflector::underscore(get_called_class());
$query = 'SELECT * FROM '.$table_name.' WHERE '.$column_name.'_id=?';
$reflection = new ReflectionClass($class_name);
$sth = self::db()->prepare($query);
$sth->setFetchMode(PDO::FETCH_INTO, $reflection->newInstance());
$sth->execute(array($this->attributes['id']));
return $sth->fetchAll(PDO::FETCH_INTO);
}
/**
* Updates specified attributes of object in database
* @access public
* @param array $attributes Attributes to update
* @return bool Result of executing query
*/
function update($attributes)
{
$attributes = array_filter($attributes);
$attributes['id'] = $this->attributes['id'];
$columns = array_keys($attributes);
$columns = array_diff($columns, array('id'));
$columns = array_map(function ($elem) {
return "$elem=:$elem";
}, $columns);
$query = 'UPDATE '.self::table_name().' SET '.join(', ', $columns).' WHERE id=:id';
$sth = self::db()->prepare($query);
return $sth->execute($attributes);
}
/**
* Saves new object to database or updates existing
* @access public
* @return mixed Object corresponding database record or result of executing query
*/
function save()
{
if ((!isset($this->attributes['id']) && count($this->attributes) > 0) || count($this->attributes) > 1) {
if (isset($this->attributes['id']))
{
return $this->update($this->attributes);
} else {
return self::create($this->attributes);
}
} else {
trigger_error('Not specified attributes to save', E_USER_NOTICE);
}
}
/**
* Sets object properties as elements of attributes array
* @param string $name Name of property
* @param mixed $value Value of property
* @return void
*/
function __set($name, $value)
{
$this->attributes[$name] = $value;
}
/**
* Gets object's attributes or associated objects
* @param string $name Name of property
* @return mixed Value of property or associated objects
*/
function __get($name)
{
if (array_key_exists($name, $this->attributes)) {
return $this->attributes[$name];
} elseif (array_key_exists($name.'_id', $this->attributes)) {
$class = Inflector::classify($name);
return $class::find($this->attributes[$name.'_id']);
} else {
$class = Inflector::classify($name);
$result = $this->find_assoc($class);
if (!empty($result)) {
return $result;
} else {
$trace = debug_backtrace();
trigger_error('No objects associated or undefined attribute '.$name.' in '.$trace[0]['file'].' on line ' . $trace[0]['line'], E_USER_NOTICE);
return null;
}
}
}
/**
* Initializes object
* @param array $attributes Attributes to save in databse
* @return void
*/
function __construct($attributes = array())
{
$this->attributes = $attributes;
}
/**
* Deletes corresponding record from database
* @access public
* @return bool Result of executing query
*/
function destroy() {
if (isset($this->attributes['id']))
self::delete($this->attributes['id']);
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment