removed own DAL and ORM
ready to be replaced by doctrine
This commit is contained in:
parent
2818b77d46
commit
2c173faa4e
11 changed files with 2 additions and 1320 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -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?
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -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 {}
|
||||
|
||||
?>
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -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>';
|
||||
|
||||
?>
|
|
@ -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>';
|
||||
|
||||
?>
|
Loading…
Add table
Reference in a new issue