PATH:
home
/
lab2454c
/
keebchat.com
/
core
/
libs
/
DB
/
vendor
/
thingengineer
/
mysqli-database-class
<?php /** * Mysqli Model wrapper * * @category Database Access * @package MysqliDb * @author Alexander V. Butenko <a.butenka@gmail.com> * @copyright Copyright (c) 2015-2017 * @license http://opensource.org/licenses/gpl-3.0.html GNU Public License * @link http://github.com/joshcam/PHP-MySQLi-Database-Class * @version 2.9-master * * @method int count () * @method dbObject ArrayBuilder() * @method dbObject JsonBuilder() * @method dbObject ObjectBuilder() * @method mixed byId(string $id, mixed $fields) * @method mixed get(mixed $limit, mixed $fields) * @method mixed getOne(mixed $fields) * @method mixed paginate(int $page, array $fields) * @method dbObject query($query, $numRows = null) * @method dbObject rawQuery($query, $bindParams = null) * @method dbObject join(string $objectName, string $key, string $joinType, string $primaryKey) * @method dbObject with(string $objectName) * @method dbObject groupBy(string $groupByField) * @method dbObject orderBy($orderByField, $orderbyDirection = "DESC", $customFieldsOrRegExp = null) * @method dbObject where($whereProp, $whereValue = 'DBNULL', $operator = '=', $cond = 'AND') * @method dbObject orWhere($whereProp, $whereValue = 'DBNULL', $operator = '=') * @method dbObject having($havingProp, $havingValue = 'DBNULL', $operator = '=', $cond = 'AND') * @method dbObject orHaving($havingProp, $havingValue = null, $operator = null) * @method dbObject setQueryOption($options) * @method dbObject setTrace($enabled, $stripPrefix = null) * @method dbObject withTotalCount() * @method dbObject startTransaction() * @method dbObject commit() * @method dbObject rollback() * @method dbObject ping() * @method string getLastError() * @method string getLastQuery() */ class dbObject { /** * Working instance of MysqliDb created earlier * * @var MysqliDb */ private $db; /** * Models path * * @var modelPath */ protected static $modelPath; /** * An array that holds object data * * @var array */ public $data; /** * Flag to define is object is new or loaded from database * * @var boolean */ public $isNew = true; /** * Return type: 'Array' to return results as array, 'Array' as object * 'Json' as json string * * @var string */ public $returnType = 'Array'; /** * An array that holds has* objects which should be loaded togeather with main * object togeather with main object * * @var string */ private $_with = Array(); /** * Per page limit for pagination * * @var int */ public static $pageLimit = 20; /** * Variable that holds total pages count of last paginate() query * * @var int */ public static $totalPages = 0; /** * Variable which holds an amount of returned rows during paginate queries * @var string */ public static $totalCount = 0; /** * An array that holds insert/update/select errors * * @var array */ public $errors = null; /** * Primary key for an object. 'id' is a default value. * * @var stating */ protected $primaryKey = 'id'; /** * Table name for an object. Class name will be used by default * * @var stating */ protected $dbTable; /** * @var array name of the fields that will be skipped during validation, preparing & saving */ protected $toSkip = array(); /** * @param array $data Data to preload on object creation */ public function __construct ($data = null) { $this->db = MysqliDb::getInstance(); if (empty ($this->dbTable)) $this->dbTable = get_class ($this); if ($data) $this->data = $data; } /** * Magic setter function * * @return mixed */ public function __set ($name, $value) { if (property_exists ($this, 'hidden') && array_search ($name, $this->hidden) !== false) return; $this->data[$name] = $value; } /** * Magic getter function * * @param $name Variable name * * @return mixed */ public function __get ($name) { if (property_exists ($this, 'hidden') && array_search ($name, $this->hidden) !== false) return null; if (isset ($this->data[$name]) && $this->data[$name] instanceof dbObject) return $this->data[$name]; if (property_exists ($this, 'relations') && isset ($this->relations[$name])) { $relationType = strtolower ($this->relations[$name][0]); $modelName = $this->relations[$name][1]; switch ($relationType) { case 'hasone': $key = isset ($this->relations[$name][2]) ? $this->relations[$name][2] : $name; $obj = new $modelName; $obj->returnType = $this->returnType; return $this->data[$name] = $obj->byId($this->data[$key]); break; case 'hasmany': $key = $this->relations[$name][2]; $obj = new $modelName; $obj->returnType = $this->returnType; return $this->data[$name] = $obj->where($key, $this->data[$this->primaryKey])->get(); break; default: break; } } if (isset ($this->data[$name])) return $this->data[$name]; if (property_exists ($this->db, $name)) return $this->db->$name; } public function __isset ($name) { if (isset ($this->data[$name])) return isset ($this->data[$name]); if (property_exists ($this->db, $name)) return isset ($this->db->$name); } public function __unset ($name) { unset ($this->data[$name]); } /** * Helper function to create dbObject with Json return type * * @return dbObject */ private function JsonBuilder () { $this->returnType = 'Json'; return $this; } /** * Helper function to create dbObject with Array return type * * @return dbObject */ private function ArrayBuilder () { $this->returnType = 'Array'; return $this; } /** * Helper function to create dbObject with Object return type. * Added for consistency. Works same way as new $objname () * * @return dbObject */ private function ObjectBuilder () { $this->returnType = 'Object'; return $this; } /** * Helper function to create a virtual table class * * @param string tableName Table name * @return dbObject */ public static function table ($tableName) { $tableName = preg_replace ("/[^-a-z0-9_]+/i",'', $tableName); if (!class_exists ($tableName)) eval ("class $tableName extends dbObject {}"); return new $tableName (); } /** * @return mixed insert id or false in case of failure */ public function insert () { if (!empty ($this->timestamps) && in_array ("createdAt", $this->timestamps)) $this->createdAt = date("Y-m-d H:i:s"); $sqlData = $this->prepareData (); if (!$this->validate ($sqlData)) return false; $id = $this->db->insert ($this->dbTable, $sqlData); if (!empty ($this->primaryKey) && empty ($this->data[$this->primaryKey])) $this->data[$this->primaryKey] = $id; $this->isNew = false; $this->toSkip = array(); return $id; } /** * @param array $data Optional update data to apply to the object */ public function update ($data = null) { if (empty ($this->dbFields)) return false; if (empty ($this->data[$this->primaryKey])) return false; if ($data) { foreach ($data as $k => $v) { if (in_array($k, $this->toSkip)) continue; $this->$k = $v; } } if (!empty ($this->timestamps) && in_array ("updatedAt", $this->timestamps)) $this->updatedAt = date("Y-m-d H:i:s"); $sqlData = $this->prepareData (); if (!$this->validate ($sqlData)) return false; $this->db->where ($this->primaryKey, $this->data[$this->primaryKey]); $res = $this->db->update ($this->dbTable, $sqlData); $this->toSkip = array(); return $res; } /** * Save or Update object * * @return mixed insert id or false in case of failure */ public function save ($data = null) { if ($this->isNew) return $this->insert(); return $this->update ($data); } /** * Delete method. Works only if object primaryKey is defined * * @return boolean Indicates success. 0 or 1. */ public function delete () { if (empty ($this->data[$this->primaryKey])) return false; $this->db->where ($this->primaryKey, $this->data[$this->primaryKey]); $res = $this->db->delete ($this->dbTable); $this->toSkip = array(); return $res; } /** * chained method that append a field or fields to skipping * @param mixed|array|false $field field name; array of names; empty skipping if false * @return $this */ public function skip($field){ if(is_array($field)) { foreach ($field as $f) { $this->toSkip[] = $f; } } else if($field === false) { $this->toSkip = array(); } else{ $this->toSkip[] = $field; } return $this; } /** * Get object by primary key. * * @access public * @param $id Primary Key * @param array|string $fields Array or coma separated list of fields to fetch * * @return dbObject|array */ private function byId ($id, $fields = null) { $this->db->where (MysqliDb::$prefix . $this->dbTable . '.' . $this->primaryKey, $id); return $this->getOne ($fields); } /** * Convinient function to fetch one object. Mostly will be togeather with where() * * @access public * @param array|string $fields Array or coma separated list of fields to fetch * * @return dbObject */ protected function getOne ($fields = null) { $this->processHasOneWith (); $results = $this->db->ArrayBuilder()->getOne ($this->dbTable, $fields); if ($this->db->count == 0) return null; $this->processArrays ($results); $this->data = $results; $this->processAllWith ($results); if ($this->returnType == 'Json') return json_encode ($results); if ($this->returnType == 'Array') return $results; $item = new static ($results); $item->isNew = false; return $item; } /** * A convenient SELECT COLUMN function to get a single column value from model object * * @param string $column The desired column * @param int $limit Limit of rows to select. Use null for unlimited..1 by default * * @return mixed Contains the value of a returned column / array of values * @throws Exception */ protected function getValue ($column, $limit = 1) { $res = $this->db->ArrayBuilder()->getValue ($this->dbTable, $column, $limit); if (!$res) return null; return $res; } /** * A convenient function that returns TRUE if exists at least an element that * satisfy the where condition specified calling the "where" method before this one. * * @return bool * @throws Exception */ protected function has() { return $this->db->has($this->dbTable); } /** * Fetch all objects * * @access public * @param integer|array $limit Array to define SQL limit in format Array ($count, $offset) * or only $count * @param array|string $fields Array or coma separated list of fields to fetch * * @return array Array of dbObjects */ protected function get ($limit = null, $fields = null) { $objects = Array (); $this->processHasOneWith (); $results = $this->db->ArrayBuilder()->get ($this->dbTable, $limit, $fields); if ($this->db->count == 0) return null; foreach ($results as $k => &$r) { $this->processArrays ($r); $this->data = $r; $this->processAllWith ($r, false); if ($this->returnType == 'Object') { $item = new static ($r); $item->isNew = false; $objects[$k] = $item; } } $this->_with = Array(); if ($this->returnType == 'Object') return $objects; if ($this->returnType == 'Json') return json_encode ($results); return $results; } /** * Function to set witch hasOne or hasMany objects should be loaded togeather with a main object * * @access public * @param string $objectName Object Name * * @return dbObject */ private function with ($objectName) { if (!property_exists ($this, 'relations') || !isset ($this->relations[$objectName])) die ("No relation with name $objectName found"); $this->_with[$objectName] = $this->relations[$objectName]; return $this; } /** * Function to join object with another object. * * @access public * @param string $objectName Object Name * @param string $key Key for a join from primary object * @param string $joinType SQL join type: LEFT, RIGHT, INNER, OUTER * @param string $primaryKey SQL join On Second primaryKey * * @return dbObject */ private function join ($objectName, $key = null, $joinType = 'LEFT', $primaryKey = null) { $joinObj = new $objectName; if (!$key) $key = $objectName . "id"; if (!$primaryKey) $primaryKey = MysqliDb::$prefix . $joinObj->dbTable . "." . $joinObj->primaryKey; if (!strchr ($key, '.')) $joinStr = MysqliDb::$prefix . $this->dbTable . ".{$key} = " . $primaryKey; else $joinStr = MysqliDb::$prefix . "{$key} = " . $primaryKey; $this->db->join ($joinObj->dbTable, $joinStr, $joinType); return $this; } /** * Function to get a total records count * * @return int */ protected function count () { $res = $this->db->ArrayBuilder()->getValue ($this->dbTable, "count(*)"); if (!$res) return 0; return $res; } /** * Pagination wraper to get() * * @access public * @param int $page Page number * @param array|string $fields Array or coma separated list of fields to fetch * @return array */ private function paginate ($page, $fields = null) { $this->db->pageLimit = self::$pageLimit; $objects = Array (); $this->processHasOneWith (); $res = $this->db->paginate ($this->dbTable, $page, $fields); self::$totalPages = $this->db->totalPages; self::$totalCount = $this->db->totalCount; if ($this->db->count == 0) return null; foreach ($res as $k => &$r) { $this->processArrays ($r); $this->data = $r; $this->processAllWith ($r, false); if ($this->returnType == 'Object') { $item = new static ($r); $item->isNew = false; $objects[$k] = $item; } } $this->_with = Array(); if ($this->returnType == 'Object') return $objects; if ($this->returnType == 'Json') return json_encode ($res); return $res; } /** * Catches calls to undefined methods. * * Provides magic access to private functions of the class and native public mysqlidb functions * * @param string $method * @param mixed $arg * * @return mixed */ public function __call ($method, $arg) { if (method_exists ($this, $method)) return call_user_func_array (array ($this, $method), $arg); call_user_func_array (array ($this->db, $method), $arg); return $this; } /** * Catches calls to undefined static methods. * * Transparently creating dbObject class to provide smooth API like name::get() name::orderBy()->get() * * @param string $method * @param mixed $arg * * @return mixed */ public static function __callStatic ($method, $arg) { $obj = new static; $result = call_user_func_array (array ($obj, $method), $arg); if (method_exists ($obj, $method)) return $result; return $obj; } /** * Converts object data to an associative array. * * @return array Converted data */ public function toArray () { $data = $this->data; $this->processAllWith ($data); foreach ($data as &$d) { if ($d instanceof dbObject) $d = $d->data; } return $data; } /** * Converts object data to a JSON string. * * @return string Converted data */ public function toJson () { return json_encode ($this->toArray()); } /** * Converts object data to a JSON string. * * @return string Converted data */ public function __toString () { return $this->toJson (); } /** * Function queries hasMany relations if needed and also converts hasOne object names * * @param array $data */ private function processAllWith (&$data, $shouldReset = true) { if (count ($this->_with) == 0) return; foreach ($this->_with as $name => $opts) { $relationType = strtolower ($opts[0]); $modelName = $opts[1]; if ($relationType == 'hasone') { $obj = new $modelName; $table = $obj->dbTable; $primaryKey = $obj->primaryKey; if (!isset ($data[$table])) { $data[$name] = $this->$name; continue; } if ($data[$table][$primaryKey] === null) { $data[$name] = null; } else { if ($this->returnType == 'Object') { $item = new $modelName ($data[$table]); $item->returnType = $this->returnType; $item->isNew = false; $data[$name] = $item; } else { $data[$name] = $data[$table]; } } unset ($data[$table]); } else $data[$name] = $this->$name; } if ($shouldReset) $this->_with = Array(); } /* * Function building hasOne joins for get/getOne method */ private function processHasOneWith () { if (count ($this->_with) == 0) return; foreach ($this->_with as $name => $opts) { $relationType = strtolower ($opts[0]); $modelName = $opts[1]; $key = null; if (isset ($opts[2])) $key = $opts[2]; if ($relationType == 'hasone') { $this->db->setQueryOption ("MYSQLI_NESTJOIN"); $this->join ($modelName, $key); } } } /** * @param array $data */ private function processArrays (&$data) { if (isset ($this->jsonFields) && is_array ($this->jsonFields)) { foreach ($this->jsonFields as $key) $data[$key] = json_decode ($data[$key]); } if (isset ($this->arrayFields) && is_array($this->arrayFields)) { foreach ($this->arrayFields as $key) $data[$key] = explode ("|", $data[$key]); } } /** * @param array $data */ private function validate ($data) { if (!$this->dbFields) return true; foreach ($this->dbFields as $key => $desc) { if(in_array($key, $this->toSkip)) continue; $type = null; $required = false; if (isset ($data[$key])) $value = $data[$key]; else $value = null; if (is_array ($value)) continue; if (isset ($desc[0])) $type = $desc[0]; if (isset ($desc[1]) && ($desc[1] == 'required')) $required = true; if ($required && strlen ($value) == 0) { $this->errors[] = Array ($this->dbTable . "." . $key => "is required"); continue; } if ($value == null) continue; switch ($type) { case "text": $regexp = null; break; case "int": $regexp = "/^[0-9]*$/"; break; case "double": $regexp = "/^[0-9\.]*$/"; break; case "bool": $regexp = '/^(yes|no|0|1|true|false)$/i'; break; case "datetime": $regexp = "/^[0-9a-zA-Z -:]*$/"; break; default: $regexp = $type; break; } if (!$regexp) continue; if (!preg_match ($regexp, $value)) { $this->errors[] = Array ($this->dbTable . "." . $key => "$type validation failed"); continue; } } return !count ($this->errors) > 0; } private function prepareData () { $this->errors = Array (); $sqlData = Array(); if (count ($this->data) == 0) return Array(); if (method_exists ($this, "preLoad")) $this->preLoad ($this->data); if (!$this->dbFields) return $this->data; foreach ($this->data as $key => &$value) { if(in_array($key, $this->toSkip)) continue; if ($value instanceof dbObject && $value->isNew == true) { $id = $value->save(); if ($id) $value = $id; else $this->errors = array_merge ($this->errors, $value->errors); } if (!in_array ($key, array_keys ($this->dbFields))) continue; if (!is_array($value)) { $sqlData[$key] = $value; continue; } if (isset ($this->jsonFields) && in_array ($key, $this->jsonFields)) $sqlData[$key] = json_encode($value); else if (isset ($this->arrayFields) && in_array ($key, $this->arrayFields)) $sqlData[$key] = implode ("|", $value); else $sqlData[$key] = $value; } return $sqlData; } private static function dbObjectAutoload ($classname) { $filename = static::$modelPath . $classname .".php"; if (file_exists ($filename)) include ($filename); } /* * Enable models autoload from a specified path * * Calling autoload() without path will set path to dbObjectPath/models/ directory * * @param string $path */ public static function autoload ($path = null) { if ($path) static::$modelPath = $path . "/"; else static::$modelPath = __DIR__ . "/models/"; spl_autoload_register ("dbObject::dbObjectAutoload"); } }
[-] .gitattributes
[edit]
[-] composer.json
[edit]
[+]
..
[-] dbObject.php
[edit]
[-] readme.md
[edit]
[-] MysqliDb.php
[edit]
[-] dbObject.md
[edit]
[-] LICENSE
[edit]