. */ namespace Volkszaehler\Interpreter; use Volkszaehler\Util; use Volkszaehler\Interpreter\Iterator; use Doctrine\ORM; use Volkszaehler\Model; use Doctrine\ORM\Query; /** * Interpreter superclass for all interpreters * * @author Steffen Vogel * @package default * */ abstract class Interpreter implements InterpreterInterface { protected $channel; /** @var Database connection */ protected $conn; protected $from; protected $to; /** * Constructor * * @param Channel $channel * @param EntityManager $em * @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) { $this->channel = $channel; // 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; if (!is_null($this->from) && !is_null($this->from) && $this->from > $this->to) { throw new \Exception('&from is larger than &to parameter'); } } /** * Get raw data * * @param string|integer $groupBy * @return Volkszaehler\DataIterator */ protected function getData($tuples = NULL, $groupBy = NULL) { // 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)) { $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']; } else { $sql['rowCount'] = 'SELECT COUNT(*)' . $sql['from'] . $sql['where']; $sql['fields'] = ' timestamp, value, 1'; $sql['groupBy'] = ''; } // get total row count for grouping $rowCount = $this->conn->fetchColumn($sql['rowCount'], array($this->channel->getId()), 0); // 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($tuples) || $rowCount < $tuples) { return new Iterator\DataIterator($stmt, $rowCount); } else { return new Iterator\DataAggregationIterator($stmt, $rowCount, $tuples); } } /** * Builds sql query part for grouping data by date functions * * @param string $groupBy * @return string the sql part * @todo make compatible with: MSSql (Transact-SQL), Sybase, Firebird/Interbase, IBM, Informix, MySQL, Oracle, DB2, PostgreSQL, SQLite */ protected static function buildGroupBySQL($groupBy) { $ts = 'FROM_UNIXTIME(timestamp/1000)'; // just for saving space switch ($groupBy) { case 'year': return 'YEAR(' . $ts . ')'; break; case 'month': return 'YEAR(' . $ts . '), MONTH(' . $ts . ')'; break; case 'week': return 'YEAR(' . $ts . '), WEEKOFYEAR(' . $ts . ')'; break; case 'day': return 'YEAR(' . $ts . '), DAYOFYEAR(' . $ts . ')'; break; case 'hour': return 'YEAR(' . $ts . '), DAYOFYEAR(' . $ts . '), HOUR(' . $ts . ')'; break; case 'minute': return 'YEAR(' . $ts . '), DAYOFYEAR(' . $ts . '), HOUR(' . $ts . '), MINUTE(' . $ts . ')'; break; case 'second': return 'YEAR(' . $ts . '), DAYOFYEAR(' . $ts . '), HOUR(' . $ts . '), MINUTE(' . $ts . '), SECOND(' . $ts . ')'; break; default: return FALSE; } } /** * Build sql query part to filter specified time interval * * @param integer $from timestamp in ms since 1970 * @param integer $to timestamp in ms since 1970 * @return string the sql part */ protected static function buildDateTimeFilterSQL($from = NULL, $to = NULL) { $sql = ''; if (isset($from)) { $sql .= ' AND timestamp >= ' . $from; } if (isset($to)) { $sql .= ' AND timestamp <= ' . $to; } return $sql; } /** * Parses a timestamp * * @link http://de3.php.net/manual/en/datetime.formats.php * @todo add millisecond resolution * * @param string $ts string to parse * @param float $now in ms since 1970 * @return float */ protected static function parseDateTimeString($string, $now) { if (ctype_digit($string)) { return (float) $string; } elseif ($ts = strtotime($string, $now / 1000)) { return $ts * 1000; } else { throw new \Exception('Invalid time format: ' . $string); } } /* * Getter & setter */ public function getUuid() { return $this->channel->getUuid(); } } ?>