huge commit for doctrine integration

starting adding support for multiple APIs
This commit is contained in:
Steffen Vogel 2010-07-18 17:12:00 +02:00
parent 636c15bb1f
commit f9e8f22798
46 changed files with 1923 additions and 686 deletions

View file

@ -1,6 +0,0 @@
<?php
$cliConfig = new Doctrine\Common\Cli\Configuration();
$cliConfig->setAttribute('em', $entityManager);
?>

View file

@ -1 +0,0 @@
/home/steffen/workspace/doctrine2/bin/doctrine

4
backend/bin/doctrine Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env php
<?php
include('doctrine.php');

View file

@ -1 +0,0 @@
/home/steffen/workspace/doctrine2/bin/doctrine.php

52
backend/bin/doctrine.php Normal file
View file

@ -0,0 +1,52 @@
<?php
// TODO replace by state class
const BACKEND_DIR = '/home/steffen/workspace/volkszaehler.org/backend';
// class autoloading
require BACKEND_DIR . '/lib/Util/ClassLoader.php';
$classLoaders = array();
$classLoaders[] = new Volkszaehler\Util\ClassLoader('Doctrine', BACKEND_DIR . '/lib/vendor/Doctrine');
$classLoaders[] = new Volkszaehler\Util\ClassLoader('Symfony', BACKEND_DIR . '/lib/vendor/Symfony');
$classLoaders[] = new Volkszaehler\Util\ClassLoader('Volkszaehler', BACKEND_DIR . '/lib');
foreach ($classLoaders as $loader) {
$loader->register(); // register on SPL autoload stack
}
// load configuration into registry
if (!file_exists(BACKEND_DIR . '/volkszaehler.conf.php')) {
throw new Exception('No configuration available! Use volkszaehler.conf.default.php as an template');
}
include BACKEND_DIR . '/volkszaehler.conf.php';
$em = Volkszaehler\Dispatcher::createEntityManager();
$helperSet = new \Symfony\Components\Console\Helper\HelperSet(array('em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)));
$cli = new \Symfony\Components\Console\Application('Doctrine Command Line Interface', Doctrine\ORM\Version::VERSION);
$cli->setCatchExceptions(true);
$cli->setHelperSet($helperSet);
$cli->addCommands(array(
// DBAL Commands
new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
// ORM Commands
new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
));
$cli->run();

View file

@ -19,29 +19,39 @@
* http://www.gnu.org/copyleft/gpl.html
*/
namespace Volkszaehler;
use Volkszaehler\Util;
use Volkszaehler\Controller;
// TODO replace by state class
const VERSION = 1.1;
const BACKEND_DIR = '/home/steffen/workspace/volkszaehler.org/backend'; // TODO realpath(__DIR__)
const DEV_ENV = true;
// class autoloading
require 'lib/vendor/doctrine/Common/ClassLoader.php';
require BACKEND_DIR . '/lib/Util/ClassLoader.php';
$doctrineLoader = new \Doctrine\Common\ClassLoader('Doctrine', 'lib/vendor/doctrine');
$doctrineLoader->register(); // register on SPL autoload stack
$classLoaders = array();
$classLoaders[] = new Util\ClassLoader('Doctrine', BACKEND_DIR . '/lib/vendor/Doctrine');
$classLoaders[] = new Util\ClassLoader('Symfony', BACKEND_DIR . '/lib/vendor/Symfony');
$classLoaders[] = new Util\ClassLoader('Volkszaehler', BACKEND_DIR . '/lib');
$vzLoader = new \Doctrine\Common\ClassLoader('Volkszaehler', 'lib');
$vzLoader->register(); // register on SPL autoload stack
// API version
define('VERSION', '0.2');
foreach ($classLoaders as $loader) {
$loader->register(); // register on SPL autoload stack
}
// enable strict error reporting
error_reporting(E_ALL);
// load configuration into registry
if (!file_exists(__DIR__ . '/volkszaehler.conf.php')) {
if (!file_exists(BACKEND_DIR . '/volkszaehler.conf.php')) {
throw new Exception('No configuration available! Use volkszaehler.conf.default.php as an template');
}
include __DIR__ . '/volkszaehler.conf.php';
include BACKEND_DIR . '/volkszaehler.conf.php';
$fc = new FrontController(); // spawn frontcontroller
$fc->run(); // execute controller and sends output
$fc = new Dispatcher; // spawn frontcontroller / dispatcher
$fc->run(); // execute controller and sends output
?>

View file

@ -19,40 +19,42 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class ChannelController extends Controller {
namespace Volkszaehler\Controller;
use \Volkszaehler\Model;
class Channel extends Controller {
public function get() {
// TODO get channels from entity manager
// TODO filter by uuid, type etc...
$channels = $this->em->getRepository('Volkszaehler\Model\Channel\Channel')->findAll();
foreach ($channels as $channel) {
$this->view->addChannel($channel);
$this->view->add($channel);
}
}
public function add() {
$channel = new Channel();
// TODO validate input
$channel = new Model\Channel\Meter('power');
// TODO how do differ the 1-wire sensors?
/*if (substr($channel->uuid, 0, 19) == OneWireSensor::$uuidPrefix) {
$channel->type = 'OneWireSensor';
$channel->description = OneWireSensor::getFamilyDescription($channel);
}
else {
$channel->type = 'Channel';
}*/
$channel->setName($this->view->request->getParameter('name'));
$channel->setResolution($this->view->request->getParameter('resolution'));
$channel->setDescription($this->view->request->getParameter('description'));
$channel->setCost($this->view->request->getParameter('cost'));
// TODO adapt to doctrine orm
$channel->persist();
$channel->save();
$this->em->persist($channel);
$this->em->flush();
$this->view->addChannel($channel);
$this->view->add($channel);
}
// TODO check for valid user identity
public function delete() {
$channel = Channel::getByUuid($this->view->request->get['ucid']);
$ucid = $this->view->request->getParameter('ucid');
$channel = $this->em->getRepository('Volkszaehler\Model\Channel\Channel')->findOneBy(array('uuid' => $ucid));
// TODO adapt to doctrine orm
$channel->delete();
$this->em->remove($channel);
$this->em->flush();
}
public function edit() {

View file

@ -19,20 +19,44 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class ControllerException extends Exception {};
namespace Volkszaehler\Controller;
abstract class Controller {
protected $view;
protected $em;
public function __construct(View $view) {
/*
* constructor
*/
public function __construct(\Volkszaehler\View\View $view, \Doctrine\ORM\EntityManager $em) {
$this->view = $view;
$this->em = $em;
}
/*
* catches unknown actions
* creates new view instance depending on the requested format
*/
public function __call($method, $param) {
throw new ControllerException('Undefined controller action!');
public static function factory(\Volkszaehler\View\View $view, \Doctrine\ORM\EntityManager $em) {
$controller = ucfirst(strtolower($view->request->getParameter('controller')));
$controllerClassName = 'Volkszaehler\Controller\\' . $controller;
if (!(\Volkszaehler\Util\ClassLoader::classExists($controllerClassName)) || !is_subclass_of($controllerClassName, '\Volkszaehler\Controller\Controller')) {
throw new \InvalidArgumentException('\'' . $controllerClassName . '\' is not a valid controller');
}
return new $controllerClassName($view, $em);
}
/**
* run controller actions
*
* @param string $action runs the action if class method is available
*/
public function run($action) {
if (!method_exists($this, $action)) {
throw new \InvalidArgumentException('\'' . $action . '\' is not a valid controller action');
}
$this->$action();
}
}

View file

@ -0,0 +1,77 @@
<?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
*/
namespace Volkszaehler\Controller;
class Data extends Controller {
public function get() {
// TODO why not ucids?
$ids = explode(',', trim($this->view->request->getParameter('ids')));
$q = $this->em->createQuery('SELECT c FROM Volkszaehler\Model\Channel\Channel c WHERE c.id IN (' . implode(', ', $ids) . ')');
$channels = $q->execute();
$from = ($this->view->request->getParameter('from')) ? (int) $this->view->request->getParameter('from') : NULL;
$to = ($this->view->request->getParameter('to')) ? (int) $this->view->request->getParameter('to') : NULL;
$groupBy = ($this->view->request->getParameter('groupBy')) ? $this->view->request->getParameter('groupBy') : NULL; // get all readings by default
foreach ($channels as $channel) {
$interpreter = $channel->getInterpreter($this->em);
$this->view->add($interpreter->getValues($from, $to, $groupBy));
}
}
public function add() {
$ucid = $this->view->request->getParameter('ucid');
$channel = $this->em->getRepository('Volkszaehler\Model\Channel\Channel')->findOneBy(array('uuid' => $ucid));
$value = (float) $this->view->request->getParameter('value');
$ts = (int) $this->view->request->getParameter('timestamp');
if ($ts == 0) {
$ts = microtime(true) * 1000;
}
$data = new \Volkszaehler\Model\Data($channel, $value, $ts);
$channel->addData($data);
$this->em->persist($data);
$this->em->flush();
}
/*
* prune all data from database
*/
public function delete() { // TODO add user authentification
$dql = 'DELETE FROM \Volkszaehler\Model\Data WHERE channel_id = ' . $this->id;
if ($this->view->request->getParameter('from')) {
$dql .= ' && timestamp > ' . (int) $this->view->request->getParameter('from');
}
if ($this->view->request->getParameter('to')) {
$dql .= ' && timestamp < ' . $this->view->request->getParameter('to');
}
$q = $em->createQuery($dql);
$q->execute();
}
}

View file

@ -1,42 +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
*/
class DataController extends Controller {
public function get() {
$ids = explode(',', trim($this->view->request->get['ids']));
$channels = Channel::getByFilter(array('id' => $ids), true, false); // get all channels with id in $ids as an array
$from = (isset($this->view->request->get['from'])) ? (int) $this->view->request->get['from'] : NULL;
$to = (isset($this->view->request->get['to'])) ? (int) $this->view->request->get['to'] : NULL;
$groupBy = (isset($this->view->request->get['groupBy'])) ? $this->view->request->get['groupBy'] : NULL; // get all readings by default
foreach ($channels as $channel) {
// TODO change to Channel::getValues()
$this->view->addChannel($channel, $channel->getPulses($from, $to, $groupBy));
}
}
public function add() {
$ucid = $this->view->request->get['ucid'];
$channel = Channel::getByUuid($ucid);
$channel->addData($this->view->request->get); // array(timestamp, value, count)
}
}

View file

@ -1,80 +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
*/
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Configuration;
final class FrontController {
// MVC
private $em = NULL; // Model (Doctrine Entitymanager)
private $view = NULL; // View
private $controller = NULL; // Controller
public function __construct() {
// create view instance
$view = $request->get['format'] . 'View';
if (!class_exists($view) || !is_subclass_of($view, 'View')) {
throw new InvalidArgumentException('\'' . $view . '\' is not a valid View');
}
$this->view = new $view;
$this->em = self::createEntityManager();
}
public static function createEntityManager() {
$config = Registry::get('config');
// Doctrine
$doctConfig = new Configuration;
//$cache = new \Doctrine\Common\Cache\ApcCache;
//$config->setMetadataCacheImpl($cache);
$driverImpl = $doctConfig->newDefaultAnnotationDriver('lib/Model');
$doctConfig->setMetadataDriverImpl($driverImpl);
//$config->setQueryCacheImpl($cache);
$doctConfig->setProxyDir('lib/Model/Proxies');
$doctConfig->setProxyNamespace('Volkszaehler\Model\Proxies');
return EntityManager::create($config['db'], $doctConfig);
}
public function run() {
// create controller instance
$controller = $request->get['controller'] . 'Controller';
if (!class_exists($controller) || !is_subclass_of($controller, 'Controller')) {
throw new ControllerException('\'' . $controller . '\' is not a valid controller');
}
$controller = new $controller($this->view);
$action = $this->view->request->get['action'];
$controller->$action(); // run controllers actions (usually CRUD: http://de.wikipedia.org/wiki/CRUD)
}
public function __destruct() {
$this->view->render(); // render view & send http response
}
}
?>

View file

@ -19,7 +19,9 @@ chann<?php
* http://www.gnu.org/copyleft/gpl.html
*/
class GroupController extends Controller {
namespace Volkszaehler\Controller;
class Group extends Controller {
public function get() {
// TODO get groups from entitymanager according to API specs
@ -32,21 +34,21 @@ class GroupController extends Controller {
public function add() {
$group = new Group();
$group->name = $this->view->request->get['name'];
$group->description = $this->view->request->get['description'];
$group->name = $this->view->request->getParameter('name');
$group->description = $this->view->request->getParameter('description');
// TODO adapt to doctrine orm
$group->save();
$this->em->persist($group);
$this->em->flush();
$this->view->addGroup($group);
$this->view->add($group);
}
// TODO check for valid user identity
public function delete() {
$group = Group::getByUuid($this->view->request->get['ugid']);
$group = Group::getByUuid($this->view->request->getParameter('ugid'));
// TODO adapt to doctrine orm
$group->delete();
$this->em->remove($group);
$this->em->flush();
}
public function edit() {

View file

@ -19,7 +19,9 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class UserController extends Controller {
namespace Volkszaehler\Controller;
class User extends Controller {
// TODO do we need this?
public function get() {
@ -27,20 +29,20 @@ class UserController extends Controller {
public function add() {
$user = new User();
$user->password = $this->view->request->get['password'];
$user->setPassword($this->view->request->getParameter('password'));
// TODO adapt to doctrine orm
$user->save();
$this->em->persist($user);
$this->em->flush();
$this->view->addUser($user);
$this->view->add($user);
}
// TODO check for valid user identity
public function delete() {
$user = User::getByUuid($this->view->request->get['uuid']);
$user = User::getByUuid($this->view->request->getParameter('uuid'));
// TODO adapt to doctrine orm
$user->delete();
$this->em->remove($user);
$this->em->flush();
}
public function edit() {

View file

@ -0,0 +1,94 @@
<?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
*/
namespace Volkszaehler;
use Volkszaehler\View;
use Volkszaehler\Controller;
use Volkszaehler\Util;
/*
* frontcontroller / dispatcher
*/
final class Dispatcher {
// MVC
private $em = NULL; // Model (Doctrine EntityManager)
private $view = NULL; // View
private $controller = NULL; // Controller
/*
* constructor
*/
public function __construct() {
$request = new View\Http\Request();
$response = new View\Http\Response();
$format = $request->getParameter('format');
$controller = $request->getParameter('controller');
$this->em = Dispatcher::createEntityManager();
$this->view = View\View::factory($request, $response);
$this->controller = Controller\Controller::factory($this->view, $this->em);
}
/**
* execute application
*/
public function run() {
$action = (is_null($this->view->request->getParameter('action'))) ? 'get' : $this->view->request->getParameter('action'); // default action
$this->controller->run($action); // run controllers actions (usually CRUD: http://de.wikipedia.org/wiki/CRUD)
$this->view->render(); // render view & send http response
}
/**
* factory for doctrines entitymanager
*
* @todo create extra singleton class or registry?
*/
public static function createEntityManager() {
$vzConfig = Util\Registry::get('config');
// Doctrine
$dcConfig = new \Doctrine\ORM\Configuration;
if (extension_loaded('apc')) {
$cache = new \Doctrine\Common\Cache\ApcCache;
$dcConfig->setMetadataCacheImpl($cache);
$dcConfig->setQueryCacheImpl($cache);
}
$driverImpl = $dcConfig->newDefaultAnnotationDriver(BACKEND_DIR . '/lib/Model');
$dcConfig->setMetadataDriverImpl($driverImpl);
$dcConfig->setProxyDir(BACKEND_DIR . '/lib/Model/Proxies');
$dcConfig->setProxyNamespace('Volkszaehler\Model\Proxies');
$dcConfig->setAutoGenerateProxyClasses(DEV_ENV == true);
$dcConfig->setSQLLogger(Util\Debug::getSQLLogger());
$em = \Doctrine\ORM\EntityManager::create($vzConfig['db'], $dcConfig);
return $em;
}
}
?>

View file

@ -19,67 +19,28 @@
* http://www.gnu.org/copyleft/gpl.html
*/
interface ChannelInterface {
// data management
public function addData($data);
public function getData($from = NULL, $to = NULL, $groupBy = NULL);
public function reset();
namespace Volkszaehler\Interpreter;
// some statistical functions
interface InterpreterInterface {
public function getValues($from = NULL, $to = NULL, $groupBy = NULL);
public function getMin($from = NULL, $to = NULL);
public function getMax($from = NULL, $to = NULL);
public function getAverage($from = NULL, $to = NULL);
}
/**
* Channel class
*
* @Entity
* @Table(name="channels")
*/
abstract class Channel extends Entity implements ChannelInterface {
/** @Column(type="string") */
protected $type;
/** @Column(type="integer") */
protected $resolution;
/** @Column(type="integer") */
protected $cost;
/** @Column(type="string") */
protected $name;
/** @Column(type="string") */
protected $description;
abstract class Interpreter implements InterpreterInterface {
protected $channel;
protected $em;
/*
* prune all data from database
*/
public function reset($from = 0, $to = NULL) {
// TODO add timefilter
$sql = 'DELETE FROM data WHERE channel_id = ' . (int) $this->id . ' && from to';
// TODO delelte with doctrine dal
}
/*
* add a new data to the database
* constructor
*/
public function addData($data) {
$sql = 'INSERT INTO data (channel_id, timestamp, value) VALUES(' . $this->dbh->escape($this) . ', ' . $this->dbh->escape($data['timestamp']) . ', ' . $this->dbh->escape($data['value']) . ')';
// TODO insert with doctrine dal
public function __construct(\Volkszaehler\Model\Channel\Channel $channel, \Doctrine\ORM\EntityManager $em) {
$this->channel = $channel;
$this->em = $em;
}
/*
* retrieve data from the database
*
* If desired it groups it into packages ($groupBy parameter)
*
* @return array() Array with timestamps => value (sorted by timestamp from newest to oldest)
* @param $groupBy determines how readings are grouped. Possible values are: year, month, day, hour, minute or an integer for the desired size of the returned array
*/
public function getData($from = NULL, $to = NULL, $groupBy = NULL) {
protected function getData($from = NULL, $to = NULL, $groupBy = NULL) {
$ts = 'FROM_UNIXTIME(timestamp/1000)'; // just for saving space
switch ($groupBy) {
case 'year':
@ -107,7 +68,7 @@ abstract class Channel extends Entity implements ChannelInterface {
break;
default:
if (is_numeric($groupBy)) {
if (is_numeric($groupBy)) { // lets agrregate it with php
$groupBy = (int) $groupBy;
}
$sqlGroupBy = false;
@ -115,18 +76,26 @@ abstract class Channel extends Entity implements ChannelInterface {
$sql = 'SELECT';
$sql .= ($sqlGroupBy === false) ? ' timestamp, value' : ' MAX(timestamp) AS timestamp, SUM(value) AS value, COUNT(timestamp) AS count';
$sql .= ' FROM data WHERE channel_id = ' . (int) $this->id . $this->buildFilterTime($from, $to);
$sql .= ' FROM data WHERE channel_id = ' . (int) $this->channel->getId(); // TODO add time filter
if ($sqlGroupBy !== false) {
$sql .= ' GROUP BY ' . $sqlGroupBy;
}
$sql .= ' ORDER BY timestamp DESC';
// TODO query with doctrine dal
//$result = $this->dbh->query($sql);
//$totalCount = $result->count();
$rsm = new \Doctrine\ORM\Query\ResultsetMapping;
$rsm->addScalarResult('timestamp', 'timestamp');
$rsm->addScalarResult('value', 'value');
if ($sqlGroupBy) {
$rsm->addScalarResult('count', 'count');
}
$query = $this->em->createNativeQuery($sql, $rsm);
$result = $query->getResult();
$totalCount = count($result);
if (is_int($groupBy) && $groupBy < $totalCount) { // return $groupBy values
$packageSize = floor($totalCount / $groupBy);
$packageCount = $groupBy;
@ -137,23 +106,25 @@ abstract class Channel extends Entity implements ChannelInterface {
}
$packages = array();
$reading = $result->rewind();
$reading = reset($result);
for ($i = 1; $i <= $packageCount; $i++) {
$package = array('timestamp' => $reading['timestamp'], // last timestamp in package
'value' => (float) $reading['value'], // sum of values
'count' => ($sqlGroupBy === false) ? 1 : $reading['count']); // total count of values or pulses in the package
while ($package['count'] < $packageSize) {
$reading = $result->next();
$reading = next($result);
$package['value'] += $reading['value'];
$package['count']++;
}
$packages[] = $package;
$reading = $result->next();
$reading = next($result);
}
return array_reverse($packages); // start with oldest ts and ends with newest ts (reverse array order due to descending order in sql statement)
}
}
}
?>

View file

@ -0,0 +1,92 @@
<?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
*/
namespace Volkszaehler\Interpreter;
class Meter extends Interpreter {
public function getConsumption($from = NULL, $to = NULL) { // TODO untested
$sql = 'SELECT SUM(value) AS count
FROM data
WHERE
channel_id = ' . (int) $this->id . ' &&
' . $this->getTimeFilter($from, $to) . '
GROUP BY channel_id';
$result = $this->dbh->query($sql)->rewind();
return $result['count'] / $this->resolution / 1000; // returns Wh
}
public function getMin($from = NULL, $to = NULL) {
$data = $this->getData($from, $to);
$min = current($data);
foreach ($data as $reading) {
if ($reading['value '] < $min['value']) {
$min = $reading;
}
}
return $min;
}
public function getMax($from = NULL, $to = NULL) {
$data = $this->getData($from, $to);
$min = current($data);
foreach ($data as $reading) {
if ($reading['value '] > $min['value']) {
$min = $reading;
}
}
return $min;
}
public function getAverage($from = NULL, $to = NULL) { // TODO calculate timeinterval if no params were given
return $this->getConsumption($from, $to) / ($to - $from) / 1000; // return W
}
/*
* just a passthru of raw data
*/
public function getPulses($from = NULL, $to = NULL, $groupBy = NULL) {
return parent::getData($from, $to, $groupBy);
}
/*
* raw pulses to power conversion
*/
public function getValues($from = NULL, $to = NULL, $groupBy = NULL) {
$pulses = parent::getData($from, $to, $groupBy);
$pulseCount = count($pulses);
for ($i = 1; $i < $pulseCount; $i++) {
$delta = $pulses[$i]['timestamp'] - $pulses[$i-1]['timestamp'];
$pulses[$i]['timestamp'] -= $delta/2;
$pulses[$i]['value'] *= 3600000/(($this->channel->getResolution() / 1000) * $delta); // TODO untested
}
return $pulses; // returns W
}
}
?>

View file

@ -0,0 +1,49 @@
<?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
*/
namespace Volkszaehler\Interpreter;
class Sensor extends Interpreter {
public function getData($from = NULL, $to = NULL, $groupBy = NULL) {
$data = parent::getData($from, $to, $groupBy);
array_walk($data, function(&$reading) {
$reading['value'] /= $reading['count']; // calculate average (ungroup the sql sum() function)
});
return $data;
}
public function getMin($from = NULL, $to = NULL) { // TODO untested
return $this->dbh->query('SELECT value, timestamp FROM data WHERE channel_id = ' . (int) $this->id . self::buildFilterTime($from, $to) . ' ORDER BY value ASC', 1)->current();
}
public function getMax($from = NULL, $to = NULL) { // TODO untested
return $this->dbh->query('SELECT value, timestamp FROM data WHERE channel_id = ' . (int) $this->id . self::buildFilterTime($from, $to) . ' ORDER BY value DESC', 1)->current();
}
public function getAverage($from = NULL, $to = NULL) { // TODO untested
return $this->dbh->query('SELECT AVG(value) AS value FROM data WHERE channel_id = ' . (int) $this->id . self::buildFilterTime($from, $to))->current();
}
}
?>

View file

@ -19,8 +19,10 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class PowerMeter extends Meter {
const unit = 'kW/h';
namespace Volkszaehler\Logger;
class Flukso implements Logger {
}
?>

View file

@ -0,0 +1,36 @@
<?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
*/
namespace Volkszaehler\Logger;
/*
* interface for parsing diffrent logging APIs (google, flukso etc..)
*/
interface Logger {
public function __construct(\Volkszaehler\View\Http\Request $request);
/**
* @return \Volkszaehler\Model\Data $data the parsed data
*/
public function getData();
}
?>

View file

@ -0,0 +1,90 @@
<?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
*/
namespace Volkszaehler\Model\Channel;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Channel class
*
* @Entity
* @Table(name="channels")
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({
* "meter" = "Meter",
* "sensor" = "Sensor"
* })
*/
abstract class Channel extends \Volkszaehler\Model\Entity {
/** @Column(type="string") */
protected $name;
/** @Column(type="string") */
protected $description;
/** @Column(type="string") */
protected $indicator;
/**
* @OneToMany(targetEntity="Volkszaehler\Model\Data", mappedBy="channel"), cascade={"remove"}
*/
private $data = NULL;
/*
* constructor
*/
public function __construct($indicator) {
parent::__construct();
$this->indicator = $indicator;
$this->data = new ArrayCollection();
}
/*
* getter & setter
*/
public function getName() { return $this->name; }
public function setName($name) { $this->name = $name; }
public function getDescription() { return $this->description; }
public function setDescription($description) { $this->description = $description; }
public function getUnit() { return static::$indicators[$this->indicator]; }
public function getIndicator() { return $this->indicator; }
/*
* add a new data to the database
*/
public function addData(\Volkszaehler\Model\Data $data) {
$this->data->add($data);
}
/*
* obtain channels data interpreter to calculate statistical information
*/
public function getInterpreter(\Doctrine\ORM\EntityManager $em) {
$interpreterClassName = 'Volkszaehler\Interpreter\\' . substr(strrchr(get_class($this), '\\'), 1);
if (!(\Volkszaehler\Util\ClassLoader::classExists($interpreterClassName)) || !is_subclass_of($interpreterClassName, '\Volkszaehler\Interpreter\Interpreter')) {
throw new \InvalidArgumentException('\'' . $interpreterClassName . '\' is not a valid Interpreter');
}
return new $interpreterClassName($this, $em);
}
}

View file

@ -19,69 +19,31 @@
* http://www.gnu.org/copyleft/gpl.html
*/
abstract class Meter extends Channel {
public function getConsumption($from = NULL, $to = NULL) { // TODO untested
$sql = 'SELECT SUM(value) AS count
FROM data
WHERE
channel_id = ' . (int) $this->id . ' &&
' . $this->getTimeFilter($from, $to) . '
GROUP BY channel_id';
namespace Volkszaehler\Model\Channel;
$result = $this->dbh->query($sql)->rewind();
/**
* Meter class
*
* @Entity
*/
class Meter extends Channel {
/** @Column(type="integer") */
private $resolution;
return $result['count'] / $this->resolution / 1000; // returns Wh
}
public function getMin($from = NULL, $to = NULL) {
$data = $this->getData($from, $to);
$min = current($data);
foreach ($data as $reading) {
if ($reading['value '] < $min['value']) {
$min = $reading;
}
}
return $min;
}
public function getMax($from = NULL, $to = NULL) {
$data = $this->getData($from, $to);
$min = current($data);
foreach ($data as $reading) {
if ($reading['value '] > $min['value']) {
$min = $reading;
}
}
return $min;
}
public function getAverage($from = NULL, $to = NULL) { // TODO calculate timeinterval if no params were given
return $this->getConsumption($from, $to) / ($to - $from) / 1000; // return W
}
/** @Column(type="decimal") */
private $cost;
/*
* just a passthru of raw data
* indicator => unit mapping
*/
public function getPulses($from = NULL, $to = NULL, $groupBy = NULL) {
return parent::getData($from, $to, $groupBy);
}
protected static $indicators = array(
'power' => 'kW/h',
'gas' => 'qm/h',
'water' => 'qm/h'
);
/*
* raw pulses to power conversion
*/
public function getData($from = NULL, $to = NULL, $groupBy = NULL) {
$pulses = parent::getData($from, $to, $groupBy);
$pulseCount = count($pulses);
for ($i = 1; $i < $pulseCount; $i++) {
$delta = $pulses[$i]['timestamp'] - $pulses[$i-1]['timestamp'];
$pulses[$i]['timestamp'] -= $delta/2;
$pulses[$i]['value'] *= 3600000/(($this->resolution / 1000) * $delta); // TODO untested
}
return $pulses; // returns W
}
public function getResolution() { return $this->resolution; }
public function setResolution($resolution) { $this->resolution = $resolution; }
public function getCost() { return $this->cost; }
public function setCost($cost) { $this->cost = $cost; }
}

View file

@ -19,26 +19,21 @@
* http://www.gnu.org/copyleft/gpl.html
*/
abstract class Sensor extends Channel {
public function getData($from = NULL, $to = NULL, $groupBy = NULL) {
$data = parent::getData($from, $to, $groupBy);
array_walk($data, function(&$reading) {
$reading['value'] /= $reading['count']; // calculate average (ungroup the sql sum() function)
});
return $data;
}
namespace Volkszaehler\Model\Channel;
public function getMin($from = NULL, $to = NULL) { // TODO untested
return $this->dbh->query('SELECT value, timestamp FROM data WHERE channel_id = ' . (int) $this->id . self::buildFilterTime($from, $to) . ' ORDER BY value ASC', 1)->current();
}
/**
* Channel class
*
* @Entity
*/
class Sensor extends Channel {
public function getMax($from = NULL, $to = NULL) { // TODO untested
return $this->dbh->query('SELECT value, timestamp FROM data WHERE channel_id = ' . (int) $this->id . self::buildFilterTime($from, $to) . ' ORDER BY value DESC', 1)->current();
}
public function getAverage($from = NULL, $to = NULL) { // TODO untested
return $this->dbh->query('SELECT AVG(value) AS value FROM data WHERE channel_id = ' . (int) $this->id . self::buildFilterTime($from, $to))->current();
}
/*
* indicator => unit mapping
*/
protected static $indicators = array(
'temperature' => '° C',
'pressure' => 'hPa',
'humidity' => '%'
);
}

View file

@ -1,130 +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
*/
/*
* Class for Dallas Semiconductor 1-Wire sensors
* http://www.dalsemi.com/
*/
class OneWireSensor extends Sensor {
const unit = 'todo';
/*
* all 1-wire sensor should use a uuid with this prefix followed by their unique rom id
*/
static public $uuidPrefix = '07506920-6e7a-11df-';
/*
* the first byte of the rom id contains the family id describing the type of the sensors
* the rom id should be included in the uuid of the sensor. so we can determine the family out of the uuid.
*/
static function getFamilyDescription($channel) {
$family = base_convert(substr($channel->uuid, 19, 2), 16, 10);
switch($family) {
case 0x01:
return 'DS2401/DS1990A Serial Number iButton';
case 0x02:
return 'DS1425/DS1991 MultiKey iButton';
case 0x04:
return 'DS2402/DS1994 4K NVRAM memory, clock, timer';
case 0x05:
return 'DS2405 Addressable Switch';
case 0x06:
return 'DS1993 4K NVRAM Memory';
case 0x08:
return 'DS1992 1K NVRAM Memory';
case 0x09:
return 'DS2502/DS1982 1Kbit Add only memory';
case 0x0A:
return 'DS1995 16K NVRAM Memory';
case 0x0B:
return 'DS2505/DS1985 16K EPROM Memory';
case 0x0C:
return 'DS1996/x2/x4 64K to 256K NVRAM Memory';
case 0x0F:
return 'DS2506/DS1986 64K EEPROM Memory';
case 0x10:
return 'DS1820/DS18S20/DS1920 Temperature Sensor';
case 0x12:
return 'DS2406/2407 Dual Addressable Switch + 1Kbit memory';
case 0x14:
return 'DS2430A/DS1971 256bit EEPROM iButton';
case 0x18:
return 'DS1963S SHA iButton';
case 0x1A:
return 'DS1963L 4kBit MONETARY iButton';
case 0x1C:
return 'DS2422 1Kbit RAM + Counter';
case 0x1D:
return 'DS2423 4Kbit RAM + Counter';
case 0x1F:
return 'DS2409 MicroLAN Coupler';
case 0x20:
return 'DS2450 Quad A/D Converter';
case 0x21:
return 'DS1921/H/Z Thermochron iButton';
case 0x22:
return 'DS1822 Econo-Temperature Sensor';
case 0x23:
return 'DS2433/DS1973 4K EEPROM Memory';
case 0x24:
return 'DS1425/DS1904 Real Time Clock';
case 0x26:
return 'DS2438 Temperature, A/D Battery Monitor';
case 0x27:
return 'DS2417 Real Time Clock with Interrupt';
case 0x28:
return 'DS18B20 Temperature Sensor';
case 0x29:
return 'DS2408 8-Channel Addressable Switch';
case 0x2C:
return 'DS2890 Single Channel Digital Potentiometer';
case 0x30:
return 'DS2760 Temperature, Current, A/D';
case 0x33:
return 'DS2432/DS1961S 1K EEPROM with SHA-1 Engine';
case 0x3A:
return 'DS2413 Dual Channel Addressable Switch';
case 0x41:
return 'DS1923 Hygrochron Temperature/Humidity Logger with 8kB Data Log Memory';
case 0x42:
return 'DS28EA00 Temperature Sensor with Sequence Detect and PIO';
case 0x82:
return 'DS1425 Multi iButton';
case 0x84:
return 'DS1427 TIME iButton';
case 0x89:
return 'DS2502/1982 1024bit UniqueWare Add Only Memory';
case 0x8B:
return 'DS2505/1985 16Kbit UniqueWare Add Only Memory';
case 0x8F:
return 'DS2506/1986 64Kbit UniqueWare Add Only Memory';
case 0x91:
return 'DS1981 512-bit EEPROM Memory UniqueWare Only';
case 0x96:
return 'DS1955/DS1957B Java Cryptographic iButton';
default:
return false;
}
}
}
?>

View file

@ -0,0 +1,63 @@
<?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
*/
namespace Volkszaehler\Model;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @Entity
* @Table(name="data")
*/
class Data {
/**
* ending timestamp of period in ms since 1970
*
* @Id
* @Column(type="bigint")
*/
private $timestamp;
/** @Column(type="decimal") */
private $value;
/**
* @Id
* @ManyToOne(targetEntity="Volkszaehler\Model\Channel\Channel", inversedBy="data")
* @JoinColumn(name="channel_id", referencedColumnName="id")
*/
private $channel;
public function __construct(Channel\Channel $channel, $value, $timestamp) {
$this->channel = $channel;
$this->value = $value;
$this->timestamp = $timestamp;
}
/*
* setter & getter
*/
public function getValue() { return $this->value; }
public function getTimestamp() { return $this->timestamp; }
public function getChannel() { return $this->channel; }
}
?>

View file

@ -19,19 +19,33 @@
* http://www.gnu.org/copyleft/gpl.html
*/
namespace Volkszaehler\Model;
use Volkszaehler\Util;
/**
* Database Entity
*
* @todo doctrine abstract entity?
* @Entity
* @MappedSuperclass
*/
abstract class Entity {
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
/** @Column(type="string", length=36) */
protected $uuid;
public function __construct() {
$this->uuid = Util\Uuid::mint();
}
/*
* getter & setter
*/
public function getId() { return $this->id; } // read only
public function getUuid() { return $this->uuid; } // read only
}

View file

@ -19,6 +19,8 @@
* http://www.gnu.org/copyleft/gpl.html
*/
namespace Volkszaehler\Model;
use Doctrine\Common\Collections\ArrayCollection;
/**
@ -29,21 +31,46 @@ use Doctrine\Common\Collections\ArrayCollection;
*/
class Group extends Entity {
/** @Column(type="string") */
protected $name;
private $name;
/** @Column(type="string") */
protected $description;
private $description;
// TODO doctrine join
protected $channels = NULL;
/**
* @ManyToMany(targetEntity="Volkszaehler\Model\Channel\Channel")
* @JoinTable(name="groups_channel",
* joinColumns={@JoinColumn(name="group_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="channel_id", referencedColumnName="id")}
* )
*/
private $channels = NULL;
// TODO doctrine nested selfjoin
protected $children = NULL;
/**
* @ManyToMany(targetEntity="Group")
* @JoinTable(name="groups_groups",
* joinColumns={@JoinColumn(name="parent_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="child_id", referencedColumnName="id")}
* )
*/
private $children = NULL;
/*
* construct
*/
public function __construct() {
parent::__construct();
$this->channels = new ArrayCollection();
$this->children = new ArrayCollection();
}
/*
* getter & setter
*/
public function getName() { return $this->name; }
public function setName($name) { $this->name = $name; }
public function getDescription() { return $this->description; }
public function setDescription($description) { $this->description = $description; }
}
?>

View file

@ -0,0 +1,93 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelChannelChannelProxy extends \Volkszaehler\Model\Channel\Channel implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getName()
{
$this->_load();
return parent::getName();
}
public function setName($name)
{
$this->_load();
return parent::setName($name);
}
public function getDescription()
{
$this->_load();
return parent::getDescription();
}
public function setDescription($description)
{
$this->_load();
return parent::setDescription($description);
}
public function getUnit()
{
$this->_load();
return parent::getUnit();
}
public function addData(\Volkszaehler\Model\Data $data)
{
$this->_load();
return parent::addData($data);
}
public function getInterpreter(\Doctrine\ORM\EntityManager $em)
{
$this->_load();
return parent::getInterpreter($em);
}
public function getId()
{
$this->_load();
return parent::getId();
}
public function getUuid()
{
$this->_load();
return parent::getUuid();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array('name', 'description', 'indicator', 'data', 'id', 'uuid');
}
}

View file

@ -0,0 +1,117 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelChannelMeterProxy extends \Volkszaehler\Model\Channel\Meter implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getResolution()
{
$this->_load();
return parent::getResolution();
}
public function setResolution($resolution)
{
$this->_load();
return parent::setResolution($resolution);
}
public function getCost()
{
$this->_load();
return parent::getCost();
}
public function setCost($cost)
{
$this->_load();
return parent::setCost($cost);
}
public function getName()
{
$this->_load();
return parent::getName();
}
public function setName($name)
{
$this->_load();
return parent::setName($name);
}
public function getDescription()
{
$this->_load();
return parent::getDescription();
}
public function setDescription($description)
{
$this->_load();
return parent::setDescription($description);
}
public function getUnit()
{
$this->_load();
return parent::getUnit();
}
public function addData(\Volkszaehler\Model\Data $data)
{
$this->_load();
return parent::addData($data);
}
public function getInterpreter(\Doctrine\ORM\EntityManager $em)
{
$this->_load();
return parent::getInterpreter($em);
}
public function getId()
{
$this->_load();
return parent::getId();
}
public function getUuid()
{
$this->_load();
return parent::getUuid();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array('name', 'description', 'indicator', 'data', 'id', 'uuid', 'resolution', 'cost');
}
}

View file

@ -0,0 +1,93 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelChannelSensorProxy extends \Volkszaehler\Model\Channel\Sensor implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getName()
{
$this->_load();
return parent::getName();
}
public function setName($name)
{
$this->_load();
return parent::setName($name);
}
public function getDescription()
{
$this->_load();
return parent::getDescription();
}
public function setDescription($description)
{
$this->_load();
return parent::setDescription($description);
}
public function getUnit()
{
$this->_load();
return parent::getUnit();
}
public function addData(\Volkszaehler\Model\Data $data)
{
$this->_load();
return parent::addData($data);
}
public function getInterpreter(\Doctrine\ORM\EntityManager $em)
{
$this->_load();
return parent::getInterpreter($em);
}
public function getId()
{
$this->_load();
return parent::getId();
}
public function getUuid()
{
$this->_load();
return parent::getUuid();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array('name', 'description', 'indicator', 'data', 'id', 'uuid');
}
}

View file

@ -0,0 +1,57 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelDataProxy extends \Volkszaehler\Model\Data implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getValue()
{
$this->_load();
return parent::getValue();
}
public function getTimestamp()
{
$this->_load();
return parent::getTimestamp();
}
public function getChannel()
{
$this->_load();
return parent::getChannel();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array('timestamp', 'value', 'channel');
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelEntityProxy extends \Volkszaehler\Model\Entity implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getId()
{
$this->_load();
return parent::getId();
}
public function getUuid()
{
$this->_load();
return parent::getUuid();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array();
}
}

View file

@ -0,0 +1,75 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelGroupProxy extends \Volkszaehler\Model\Group implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getName()
{
$this->_load();
return parent::getName();
}
public function setName($name)
{
$this->_load();
return parent::setName($name);
}
public function getDescription()
{
$this->_load();
return parent::getDescription();
}
public function setDescription($description)
{
$this->_load();
return parent::setDescription($description);
}
public function getId()
{
$this->_load();
return parent::getId();
}
public function getUuid()
{
$this->_load();
return parent::getUuid();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array('name', 'description', 'channels', 'children', 'id', 'uuid');
}
}

View file

@ -0,0 +1,75 @@
<?php
namespace Volkszaehler\Model\Proxies;
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class VolkszaehlerModelUserProxy extends \Volkszaehler\Model\User implements \Doctrine\ORM\Proxy\Proxy
{
private $_entityPersister;
private $_identifier;
public $__isInitialized__ = false;
public function __construct($entityPersister, $identifier)
{
$this->_entityPersister = $entityPersister;
$this->_identifier = $identifier;
}
private function _load()
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}
unset($this->_entityPersister);
unset($this->_identifier);
}
}
public function getEmail()
{
$this->_load();
return parent::getEmail();
}
public function setEmail($email)
{
$this->_load();
return parent::setEmail($email);
}
public function setPassword($password)
{
$this->_load();
return parent::setPassword($password);
}
public function checkPassword($password)
{
$this->_load();
return parent::checkPassword($password);
}
public function getId()
{
$this->_load();
return parent::getId();
}
public function getUuid()
{
$this->_load();
return parent::getUuid();
}
public function __sleep()
{
if (!$this->__isInitialized__) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
return array('email', 'password', 'groups', 'id', 'uuid');
}
}

View file

@ -19,6 +19,8 @@
* http://www.gnu.org/copyleft/gpl.html
*/
namespace Volkszaehler\Model;
use Doctrine\Common\Collections\ArrayCollection;
/**
@ -29,17 +31,42 @@ use Doctrine\Common\Collections\ArrayCollection;
*/
class User extends Entity {
/** @Column(type="string") */
protected $email;
private $email;
/** @Column(type="string") */
protected $passwords;
private $password;
// TODO doctrine join
protected $groups = NULL;
/**
* @ManyToMany(targetEntity="Group")
* @JoinTable(name="groups_users",
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
private $groups = NULL;
/*
* constructor
*/
public function __construct() {
parent::__construct();
$this->groups = new ArrayCollection();
}
/*
* getter & setter
*/
public function getEmail() { return $this->email; }
public function setEmail($email) { $this->email = $email; }
public function setPassword($password) { $this->password = sha1($password); }
/*
* check hashed password against cleartext
*/
public function checkPassword($password) {
return (sha1($password) === $this->password);
}
}
?>

View file

@ -0,0 +1,204 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
/*
* slightly modified from doctrine
*/
namespace Volkszaehler\Util;
class ClassLoader {
private $fileExtension = '.php';
private $namespace;
private $includePath;
private $namespaceSeparator = '\\';
/**
* Creates a new <tt>ClassLoader</tt> that loads classes of the
* specified namespace from the specified include path.
*
* If no include path is given, the ClassLoader relies on the PHP include_path.
* If neither a namespace nor an include path is given, the ClassLoader will
* be responsible for loading all classes, thereby relying on the PHP include_path.
*
* @param string $ns The namespace of the classes to load.
* @param string $includePath The base include path to use.
*/
public function __construct($ns = null, $includePath = null) {
$this->namespace = $ns;
$this->includePath = $includePath;
}
/**
* Sets the base include path for all class files in the namespace of this ClassLoader.
*
* @param string $includePath
*/
public function setIncludePath($includePath) {
$this->includePath = $includePath;
}
/**
* Gets the base include path for all class files in the namespace of this ClassLoader.
*
* @return string
*/
public function getIncludePath() {
return $this->includePath;
}
/**
* Sets the file extension of class files in the namespace of this ClassLoader.
*
* @param string $fileExtension
*/
public function setFileExtension($fileExtension) {
$this->fileExtension = $fileExtension;
}
/**
* Gets the file extension of class files in the namespace of this ClassLoader.
*
* @return string
*/
public function getFileExtension() {
return $this->fileExtension;
}
/**
* Registers this ClassLoader on the SPL autoload stack.
*/
public function register() {
spl_autoload_register(array($this, 'loadClass'));
}
/**
* Removes this ClassLoader from the SPL autoload stack.
*/
public function unregister() {
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $classname The name of the class to load.
* @return boolean TRUE if the class has been successfully loaded, FALSE otherwise.
*/
public function loadClass($className) {
if ($this->namespace !== null && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) {
return false;
}
$subNamespace = substr($className, strlen($this->namespace));
$parts = explode($this->namespaceSeparator, $subNamespace);
$path = implode(DIRECTORY_SEPARATOR, $parts);
require_once ($this->includePath !== null ? $this->includePath : '') . $path . $this->fileExtension;
return true;
}
/**
* Asks this ClassLoader whether it can potentially load the class (file) with
* the given name.
*
* @param string $className The fully-qualified name of the class.
* @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise.
*/
public function canLoadClass($className) {
if ($this->namespace !== null && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) {
return false; // TODO handle with exceptions
}
$subNamespace = substr($className, strlen($this->namespace));
$parts = explode($this->namespaceSeparator, $subNamespace);
$path = implode(DIRECTORY_SEPARATOR, $parts);
return file_exists(($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '') . $path . $this->fileExtension);
}
/**
* Checks whether a class with a given name exists. A class "exists" if it is either
* already defined in the current request or if there is an autoloader on the SPL
* autoload stack that is a) responsible for the class in question and b) is able to
* load a class file in which the class definition resides.
*
* If the class is not already defined, each autoloader in the SPL autoload stack
* is asked whether it is able to tell if the class exists. If the autoloader is
* a <tt>ClassLoader</tt>, {@link canLoadClass} is used, otherwise the autoload
* function of the autoloader is invoked and expected to return a value that
* evaluates to TRUE if the class (file) exists. As soon as one autoloader reports
* that the class exists, TRUE is returned.
*
* Note that, depending on what kinds of autoloaders are installed on the SPL
* autoload stack, the class (file) might already be loaded as a result of checking
* for its existence. This is not the case with a <tt>ClassLoader</tt>, who separates
* these responsibilities.
*
* @param string $className The fully-qualified name of the class.
* @return boolean TRUE if the class exists as per the definition given above, FALSE otherwise.
*/
public static function classExists($className) {
if (class_exists($className, false)) {
return true;
}
foreach (spl_autoload_functions() as $loader) {
if (is_array($loader)) { // array(???, ???)
if (is_object($loader[0])) {
if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName')
if ($loader[0]->canLoadClass($className)) {
return true;
}
} else if ($loader[0]->{$loader[1]}($className)) {
return true;
}
} else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName')
return true;
}
} else if ($loader instanceof \Closure) { // function($className) {..}
if ($loader($className)) {
return true;
}
} else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
return true;
}
}
return false;
}
/**
* Gets the <tt>ClassLoader</tt> from the SPL autoload stack that is responsible
* for (and is able to load) the class with the given name.
*
* @param string $className The name of the class.
* @return The <tt>ClassLoader</tt> for the class or NULL if no such <tt>ClassLoader</tt> exists.
*/
public static function getClassLoader($className) {
foreach (spl_autoload_functions() as $loader) {
if (is_array($loader) && $loader[0] instanceof ClassLoader &&
$loader[0]->canLoadClass($className)) {
return $loader[0];
}
}
return null;
}
}

View file

@ -19,18 +19,16 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class Configuration extends Registry implements ArrayAccess {
public function offsetSet($offset, $value) {
$this->registry[$offset] = $value;
}
public function offsetExists($offset) {
return isset($this->registry[$offset]);
}
public function offsetUnset($offset) {
unset($this->registry[$offset]);
}
public function offsetGet($offset) {
return isset($this->registry[$offset]) ? $this->registry[$offset] : null;
namespace Volkszaehler\Util;
class Debug {
private static $logger = NULL;
static public function getSQLLogger() {
if (is_null(self::$logger)) {
self::$logger = new \Doctrine\DBAL\Logging\DebugStack();
}
return self::$logger;
}
}

View file

@ -19,6 +19,8 @@
* http://www.gnu.org/copyleft/gpl.html
*/
namespace Volkszaehler\Util;
/**
* Registry class to pass global variables between classes.
*/
@ -43,7 +45,7 @@ abstract class Registry {
self::$registry[$key] = $value;
return true;
} else {
throw new Exception('Unable to set variable `' . $key . '`. It was already set.');
throw new \Exception('Unable to set variable `' . $key . '`. It was already set.');
}
}

View file

@ -31,6 +31,10 @@
* Last revised 2010-02-15
*/
namespace Volkszaehler\Util;
class Exception extends \Exception {}
class Uuid {
const MD5 = 3;
const SHA1 = 5;
@ -69,7 +73,7 @@ class Uuid {
return new self(self::mintTime($node));
case 2:
// Version 2 is not supported
throw new UUIDException("Version 2 is unsupported.");
throw new Exception("Version 2 is unsupported.");
case 3:
return new self(self::mintName(self::MD5, $node, $ns));
case 4:
@ -77,7 +81,7 @@ class Uuid {
case 5:
return new self(self::mintName(self::SHA1, $node, $ns));
default:
throw new UUIDException("Selected version is invalid or unsupported.");
throw new Exception("Selected version is invalid or unsupported.");
}
}
@ -145,9 +149,12 @@ class Uuid {
}
protected function __construct($uuid) {
if (strlen($uuid) != 16)
throw new UUIDException("Input must be a 128-bit integer.");
if (strlen($uuid) != 16) {
throw new Exception("Input must be a 128-bit integer.");
}
$this->bytes = $uuid;
// Optimize the most common use
$this->string =
bin2hex(substr($uuid,0,4))."-".
@ -208,11 +215,11 @@ class Uuid {
/* Generates a Version 3 or Version 5 UUID.
These are derived from a hash of a name and its namespace, in binary form. */
if (!$node)
throw new UUIDException("A name-string is required for Version 3 or 5 UUIDs.");
throw new Exception("A name-string is required for Version 3 or 5 UUIDs.");
// if the namespace UUID isn't binary, make it so
$ns = self::makeBin($ns, 16);
if (!$ns)
throw new UUIDException("A binary namespace is required for Version 3 or 5 UUIDs.");
throw new Exception("A binary namespace is required for Version 3 or 5 UUIDs.");
switch($ver) {
case self::MD5:
$version = self::version3;
@ -258,7 +265,7 @@ class Uuid {
self::$randomSource = new COM('CAPICOM.Utilities.1'); // See http://msdn.microsoft.com/en-us/library/aa388182(VS.85).aspx
self::$randomFunc = 'randomCOM';
}
catch(Exception $e) {}
catch(\Exception $e) {}
}
return self::$randomFunc;
}
@ -291,6 +298,3 @@ class Uuid {
return base64_decode(self::$randomSource->GetRandom($bytes,0)); // straight binary mysteriously doesn't work, hence the base64
}
}
class UUIDException extends Exception {
}

View file

@ -0,0 +1,61 @@
<?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
*/
namespace Volkszaehler\View\Http;
class Request {
protected $headers;
protected $parameters;
/**
* HTTP request methods
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
*/
public $method;
/*
* constructor
*/
public function __construct() {
$this->headers = apache_response_headers(); // NOTICE only works for Apache Webservers
$this->method = $_SERVER['REQUEST_METHOD'];
$this->parameters= array(
'get' => $_GET,
'post' => $_POST,
'cookies' => $_COOKIE,
'files' => $_FILES
);
unset($_GET, $_POST, $_COOKIE, $_FILES);
}
/*
* setter & getter
*/
public function getHeader($header) { return $this->headers[$header]; }
public function getParameter($name, $method = 'get') {
return (isset($this->parameters[$method][$name])) ? $this->parameters[$method][$name] : NULL;
}
}

View file

@ -19,9 +19,14 @@
* http://www.gnu.org/copyleft/gpl.html
*/
abstract class HttpHandle {
public $code;
namespace Volkszaehler\View\Http;
/*
* simple class to control the output buffering
*/
class Response {
protected $headers = array();
protected $code = 200; // default code (OK)
protected static $codes = array(
100 => 'Continue',
@ -65,6 +70,40 @@ abstract class HttpHandle {
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported'
);
/*
* constructor
*/
public function __construct() {
$this->headers = apache_response_headers();
ob_start(array($this, 'obCallback'));
}
public function obCallback($output) {
return $output; // simple passthrough
}
public function send() {
// change returncode
header('HTTP/1.1 ' . $this->code . ' ' . self::getCodeDescription($this->code)); // TODO untested
// send headers
foreach ($this->headers as $name => $value) {
header($name . ': ' . $value);
}
ob_end_flush();
}
/*
* setter & getter
*/
public function setHeader($header, $value) { $this->headers[$header] = $value; }
public function getHeader($header) { return $this->headers[$header]; }
public function getCode() { return $this->code; }
public function setCode($code) { $this->code = $code; }
static public function getCodeDescription($code) {
return (isset(self::$codes[$code])) ? self::$codes[$code] : false;
}
}
?>

68
backend/lib/View/Json.php Normal file
View file

@ -0,0 +1,68 @@
<?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
*/
namespace Volkszaehler\View;
use Volkszaehler\Util;
class Json extends View {
protected $json = array();
/*
* constructor
*/
public function __construct(Http\Request $request, Http\Response $response) {
parent::__construct($request, $response);
$this->json['source'] = 'volkszaehler.org';
$this->json['version'] = \Volkszaehler\VERSION;
$this->response->setHeader('Content-type', 'application/json');
}
public function render() {
parent::render();
echo json_encode($this->json);
}
protected function addDebug() {
$config = Util\Registry::get('config');
$this->json['debug'] = array('time' => $this->getTime(),
'database' => array('driver' => $config['db']['driver'],
'queries' => Util\Debug::getSQLLogger()->queries)
);
}
protected function addException(\Exception $exception) {
$this->json['exception'] = array('type' => get_class($exception),
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace()
);
}
}
?>

View file

@ -0,0 +1,51 @@
<?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
*/
namespace Volkszaehler\View\Json;
class Channel extends \Volkszaehler\View\Json {
public function add(\Volkszaehler\Model\Channel\Channel $obj, $data = NULL) {
$channel['id'] = (int) $obj->getId();
$channel['uuid'] = (string) $obj->getUuid();
$channel['type'] = strtolower(substr(strrchr(get_class($obj), '\\'), 1));
$channel['indicator'] = $obj->getIndicator();
$channel['unit'] = $obj->getUnit();
$channel['name'] = $obj->getName();
$channel['description'] = $obj->getDescription();
if (is_subclass_of($obj, '\Volkszaehler\Model\Channel\Meter')) {
$channel['resolution'] = (int) $obj->getResolution();
$channel['cost'] = (float) $obj->getCost();
}
if (!is_null($data) && is_array($data)) {
$channel['data'] = array();
foreach ($data as $reading) {
$channel['data'][] = array($reading['timestamp'], $reading['value'], $reading['count']);
}
}
$this->json['channels'][] = $channel;
}
}
?>

View file

@ -0,0 +1,30 @@
<?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
*/
namespace Volkszaehler\View\Json;
class Data extends \Volkszaehler\View\Json {
public function add($data) {
$this->json['data'][] = $data;
}
}
?>

View file

@ -19,33 +19,24 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class HttpResponse extends HttpHandle {
namespace Volkszaehler\View\Json;
class Group extends \Volkszaehler\View\Json {
public $code = 200; // default code (OK)
public function __construct() {
$this->headers = apache_response_headers();
public function add(\Volkszaehler\Model\Group $obj, $recursive = false) {
$group['id'] = (int) $obj->getId();
$group['uuid'] = (string) $obj->getUuid();
$group['name'] = $obj->getName();
$group['description'] = $obj->getDescription();
ob_start(array($this, 'obCallback'));
}
public function obCallback($output) {
return $output;
}
public function send() {
// change returncode
header('HTTP/1.1 ' . $this->code . ' ' . HttpHandle::$codes[$this->code]); // TODO untested
// send headers
foreach ($this->headers as $name => $value) {
header($name . ': ' . $value);
if ($recursive) { // TODO add really nested sub groups
$children = $obj->getChildren();
foreach ($children as $child) {
$this->addGroup($child, $recursive);
}
}
ob_end_flush();
}
public function setHeader($header, $value) {
$this->headers[$header] = $value;
$this->json['groups'][] = $group;
}
}

View file

@ -19,32 +19,17 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class HttpRequest extends HttpHandle {
public $code;
namespace Volkszaehler\View\Json;
class User extends \Volkszaehler\View\Json {
public $server;
public $get;
public $post;
public $cookies;
public $files;
public function __construct() {
$this->headers = apache_response_headers();
$this->server = $_SERVER;
$this->get = $_GET;
$this->post = $_POST;
$this->cookies = $_COOKIE;
$this->files = $_FILES;
unset($_SERVER);
unset($_GET);
unset($_POST);
unset($_COOKIE);
unset($_FILES);
public function add(\Volkszaehler\Model\User $obj) {
$user['id'] = (int) $obj->getId();
$user['uuid'] = (string) $obj->addUuid();
$user['email'] = $obj->getEmail();
$this->json['users'][] = $user;
}
public function getHeader($header) {
return $this->headers[$header];
}
}
}
?>

View file

@ -1,115 +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
*/
class JsonView extends View {
public $jsonData = array();
public function __construct() {
parent::__construct();
$config = Registry::get('config');
$this->jsonData['source'] = 'volkszaehler.org';
$this->jsonData['version'] = VERSION;
$this->jsonData['storage'] = $config['db']['backend'];
$this->jsonData['controller'] = $request->get['controller'];
$this->jsonData['action'] = $request->get['action'];
$this->response->setHeader('Content-type', 'application/json');
}
public function render() {
$this->jsonData['time'] = $this->getTime();
echo json_encode($this->jsonData);
}
protected function addException(Exception $exception) {
$this->jsonData['exception'] = array('message' => $exception->getMessage(),
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace()
);
}
public function addChannel(Channel $obj, $data = NULL) {
$channel['id'] = (int) $obj->id;
$channel['uuid'] = $obj->uuid;
$channel['type'] = $obj->type;
$channel['unit'] = $obj::unit;
$channel['name'] = $obj->name;
$channel['description'] = $obj->description;
$channel['resolution'] = (int) $obj->resolution;
$channel['cost'] = (float) $obj->cost;
if (!is_null($data) && is_array($data)) {
$channel['data'] = array();
foreach ($data as $reading) {
$channel['data'][] = array($reading['timestamp'], $reading['value'], $reading['count']);
}
}
$this->jsonData['channels'][] = $channel;
}
public function addUser(User $obj) {
$user['id'] = (int) $obj->id;
$user['uuid'] = $obj->uuid;
$this->jsonData['users'][] = $user;
}
public function addGroup(Group $obj, $recursive = false) { // TODO fix this. how do we want to handly nested set structures?
$group['id'] = (int) $obj->id;
$group['uuid'] = $obj->uuid;
$group['name'] = $obj->name;
$group['description'] = $obj->description;
$backtrace = array(&$group);
if ($recursive) {
$children = $obj->getChildren();
foreach ($children as $child) {
$subGroup['id'] = (int) $child->id;
$subGroup['uuid'] = $child->uuid;
$subGroup['name'] = $child->name;
$subGroup['description'] = $child->description;
if ($child->level > $lastLevel) {
array_push(end($backtrace), $subGroup);
// array_push($backtrace, &$subgroup); // TODO: Deprecated: Call-time pass-by-reference has been deprecated
}
elseif ($child->level < $lastLevel) {
array_pop($backtrace);
array_push(end($backtrace), $subGroup);
}
elseif ($child->level == $lastLevel) {
array_push(end($backtrace), $subGroup);
}
}
}
$this->jsonData['groups'][] = $group;
}
}
?>

View file

@ -19,25 +19,19 @@
* http://www.gnu.org/copyleft/gpl.html
*/
interface ViewInterface {
public function render();
public function exceptionHandler(Exception $exception);
public function errorHandler($errno, $errstr, $errfile, $errline);
public function addChannel(Channel $obj);
public function addUser(User $obj);
public function addGroup(Group $obj);
}
namespace Volkszaehler\View;
abstract class View implements ViewInterface {
abstract class View {
public $request;
protected $response;
private $created; // holds timestamp of creation, used later to return time of execution
public function __construct() {
$this->request = new HttpRequest();
$this->response = new HttpResponse();
public function __construct(Http\Request $request, Http\Response $response) {
$this->request = $request;
$this->response = $response;
// TODO move to Debug or State class
$this->created = microtime(true);
// error & exception handling by view
@ -45,25 +39,50 @@ abstract class View implements ViewInterface {
set_error_handler(array($this, 'errorHandler'));
}
final public function errorHandler($errno, $errstr, $errfile, $errline) {
$this->exceptionHandler(new ErrorException($errstr, 0, $errno, $errfile, $errline));
/*
* creates new view instance depending on the requested format
*/
public static function factory(Http\Request $request, Http\Response $response) {
$format = ucfirst(strtolower($request->getParameter('format')));
$controller = ucfirst(strtolower($request->getParameter('controller')));
$viewClassName = 'Volkszaehler\View\\' . $format . '\\' . $controller;
if (!(\Volkszaehler\Util\ClassLoader::classExists($viewClassName)) || !is_subclass_of($viewClassName, '\Volkszaehler\View\View')) {
throw new \InvalidArgumentException('\'' . $viewClassName . '\' is not a valid View');
}
return new $viewClassName($request, $response);
}
final public function exceptionHandler(Exception $exception) {
/*
* error & exception handling
*/
final public function errorHandler($errno, $errstr, $errfile, $errline) {
$this->exceptionHandler(new \ErrorException($errstr, 0, $errno, $errfile, $errline));
}
final public function exceptionHandler(\Exception $exception) {
$this->addException($exception);
//$this->status = STATUS_EXCEPTION; // TODO add status reporting to API
$this->code = 400; // TODO add Exception => HTTP code mapping
$code = ($exception->getCode() == 0 && Http\Response::getCodeDescription($exception->getCode())) ? 400 : $exception->getCode();
$this->response->setCode($code);
$this->render();
die();
}
// TODO move this into Debug or State Class
protected function getTime() {
return round(microtime(true) - $this->created, 4);
}
public function __destruct() {
$this->response->send(); // send response
public function render() {
if (!is_null($this->request->getParameter('debug')) && $this->request->getParameter('debug') > 0) {
$this->addDebug();
}
$this->response->send();
}
}

View file

@ -19,7 +19,11 @@
* http://www.gnu.org/copyleft/gpl.html
*/
class XmlView extends View {
namespace Volkszaehler\View;
// TODO outdated
class Xml extends View {
private $xmlDoc;
private $xml;
private $xmlChannels;
@ -41,13 +45,13 @@ class XmlView extends View {
$this->xml->appendChild($this->xmlDoc->createElement('source', 'volkszaehler.org'));
$this->xml->appendChild($this->xmlDoc->createElement('storage', $config['db']['backend']));
$this->xml->appendChild($this->xmlDoc->createElement('controller', $request->get['controller']));
$this->xml->appendChild($this->xmlDoc->createElement('action', $request->get['action']));
$this->xml->appendChild($this->xmlDoc->createElement('controller', $request->getParameter('controller')));
$this->xml->appendChild($this->xmlDoc->createElement('action', $request->getParameter('action')));
$this->response->setHeader('Content-type', 'text/xml');
}
public function addChannel(Channel $obj, $data = NULL) {
public function addChannel(\Volkszaehler\Model\Channel $obj, $data = NULL) {
$xmlChannel = $this->xmlDoc->createElement('channel');
$xmlChannel->setAttribute('id', (int) $obj->id);
@ -77,7 +81,7 @@ class XmlView extends View {
$this->xmlChannels->appendChild($xmlChannel);
}
public function addUser(User $obj) {
public function addUser(\Volkszaehler\Model\User $obj) {
$xmlUser = $this->xmlDoc->createElement('user');
$xmlUser->setAttribute('id', (int) $obj->id);
$xmlUser->appendChild($this->xmlDoc->createElement('uuid', $obj->uuid));
@ -85,7 +89,7 @@ class XmlView extends View {
$this->xmlUsers->appendChild($xmlUser);
}
public function addGroup(Group $obj) {
public function addGroup(\Volkszaehler\Model\Group $obj) {
$xmlGroup = $this->xmlDoc->createElement('group');
$xmlGroup->setAttribute('id', (int) $obj->id);
$xmlGroup->appendChild($this->xmlDoc->createElement('uuid', $obj->uuid));
@ -118,7 +122,7 @@ class XmlView extends View {
echo $this->xmlDoc->saveXML();
}
protected function addException(Exception $exception) {
protected function addException(\Exception $exception) {
$xmlException = $this->xmlDoc->createElement('exception');
$xmlException->setAttribute('code', $exception->getCode());
$xmlException->appendChild($this->xmlDoc->createElement('message', $exception->getMessage()));