removed own DAL and ORM

ready to be replaced by doctrine
This commit is contained in:
Steffen Vogel 2010-07-02 14:19:48 +02:00
parent 2818b77d46
commit 2c173faa4e
11 changed files with 2 additions and 1320 deletions

View file

@ -32,13 +32,6 @@ interface ChannelInterface {
}
abstract class Channel extends DatabaseObject implements ChannelInterface {
const table = 'channels';
public function delete() {
$this->reset(); // delete all data if database doesn't support foreign keys
parent::delete();
}
/*
* deletes all data from database
*/
@ -136,33 +129,6 @@ abstract class Channel extends DatabaseObject implements ChannelInterface {
return array_reverse($packages); // start with oldest ts and ends with newest ts (reverse array order due to descending order in sql statement)
}
/*
* simple self::getByFilter() wrapper
*/
static public function getByType($type) {
return self::getByFilter(array('type' => $type));
}
/*
* create new channel instance by given database query result
*/
final static protected function factory($object) {
if (!class_exists($object['type']) || !is_subclass_of($object['type'], 'Channel')) {
throw new InvalidArgumentException('\'' . $object['type'] . '\' is not a valid channel type');
}
// code duplication from DatabaseObject::factory()
if (!isset(self::$instances[self::table])) {
self::$instances[self::table] = array();
}
if (!isset(self::$instances[self::table][$object['id']])) {
self::$instances[self::table][$object['id']] = new $object['type']($object); // create singleton instance of database object
}
return self::$instances[self::table][$object['id']]; // return singleton instance of database object
}
/*
* build simple timeframe filter
*/
@ -179,26 +145,4 @@ abstract class Channel extends DatabaseObject implements ChannelInterface {
return $sql;
}
/*
* data filtering
*/
static public function getByFilter($filters = array(), $conjunction = true) {
$joins = array();
foreach ($filters as $column => $value) {
if (!key_exists('groups', $joins) && preg_match('/^group\.([a-z_]+)$/', $column)) {
$joins['channels_in_groups'] = array('type' => 'left', 'table' => 'channels_in_groups', 'condition' => 'channels_in_groups.channel_id = ' . self::table . '.id');
$joins['groups'] = array('type' => 'left', 'table' => 'groups AS group', 'condition' => 'groups.id = channels_in_groups.group_id');
}
}
$result = Database::getConnection()->select(self::table, array(self::table . '.*'), $filters, $conjunction, $joins);
$instances = array();
foreach ($result as $object) {
$instances[$object['id']] = static::factory($object);
}
return $instances;
}
}

View file

