diff options
author | Malf Furious <m@lfurio.us> | 2018-10-27 18:28:22 -0400 |
---|---|---|
committer | Malf Furious <m@lfurio.us> | 2018-10-27 18:28:22 -0400 |
commit | 0421aa1b60f4fe6bf140888159c58059c1013588 (patch) | |
tree | c3285276f6c53b6789e2f6dc82cb3b0fd17b38a4 /app/class/table.class.php | |
parent | 495157341d60522084dcc9f6219877b6ba497312 (diff) | |
parent | 6512655aee73d3d295daa4de0e4ef25c08cfec9e (diff) | |
download | scrott-05af670f00a270ee69f487891741116ef5b82de8.tar.gz scrott-05af670f00a270ee69f487891741116ef5b82de8.zip |
Merge branch 'rel/v0.1'v0.1
Diffstat (limited to 'app/class/table.class.php')
-rw-r--r-- | app/class/table.class.php | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/app/class/table.class.php b/app/class/table.class.php new file mode 100644 index 0000000..618d938 --- /dev/null +++ b/app/class/table.class.php @@ -0,0 +1,238 @@ +<?php + +/* + * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to UNLICENSE + */ + +require_once "class/database.class.php"; + +/* + * This class provides functionality for retrieving data from and updating + * data in a database table. + */ +abstract class table +{ + /* + * This is an array acting as a dictionary, mapping a table name (key) + * into another array acting as a list (value) of the fields in that + * table. Classes that extend this class, should append a key=>val to + * this array that represents the table being modeled. This array is + * used by db table IO functions to construct SQL queries. + */ + protected $fields = array(); + + /* + * Instanciate an object representing an existing database entity + * named by the given GUID. If no such GUID exists, an exception + * is thrown. If NULL is passed, no database lookups are attempted. + * This is helpful for assembling new database objects. + */ + public function __construct(?string $guid = NULL) + { + if ($guid !== NULL) + $this->loadObj($guid); + } + + /* + * This function will iterate the $fields array and initialize this + * object's class properties based on the table=>fields mapping. If + * no such GUID exists, an exception is thrown. + */ + private function loadObj(string $guid) : void + { + $guid = database::esc($guid); + + if (!self::isGUID($guid)) + throw new Exception("GUID '" . $guid . "' does not exist"); + + foreach ($this->fields as $tbl => $flds) + { + $tbl = database::esc($tbl); + $query = "SELECT * FROM " . $tbl . " WHERE guid = '" . $guid . "'"; + $res = database::query($query); + + /* no results */ + if (count($res) == 0) + continue; + + $res = $res[0]; + + foreach ($flds as $fld) + { + if (isset($res[$fld])) + $this->$fld = $res[$fld]; + } + } + } + + /* + * This function uses loadObj to re-initialize this object, if in + * the case it gets modified in another scope. + */ + public function refreshObj() : void + { + $this->loadObj($this->guid); + } + + /* + * This function will update this object in the database, or insert new + * data if this object does not yet have a GUID. This function uses the + * $fields array to construct SQL queries. + */ + public function saveObj() : void + { + /* update existing object */ + if (isset($this->guid)) + { + $this->updated = self::getCurrentTimestamp(); + + foreach ($this->fields as $tbl => $flds) + { + $tbl = database::esc($tbl); + $udstr = ""; + + foreach ($flds as $fld) + { + if (!isset($this->$fld)) + continue; + + $fld = database::esc($fld); + $udstr .= $fld . " = '" . database::esc($this->$fld) . "', "; + } + + if (strlen($udstr) > 0) + { + $udstr = substr($udstr, 0, -2); // remove ", " from the end + $query = "UPDATE " . $tbl . " SET " . $udstr . " WHERE guid = '" . database::esc($this->guid) . "'"; + database::query($query); + } + } + } + + /* create new object */ + else + { + $this->guid = self::getNewGUID(); + $this->created = self::getCurrentTimestamp(); + $this->updated = $this->created; + + foreach ($this->fields as $tbl => $flds) + { + $tbl = database::esc($tbl); + $fldstr = ""; + $valstr = ""; + + foreach ($flds as $fld) + { + if (!isset($this->$fld)) + continue; + + $fld = database::esc($fld); + $fldstr .= $fld . ", "; + $valstr .= "'" . database::esc($this->$fld) . "', "; + } + + if (strlen($fldstr) > 0) + { + $fldstr = substr($fldstr, 0, -2); // remove ", " + $valstr = substr($valstr, 0, -2); + $query = "INSERT INTO " . $tbl . " (" . $fldstr . ") VALUES (" . $valstr . ")"; + database::query($query); + } + } + + $this->refreshObj(); // fetch default, unset values from database + } + } + + /* + * This function will remove this object from the database by deleting + * rows with this object's GUID from tables in $fields. If this object + * does not have a GUID, throw an exception. + */ + public function delObj() : void + { + if (!isset($this->guid)) + throw new Exception("GUID (null) does not exist"); + + $guid = database::esc($this->guid); + + foreach ($this->fields as $tbl => $flds) + { + $tbl = database::esc($tbl); + $query = "DELETE FROM " . $tbl . " WHERE guid = '" . $guid . "'"; + database::query($query); + } + + /* garbage collection */ + $query = "DELETE FROM members WHERE guid = '" . $guid . "' OR member = '" . $guid . "'"; + database::query($query); + + $query = "DELETE FROM views WHERE guid = '" . $guid . "' OR viewer = '" . $guid . "'"; + database::query($query); + } + + /* + * Get a random sha256 blob, returned as a hexadecimal string + */ + public static function getBlob() : string + { + return hash("sha256", openssl_random_pseudo_bytes(64)); + } + + /* + * Get current timestamp as a string for object database purposes + */ + public static function getCurrentTimestamp() : string + { + $query = "SELECT now() AS stamp"; + $res = database::query($query); + return $res[0]['stamp']; + } + + /* + * Check whether the given GUID exists + */ + public static function isGUID(string $guid) : bool + { + $guid = database::esc($guid); + $query = "SELECT guid FROM objects WHERE guid = '" . $guid . "'"; + $res = database::query($query); + return count($res) > 0; + } + + /* + * Get a new, unique GUID for a new system object + */ + private static function getNewGUID() : string + { + do $guid = substr(self::getBlob(), 0, 8); + while (self::isGUID($guid)); + return $guid; + } + + /* + * Assert that this object is of the expected type in the database. + * Throw an exception if a type mismatch exists. Check will only + * be performed if guid and objtype are set on this object. + */ + protected function expectType(string $objtype) : void + { + if (isset($this->guid) && isset($this->objtype)) + { + if ($this->objtype != $objtype) + throw new Exception("Invalid object allocation. " . $this->guid . " is a " . + $this->objtype . ", not a " . $objtype . "."); + } + } +} + +?> |