From f90a9a9b8bd44732e346f8dc2cdefd2874d219d8 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Tue, 24 Aug 2010 15:33:55 +0200 Subject: [PATCH] added property and entity definition classes --- backend/index.php | 7 +- backend/lib/Controller/ChannelController.php | 2 +- backend/lib/Model/Channel.php | 29 +-- backend/lib/Model/Entity.php | 90 ++++++++-- backend/lib/Model/Group.php | 12 +- backend/lib/Model/Property.php | 112 +++++++++++- .../Proxies/VolkszaehlerModelChannelProxy.php | 46 ++--- .../Proxies/VolkszaehlerModelEntityProxy.php | 28 +-- .../Proxies/VolkszaehlerModelGroupProxy.php | 28 +-- .../VolkszaehlerModelPropertyProxy.php | 18 ++ backend/lib/Model/Token.php | 2 +- backend/lib/Util/Debug.php | 4 +- backend/lib/Util/JSON.php | 161 +++++++++++++++++ backend/lib/Util/JSONDefinition.php | 96 ++++++++++ backend/lib/View/CSV.php | 2 +- backend/lib/View/JSON.php | 73 +------- backend/lib/View/PlainText.php | 2 +- backend/lib/View/XML.php | 2 +- share/entities.json | 166 +++++++++--------- share/properties.json | 154 ++++++++-------- share/tests/json.php | 62 +++++++ share/tests/properties.php | 41 +++++ 22 files changed, 786 insertions(+), 351 deletions(-) create mode 100644 backend/lib/Util/JSON.php create mode 100644 backend/lib/Util/JSONDefinition.php create mode 100644 share/tests/json.php create mode 100644 share/tests/properties.php diff --git a/backend/index.php b/backend/index.php index 2d70ee7..6d728ac 100644 --- a/backend/index.php +++ b/backend/index.php @@ -30,9 +30,10 @@ 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; +define('VZ_VERSION', 0.2); +define('VZ_DIR', '/home/steffen/workspace/volkszaehler.org'); // TODO realpath(__DIR__) +define('BACKEND_DIR', VZ_DIR . '/backend'); +define('DEV_ENV', TRUE); // class autoloading require BACKEND_DIR . '/lib/Util/ClassLoader.php'; diff --git a/backend/lib/Controller/ChannelController.php b/backend/lib/Controller/ChannelController.php index 6617078..375c537 100644 --- a/backend/lib/Controller/ChannelController.php +++ b/backend/lib/Controller/ChannelController.php @@ -40,7 +40,7 @@ class ChannelController extends Controller { * @todo implement filters */ public function get() { - $dql = 'SELECT c FROM Volkszaehler\Model\Channel c'; + $dql = 'SELECT c, p FROM Volkszaehler\Model\Channel c LEFT JOIN c.properties p'; if ($uuid = $this->view->request->getParameter('uuid')) { // TODO add conditions diff --git a/backend/lib/Model/Channel.php b/backend/lib/Model/Channel.php index 47f8c59..3698e3d 100644 --- a/backend/lib/Model/Channel.php +++ b/backend/lib/Model/Channel.php @@ -44,30 +44,11 @@ class Channel extends Entity { protected $groups; /** - * indicator => interpreter, unit mapping - * - * @todo replace by properties? + * Constructor */ - protected static $indicators = array( - 'power' => array('meter', 'W'), - 'gas' => array('meter', 'm³'), - 'water' => array('meter', 'm³'), - 'temperature' => array('sensor', '°C'), - 'pressure' => array('sensor', 'hPa'), - 'humidity' => array('sensor', '%') - ); + public function __construct($properties = array()) { + parent::__construct($properties); - /** - * constructor - */ - public function __construct($indicator) { - parent::__construct(); - - if (!in_array($indicator, array_keys(self::$indicators))) { - throw new \Exception($indicator . ' is no known indicator'); - } - - $this->indicator = $indicator; $this->data = new ArrayCollection(); $this->groups = new ArrayCollection(); } @@ -118,10 +99,6 @@ class Channel extends Entity { public function setResolution($resolution) { $this->resolution = $resolution; } public function getCost() { return $this->cost; } public function setCost($cost) { $this->cost = $cost; } - - public function getType() { return self::$indicators[$this->indicator][0]; } - public function getUnit() { return self::$indicators[$this->indicator][1]; } - public function getIndicator() { return $this->indicator; } } ?> diff --git a/backend/lib/Model/Entity.php b/backend/lib/Model/Entity.php index d869c37..eee07be 100644 --- a/backend/lib/Model/Entity.php +++ b/backend/lib/Model/Entity.php @@ -46,7 +46,7 @@ abstract class Entity { */ protected $id; - /** @Column(type="string", length=36, nullable=false) */ + /** @Column(type="string", length=36, nullable=false, unique=true) */ protected $uuid; /** @@ -56,41 +56,99 @@ abstract class Entity { /** * @OneToMany(targetEntity="Property", mappedBy="entity") - * @OrderBy({"key" = "ASC"}) + * @OrderBy({"name" = "ASC"}) */ protected $properties = NULL; - public function __construct() { + /** + * Constructor + * + * @param array $properties of Model\Property + */ + public function __construct($properties = array()) { $this->uuid = Util\UUID::mint(); $this->tokens = new Collections\ArrayCollection(); $this->properties = new Collections\ArrayCollection(); } /** - * - * @param unknown_type $token + * Getter & setter */ - public function validateToken($token) { - - } - - public function getToken() { - - } + /** + * + * @param string $name + * @return Model\Property + */ public function getProperty($name) { } - public function setProperty($name) { + public function getProperties() { + return $this->properties; + } + + public function setProperty($name, $value) { + + } + + public function unsetProperty($name) { } - /** - * Getter & setter - */ public function getId() { return $this->id; } // read only public function getUuid() { return $this->uuid; } // read only } +class EntityDefiniton extends Util\JSONDefinition { + /** + * File containing the JSON definitons + * + * @var string + */ + const FILE = '/share/entities.json'; + + /** + * List of required properties + * Allowed properties = optional + required + * @var array + */ + protected $required = array(); + + /** + * List of optional properties + * Allowed properties = optional + required + * @var array + */ + protected $optional = array(); + + /** + * Classname of intepreter (see backend/lib/Interpreter/) + * @var string + */ + protected $interpreter; + + /** + * Not required for group entity + * @var string + */ + protected $unit; + + /** + * @todo url relative or absolute? + * @var string + */ + protected $icon; + + /** + * Check for required and optional properties + * + * @return boolean + */ + public function checkProperties() { + + } + +} + ?> diff --git a/backend/lib/Model/Group.php b/backend/lib/Model/Group.php index bcd6513..5ac2968 100644 --- a/backend/lib/Model/Group.php +++ b/backend/lib/Model/Group.php @@ -61,10 +61,10 @@ class Group extends Entity { protected $parents = NULL; /** - * construct + * Construct */ - public function __construct() { - parent::__construct(); + public function __construct($properties = array()) { + parent::__construct($properties); $this->channels = new ArrayCollection(); $this->children = new ArrayCollection(); @@ -72,7 +72,7 @@ class Group extends Entity { } /** - * adds group as new child + * Adds group as new child * * @param Group $child * @todo check against endless recursion @@ -88,7 +88,7 @@ class Group extends Entity { } /** - * adds channel as new child + * Adds channel as new child * * @param Channel $child * @todo check if the channel is already member of the group @@ -103,7 +103,7 @@ class Group extends Entity { } /** - * getter & setter + * Getter & setter * * @todo change to new property model */ diff --git a/backend/lib/Model/Property.php b/backend/lib/Model/Property.php index 9c094ad..8df15d6 100644 --- a/backend/lib/Model/Property.php +++ b/backend/lib/Model/Property.php @@ -23,6 +23,7 @@ namespace Volkszaehler\Model; +use Volkszaehler\Util; use Volkszaehler\Model; /** @@ -53,6 +54,15 @@ class Property { /** @ManyToOne(targetEntity="Entity", inversedBy="properties") */ protected $entity; + /** + * Property definition + * + * Used to validate + * + * @var Model\PropertyDefinition + */ + protected $definition; + /** * Constructor * @@ -60,8 +70,106 @@ class Property { * @param string $value */ public function __construct($name, $value) { - $this->name = (string) $name; - $this->value = (string) $value; + $this->definition = Model\PropertyDefinition::get($name); + + $this->setName($name); + $this->setValue($value); + } + + /* + * Setter & Getter + */ + + public function getName() { return $this->name; } + public function getValue() { return $this->value; } + + public function setValue($value) { + if (!$this->definition->validate($value)) { + throw new \Exception('invalid property value'); $this->value = $value; + } + } + + /** + * + * @param string $name + * @todo validation + */ + protected function setName($name) { $this->name = $name; } +} + +class PropertyDefinition extends Util\JSONDefinition { + /** One of: string, numeric, multiple */ + public $type; + + /** + * Regex pattern to match if type == string + * + * @var string + */ + protected $pattern; + + /** + * Minimal value if type == numeric + * Required string length if type == string + * + * @var integer|float + */ + protected $min; + + /** + * Maximal value if type == numeric + * Allowed string length if type == string + * + * @var integer|float + */ + protected $max; + + /** + * List of possible choices if type == multiple + * (type as in javascript: 1.2 => numeric, "test" => string) + * + * @var array + */ + protected $choices = array(); + + + /** + * File containing the JSON definitons + * + * @var string + */ + const FILE = '/share/properties.json'; + + /** + * Validate value according to $this->type + * + * @param mixed $value + * @return boolean + */ + public function validate($value) { + switch ($this->type) { + case 'string': + $invalid = !is_string($value); + $invalid |= isset($this->pattern) && !preg_match($this->pattern, $value); + $invalid |= isset($this->min) && strlen($value) < $this->min; + $invalid |= isset($this->max) && strlen($value) > $this->max; + break; + + case 'numeric': + $invalid = !is_numeric($value); + $invalid |= isset($this->min) && $value < $this->min; + $invalid |= isset($this->max) && $value > $this->max; + break; + + case 'multiple': + $invalid = !in_array($value, $this->choices, TRUE); + break; + + default: + throw new \Exception('unknown property type'); + } + + return !$invalid; } } diff --git a/backend/lib/Model/Proxies/VolkszaehlerModelChannelProxy.php b/backend/lib/Model/Proxies/VolkszaehlerModelChannelProxy.php index c35fc9b..a573b88 100644 --- a/backend/lib/Model/Proxies/VolkszaehlerModelChannelProxy.php +++ b/backend/lib/Model/Proxies/VolkszaehlerModelChannelProxy.php @@ -87,46 +87,28 @@ class VolkszaehlerModelChannelProxy extends \Volkszaehler\Model\Channel implemen return parent::setCost($cost); } - public function getType() - { - $this->_load(); - return parent::getType(); - } - - public function getUnit() - { - $this->_load(); - return parent::getUnit(); - } - - public function getIndicator() - { - $this->_load(); - return parent::getIndicator(); - } - - public function validateToken($token) - { - $this->_load(); - return parent::validateToken($token); - } - - public function getToken() - { - $this->_load(); - return parent::getToken(); - } - public function getProperty($name) { $this->_load(); return parent::getProperty($name); } - public function setProperty($name) + public function getProperties() { $this->_load(); - return parent::setProperty($name); + return parent::getProperties(); + } + + public function setProperty($name, $value) + { + $this->_load(); + return parent::setProperty($name, $value); + } + + public function unsetProperty($name) + { + $this->_load(); + return parent::unsetProperty($name); } public function getId() diff --git a/backend/lib/Model/Proxies/VolkszaehlerModelEntityProxy.php b/backend/lib/Model/Proxies/VolkszaehlerModelEntityProxy.php index ce51a1d..2676536 100644 --- a/backend/lib/Model/Proxies/VolkszaehlerModelEntityProxy.php +++ b/backend/lib/Model/Proxies/VolkszaehlerModelEntityProxy.php @@ -27,28 +27,28 @@ class VolkszaehlerModelEntityProxy extends \Volkszaehler\Model\Entity implements } - public function validateToken($token) - { - $this->_load(); - return parent::validateToken($token); - } - - public function getToken() - { - $this->_load(); - return parent::getToken(); - } - public function getProperty($name) { $this->_load(); return parent::getProperty($name); } - public function setProperty($name) + public function getProperties() { $this->_load(); - return parent::setProperty($name); + return parent::getProperties(); + } + + public function setProperty($name, $value) + { + $this->_load(); + return parent::setProperty($name, $value); + } + + public function unsetProperty($name) + { + $this->_load(); + return parent::unsetProperty($name); } public function getId() diff --git a/backend/lib/Model/Proxies/VolkszaehlerModelGroupProxy.php b/backend/lib/Model/Proxies/VolkszaehlerModelGroupProxy.php index dea59e7..feee410 100644 --- a/backend/lib/Model/Proxies/VolkszaehlerModelGroupProxy.php +++ b/backend/lib/Model/Proxies/VolkszaehlerModelGroupProxy.php @@ -99,28 +99,28 @@ class VolkszaehlerModelGroupProxy extends \Volkszaehler\Model\Group implements \ return parent::getInterpreter($em); } - public function validateToken($token) - { - $this->_load(); - return parent::validateToken($token); - } - - public function getToken() - { - $this->_load(); - return parent::getToken(); - } - public function getProperty($name) { $this->_load(); return parent::getProperty($name); } - public function setProperty($name) + public function getProperties() { $this->_load(); - return parent::setProperty($name); + return parent::getProperties(); + } + + public function setProperty($name, $value) + { + $this->_load(); + return parent::setProperty($name, $value); + } + + public function unsetProperty($name) + { + $this->_load(); + return parent::unsetProperty($name); } public function getId() diff --git a/backend/lib/Model/Proxies/VolkszaehlerModelPropertyProxy.php b/backend/lib/Model/Proxies/VolkszaehlerModelPropertyProxy.php index 68cd655..42860e1 100644 --- a/backend/lib/Model/Proxies/VolkszaehlerModelPropertyProxy.php +++ b/backend/lib/Model/Proxies/VolkszaehlerModelPropertyProxy.php @@ -27,6 +27,24 @@ class VolkszaehlerModelPropertyProxy extends \Volkszaehler\Model\Property implem } + public function getName() + { + $this->_load(); + return parent::getName(); + } + + public function getValue() + { + $this->_load(); + return parent::getValue(); + } + + public function setValue($value) + { + $this->_load(); + return parent::setValue($value); + } + public function __sleep() { diff --git a/backend/lib/Model/Token.php b/backend/lib/Model/Token.php index e32cc5c..7fc973f 100644 --- a/backend/lib/Model/Token.php +++ b/backend/lib/Model/Token.php @@ -55,7 +55,7 @@ class Token { * var integer timestamp until token is valid * * @Column(type="bigint") - * @todo implement + * @todo to be implemented */ protected $valid; diff --git a/backend/lib/Util/Debug.php b/backend/lib/Util/Debug.php index 7c0b219..108cea4 100644 --- a/backend/lib/Util/Debug.php +++ b/backend/lib/Util/Debug.php @@ -78,8 +78,8 @@ class Debug implements Logging\SQLLogger { * @param string $sql the sql query * @param array $parameters optional parameters for prepared queries */ - function logSQL($sql, array $parameters = NULL) { - $this->queries[] = array('sql' => $sql, 'parameters' => $parameters); + function logSQL($sql, array $parameters = NULL, $executionMS = null) { + $this->queries[] = array('sql' => $sql, 'parameters' => $parameters, 'execution' => round($executionMS, 5)); } /* diff --git a/backend/lib/Util/JSON.php b/backend/lib/Util/JSON.php new file mode 100644 index 0000000..58b4050 --- /dev/null +++ b/backend/lib/Util/JSON.php @@ -0,0 +1,161 @@ + + * @copyright Copyright (c) 2010, The volkszaehler.org project + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + */ +/* + * This file is part of volkzaehler.org + * + * volkzaehler.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * volkzaehler.org 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 volkszaehler.org. If not, see . + */ + +namespace Volkszaehler\Util; + +/** + * Custom option constant for JSON::encode() + */ +define('JSON_PRETTY', 32); + +/** + * Static JSON utility class + * + * @package util + * @author Steffen Vogel + */ +class JSON extends \ArrayObject { + /** + * OOP wrapper and factory + * @param string $json + * @return Util\JSON + */ + static public function decode($json, $assoc = false, $depth = 512) { + $data = json_decode(self::strip($json), $assoc, $depth); + + if (is_null($data)) { + throw new JSONException(); + } + + return new self($data); + } + + /** + * OOP wrapper + * @param integer $options use JSON_* constants + * @return string the JSON encoded string + */ + public function encode($options = 0) { + $json = json_encode($this->getArrayCopy(), $options); + + if ($options & JSON_PRETTY) { + $json = self::format($json); + } + + return $json; + } + + public function __toString() { + return $this->encode(); + } + + protected static function format($json, $indent = "\t", $newLine = "\n") { + $formatted = ''; + $indentLevel = 0; + $inString = FALSE; + + $len = strlen($json); + for($c = 0; $c < $len; $c++) { + $char = $json[$c]; + switch($char) { + case '{': + case '[': + $formatted .= $char; + if (!$inString && (ord($json[$c+1]) != ord($char)+2)) { + $indentLevel++; + $formatted .= $newLine . str_repeat($indent, $indentLevel); + } + break; + case '}': + case ']': + if (!$inString && (ord($json[$c-1]) != ord($char)-2)) { + $indentLevel--; + $formatted .= $newLine . str_repeat($indent, $indentLevel); + } + $formatted .= $char; + break; + case ',': + $formatted .= $char; + if (!$inString) { + $formatted .= $newLine . str_repeat($indent, $indentLevel); + } + break; + case ':': + $formatted .= $char; + if (!$inString) { + $formatted .= ' '; + } + break; + case '"': + if ($c > 0 && $json[$c-1] != '\\') { + $inString = !$inString; + } + default: + $formatted .= $char; + break; + } + } + + return $formatted; + } + + /** + * Strip whitespaces and comments from JSON string + * + * Nessecary for parsing a JSON string with json_decode() + * + * @param string $json + */ + protected static function strip($json) { + $json = preg_replace(array( + // eliminate single line comments in '// ...' form + '#//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form + '#/\*.*?\*/#s' + ), '', $json); + + // eliminate extraneous space + return trim($json); + } +} + +class JSONException extends \Exception { + /** + * @var array errorcodes defined by json_last_error() + */ + protected static $errors = array( + JSON_ERROR_NONE => 'No error has occurred', + JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded', + JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded', + JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', + JSON_ERROR_SYNTAX => 'Syntax error', + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded' + ); + + public function __construct($message = NULL, $code = 0) { + parent::__construct((is_null($message)) ? self::$errors[json_last_error()] : $message, $code); + } +} + +?> \ No newline at end of file diff --git a/backend/lib/Util/JSONDefinition.php b/backend/lib/Util/JSONDefinition.php new file mode 100644 index 0000000..515dd53 --- /dev/null +++ b/backend/lib/Util/JSONDefinition.php @@ -0,0 +1,96 @@ +. + */ + +namespace Volkszaehler\Util; + +/** + * @author Steffen Vogel + * @package util + */ +abstract class JSONDefinition { + /** + * Cached json definitions + * + * @var array + */ + protected static $definitions = NULL; + + /** Discriminator for database column */ + protected $name; + + /** + * Hide default constructor + * + * @param array $name + */ + protected function __construct($object) { + foreach (get_object_vars($object) as $name => $value) { + if (property_exists(get_class($this), $name)) { + $this->$name = $value; + } + else { + throw new \Exception('unknown definition: ' . $name); + } + } + } + + + /** + * Factory method for creating new instances + * + * @param string $name + * @return Model\PropertyDefinition + */ + public static function get($name) { + if (is_null(self::$definitions)) { + self::load(); + } + + if (!isset(self::$definitions[$name])) { + throw new \Exception('unknown definition'); + } + + return self::$definitions[$name]; + } + + /** + * Load JSON definitions from file (via lazy loading from get()) + */ + protected static function load() { + $json = file_get_contents(VZ_DIR . static::FILE); + $json = JSON::strip($json); + $json = json_decode($json); // TODO move to Util\JSON class + + if (!is_array($json) || count($json) == 0) { + throw new \Exception('syntax error in definition'); + } + + self::$definitions = array(); + + foreach ($json as $property) { + self::$definitions[$property->name] = new static($property); + } + } +} + +?> \ No newline at end of file diff --git a/backend/lib/View/CSV.php b/backend/lib/View/CSV.php index 7c8d867..9deba2b 100644 --- a/backend/lib/View/CSV.php +++ b/backend/lib/View/CSV.php @@ -46,7 +46,7 @@ class CSV extends View { parent::__construct($request, $response); echo 'source: volkszaehler.org' . PHP_EOL; - echo 'version: ' . \Volkszaehler\VERSION . PHP_EOL; + echo 'version: ' . VZ_VERSION . PHP_EOL; $this->response->setHeader('Content-type', 'text/csv'); $this->response->setHeader('Content-Disposition', 'attachment; filename="data.csv"'); diff --git a/backend/lib/View/JSON.php b/backend/lib/View/JSON.php index 0ba27df..d8b5c10 100644 --- a/backend/lib/View/JSON.php +++ b/backend/lib/View/JSON.php @@ -34,7 +34,7 @@ use Volkszaehler\Model; * @author Steffen Vogel */ class JSON extends View { - protected $json = array(); + protected $json; protected $padding = FALSE; @@ -44,8 +44,10 @@ class JSON extends View { public function __construct(HTTP\Request $request, HTTP\Response $response) { parent::__construct($request, $response); + $this->json = new Util\JSON(); + $this->json['source'] = 'volkszaehler.org'; - $this->json['version'] = \Volkszaehler\VERSION; + $this->json['version'] = VZ_VERSION; $this->response->setHeader('Content-type', 'application/json'); @@ -56,15 +58,10 @@ class JSON extends View { public function addChannel(Model\Channel $channel, array $data = NULL) { $jsonChannel['uuid'] = (string) $channel->getUuid(); - $jsonChannel['type'] = $channel->getType(); - $jsonChannel['indicator'] = $channel->getIndicator(); - $jsonChannel['unit'] = $channel->getUnit(); - $jsonChannel['name'] = $channel->getName(); - $jsonChannel['description'] = $channel->getDescription(); - if ($channel->getType() == 'meter') { - $jsonChannel['resolution'] = (int) $channel->getResolution(); - $jsonChannel['cost'] = (float) $channel->getCost(); + + foreach ($channel->getProperties() as $property) { + $jsonChannel[$property->getName()] = $property->getValue(); } if (isset($data)) { @@ -138,11 +135,7 @@ class JSON extends View { } public function renderResponse() { - $json = json_encode($this->json); - - if (Util\Debug::isActivated()) { - $json = self::format($json); - } + $json = $this->json->encode((Util\Debug::isActivated()) ? JSON_PRETTY : 0); if ($this->padding) { $json = 'if (self.' . $this->padding . ') { ' . $this->padding . '(' . $json . '); }'; @@ -150,56 +143,6 @@ class JSON extends View { echo $json; } - - protected static function format($json) { - $formatted = ''; - $indentLevel = 0; - $inString = FALSE; - - $len = strlen($json); - for($c = 0; $c < $len; $c++) { - $char = $json[$c]; - switch($char) { - case '{': - case '[': - $formatted .= $char; - if (!$inString && (ord($json[$c+1]) != ord($char)+2)) { - $indentLevel++; - $formatted .= "\n" . str_repeat("\t", $indentLevel); - } - break; - case '}': - case ']': - if (!$inString && (ord($json[$c-1]) != ord($char)-2)) { - $indentLevel--; - $formatted .= "\n" . str_repeat("\t", $indentLevel); - } - $formatted .= $char; - break; - case ',': - $formatted .= $char; - if (!$inString) { - $formatted .= "\n" . str_repeat("\t", $indentLevel); - } - break; - case ':': - $formatted .= $char; - if (!$inString) { - $formatted .= ' '; - } - break; - case '"': - if ($c > 0 && $json[$c-1] != '\\') { - $inString = !$inString; - } - default: - $formatted .= $char; - break; - } - } - - return $formatted; - } } ?> \ No newline at end of file diff --git a/backend/lib/View/PlainText.php b/backend/lib/View/PlainText.php index f0800cd..0656fc8 100644 --- a/backend/lib/View/PlainText.php +++ b/backend/lib/View/PlainText.php @@ -41,7 +41,7 @@ class PlainText extends View { parent::__construct($request, $response); echo 'source: volkszaehler.org' . PHP_EOL; - echo 'version: ' . \Volkszaehler\VERSION . PHP_EOL; + echo 'version: ' . VZ_VERSION . PHP_EOL; $this->response->setHeader('Content-type', 'text/plain'); } diff --git a/backend/lib/View/XML.php b/backend/lib/View/XML.php index 18b60f1..35147d1 100644 --- a/backend/lib/View/XML.php +++ b/backend/lib/View/XML.php @@ -47,7 +47,7 @@ class XML extends View { $this->xmlRoot = $this->xmlDoc->createElement('volkszaehler'); $this->xmlDoc->appendChild($this->xmlRoot); - $this->xmlRoot->setAttribute('version', \Volkszaehler\VERSION); + $this->xmlRoot->setAttribute('version', VZ_VERSION); $this->xmlRoot->setAttribute('source', 'volkszaehler.org'); $this->response->setHeader('Content-type', 'application/xml; charset=UTF-8'); diff --git a/share/entities.json b/share/entities.json index 8725d46..74864fc 100644 --- a/share/entities.json +++ b/share/entities.json @@ -1,5 +1,7 @@ /** * Definition of entities + + * Format is specified in EntityDefinition class * * @author Steffen Vogel * @copyright Copyright (c) 2010, The volkszaehler.org project @@ -22,87 +24,83 @@ * You should have received a copy of the GNU General Public License * along with volkszaehler.org. If not, see . */ - -{ - "entities" : [ - /*{ - "name" : "", // discriminator for database column - "required" : [], // list of required properties - "optional" : [], // list of optional properties - // allowed properties = optional + required - "interpreter" : "", // classname of intepreter (see backend/lib/Interpreter/) - "unit" : "", // not required for group - "icon" : "" // TODO url relative or absolute? - }*/ - { - "name" : "group", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "tolerance"], - "interpreter" : "GroupInterpreter", - "icon" : "" // TODO look for an group icon - }, - { - "name" : "power", - "required" : ["name", "resolution"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "MeterInterpreter", - "icon" : "" // TODO look for an power icon - }, - { - "name" : "gas", - "required" : ["name", "resolution"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "MeterInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "rainfall", - "required" : ["name", "resolution"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "MeterInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "temperature", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "SensorInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "pressure", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "SensorInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "humidity", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "SensorInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "windspeed", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "SensorInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "radition", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "SensorInterpreter", - "icon" : "" // TODO look for an water icon - }, - { - "name" : "luminosity", - "required" : ["name"], - "optional" : ["description", "details:", "owner:", "address:", "tolerance"], - "interpreter" : "SensorInterpreter", - "icon" : "" // TODO look for an water icon - }, - ] -} \ No newline at end of file + +[ + { + "name" : "group", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "tolerance"], + "interpreter" : "GroupInterpreter", + "icon" : "" // TODO look for an icon + }, + { + "name" : "power", + "required" : ["name", "resolution"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "MeterInterpreter", + "unit" : "kW/h", + "icon" : "" // TODO look for an icon + }, + { + "name" : "gas", + "required" : ["name", "resolution"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "MeterInterpreter", + "unit" : "m³/h", + "icon" : "" // TODO look for an icon + }, + { + "name" : "water", + "required" : ["name", "resolution"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "MeterInterpreter", + "unit" : "m³/h", + "icon" : "" // TODO look for an icon + }, + { + "name" : "temperature", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "SensorInterpreter", + "unit" : "°C", + "icon" : "" // TODO look for an icon + }, + { + "name" : "pressure", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "SensorInterpreter", + "unit" : "hPa", + "icon" : "" // TODO look for an icon + }, + { + "name" : "humidity", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "SensorInterpreter", + "unit" : "%", + "icon" : "" // TODO look for an icon + }, + { + "name" : "windspeed", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "SensorInterpreter", + "unit" : "km/h", + "icon" : "" // TODO look for an icon + }, + { + "name" : "radition", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "SensorInterpreter", + "icon" : "" // TODO look for an icon + }, + { + "name" : "luminosity", + "required" : ["name"], + "optional" : ["description", "details:", "owner:", "address:", "tolerance"], + "interpreter" : "SensorInterpreter", + "icon" : "" // TODO look for an icon + }, +] diff --git a/share/properties.json b/share/properties.json index 68c3726..ead82fc 100644 --- a/share/properties.json +++ b/share/properties.json @@ -1,5 +1,7 @@ /** - * Definition of properties for entities + * Definition of properties for entities + * + * Format is specified in PropertyDefinition class * * @author Steffen Vogel * @copyright Copyright (c) 2010, The volkszaehler.org project @@ -23,84 +25,72 @@ * along with volkszaehler.org. If not, see . */ -{ - "properties" : [ - /*{ - "name" : "", // discriminator for database column - "type" : "", // one of: string, numeric, multiple - "pattern" : "", // regex pattern to match if type == string - "min" : 0, // minimal value if type == numeric - // required string length if type == string - "max" : 100, // maximal value if type == numeric - // allowed string length if type == string - "choices" : ["", "", ""] // list of possible choices if type == multiple - // (type as in javascript: 1.2 => numeric, "test" => string) - },*/ - { - "name" : "name", - "type" : "string", - "pattern" : "/[a-z0-9 ]/", - "max" : 255, - }, - { - "name" : "description", - "type" : "string", - "pattern" : "/[a-z0-9 ]/", // TODO add whitespaces as \t \n \r - "max" : 255, // TODO allowed column size in database? - }, - { - "name" : "cost", - "type" : "numeric", - "min" : 0, - }, - { - "name" : "resolution", - "type" : "numeric", - "min" : 1, - }, - { - "name" : "tolerance", - "type" : "numeric", - "min" : 0, - "max" : 1 - }, - { - "name" : "address:lat", - "type" : "numeric", - "min" : -90, - "max" : 90 - }, - { - "name" : "address:lon", - "type" : "numeric", - "min" : -90, - "max" : 90 - }, - { - "name" : "address:city", - "type" : "string", - "pattern" : "" // TODO add pattern - }, - { - "name" : "address:houseno", - "type" : "string" - }, - { - "name" : "address:postal", - "type" : "string" - }, - { - "name" : "address:state", - "type" : "string" - }, - { - "name" : "address:country", - "type" : "string" - }, - { - "name" : "photo:url", - "type" : "string", - "pattern" : "" // TODO add pattern - }, - ] -} \ No newline at end of file +[ + { + "name" : "name", + "type" : "string", + "pattern" : "/[a-z0-9 ]/", + "min": 3, + "max" : 255 + }, + { + "name" : "description", + "type" : "string", + "pattern" : "/[a-z0-9 ]/", // TODO add whitespaces as \t \n \r + "max" : 255 // TODO allowed column size in database? + }, + { + "name" : "cost", + "type" : "numeric", + "min" : 0 + }, + { + "name" : "resolution", + "type" : "numeric", + "min" : 1 + }, + { + "name" : "tolerance", + "type" : "numeric", + "min" : 0, + "max" : 1 + }, + { + "name" : "address:lat", + "type" : "numeric", + "min" : -90, + "max" : 90 + }, + { + "name" : "address:lon", + "type" : "numeric", + "min" : -90, + "max" : 90 + }, + { + "name" : "address:city", + "type" : "string", + "pattern" : "" // TODO add pattern + }, + { + "name" : "address:houseno", + "type" : "string" + }, + { + "name" : "address:postal", + "type" : "string" + }, + { + "name" : "address:state", + "type" : "string" + }, + { + "name" : "address:country", + "type" : "string" + }, + { + "name" : "photo:url", + "type" : "string", + "pattern" : "" // TODO add pattern + } +] diff --git a/share/tests/json.php b/share/tests/json.php new file mode 100644 index 0000000..47396bd --- /dev/null +++ b/share/tests/json.php @@ -0,0 +1,62 @@ + + */ +/* + * This file is part of volkzaehler.org + * + * volkzaehler.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * volkzaehler.org 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 volkszaehler.org. If not, see . + */ + +use Volkszaehler\Util; +include '../../backend/lib/Util/JSON.php'; +echo '
';
+
+$data = '{
+    "glossary": {
+        "title": "example glossary",
+		"GlossDiv": {
+            "title": "S",
+			"GlossList": {
+                "GlossEntry": {
+                    "ID": "SGML",
+					"SortAs": "SGML",
+					"GlossTerm": "Standard Generalized Markup Language",
+					"Acronym": "SGML",
+					"Abbrev": "ISO 8879:1986",
+					"GlossDef": {
+                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
+						"GlossSeeAlso": ["GML", "XML"]
+                    },
+					"GlossSee": "markup"
+                }
+            }
+        }
+    }
+}';
+
+$json = Util\JSON::decode($data);
+
+$json['test'] = 2;
+
+echo $json->encode(JSON_PRETTY);
+
+
+echo '
'; +?> \ No newline at end of file diff --git a/share/tests/properties.php b/share/tests/properties.php new file mode 100644 index 0000000..5d0d7b1 --- /dev/null +++ b/share/tests/properties.php @@ -0,0 +1,41 @@ + + */ +/* + * This file is part of volkzaehler.org + * + * volkzaehler.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * volkzaehler.org 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 volkszaehler.org. If not, see . + */ + +use Volkszaehler\Util; +use Volkszaehler\Model; + +define('VZ_DIR', '/home/steffen/workspace/volkszaehler.org'); // TODO realpath(__DIR__) + +include '../../backend/lib/Util/JSONDefinition.php'; +include '../../backend/lib/Model/Property.php'; +include '../../backend/lib/Util/JSON.php'; + +echo '
';
+
+new Model\Property('name', '1as2');
+
+echo '
'; +?> \ No newline at end of file