@ -1,291 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
/**
* @brief base exception for database queries
*/
class DatabaseException extends Exception {}
/**
* @brief abstract resultset definition
*/
abstract class DatabaseResultSet implements Iterator {
/**
* @brief rowcount of the result
* @var int
*/
protected $_num_rows = 0;
/**
* @brief result
* @var array
*/
protected $_rows = array();
/**
* @param resource $resource database resource
*/
abstract function __construct($resource);
/**
* @brief current element (iterator)
* @return array
*/
public function current() {
return current($this->_rows);
}
/**
* @brief next element (iterator)
* @return array
*/
public function next() {
return next($this->_rows); // TODO with fetch_assoc
}
/**
* @brief previous element (iterator)
* @return array
*/
public function prev() {
return prev($this->_rows);
}
/**
* @brief index of current element (iterator)
* @return array
*/
public function key() {
return key($this->_rows);
}
/**
* @brief first element (pointer reset, iterator)
* @return array
*/
public function rewind() {
return reset($this->_rows);
}
/**
* @brief last element (iterator)
* @return array
*/
public function end() {
return end($this->_rows);
}
/**
* @brief check current element (iterator)
* @return bool
*/
public function valid() {
return (bool) is_array($this->current());
}
/**
* @brief count rows of the result set
* @return integer
*/
public function count() {
return $this->_num_rows;
}
}
/**
* @brief interface database definition
*/
interface DatabaseInterface {
/**
* @brief create database connection
* @param array connection info
*/
public function __construct($config);
/**
* @brief close database connection
*/
public function close();
/**
* @brief execute query
* @param string $sql query
* @return mixed
*/
public function execute($sql);
/**
* @brief query
* @param string $sql
* @param int $offset
* @param int $limit
* @return TDatabaseResultSet
*/
public function query($sql, $limit = NULL, $offset = NULL);
/**
* @brief escape strings
* @param string $string to escape
* @return string escaped string
*/
public function escapeString($string);
/**
* @brief escape expression
* @param mixed $string to escape
* @return string
*/
public function escape($value);
/**
* @brief get last inserted id
* @return integer of the last record
*/
public function lastInsertId();
public function select($table, $fields = '*', $filter = array(), $conjunction = true, $joins = array(), $limit = NULL, $offset = NULL);
public function delete($table, $filters, $conjunction = true);
public function update($table, $data, $filters, $conjunction = true);
}
/**
* @brief abstract database layer definition
*/
abstract class Database implements DatabaseInterface {
static private $connection = NULL;
/**
* @brief database handle
* @var resource
*/
protected $resource = false;
/**
* @brief container with exectuted queries
* @var array
*/
protected $statements = array();
/*
* @return singleton instance
*/
static public function getConnection() {
if (is_null(self::$connection)) {
$config = Registry::get('config');
if (!class_exists($config['db']['backend']) || !is_subclass_of($config['db']['backend'], 'Database')) {
throw new InvalidArgumentException('\'' . $config['db']['backend'] . '\' is not a valid database backend');
}
self::$connection = new $config['db']['backend']($config['db']);
}
return self::$connection;
}
public function escape($value) {
if (is_numeric($value)) {
return (string) $value;
}
else {
$value = '\'' . $this->escapeString($value) . '\'';
}
return $value;
}
public function query($sql, $limit = NULL, $offset = NULL) {
if (!is_null($limit))
$sql .= ' LIMIT ' . (int) $limit;
if (!is_null($offset))
$sql .= ' OFFSET ' . (int) $offset;
$rs = get_class($this) . 'ResultSet';
return new $rs($this->execute($sql));
}
/*
* Query functions
*/
public function select($table, $fields = '*', $filter = array(), $conjunction = true, $joins = array(), $limit = NULL, $offset = NULL) {
$sql = 'SELECT ' . implode(' ,', $fields) . ' FROM ' . $table;
foreach ($joins as $join) {
$sql .= $this->buildJoin($join);
}
$sql .= $this->buildFilter($filter, $conjunction);
return $this->query($sql, $limit, $offset);
}
public function delete($table, $filters, $conjunction = true) {
return $this->execute('DELETE FROM ' . $table . $this->buildFilter($filters, $conjunction));
}
public function update($table, $data, $filters, $conjunction = true) {
$updateFields = array();
foreach ($data as $column => $value) {
$updateFields[] = $column . ' = ' . $this->escape($value);
}
$sql = 'UPDATE ' . $table . ' SET' . implode(' ,' , $updateFields) . $this->filter($filters, $conjunction);
return $this->execute($sql);
}
public function insert($table, $data) {
$sql = 'INSERT INTO ' . $table . ' (' . implode(' ,' , array_keys($data)) . ') VALUES (' . implode(', ', array_map(array($this, 'escape'), $value)) . ')';
return $this->execute($sql);
}
protected function buildFilter($filters, $conjunction) {
$where = array();
foreach ($filters as $column => $value) {
if (is_array($value)) {
$where[] = $column . ' IN (' . implode(', ', array_map(array($this, 'escape'), $value)) . ')';
}
else {
$where[] = $column . ' = ' . $this->escape($value);
}
}
if (count($where) > 0) {
return ' WHERE ' . implode(($conjunction === true) ? ' && ' : ' || ', $where);
}
}
protected function buildJoin($join) {
if (!isset($join['type'])) {
$join['type'] = 'left';
}
return ' ' . strtoupper($join['type']) . ' JOIN ' . $join['table'] . ' ON ' . $join['condition'];
}
public function __desctruct() {
$this->close();
}
}
?>

View file

