diff --git a/backend/init.php b/backend/init.php index 6408aa6..dabb72c 100644 --- a/backend/init.php +++ b/backend/init.php @@ -34,7 +34,7 @@ function __autoload($className) { '/^Uuid$/' => 'util/uuid', // model classes - '/^(Channel|User|Group|Database(Object)?)$/'=> 'model/$1', + '/^(Channel|User|Group|(Nested)?Database(Object)?)$/'=> 'model/$1', '/^(MySql|PgSql|SqLite)$/i' => 'model/db/$1', '/^(.+(Meter|Sensor))$/' => 'model/channel/$2/$1', '/^(Meter|Sensor)$/' => 'model/channel/$1', diff --git a/backend/lib/model/database.php b/backend/lib/model/database.php index bcc0b22..3840896 100644 --- a/backend/lib/model/database.php +++ b/backend/lib/model/database.php @@ -207,9 +207,6 @@ abstract class Database implements DatabaseInterface { if (is_numeric($value)) { return $value; } - elseif ($value instanceof DatabaseObject) { - return (int) $value->id; - } else { $value = '\'' . $this->escapeString($value) . '\''; } diff --git a/backend/lib/model/databaseobject.php b/backend/lib/model/databaseobject.php index 51c9c89..7e973dd 100644 --- a/backend/lib/model/databaseobject.php +++ b/backend/lib/model/databaseobject.php @@ -25,7 +25,7 @@ abstract class DatabaseObject { private $dirty; // do we need to update the database? private $data = array(); - static protected $instances = array(); // singletons of objects + static private $instances = array(); // singletons of objects /* * magic functions @@ -69,13 +69,12 @@ abstract class DatabaseObject { * insert oder update the database representation of the object */ public function save() { - if ($this->id) { // just update + if (isset($this->id)) { // just update $this->update(); } else { // insert new row $this->insert(); } - } private function insert() { diff --git a/backend/lib/model/group.php b/backend/lib/model/group.php index ba8f2a1..7ae4cc4 100644 --- a/backend/lib/model/group.php +++ b/backend/lib/model/group.php @@ -22,7 +22,7 @@ /* * Grouping class * - * the group class groups users, channels and groups + * the group class groups users, channels and groups itself */ class Group extends NestedDatabaseObject { const table = 'groups'; @@ -54,7 +54,7 @@ class Group extends NestedDatabaseObject { $filters = preg_replace('/^user\.([a-z_]+)$/', 'users.$1', $filters); } - // join channels + // join channels // TODO preg_filter or preg_grep? if (preg_match('/^channel\.([a-z_]+)$/', $filters)) { $sql .= ' LEFT JOIN channels_in_groups ON channels_in_groups.group_id = ' . self::table . '.id'; $sql .= ' LEFT JOIN channels ON channels.id = channels_in_groups.channel_id'; diff --git a/backend/lib/model/nesteddatabaseobject.php b/backend/lib/model/nesteddatabaseobject.php index b11d991..8e922a2 100644 --- a/backend/lib/model/nesteddatabaseobject.php +++ b/backend/lib/model/nesteddatabaseobject.php @@ -21,11 +21,20 @@ /* * DatabaseObject which is structured by nested sets + * @url // TODO add url */ -class NestedDatabaseObject extends DatabaseObject { +abstract class NestedDatabaseObject extends DatabaseObject { + public function __set($key, $value) { + if ($key == 'left' || $key == 'right') { + throw new NestedDatabaseException('nested set fields are read only! please make use of move() or delete() instead'); + } + + parent::__set($key, $value); + } + public function addChild(NestedDatabaseObject $child) { if (isset($child->id)) { - throw new DatabaseException('group is already part of the tree'); + throw new NestedDatabaseException('Object is already part of the tree'); } // TODO start transaction @@ -34,21 +43,27 @@ class NestedDatabaseObject extends DatabaseObject { $child->left = $this->right; $child->right = $this->right + 1; + + $this->right += 2; + $child->insert(); } public function getChilds() { - $sql = 'SELECT * FROM ' . static::table . ' WHERE id != ' . $this->id . ' && left BETWEEN ' . $this->left . ' AND ' . $this->right; + $sql = 'SELECT * FROM ' . static::table . ' WHERE left > ' . $this->left . ' && left < ' . $this->right; $result = $this->dbh->query($sql); - $groups = array(); - foreach ($result as $group) { - $groups[$group['id']] = static::factory($group); + $objs = array(); + foreach ($result as $obj) { + $objs[$obj['id']] = static::factory($obj); } return $groups; } + /* + * deletes subset under $this + */ public function delete() { $move = floor(($this->right - $this->left) / 2); $move = 2 * (1 + $move); @@ -56,29 +71,48 @@ class NestedDatabaseObject extends DatabaseObject { // TODO start transaction // delete nodes - $this->dbh->execute('DELETE FROM ' . static::table . ' WHERE AND left BETWEEN ' . $this->left . ' AND ' . $this->right); // TODO SQL92 compilant? - - // move the rest of the nodes ... + $result = $this->dbh->query('SELECT * FROM ' . static::table . ' WHERE left >= ' . $this->left . ' && left <= ' . $this->right); + foreach ($result as $obj) { + $obj->delete(); // TODO optimize (all in one query) + } + + // move remaining nodes ... $this->dbh->execute('UPDATE ' . static::table . ' SET left = left - ' . $move . ' WHERE left > ' . $this->right); $this->dbh->execute('UPDATE ' . static::table . ' SET right = right - ' . $move . ' WHERE right > ' . $this->right); - - // TODO unset singleton instances in DatabaseObject::$instances } + /* + * checks if $child is a child of $this + * @return bool + */ public function contains(NestedDatabaseObject $child) { // TODO untested - if (array_search($child, $this->getChilds(), true) === false) { - return false; - } - else { - return true; - } + $sql = 'SELECT * FROM ' . static::table . ' WHERE left > ' . $this->left . ' && left < ' . $this->right . ' && id = ' . $child->id; + $result = $this->dbh->query($sql); + + return ($result->count() > 0) ? true : false; } - public function moveTo(NestedDatabaseObject $obj) { // TODO implement + public function moveTo(NestedDatabaseObject $destination) { // TODO implement // $this->getChilds - // $this->delete - // $group->addChilds + $obj = $this->getChilds(); + foreach ($objs as $obj) { + $obj->right += $destination->left - $this->left; + $obj->left = $destination->left; + } + + // close whole + $move = floor(($this->right - $this->left) / 2); + $move = 2 * (1 + $move); + + $this->dbh->execute('UPDATE ' . static::table . ' SET left = left - ' . $move . ' WHERE left > ' . $this->right); + $this->dbh->execute('UPDATE ' . static::table . ' SET right = right - ' . $move . ' WHERE right > ' . $this->right); + + // create hole + $this->dbh->execute('UPDATE ' . static::table . ' SET left = left + ' . $move . ' WHERE left > ' . $this->right); + $this->dbh->execute('UPDATE ' . static::table . ' SET right = right + ' . $move . ' WHERE right >= ' . $this->right); } } +class NestedDatabaseException extends Exception {} + ?> \ No newline at end of file