several cosmetic changes
This commit is contained in:
parent
b3c85c8239
commit
948f7cc13b
17 changed files with 273 additions and 155 deletions
1
backend/.gitignore
vendored
Normal file
1
backend/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/database.sqlite
|
|
@ -27,7 +27,9 @@
|
|||
use Volkszaehler\Util;
|
||||
|
||||
// TODO replace by state class
|
||||
const VZ_BACKEND_DIR = '/home/steffen/workspace/volkszaehler.org/backend';
|
||||
define('VZ_VERSION', 0.2);
|
||||
define('VZ_DIR', realpath(__DIR__ . '/../..'));
|
||||
define('VZ_BACKEND_DIR', VZ_DIR . '/backend');
|
||||
|
||||
// class autoloading
|
||||
require VZ_BACKEND_DIR . '/lib/Util/ClassLoader.php';
|
||||
|
@ -44,7 +46,7 @@ foreach ($classLoaders as $loader) {
|
|||
// load configuration
|
||||
Util\Configuration::load(VZ_BACKEND_DIR . '/volkszaehler.conf');
|
||||
|
||||
$em = Volkszaehler\Dispatcher::createEntityManager();
|
||||
$em = Volkszaehler\Router::createEntityManager();
|
||||
|
||||
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
|
||||
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
|
||||
|
|
|
@ -30,13 +30,12 @@ use Volkszaehler\Util;
|
|||
use Volkszaehler\Controller;
|
||||
|
||||
// enable strict error reporting
|
||||
error_reporting(E_ALL);
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// TODO replace by state class
|
||||
define('VZ_VERSION', 0.2);
|
||||
define('VZ_DIR', realpath(__DIR__ . '/..'));
|
||||
define('VZ_BACKEND_DIR', VZ_DIR . '/backend');
|
||||
define('DEV_ENV', TRUE);
|
||||
|
||||
// class autoloading
|
||||
require VZ_BACKEND_DIR . '/lib/Util/ClassLoader.php';
|
||||
|
@ -44,7 +43,6 @@ require VZ_BACKEND_DIR . '/lib/Util/ClassLoader.php';
|
|||
$classLoaders = array();
|
||||
$classLoaders[] = new Util\ClassLoader('Volkszaehler', VZ_BACKEND_DIR . '/lib');
|
||||
$classLoaders[] = new Util\ClassLoader('Doctrine', VZ_BACKEND_DIR . '/lib/vendor/Doctrine');
|
||||
//$classLoaders[] = new Util\ClassLoader('Symfony', VZ_BACKEND_DIR . '/lib/vendor/Symfony'); // only required for the cli
|
||||
|
||||
foreach ($classLoaders as $loader) {
|
||||
$loader->register(); // register on SPL autoload stack
|
||||
|
@ -52,7 +50,8 @@ foreach ($classLoaders as $loader) {
|
|||
|
||||
Util\Configuration::load(VZ_BACKEND_DIR . '/volkszaehler.conf');
|
||||
|
||||
$fc = new Dispatcher; // spawn frontcontroller / dispatcher
|
||||
$fc->run(); // execute controller and sends output
|
||||
$r = new Router();
|
||||
$r->run();
|
||||
$r->view->send();
|
||||
|
||||
?>
|
||||
|
|
|
@ -56,7 +56,7 @@ class AggregatorInterpreter {
|
|||
|
||||
foreach ($aggregator->getChannels() as $channels) {
|
||||
if (isset($indicator) && $indicator != $channel->getIndicator()) {
|
||||
throw new \Exception('we only can aggregate channels of the same indicator');
|
||||
throw new \Exception('Can\'t aggregate entities of mixed types!');
|
||||
}
|
||||
else {
|
||||
$indicator = $channel->getIndicator();
|
||||
|
|
|
@ -115,7 +115,7 @@ abstract class Interpreter implements InterpreterInterface {
|
|||
return new Iterator\DataAggregationIterator($stmt, $rowCount, $tuples);
|
||||
}
|
||||
else {
|
||||
throw new \Exception('invalid groupBy parameter');
|
||||
throw new \Exception('Invalid parameter: "groupBy"');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ class MeterInterpreter extends Interpreter {
|
|||
$delta = $next[0] - $last[0];
|
||||
|
||||
return array(
|
||||
(int) ($next[0] - $delta / 2), // timestamp
|
||||
($next[0] - $delta / 2), // timestamp
|
||||
$next[1] * (3600000 / (($this->channel->getProperty('resolution')->getValue() / 1000) * $delta)), // value
|
||||
(isset($next[2])) ? $next[2] : 1
|
||||
);
|
||||
|
|
|
@ -76,9 +76,6 @@ abstract class Logger implements LoggerInterface {
|
|||
$data = array($data);
|
||||
}
|
||||
|
||||
foreach ($data as $reading) {
|
||||
$this->em->persist($reading);
|
||||
}
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,12 @@ use Volkszaehler\Model;
|
|||
* @todo rename? Bsp: DataSample, Sample, Reading
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="data")
|
||||
* @Table(
|
||||
* name="data",
|
||||
* uniqueConstraints={
|
||||
* @UniqueConstraint(name="unique_timestamp", columns={"timestamp", "channel_id"})
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Data {
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,7 @@ abstract class Definition {
|
|||
$this->$name = $value;
|
||||
}
|
||||
else {
|
||||
throw new \Exception('unknown definition syntax: ' . $name);
|
||||
throw new \Exception('Unknown definition syntax: ' . $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,12 @@ abstract class Definition {
|
|||
* @return Util\Definition
|
||||
*/
|
||||
public static function get($name) {
|
||||
if (is_null(static::$definitions)) {
|
||||
static::load();
|
||||
}
|
||||
|
||||
if (!static::exists($name)) {
|
||||
throw new \Exception('unknown definition');
|
||||
throw new \Exception('Unknown definition');
|
||||
}
|
||||
|
||||
return static::$definitions[$name];
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
namespace Volkszaehler\Model;
|
||||
|
||||
use Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Collections;
|
||||
use Volkszaehler\Util;
|
||||
|
||||
|
@ -63,7 +65,7 @@ abstract class Entity {
|
|||
|
||||
/**
|
||||
* @OneToMany(targetEntity="Property", mappedBy="entity", cascade={"remove", "persist"})
|
||||
* @OrderBy({"name" = "ASC"})
|
||||
* @OrderBy({"key" = "ASC"})
|
||||
*/
|
||||
protected $properties = NULL;
|
||||
|
||||
|
@ -71,77 +73,103 @@ abstract class Entity {
|
|||
* Constructor
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $properties of Model\Property
|
||||
*/
|
||||
public function __construct($type) {
|
||||
if (!EntityDefinition::exists($type)) {
|
||||
throw new \Exception('unknown entity type');
|
||||
throw new \Exception('Unknown entity type');
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
$this->uuid = Util\UUID::mint();
|
||||
$this->uuid = (string) Util\UUID::mint();
|
||||
|
||||
$this->tokens = new Collections\ArrayCollection();
|
||||
$this->properties = new Collections\ArrayCollection();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks for optional and required properties according to share/entities.json
|
||||
*
|
||||
* Throws an exception if something is incorrect
|
||||
* Checks for required and invalid properties
|
||||
*
|
||||
* @PrePersist
|
||||
* @PreUpdate
|
||||
* @PostLoad
|
||||
* @todo to be implemented
|
||||
*/
|
||||
protected function validate() {
|
||||
public function checkProperties() {
|
||||
$missingProperties = array_diff($this->getDefinition()->getRequiredProperties(), array_keys($this->getProperties()));
|
||||
$invalidProperties = array_diff(array_keys($this->getProperties()), $this->getDefinition()->getValidProperties());
|
||||
|
||||
if (count($missingProperties) > 0) {
|
||||
throw new \Exception('Entity "' . $this->getType() . '" requires propert' . ((count($missingProperties) == 1) ? 'y' : 'ies') . ': "' . implode(', ', $missingProperties) . '"');
|
||||
}
|
||||
|
||||
if (count($invalidProperties) > 0) {
|
||||
throw new \Exception('Propert' . ((count($invalidProperties) == 1) ? 'y' : 'ies') . ' "' . implode(', ', $unallowedProperties) . '" ' . ((count($unallowedProperties) == 1) ? 'is' : 'are') . ' not allowed for entity "' . $this->getType() . '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return Model\Property
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getProperty($name) {
|
||||
return $this->properties->filter(function($property) use ($name) {
|
||||
return $property->getName() == $name;
|
||||
})->first();
|
||||
public function getProperty($key) {
|
||||
return $this->findProperty($key)->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all properties or properties by prefix
|
||||
*
|
||||
* @param string $prefix
|
||||
* @return array
|
||||
*/
|
||||
public function getProperties($prefix = NULL) {
|
||||
if (is_null($prefix)) {
|
||||
return $this->properties;
|
||||
$properties = array();
|
||||
foreach ($this->properties as $property) {
|
||||
if (substr($property->getKey(), 0, strlen($prefix)) == $prefix) {
|
||||
$properties[$property->getKey()] = $property->getValue();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $this->properties->filter(function($property) use ($prefix) {
|
||||
return substr($property->getName(), 0, strlen($prefix) + 1) == $prefix . ':';
|
||||
});
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $key
|
||||
* @return Model\Property
|
||||
*/
|
||||
protected function findProperty($key) {
|
||||
foreach ($this->properties as $property) {
|
||||
if ($property->getKey() == $key) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name of the property
|
||||
* @param string|integer|float $value of the property
|
||||
* @todo check if already set for this entity
|
||||
* Set property
|
||||
*
|
||||
* @param string $key name of the property
|
||||
* @param mixed $value of the property
|
||||
*/
|
||||
public function setProperty(Property $property) {
|
||||
$this->properties->add($property);
|
||||
public function setProperty($key, $value) {
|
||||
if ($property = $this->findProperty($key)) { // property already exists; just change value
|
||||
$property->setValue($value);
|
||||
}
|
||||
else { // create new property
|
||||
$property = new Property($this, $key, $value);
|
||||
$this->properties->add($property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset property
|
||||
*
|
||||
* @param string $name of the property
|
||||
* @todo to be implemented
|
||||
* @param Doctrine\EntityManager $em
|
||||
*/
|
||||
public function unsetProperty($name) {
|
||||
|
||||
public function unsetProperty($key, ORM\EntityManager $em) {
|
||||
$property = $this->findProperty($key);
|
||||
$em->remove($property);
|
||||
$this->properties->remove($index);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -161,8 +189,8 @@ abstract class Entity {
|
|||
* @return Interpreter
|
||||
*/
|
||||
public function getInterpreter(\Doctrine\ORM\EntityManager $em, $from, $to) {
|
||||
$interpreterClassName = 'Volkszaehler\Interpreter\\' . $this->getDefinition()->getInterpreter();
|
||||
return new $interpreterClassName($this, $em, $from, $to);
|
||||
$class = 'Volkszaehler\Interpreter\\' . $this->getDefinition()->getInterpreter();
|
||||
return new $class($this, $em, $from, $to);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ use Volkszaehler\Model;
|
|||
* @Table(
|
||||
* name="properties",
|
||||
* uniqueConstraints={
|
||||
* @UniqueConstraint(name="unique_properties", columns={"id", "name"})
|
||||
* @UniqueConstraint(name="unique_keys", columns={"entity_id", "`key` "})
|
||||
* }
|
||||
* )
|
||||
* @HasLifecycleCallbacks
|
||||
|
@ -51,8 +51,8 @@ class Property {
|
|||
*/
|
||||
protected $id;
|
||||
|
||||
/** @Column(type="string", nullable=false) */
|
||||
protected $name;
|
||||
/** @Column(name="`key`", type="string", nullable=false) */
|
||||
protected $key;
|
||||
|
||||
/** @Column(type="string", nullable=false) */
|
||||
protected $value;
|
||||
|
@ -66,11 +66,11 @@ class Property {
|
|||
* @param string $key
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct(Model\Entity $entity, $name, $value) {
|
||||
$this->setName($name);
|
||||
$this->setValue($value);
|
||||
|
||||
public function __construct(Model\Entity $entity, $key, $value) {
|
||||
$this->entity = $entity;
|
||||
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,14 +78,14 @@ class Property {
|
|||
*
|
||||
* @PostLoad
|
||||
*/
|
||||
public function castValue() {
|
||||
public function cast() {
|
||||
if ($this->getDefinition()->getType() != 'multiple') {
|
||||
settype($this->value, $this->getDefinition()->getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate property name & value
|
||||
* Validate property key & value
|
||||
*
|
||||
* Throws an exception if something is incorrect
|
||||
*
|
||||
|
@ -93,24 +93,43 @@ class Property {
|
|||
* @PreUpdate
|
||||
*/
|
||||
public function validate() {
|
||||
if (!PropertyDefinition::exists($this->name)) {
|
||||
throw new \Exception('invalid property name: ' . $this->name);
|
||||
if (!PropertyDefinition::exists($this->key)) {
|
||||
throw new \Exception('Invalid property key: ' . $this->key);
|
||||
}
|
||||
|
||||
$this->cast(); // TODO not safe
|
||||
|
||||
if (!$this->getDefinition()->validateValue($this->value)) {
|
||||
throw new \Exception('invalid property value: ' . $this->value);
|
||||
throw new \Exception('Invalid property value: ' . $this->value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @PreRemove
|
||||
*/
|
||||
public function checkRemove() {
|
||||
if (in_array($this->key, $this->entity->getDefinition()->getRequiredProperties())) {
|
||||
throw new \Exception('"' . $this->key . '" is a required property for the "' . $this->entity->getType() . '" entity');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @PrePersist
|
||||
*/
|
||||
public function checkPersist() {
|
||||
if (!in_array($this->key, $this->entity->getDefinition()->getValidProperties())) {
|
||||
throw new \Exception('"' . $this->key . '" is not a valid property for the "' . $this->entity->getType() . '" entity');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setter & Getter
|
||||
*/
|
||||
public function getName() { return $this->name; }
|
||||
public function getKey() { return $this->key; }
|
||||
public function getValue() { return $this->value; }
|
||||
public function getDefinition() { return PropertyDefinition::get($this->name); }
|
||||
public function getDefinition() { return PropertyDefinition::get($this->key); }
|
||||
|
||||
public function setValue($value) { $this->value = $value; }
|
||||
protected function setName($name) { $this->name = $name; }
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -25,8 +25,6 @@ namespace Volkszaehler\Model;
|
|||
|
||||
use Volkszaehler\Util;
|
||||
|
||||
use Volkszaehler\Model;
|
||||
|
||||
/**
|
||||
* Token entity
|
||||
*
|
||||
|
|
|
@ -108,15 +108,15 @@ class ClassLoader {
|
|||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $classname The name of the class to load.
|
||||
* @param string $class 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) {
|
||||
public function loadClass($class) {
|
||||
if ($this->namespace !== NULL && strpos($class, $this->namespace . $this->namespaceSeparator) !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$subNamespace = substr($className, strlen($this->namespace));
|
||||
$subNamespace = substr($class, strlen($this->namespace));
|
||||
$parts = explode($this->namespaceSeparator, $subNamespace);
|
||||
$path = implode(DIRECTORY_SEPARATOR, $parts);
|
||||
|
||||
|
@ -128,15 +128,15 @@ class ClassLoader {
|
|||
* 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.
|
||||
* @param string $class 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) {
|
||||
public function canLoadClass($class) {
|
||||
if ($this->namespace !== NULL && strpos($class, $this->namespace . $this->namespaceSeparator) !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$subNamespace = substr($className, strlen($this->namespace));
|
||||
$subNamespace = substr($class, strlen($this->namespace));
|
||||
$parts = explode($this->namespaceSeparator, $subNamespace);
|
||||
$path = implode(DIRECTORY_SEPARATOR, $parts);
|
||||
|
||||
|
@ -161,11 +161,11 @@ class ClassLoader {
|
|||
* 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.
|
||||
* @param string $class 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)) {
|
||||
public static function classExists($class) {
|
||||
if (class_exists($class, FALSE)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -173,20 +173,20 @@ class ClassLoader {
|
|||
if (is_array($loader)) { // array(???, ???)
|
||||
if (is_object($loader[0])) {
|
||||
if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName')
|
||||
if ($loader[0]->canLoadClass($className)) {
|
||||
if ($loader[0]->canLoadClass($class)) {
|
||||
return TRUE;
|
||||
}
|
||||
} else if ($loader[0]->{$loader[1]}($className)) {
|
||||
} else if ($loader[0]->{$loader[1]}($class)) {
|
||||
return TRUE;
|
||||
}
|
||||
} else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName')
|
||||
} else if ($loader[0]::$loader[1]($class)) { // array('className', 'methodName')
|
||||
return TRUE;
|
||||
}
|
||||
} else if ($loader instanceof \Closure) { // function($className) {..}
|
||||
if ($loader($className)) {
|
||||
} else if ($loader instanceof \Closure) { // function($class) {..}
|
||||
if ($loader($class)) {
|
||||
return TRUE;
|
||||
}
|
||||
} else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass"
|
||||
} else if (is_string($loader) && $loader($class)) { // "MyClass::loadClass"
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -198,13 +198,13 @@ class ClassLoader {
|
|||
* 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.
|
||||
* @param string $class 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) {
|
||||
public static function getClassLoader($class) {
|
||||
foreach (spl_autoload_functions() as $loader) {
|
||||
if (is_array($loader) && $loader[0] instanceof ClassLoader &&
|
||||
$loader[0]->canLoadClass($className)) {
|
||||
$loader[0]->canLoadClass($class)) {
|
||||
return $loader[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class Configuration {
|
|||
*/
|
||||
static public function write($var, $value) {
|
||||
if (!is_scalar($value) && !is_array($value)) {
|
||||
throw new \Exception('sry we can\'t store this datatype in the configuration');
|
||||
throw new \Exception('Can\'t store this datatype in the configuration');
|
||||
}
|
||||
|
||||
$values =& self::$values;
|
||||
|
@ -94,13 +94,13 @@ class Configuration {
|
|||
$filename .= '.php';
|
||||
|
||||
if (!file_exists($filename)) {
|
||||
throw new \Exception('configuration file not found: ' . $filename);
|
||||
throw new \Exception('Configuration file not found: ' . $filename);
|
||||
}
|
||||
|
||||
include $filename;
|
||||
|
||||
if (!isset($config)) {
|
||||
throw new \Exception('no variable $config found in ' . $filename);
|
||||
throw new \Exception('No variable $config found in ' . $filename);
|
||||
}
|
||||
|
||||
self::$values = $config;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
namespace Volkszaehler\Util;
|
||||
|
||||
use Doctrine\ORM;
|
||||
|
||||
use Doctrine\DBAL\Logging;
|
||||
|
||||
/**
|
||||
|
@ -62,7 +61,7 @@ class Debug {
|
|||
$em->getConnection()->getConfiguration()->setSQLLogger($this->sqlLogger);
|
||||
|
||||
if (isset(self::$instance)) {
|
||||
throw new \Exception('debugging has already been started. please use the static functions!');
|
||||
throw new \Exception('Debugging has already been started. please use the static functions!');
|
||||
}
|
||||
self::$instance = $this;
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ class UUID {
|
|||
return new self(self::mintTime($node));
|
||||
case 2:
|
||||
// Version 2 is not supported
|
||||
throw new \Exception("Version 2 is unsupported.");
|
||||
throw new \Exception('Version 2 is unsupported.');
|
||||
case 3:
|
||||
return new self(self::mintName(self::MD5, $node, $ns));
|
||||
case 4:
|
||||
|
@ -102,19 +102,42 @@ class UUID {
|
|||
case 5:
|
||||
return new self(self::mintName(self::SHA1, $node, $ns));
|
||||
default:
|
||||
throw new \Exception("Selected version is invalid or unsupported.");
|
||||
throw new \Exception('Selected version is invalid or unsupported.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import an existing UUID
|
||||
*
|
||||
* @param unkown_type $uuid
|
||||
* @param unknown_type $uuid
|
||||
*/
|
||||
public static function import($uuid) {
|
||||
return new self(self::makeBin($uuid, 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performant validation of UUID's
|
||||
*
|
||||
* Replaces preg_match('/[a-f0-9\-]{36}/', $uuid);
|
||||
*
|
||||
* @param string $uuid
|
||||
* @param boolen $short whether to allow abbreviated form of UUID's or not
|
||||
*/
|
||||
public static function validate($uuid, $short = FALSE) {
|
||||
$len = strlen($uuid);
|
||||
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$char = $uuid[$i];
|
||||
$ord = ord($char);
|
||||
|
||||
if (($ord > 57 || $ord < 48) && ($ord > 70 || $ord < 65) && ($ord > 102 || $ord < 97) && $ord != 45) {
|
||||
return FALSE; // char not allowed
|
||||
}
|
||||
}
|
||||
|
||||
return ($short) ? $len <= 36 : $len == 36; // check for strlen
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the binary representations of two UUIDs.
|
||||
* The comparison will return TRUE if they are bit-exact,
|
||||
|
@ -133,43 +156,42 @@ class UUID {
|
|||
|
||||
public function __get($var) {
|
||||
switch($var) {
|
||||
case "bytes":
|
||||
case 'bytes':
|
||||
return $this->bytes;
|
||||
case "hex":
|
||||
case 'hex':
|
||||
return bin2hex($this->bytes);
|
||||
case "string":
|
||||
case 'string':
|
||||
return $this->__toString();
|
||||
case "urn":
|
||||
return "urn:uuid:".$this->__toString();
|
||||
case "version":
|
||||
case 'urn':
|
||||
return 'urn:uuid:' . $this->__toString();
|
||||
case 'version':
|
||||
return ord($this->bytes[6]) >> 4;
|
||||
case "variant":
|
||||
case 'variant':
|
||||
$byte = ord($this->bytes[8]);
|
||||
if ($byte >= self::varRes)
|
||||
return 3;
|
||||
if ($byte >= self::varMS)
|
||||
return 2;
|
||||
if ($byte >= self::varRFC)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
case "node":
|
||||
if (ord($this->bytes[6])>>4==1)
|
||||
return bin2hex(substr($this->bytes,10));
|
||||
else
|
||||
return NULL;
|
||||
case "time":
|
||||
if ($byte >= self::varRes) return 3;
|
||||
if ($byte >= self::varMS) return 2;
|
||||
if ($byte >= self::varRFC) return 1;
|
||||
else return 0;
|
||||
case 'node':
|
||||
if (ord($this->bytes[6])>>4==1) {
|
||||
return bin2hex(substr($this->bytes,10));
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
case 'time':
|
||||
if (ord($this->bytes[6])>>4==1) {
|
||||
// Restore contiguous big-endian byte order
|
||||
$time = bin2hex($this->bytes[6].$this->bytes[7].$this->bytes[4].$this->bytes[5].$this->bytes[0].$this->bytes[1].$this->bytes[2].$this->bytes[3]);
|
||||
// Clear version flag
|
||||
$time[0] = "0";
|
||||
$time[0] = '0';
|
||||
// Do some reverse arithmetic to get a Unix timestamp
|
||||
$time = (hexdec($time) - self::interval) / 10000000;
|
||||
return $time;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -177,76 +199,104 @@ class UUID {
|
|||
|
||||
protected function __construct($uuid) {
|
||||
if (strlen($uuid) != 16) {
|
||||
throw new \Exception("Input must be a 128-bit integer.");
|
||||
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))."-".
|
||||
bin2hex(substr($uuid,4,2))."-".
|
||||
bin2hex(substr($uuid,6,2))."-".
|
||||
bin2hex(substr($uuid,8,2))."-".
|
||||
bin2hex(substr($uuid,0,4)).'-'.
|
||||
bin2hex(substr($uuid,4,2)).'-'.
|
||||
bin2hex(substr($uuid,6,2)).'-'.
|
||||
bin2hex(substr($uuid,8,2)).'-'.
|
||||
bin2hex(substr($uuid,10,6));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Version 1 UUID.
|
||||
* These are derived from the time at which they were generated.
|
||||
*
|
||||
* @param $node
|
||||
*/
|
||||
protected static function mintTime($node = NULL) {
|
||||
/* Generates a Version 1 UUID.
|
||||
These are derived from the time at which they were generated. */
|
||||
// Get time since Gregorian calendar reform in 100ns intervals
|
||||
// This is exceedingly difficult because of PHP's (and pack()'s)
|
||||
// integer size limits.
|
||||
// Note that this will never be more accurate than to the microsecond.
|
||||
$time = microtime(1) * 10000000 + self::interval;
|
||||
$time = microtime(TRUE) * 10000000 + self::interval;
|
||||
|
||||
// Convert to a string representation
|
||||
$time = sprintf("%F", $time);
|
||||
preg_match("/^\d+/", $time, $time); //strip decimal point
|
||||
$time = sprintf('%F', $time);
|
||||
preg_match('/^\d+/', $time, $time); //strip decimal point
|
||||
|
||||
// And now to a 64-bit binary representation
|
||||
$time = base_convert($time[0], 10, 16);
|
||||
$time = pack("H*", str_pad($time, 16, "0", STR_PAD_LEFT));
|
||||
$time = pack('H*', str_pad($time, 16, '0', STR_PAD_LEFT));
|
||||
|
||||
// Reorder bytes to their proper locations in the UUID
|
||||
$uuid = $time[4].$time[5].$time[6].$time[7].$time[2].$time[3].$time[0].$time[1];
|
||||
|
||||
// Generate a random clock sequence
|
||||
$uuid .= Random::getBytes(2);
|
||||
|
||||
// set variant
|
||||
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
|
||||
|
||||
// set version
|
||||
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version1);
|
||||
|
||||
// Set the final 'node' parameter, a MAC address
|
||||
if ($node)
|
||||
$node = self::makeBin($node, 6);
|
||||
if (!$node) {
|
||||
if ($node) {
|
||||
$node = self::makeBin($node, 6);
|
||||
}
|
||||
else {
|
||||
// If no node was provided or if the node was invalid,
|
||||
// generate a random MAC address and set the multicast bit
|
||||
$node = Random::getBytes(6);
|
||||
$node[0] = pack("C", ord($node[0]) | 1);
|
||||
$node[0] = pack('C', ord($node[0]) | 1);
|
||||
}
|
||||
|
||||
$uuid .= $node;
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a Version 4 UUID.
|
||||
* These are derived soly from random numbers.
|
||||
*/
|
||||
protected static function mintRand() {
|
||||
/* Generate a Version 4 UUID.
|
||||
These are derived soly from random numbers. */
|
||||
// generate random fields
|
||||
$uuid = Random::getBytes(16);
|
||||
|
||||
// set variant
|
||||
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
|
||||
|
||||
// set version
|
||||
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version4);
|
||||
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Version 3 or Version 5 UUID.
|
||||
* These are derived from a hash of a name and its namespace, in binary form.
|
||||
*
|
||||
* @param integer $ver the version (MD5 or SHA1)
|
||||
* @param string $node the name string
|
||||
* $param string $ns the namespace
|
||||
*/
|
||||
protected static function mintName($ver, $node, $ns) {
|
||||
/* 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 \Exception("A name-string is required for Version 3 or 5 UUIDs.");
|
||||
if (!$node) {
|
||||
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 \Exception("A binary namespace is required for Version 3 or 5 UUIDs.");
|
||||
if (!$ns) {
|
||||
throw new \Exception('A binary namespace is required for Version 3 or 5 UUIDs.');
|
||||
}
|
||||
|
||||
switch($ver) {
|
||||
case self::MD5:
|
||||
$version = self::version3;
|
||||
|
@ -257,27 +307,43 @@ class UUID {
|
|||
$uuid = substr(sha1($ns.$node,1),0, 16);
|
||||
break;
|
||||
}
|
||||
|
||||
// set variant
|
||||
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
|
||||
|
||||
// set version
|
||||
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | $version);
|
||||
|
||||
return ($uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insure that an input string is either binary or hexadecimal.
|
||||
* Returns binary representation, or FALSE on failure.
|
||||
*
|
||||
* @param unkown_type $str
|
||||
* @param integer $len
|
||||
*/
|
||||
protected static function makeBin($str, $len) {
|
||||
/* Insure that an input string is either binary or hexadecimal.
|
||||
Returns binary representation, or FALSE on failure. */
|
||||
if ($str instanceof self)
|
||||
return $str->bytes;
|
||||
if (strlen($str)==$len)
|
||||
return $str;
|
||||
else
|
||||
$str = preg_replace("/^urn:uuid:/is", "", $str); // strip URN scheme and namespace
|
||||
$str = preg_replace("/[^a-f0-9]/is", "", $str); // strip non-hex characters
|
||||
if (strlen($str) != ($len * 2))
|
||||
return FALSE;
|
||||
else
|
||||
return pack("H*", $str);
|
||||
if ($str instanceof self) {
|
||||
return $str->bytes;
|
||||
}
|
||||
|
||||
if (strlen($str) == $len) {
|
||||
return $str;
|
||||
}
|
||||
else {
|
||||
$str = preg_replace('/^urn:uuid:/is', '', $str); // strip URN scheme and namespace
|
||||
}
|
||||
|
||||
$str = preg_replace('/[^a-f0-9]/is', '', $str); // strip non-hex characters
|
||||
|
||||
if (strlen($str) != ($len * 2)) {
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
return pack('H*', $str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$.getJSON('../../backend/index.php?format=json&controller=group&action=get&recursive=1', function(data) {
|
||||
$.getJSON('../../backend/group.json?operation=get&recursive=1', function(data) {
|
||||
$('#tree').jstree({
|
||||
'plugins' : [ 'themes', 'ui', ],
|
||||
'types' : {
|
||||
|
|
Loading…
Add table
Reference in a new issue