@ -1,187 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
abstract class DatabaseObject {
protected $dbh; // database handle for all queries in DBObject subclasses
protected $data = array();
const STATE_UNKNOWN = 0; // we don't know the current status of the object (deprecated)
const STATE_UNLINKED = 1; // there is no database representation of the object
const STATE_DIRTY = 2; // there is a database representation of the object which has been altered
const STATE_CLEAN = 4; // there is a database representation of the object which which is in sync with the database
private $state = DatabaseObject::STATE_UNKNOWN;
static protected $instances = array(); // singletons of objects
/*
* magic functions
*/
final public function __construct($object = array()) {
$this->dbh = Database::getConnection();
$this->data = $object;
}
public function __get($key) {
if (!isset($this->$key) && ($this->state != DatabaseObject::STATE_UNLINKED)) {
$this->load();
}
return $this->data[$key];
}
public function __set($key, $value) { // TODO untested
if ($key == 'id' || $key == 'uuid') {
throw new Exception($key . ' will be generated automatically');
}
$this->data[$key] = $value;
$this->state = DatabaseObject::STATE_DIRTY;
}
final public function __sleep() {
$this->save();
return array('id');
}
final public function __wakeup() {
$this->state = DatabaseObject::STATE_UNKNOWN;
$this->dbh = Database::getConnection();
}
final public function __isset($key) {
return isset($this->data[$key]);
}
/*
* insert oder update the database representation of the object
*/
public function save() {
if (isset($this->id)) { // just update
$this->update();
}
else { // insert new row
$this->insert();
}
}
protected function insert() {
$this->data['uuid'] = Uuid::mint();
$this->dbh->insert(static::table, $this->data);
$this->data['id'] = $this->dbh->lastInsertId();
$this->state = DatabaseObject::STATE_CLEAN;
}
protected function update() {
$this->dbh->update(static::table, $this->data, array('id' => $this->id));
$this->dbh->execute($sql);
$this->state = DatabaseObject::STATE_CLEAN;
}
/*
* loads all columns from the database and caches them in $this->data
*/
private function load() {
$result = $this->dbh->select(static::table, array('*'), array('id' => $this->id))->current();
if ($result == false) {
$this->unlink();
throw new Exception('Missing database representation');
}
$this->state = DatabaseObject::STATE_CLEAN;
$this->data = $result;
}
/*
* unlinks instance from database
*/
protected function unlink() {
unset($this->data['id']);
unset($this->data['uuid']);
$this->status = DatabaseObject::STATE_UNLINKED;
}
/*
* deletes database representation of this object, but leaves object members.
* by calling $this->save() you can easily reinsert the object with a new id
*/
public function delete() {
$this->unlink();
return $this->dbh->delete(static::table, array('id' => $this->id));
}
/*
* simple self::getByFilter() wrapper
*/
public static function getByUuid($uuid) {
$obj = current(self::getByFilter(array('uuid' => $uuid)));
if ($obj === false) {
throw new InvalidArgumentException('No such object!');
}
return $obj;
}
/*
* simple self::getByFilter() wrapper
*/
public static function getById($id) {
return static::factory(array('id' => $id)); // TODO LSB nescessary?
}
static protected function factory($object) {
if (!isset(self::$instances[static::table])) {
self::$instances[static::table] = array();
}
if (!isset(self::$instances[static::table][$object['id']])) {
self::$instances[static::table][$object['id']] = new static($object); // create singleton instance of database object
}
return self::$instances[static::table][$object['id']]; // return singleton instance of database object
}
/*
* data filtering
*/
static public function getByFilter($filters = array(), $conjunction = true) {
$result = Database::getConnection()->select(static::table, array(static::table . '.*'), $filters, $conjunction);
$instances = array();
foreach ($result as $object) {
$instances[$object['id']] = static::factory($object);
}
return $instances;
}
public function __toString() {
return (string) $this->id;
}
}
?>

View file

