From e4b1f69548f3e09ff8377d12902b5fcd02e84277 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Tue, 14 Jun 2011 22:59:08 +0200 Subject: [PATCH] applied changes from jahir (thank you) --- lib/Interpreter/DataIterator.php | 10 +++---- lib/Interpreter/Interpreter.php | 42 +++++++++++++++++---------- lib/Interpreter/MeterInterpreter.php | 9 +++++- lib/Interpreter/SensorInterpreter.php | 3 -- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/lib/Interpreter/DataIterator.php b/lib/Interpreter/DataIterator.php index f62775a..58cb550 100644 --- a/lib/Interpreter/DataIterator.php +++ b/lib/Interpreter/DataIterator.php @@ -71,6 +71,7 @@ class DataIterator implements \Iterator, \Countable { /** * Aggregate data + * @return next aggregated tuple */ public function next() { if ( $this->packageSize == 1) { // return each row as single tuple @@ -78,9 +79,7 @@ class DataIterator implements \Iterator, \Countable { } else { // summarize rows $package = array(0, 0, 0); - for ($i = 0; $i < $this->packageSize && $this->rowKey < $this->rowCount; $i++) { - $tuple = $this->stmt->fetch(); - + for ($i = 0; $i < $this->packageSize && $tuple = $this->stmt->fetch(); $i++) { $package[0] = $tuple[0]; $package[1] += $tuple[1]; $package[2] += $tuple[2]; @@ -96,8 +95,7 @@ class DataIterator implements \Iterator, \Countable { /** * Rewind the iterator * - * Should only be called once - * PDOStatement hasn't a rewind() + * @internal Should only be called once: PDOStatement hasn't a rewind() */ public function rewind() { $this->key = $this->rowKey = 0; @@ -105,7 +103,7 @@ class DataIterator implements \Iterator, \Countable { } public function valid() { - return $this->key <= $this->tupleCount; + return ($this->current[2] > 0); // current package contains at least 1 tuple } /** diff --git a/lib/Interpreter/Interpreter.php b/lib/Interpreter/Interpreter.php index 26fe07e..7bf358a 100644 --- a/lib/Interpreter/Interpreter.php +++ b/lib/Interpreter/Interpreter.php @@ -36,7 +36,9 @@ use Doctrine\ORM; abstract class Interpreter { protected $channel; - /** @var Database connection */ + /** + * @var Database connection + */ protected $conn; protected $from; @@ -84,27 +86,37 @@ abstract class Interpreter { */ protected function getData() { // prepare sql - $sql['from'] = ' FROM data'; - $sql['where'] = ' WHERE channel_id = ?' . self::buildDateTimeFilterSQL($this->from, $this->to); - $sql['orderBy'] = ' ORDER BY timestamp ASC'; + $sqlWhere = ' WHERE channel_id = ?'; - if ($this->groupBy && $sql['groupFields'] = self::buildGroupBySQL($this->groupBy)) { - $sql['rowCount'] = 'SELECT COUNT(DISTINCT ' . $sql['groupFields'] . ')' . $sql['from'] . $sql['where']; - $sql['fields'] = ' MAX(timestamp) AS timestamp, SUM(value) AS value, COUNT(timestamp) AS count'; - $sql['groupBy'] = ' GROUP BY ' . $sql['groupFields']; + if ($this->groupBy && $sqlGroupFields = self::buildGroupBySQL($this->groupBy)) { + $sqlRowCount = 'SELECT COUNT(DISTINCT ' . $sqlGroupFields . ') FROM data' . $sqlWhere; + $sqlFields = ' MAX(timestamp) AS timestamp, SUM(value) AS value, COUNT(timestamp) AS count'; + + $sql = 'SELECT' . $sqlFields . ' + FROM data' . + $sqlWhere . + self::buildDateTimeFilterSQL($this->from, $this->to) . + ' GROUP BY ' . $sqlGroupFields; + + $sqlParameters = array($this->channel->getId()); } else { - $sql['rowCount'] = 'SELECT COUNT(*)' . $sql['from'] . $sql['where']; - $sql['fields'] = ' timestamp, value, 1'; - $sql['groupBy'] = ''; + $sqlRowCount = 'SELECT COUNT(*) FROM data' . $sqlWhere . self::buildDateTimeFilterSQL($this->from, $this->to); + $sqlComon = 'SELECT timestamp, value, 1 FROM data' . $sqlWhere; + + $sqlFirst = '(' . $sqlComon . ' AND timestamp <= ' . $this->from . ' ORDER BY timestamp DESC LIMIT 1) UNION '; + $sqlMiddle = '(' . $sqlComon . self::buildDateTimeFilterSQL($this->from, $this->to) . ' ORDER BY timestamp ASC)'; + $sqlLast = ' UNION (' . $sqlComon . ' AND timestamp >= ' . $this->to . ' ORDER BY timestamp ASC LIMIT 2)'; // we need 2 tuples in MeterInterpreter + + $sql = ((isset($this->from)) ? $sqlFirst : '') . $sqlMiddle . ((isset($this->to)) ? $sqlLast : ''); + $sqlParameters = array_fill(0, 1 + isset($this->from) + isset($this->to), $this->channel->getId()); } - + // get total row count for grouping - $this->rowCount = $this->conn->fetchColumn($sql['rowCount'], array($this->channel->getId()), 0); + $this->rowCount = $this->conn->fetchColumn($sqlRowCount, array($this->channel->getId()), 0); if ($this->rowCount > 0) { - // query for data - $stmt = $this->conn->executeQuery('SELECT ' . $sql['fields'] . $sql['from'] . $sql['where'] . $sql['groupBy'] . $sql['orderBy'], array($this->channel->getId())); + $stmt = $this->conn->executeQuery($sql, $sqlParameters); // query for data return new DataIterator($stmt, $this->rowCount, $this->tupleCount); } diff --git a/lib/Interpreter/MeterInterpreter.php b/lib/Interpreter/MeterInterpreter.php index b32784c..30c83bc 100644 --- a/lib/Interpreter/MeterInterpreter.php +++ b/lib/Interpreter/MeterInterpreter.php @@ -37,6 +37,9 @@ class MeterInterpreter extends Interpreter { protected $min = NULL; protected $max = NULL; + protected $first = NULL; + protected $last = NULL; + protected $pulseCount = NULL; protected $resolution; @@ -73,7 +76,8 @@ class MeterInterpreter extends Interpreter { * @return float 3600: 3600 s/h; 1000: ms -> s */ public function getAverage() { - return (3600 * 1000 * $this->getConsumption()) / ($this->to - $this->from); + $delta = ($this->getConsumption()) ? $this->last[0] - $this->first[0] : 1; // prevent division by zero + return (3600 * 1000 * $this->getConsumption()) / $delta; } /** @@ -109,6 +113,9 @@ class MeterInterpreter extends Interpreter { $last = $next; $next = $pulses->next(); } + + $this->first = reset($tuples); + $this->last = end($tuples); return $tuples; } diff --git a/lib/Interpreter/SensorInterpreter.php b/lib/Interpreter/SensorInterpreter.php index 29a7d72..5dbee57 100644 --- a/lib/Interpreter/SensorInterpreter.php +++ b/lib/Interpreter/SensorInterpreter.php @@ -33,9 +33,6 @@ use Volkszaehler\Util; class SensorInterpreter extends Interpreter { - /** - * @param string|integer $groupBy - */ public function processData($callback) { $data = parent::getData();