Ai
1 Star 0 Fork 0

cuiyihang/PHP-MySQLi-Database-Class

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
dbObject.php 23.63 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
<?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, 'Object' as object
* 'Json' as json string
*
* @var string
*/
public $returnType = 'Object';
/**
* 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) && !is_object($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");
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/cuiyihang/PHP-MySQLi-Database-Class.git
git@gitee.com:cuiyihang/PHP-MySQLi-Database-Class.git
cuiyihang
PHP-MySQLi-Database-Class
PHP-MySQLi-Database-Class
master

搜索帮助