@ -1,140 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
/**
* @brief base exception for mysql queries
*/
class MySqlException extends DatabaseException {
function __construct($message = NULL, $code = 0) {
$message = sprintf('%04d: %s', mysql_errno(), mysql_error());
parent::__construct($message, mysql_errno());
}
}
/**
* @brief resultset of a mysql query
*/
class MySqlResultSet extends DatabaseResultSet {
/**
* @param resource $resource mysql resultset
*/
function __construct($resource) {
while ($row = mysql_fetch_assoc($resource)) {
$this->_rows[] = $row;
++$this->_num_rows;
}
}
}
/**
* @brief mysql layer
*/
class MySql extends Database { // TODO replace by mysqli
/**
* @param string $host IP or domain of the database host
* @param string $name database name
* @param string $user user
* @param string $passwd password
*/
function __construct($config) {
$this->connect($config['host'], $config['user'], $config['password']);
$this->selectDatabase($config['database']);
}
function __destruct() {
$this->close();
}
/**
* @brief create database connection
* @param string $host IP or domain of the database host
* @param string $user user
* @param string $passwd password
*/
public function connect($host, $user, $pw) {
$this->close();
$__er = error_reporting(E_ERROR);
if (!$this->resource = mysql_connect($host, $user, rawurlencode($pw))) {
error_reporting($__er);
throw new MySqlException();
}
error_reporting($__er);
}
/**
* @brief close database connection
*/
public function close() {
if (!$this->resource)
return;
mysql_close($this->resource);
$this->resource = false;
}
/**
* @brief select database
* @param string $name database name
*/
public function selectDatabase($db) {
if (!mysql_select_db($db, $this->resource))
throw new MySqlException();
$this->database = $db;
}
/**
* @brief execute query
* @param string $sql query
* @return mixed
*/
public function execute($sql) {
if (!($result = mysql_unbuffered_query($sql, $this->resource)))
throw new MySqlException();
$this->statements[] = $sql;
return $result;
}
/**
* @brief mysql escape string
* @param string $string query
*/
public function escapeString($string) {
return mysql_real_escape_string($string, $this->resource);
}
/**
* @brief count affected rows during last query or execute
*/
public function affectedRows() {
return mysql_affected_rows($this->resource);
}
public function lastInsertId() {
return mysql_insert_id($this->resource);
}
}
?>

View file

@ -1,135 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
/**
* @brief base exception for pgsql queries
*/
class PgSqlException extends DatabaseException
{
function __construct($message = null, $code = 0) {
parent::__construct(pg_last_error());
}
}
/**
* @brief resultset of a pgsql query
*/
class PgSqlResultSet extends DatabaseResultSet
{
/**
* @param resource $resource pgsql resultset
*/
function __construct($resource) {
while ($row = pg_fetch_assoc($ressource)) {
$this->_rows[] = $row;
++$this->_num_rows;
}
}
}
/**
* @brief mysql layer
*/
class PgSql extends Database {
/**
* @param string $host IP or domain of the database host
* @param string $name database name
* @param string $user user
* @param string $passwd password
*/
function __construct($config) {
$this->connect($config['host'], $config['user'], $config['password']);
$this->select($config['database']);
}
function __destruct() {
$this->close();
}
/**
* @brief create database connection
* @param string $host IP or domain of the database host
* @param string $user user
* @param string $passwd password
*/
public function connect($host, $user, $pw) {
$this->close();
$__er = error_reporting(E_ERROR);
if (!$this->resource = pg_connect('dbname=' . $db . ' host=' . $host . ' user=' . $user . ' password=' . $pw)) {
error_reporting($__er);
throw new PgSqlException();
}
error_reporting($__er);
}
/**
* @brief close database connection
*/
public function close() {
if (!$this->resource)
return;
pg_close($this->resource);
$this->resource = false;
}
/**
* @brief select database
* @param string $name database name
*/
public function select($db) {
if (!pgsql_select_db($db, $this->resource))
throw new PgSqlException();
$this->database = $db;
}
/**
* @brief execute query
* @param string $sql query
* @return mixed
*/
public function execute($sql) {
if (!($result = pg_query($sql, $this->resource)))
throw new PgSqlException();
$this->statements[] = $sql;
return new PgSqlResultSet($result);
}
/**
* @brief pgsql escape string
* @param string $string query
*/
public function escapeString($string) {
return pg_escape_string($this->resource, $string);
}
public function getLastInsertId() {
throw new Exception('PgSql::getLastInsertId() hasn\'t implemented yet!'); // TODO find solution, use PDO?
}
}
?>

