summaryrefslogtreecommitdiffstats
path: root/app/class/table.class.php
diff options
context:
space:
mode:
authorMalf Furious <m@lfurio.us>2018-10-27 18:28:22 -0400
committerMalf Furious <m@lfurio.us>2018-10-27 18:28:22 -0400
commit0421aa1b60f4fe6bf140888159c58059c1013588 (patch)
treec3285276f6c53b6789e2f6dc82cb3b0fd17b38a4 /app/class/table.class.php
parent495157341d60522084dcc9f6219877b6ba497312 (diff)
parent6512655aee73d3d295daa4de0e4ef25c08cfec9e (diff)
downloadscrott-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.php238
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 . ".");
+ }
+ }
+}
+
+?>