From e5a9b706b2491e21de9b20641bbbe634136a9aee Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 14 Mar 2011 15:58:03 +0100 Subject: [PATCH] simplified data processing --- lib/Controller/DataController.php | 5 +- ...gregationIterator.php => DataIterator.php} | 62 ++++++----- lib/Interpreter/Interpreter.php | 35 +++--- lib/Interpreter/Iterator/DataIterator.php | 100 ------------------ lib/Interpreter/MeterInterpreter.php | 7 +- lib/Model/Entity.php | 13 --- lib/View/JSON.php | 2 - 7 files changed, 65 insertions(+), 159 deletions(-) rename lib/Interpreter/{Iterator/DataAggregationIterator.php => DataIterator.php} (55%) delete mode 100644 lib/Interpreter/Iterator/DataIterator.php diff --git a/lib/Controller/DataController.php b/lib/Controller/DataController.php index a973fe6..9a2e07b 100644 --- a/lib/Controller/DataController.php +++ b/lib/Controller/DataController.php @@ -40,8 +40,11 @@ class DataController extends Controller { public function get(Model\Entity $entity) { $from = $this->view->request->getParameter('from'); $to = $this->view->request->getParameter('to'); + $tuples = $this->view->request->getParameter('tuples'); + $groupBy = $this->view->request->getParameter('group'); + $class = $entity->getDefinition()->getInterpreter(); - return $entity->getInterpreter($this->em, $from, $to); + return new $class($entity, $this->em, $from, $to, $tuples, $groupBy); } /** diff --git a/lib/Interpreter/Iterator/DataAggregationIterator.php b/lib/Interpreter/DataIterator.php similarity index 55% rename from lib/Interpreter/Iterator/DataAggregationIterator.php rename to lib/Interpreter/DataIterator.php index 6d161b1..dfd7382 100644 --- a/lib/Interpreter/Iterator/DataAggregationIterator.php +++ b/lib/Interpreter/DataIterator.php @@ -21,21 +21,25 @@ * along with volkszaehler.org. If not, see . */ -namespace Volkszaehler\Interpreter\Iterator; +namespace Volkszaehler\Interpreter; use Volkszaehler\Util; - use Doctrine\DBAL; /** * @author Steffen Vogel * @package default */ -class DataAggregationIterator implements \Iterator, \Countable { +class DataIterator implements \Iterator, \Countable { + protected $stmt; // PDO statement + protected $current; // the current data protected $key; // key - protected $size; // total readings in PDOStatement - protected $iterator; // subiterator + private $rowKey; // internal key for PDO statement + + protected $rowCount; // num of readings in PDOStatement + protected $tupleCount; // num of requested tuples + protected $packageSize; // num of rows we aggregate in each tuple /** * Constructor @@ -44,28 +48,40 @@ class DataAggregationIterator implements \Iterator, \Countable { * @param integer $size * @param integer $tuples */ - public function __construct(\PDOStatement $stmt, $rows, $count) { - $this->iterator = new DataIterator($stmt, $rows); + public function __construct(\PDOStatement $stmt, $rowCount, $tupleCount) { + $this->rowCount = $rowCount; + $this->tupleCount = $tupleCount; + + $this->stmt = $stmt; + $this->stmt->setFetchMode(\PDO::FETCH_NUM); - $this->packageSize = floor($rows / $count); - $this->size = $count; + if ($this->rowCount > $this->tupleCount) { + $this->packageSize = floor($this->rowCount / $this->tupleCount); + $this->tupleCount = floor($this->rowCount / $this->packageSize) + $this->rowCount % $this->packageSize; + } + else { + $this->packageSize = 1; + } } /** * Aggregate data */ public function next() { - $this->current = array(0, 0, 0); - for ($i = 0; $i < $this->packageSize; $i++, $this->iterator->next()) { - $tuple = $this->iterator->current(); + $package = array(0, 0, 0); + for ($i = 0; $i < $this->packageSize && $this->valid(); $i++) { + $tuple = $this->stmt->fetch(); - $this->current[0] = $tuple[0]; - $this->current[1] += $tuple[1]; - $this->current[2] += $tuple[2]; + $package[0] = $tuple[0]; + $package[1] += $tuple[1]; + $package[2] += $tuple[2]; + + $this->rowKey++; } - + $this->key++; - return $this->current; + Util\Debug::log('key++', $this->key); + return $this->current = $package; } /** @@ -75,24 +91,18 @@ class DataAggregationIterator implements \Iterator, \Countable { * PDOStatement hasn't a rewind() */ public function rewind() { - $this->iterator->rewind(); - // skip first readings to get an even divisor - $skip = count($this->iterator) - count($this) * $this->packageSize; - for ($i = 0; $i < $skip; $i++) { - $this->iterator->next(); - } - return $this->next(); + $this->key = $this->rowKey = 0; } public function valid() { - return $this->key <= $this->size; + return $this->rowKey < $this->rowCount; } /** * Getter & setter */ public function getPackageSize() { return $this->packageSize; } - public function count() { return $this->size; } + public function count() { return $this->tupleCount; } public function key() { return $this->key; } public function current() { return $this->current; } } diff --git a/lib/Interpreter/Interpreter.php b/lib/Interpreter/Interpreter.php index ca012d2..67b0534 100644 --- a/lib/Interpreter/Interpreter.php +++ b/lib/Interpreter/Interpreter.php @@ -43,6 +43,7 @@ abstract class Interpreter { protected $from; protected $to; + protected $groupBy; protected $rowCount = NULL; protected $tupleCount = NULL; @@ -55,14 +56,25 @@ abstract class Interpreter { * @param integer $from timestamp in ms since 1970 * @param integer $to timestamp in ms since 1970 */ - public function __construct(Model\Channel $channel, ORM\EntityManager $em, $from, $to) { + public function __construct(Model\Channel $channel, ORM\EntityManager $em, $from, $to, $tupleCount, $groupBy) { $this->channel = $channel; + $this->tupleCount = $tupleCount; + $this->groupBy = $groupBy; // get dbal connection from EntityManager $this->conn = $em->getConnection(); - $this->from = (isset($from)) ? self::parseDateTimeString($from, time() * 1000) : NULL; - $this->to = (isset($to)) ? self::parseDateTimeString($to, (isset($this->from)) ? $this->from : time() * 1000) : NULL; + $this->from = $from; + $this->to = $to; + + // parse interval + if (isset($from)) { + $this->from = self::parseDateTimeString($from, time() * 1000); + } + + if (isset($to)) { + $this->to = self::parseDateTimeString($to, (isset($this->from)) ? $this->from : time() * 1000); + } if (isset($this->from) && isset($this->to) && $this->from > $this->to) { throw new \Exception('&from is larger than &to parameter'); @@ -75,13 +87,13 @@ abstract class Interpreter { * @param string|integer $groupBy * @return Volkszaehler\DataIterator */ - protected function getData($count = NULL, $groupBy = NULL) { + 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'; - if ($groupBy && $sql['groupFields'] = self::buildGroupBySQL($groupBy)) { + 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']; @@ -98,15 +110,10 @@ abstract class Interpreter { // query for data $stmt = $this->conn->executeQuery('SELECT ' . $sql['fields'] . $sql['from'] . $sql['where'] . $sql['groupBy'] . $sql['orderBy'], array($this->channel->getId())); - // return iterators - if ($sql['groupBy'] || is_null($count) || $this->rowCount < $count) { - $this->tupleCount = $this->rowCount; - return new Iterator\DataIterator($stmt, $this->rowCount); - } - else { - $this->tupleCount = $count; - return new Iterator\DataAggregationIterator($stmt, $this->rowCount, $count); - } + Util\Debug::log('rowcount', $this->rowCount); + Util\Debug::log('tuplecount', $this->tupleCount); + + return new DataIterator($stmt, $this->rowCount, $this->tupleCount); } /** diff --git a/lib/Interpreter/Iterator/DataIterator.php b/lib/Interpreter/Iterator/DataIterator.php deleted file mode 100644 index ad3f590..0000000 --- a/lib/Interpreter/Iterator/DataIterator.php +++ /dev/null @@ -1,100 +0,0 @@ -. - */ - -namespace Volkszaehler\Interpreter\Iterator; - -use Volkszaehler\Util; -use Doctrine\DBAL; - -/** - * @author Steffen Vogel - * @package default - */ -class DataIterator implements \Iterator, \Countable { - protected $current; // the current data - protected $key; // key - protected $stmt; // PDOStatement - protected $size; // total readings in PDOStatement - - /** - * Constructor - * - * @param \PDOStatement $stmt - * @param integer $size - */ - public function __construct(\PDOStatement $stmt, $size) { - $this->size = $size; - $this->stmt = $stmt; - $this->stmt->setFetchMode(\PDO::FETCH_NUM); - } - - /** - * @return array with data - */ - public function current() { - return $this->current; - } - - /** - * Fetch next row from database - */ - public function next() { - $this->key++; - return $this->current = $this->stmt->fetch(); - } - - /** - * @return integer the nth data row - */ - public function key() { - return $this->key; - } - - /** - * @return boolean do we have another row in the resultset? - */ - public function valid() { - return is_array($this->current); - } - - /** - * Rewind the iterator - * - * Should only be called once - * PDOStatement hasn't a rewind() aquivalent - */ - public function rewind() { - $this->key = 0; - return $this->current = $this->stmt->fetch(); - } - - /** - * Get total num of rows - * @return integer - */ - public function count() { - return $this->size; - } -} - -?> diff --git a/lib/Interpreter/MeterInterpreter.php b/lib/Interpreter/MeterInterpreter.php index c06ab8b..b544914 100644 --- a/lib/Interpreter/MeterInterpreter.php +++ b/lib/Interpreter/MeterInterpreter.php @@ -85,14 +85,15 @@ class MeterInterpreter extends Interpreter { * @todo untested * @return array with timestamp, values, and pulse count */ - public function processData($count, $groupBy, $callback) { - $pulses = parent::getData($count, $groupBy); + public function processData($callback) { + $pulses = parent::getData(); $this->resolution = $this->channel->getProperty('resolution'); $this->pulseCount = 0; $tuples = array(); - $last = $pulses->rewind(); + $pulses->rewind(); + $last = $pulses->next(); $next = $pulses->next(); while ($pulses->valid()) { diff --git a/lib/Model/Entity.php b/lib/Model/Entity.php index b6ac43b..6b37704 100644 --- a/lib/Model/Entity.php +++ b/lib/Model/Entity.php @@ -185,19 +185,6 @@ abstract class Entity { public function getUuid() { return $this->uuid; } // read only public function getType() { return $this->type; } // read only public function getDefinition() { return Definition\EntityDefinition::get($this->type); } - - /** - * Get interpreter to obtain data and statistical information for a given time interval - * - * @param Doctrine\ORM\EntityManager $em - * @param integer $from timestamp in ms since 1970 - * @param integer $to timestamp in ms since 1970 - * @return Interpreter - */ - public function getInterpreter(\Doctrine\ORM\EntityManager $em, $from, $to) { - $class = $this->getDefinition()->getInterpreter(); - return new $class($this, $em, $from, $to); - } } ?> diff --git a/lib/View/JSON.php b/lib/View/JSON.php index 1b03a42..5ac087c 100644 --- a/lib/View/JSON.php +++ b/lib/View/JSON.php @@ -202,8 +202,6 @@ class JSON extends View { $this->json['data']['uuid'] = $interpreter->getEntity()->getUuid(); $data = $interpreter->processData( - $this->request->getParameter('tuples'), - $this->request->getParameter('group'), function($tuple) { return array( $tuple[0],