View file

@ -1,116 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
/**
* @brief base exception for mysql queries
*/
class SqLiteException extends DatabaseException
{
function __construct($message = null, $code = 0) {
$message = sprintf('%04d: %s', sqlite_error_string(sqlite_last_error()), sqlite_last_error());
parent::__construct($message, sqlite_last_error());
}
}
/**
* @brief resultset of a mysql query
*/
class SqLiteResultSet extends DatabaseResultSet
{
/**
* @param resource $resource mysql resultset
*/
function __construct($resource) {
while ($row = sqlite_fetch_array($resource, SQLITE_ASSOC)) {
$this->_rows[] = $row;
++$this->_num_rows;
}
}
}
/**
* @brief mysql layer
*/
class SqLite extends Database {
/**
* @param string $host IP or domain of the database host
* @param string $name database name
* @param string $user user
* @param string $passwd password
*/
function __construct($config) {
$this->select($config['filename']);
}
function __destruct() {
$this->close();
}
/**
* @brief close database connection
*/
public function close() {
if (!$this->resource)
return;
sqlite_close($this->resource);
$this->resource = false;
}
/**
* @brief select database
* @param string $name database name
*/
public function select($filename) {
if (!mysql_select_db($db, $this->resource))
throw new SqLiteException();
$this->database = $db;
}
/**
* @brief execute query
* @param string $sql query
* @return mixed
*/
public function execute($sql) {
if (!($result = sqlite_query($this->resource, $sql)))
throw new SqLiteException();
$this->statements[] = $sql;
return new SqLiteResultSet($result);
}
/**
* @brief sqlite escape string
* @param string $string query
*/
public function escapeString($string) {
return sqlite_escape_string($string);
}
public function lastInsertId() {
return sqlite_last_insert_rowid();
}
}
?>

View file

@ -25,50 +25,7 @@
* the group class groups users, channels and groups itself
*/
class Group extends NestedDatabaseObject {
const table = 'groups';
public function getUsers($recursive = false) { // TODO rework for nested sets
$groups[$this->id] = $this;
if ($recursive === true) {
$groups += $this->getChilds();
}
return User::getByFilter(array('group.id' => $groups));
}
public function getChannels($recursive = false) { // TODO rework for nested sets
$groups[$this->id] = $this;
if ($recursive === true) {
$groups += $this->getChilds();
}
return Channel::getByFilter(array('group.id' => $groups));
}
/*
* data filtering
*/
static public function getByFilter($filters = array(), $conjunction = true) {
$joins = array();
foreach ($filters as $column => $value) {
if (!key_exists('users', $joins) && preg_match('/^user\.([a-z_]+)$/', $column)) {
$joins['users_in_groups'] = array('type' => 'left', 'table' => 'users_in_groups', 'condition' => 'users_in_groups.group_id = ' . self::table . '.id');
$joins['users'] = array('type' => 'left', 'table' => 'users AS user', 'condition' => 'user.id = users_in_groups.user_id');
}
if (!key_exists('channels', $joins) && preg_match('/^channel\.([a-z_]+)$/', $column)) {
$joins['channels_in_groups'] = array('type' => 'left', 'table' => 'channels_in_groups', 'condition' => 'channels_in_groups.group_id = ' . self::table . '.id');
$joins['channels'] = array('type' => 'left', 'table' => 'channels AS channel', 'condition' => 'channels.id = channels_in_groups.channel_id');
}
}
$result = Database::getConnection()->select(self::table, array(self::table . '.*'), $filters, $conjunction, $joins);
$instances = array();
foreach ($result as $object) {
$instances[$object['id']] = static::factory($object);
}
return $instances;
}
}
?>

View file

@ -1,191 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* DatabaseObject which is structured by nested sets
* TODO use database transactions
*/
abstract class NestedDatabaseObject extends DatabaseObject {
public $level; // shouldn't be altered! use move or delete instead!
public $children;
/*
* inserts or updates a tree to the database
*/
public function save(NestedDatabaseObject $parent = NULL) {
if (!is_null($parent) && !isset($parent->id)) { // checks if $parent is part of the tree
throw new InvalidArgumentException('Parent node has to be part of the tree');
}
if (isset($this->id)) {
$this->update($parent);
}
else {
$this->insert($parent);
}
}
/*
* updates tree in database (optionally move it)
*/
protected function update(NestedDatabaseObject $parent = NULL) {
// TODO move it if parent is given
parent::update();
}
/*
* inserts tree to database
*/
protected function insert(NestedDatabaseObject $parent = NULL) {
if (is_null($parent)) {
throw new InvalidArgumentException('We need a parent for a new child');
}
$this->dbh->execute('UPDATE ' . static::table . ' SET lft = lft + 2 WHERE lft > ' . $parent->rgt);
$this->dbh->execute('UPDATE ' . static::table . ' SET rgt = rgt + 2 WHERE rgt >= ' . $parent->rgt);
// update singleton instances
foreach (self::$instances[static::table] as $instance) {
if ($instance->lft > $parent->rgt) {
$instance->lft = $instance->lft + 2;
}
if ($instance->rgt >= $parent->rgt) {
$instance->rgt = $instance->rgt + 2;
}
}
$this->lft = $parent->rgt - 2;
$this->rgt = $parent->rgt - 1;
parent::insert();
}
/*public function move(NestedDatabaseObject $parent) { // TODO finish
$move = $this->rgt - $this->lft + 1;
// exclude the tree which we want to move by turning the sign of left and rigth columns
$sql = 'UPDATE ' . static::table . ' SET lft = lft * -1, rgt = rgt * -1 WHERE lft > ' . $this->lft . ' && rgt < ' . $this->rgt;
// close hole
$sql = 'UPDATE ' . static::table . ' SET lft = lft - x, rgt = rgt - x WHERE lft > ' . $this->lft;
// open new hole
// include the tree which we want to move by turning the sign of left and rigth columns and adding an offset
// TODO update singletons
}*/
/*
* query database for all descending children under this node
*/
public function getChildren() {
$sql = 'SELECT
o.*,
CAST(((o.rgt - o.lft - 1) / 2) AS UNSIGNED) AS children,
COUNT(p.id) AS level
FROM
' . static::table . ' AS n,
' . static::table . ' AS p,
' . static::table . ' AS o
WHERE
o.lft > p.lft && o.rgt < p.rgt
&& o.lft > n.lft && o.rgt < n.rgt
&& n.id = ' . $this->id . '
GROUP BY
o.lft
ORDER BY
o.lft';
$result = $this->dbh->query($sql);
$children = array();
foreach ($result as $row) {
$child = static::factory(array_diff_key($row, array_fill_keys(array('children', 'level'), NULL)));
$child->children = $row['children'];
$child->level = $row['level'];
$children[$row['id']] = $child;
}
return $children;
}
static public function getRoot() {
return current(static::getByFilter(array('lft' => 0)));
}
/*
* delete the node including all descending children from the database
*/
public function delete() {
$move = $this->rgt - $this->lft + 1;
// delete children
$result = $this->dbh->execute('DELETE FROM ' . static::table . ' WHERE lft >= ' . $this->lft . ' && lft <= ' . $this->rgt);
// move remaining children ...
$this->dbh->execute('UPDATE ' . static::table . ' SET lft = lft - ' . $move . ' WHERE lft > ' . $this->rgt);
$this->dbh->execute('UPDATE ' . static::table . ' SET rgt = rgt - ' . $move . ' WHERE rgt > ' . $this->rgt);
// update singleton instances
foreach (self::$instances[static::table] as $instance) {
if ($instance->lft >= $this->lft && $instance->rgt <= $this->rgt) {
$instance->unlink();
}
else {
if ($instance->lft > $this->rgt) {
$instance->lft = $instance->lft - $move;
}
if ($instance->rgt > $this->rgt) {
$instance->rgt = $instance->rgt - $move;
}
}
}
}
/*
* unlinks instance from database
*/
protected function unlink() {
parent::unlink();
unset($this->data['lft']);
unset($this->data['rgt']);
unset($this->level);
unset($this->children);
}
/*
* checks if $child is a descendant of $this
* @return bool
*/
public function contains(NestedDatabaseObject $child) {
return ($child->lft > $this->lft && $child->rgt < $this->rgt);
}
}
class NestedDatabaseException extends Exception {}
?>

View file

@ -23,66 +23,7 @@
* User class
*/
class User extends DatabaseObject {
const table = 'users';
public static function getByEMail($email) {
$user = current(self::getByFilter(array('email' => $email)));
if ($user === false) {
throw new InvalidArgumentException('No such user!');
}
return $user;
}
public function getChannels($recursive = false) {
$groups = $this->getGroups($recursive);
return Channel::getByFilter(array('group.id' => $groups));
}
public function getGroups($recursive = false) {
$groups = Group::getByFilter(array('user.id' => $this));
if ($recursive === true) {
foreach ($groups as $subGroup) {
$groups += $subGroup->getGroups(true);
}
}
return $groups;
}
public function checkPassword($pw) {
return ($this->password == sha1($pw)) ? true : false;
}
public function __set($key, $value) { // special case for passwords
if ($key == 'password') {
$value = sha1($value);
}
parent::__set($key, $value);
}
/*
* data filtering
*/
static public function getByFilter($filters = array(), $conjunction = true) {
$joins = array();
foreach ($filters as $column => $value) {
if (!key_exists('groups', $joins) && preg_match('/^group\.([a-z_]+)$/', $column)) {
$joins['users_in_groups'] = array('type' => 'left', 'table' => 'users_in_groups', 'condition' => 'users_in_groups.user_id = ' . self::table . '.id');
$joins['groups'] = array('type' => 'left', 'table' => 'groups AS group', 'condition' => 'group.id = users_in_groups.group_id');
}
}
$result = Database::getConnection()->select(self::table, array(self::table . '.*'), $filters, $conjunction, $joins);
$instances = array();
foreach ($result as $object) {
$instances[$object['id']] = static::factory($object);
}
return $instances;
}
}
?>

View file

@ -1,62 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
include '../../backend/init.php';
$newGroup = new Group();
$newGroup->name = 'Test';
//$newGroup->save(Group::getById(58));
$groups = array(Group::getById(31));
$groups += Group::getById(31)->getChildren();
echo '<pre>';
foreach ($groups as $child) {
for ($i = 0; $i < $child->level; $i++) {
echo ' ';
}
echo '[' . $child->id . '] ' . $child->name . ' {' . $child->uuid . '} ' . $child->level . ':' . $child->children . "\n";
}
echo '</pre>';
//$newGroup->delete();
/*$groups = Group::getByFilter(array('name' => 'Test'));
foreach ($groups as $group) {
$group->delete();
}*/
/*echo '<pre>';
foreach (Group::getById(1)->getChildren() as $child) {
for ($i = 0; $i < $child->level; $i++) {
echo ' ';
}
echo '[' . $child->id . '] ' . $child->name . ' {' . $child->uuid . '}' . "\n";
}
//var_dump(Database::getConnection());*/
echo '</pre>';
?>

View file

@ -1,38 +0,0 @@
<?php
/*
* Copyright (c) 2010 by Justin Otherguy <justin@justinotherguy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (either version 2 or
* version 3) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/
include '../../backend/init.php';
$channel = current(Channel::getByType('PowerMeter'));
$data = $channel->getData(1270062000000, 1270666800000, 400);
echo '<table border="1">';
foreach ($data as $i => $reading) {
echo '<tr><td>' . ($i + 1) . '</td><td>' . date('h:i:s', $reading['timestamp']/1000) . '</td><td>' . $reading['value'] . '</td><td>' . $reading['count'] . '</td></tr>';
}
echo '</table>';
echo '<pre>';
var_dump(Database::getConnection());
echo '</pre>';
?>