123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446 |
- <?php
- namespace Qii\Driver;
- use Qii\Autoloader\Psr4;
- use Qii\Exceptions\InvalidFormat;
- use Qii\Exceptions\InvalidParams;
- use Qii\Exceptions\TableException;
- use Qii\Exceptions\Variable;
- /**
- * Class Base
- * @package Qii\Driver
- * 使用方法
- * class base extends \Qii\Driver\Model {
- * public function __construct()
- * {
- * parent::__construct();
- * }
- * public function demo()
- * {
- * $this->db->fields("*")->join(array("leftJoin", array('table' => 'ad_site', 'alias' => 'b', 'on' => 'a.uid = b.uid')))->where(array('a.create_at:greater' => 1))->limit(10)->groupBy(array('a.uid', 'a.create_at'))->orderBy(array('a.uid' => 'desc'))->selectAll('user a');
- * $this->db->where(array('uid' => 1))->set(array('create_at:plus' => time(), 'status' => 1))->update('user');
- * $this->db->updateObject('user', array('create_at:plus' => time(), 'status' => 1), array('uid' => 1));
- * $this->db->where(array('uid:greater' => 1))->delete('user');
- * $this->db->deleteObject('user', array('uid' => 1));
- * $this->db->where(array('uid:greater' => 1))->like("email like '%test@test.com%'")->selectAll('user');
- * $this->db->where(array('uid:greater' => 1))->where("or")->like(array('email' => 'test@testcom'))->selectAll('user');
- * $this->db->where(array('uid:greater' => 1, 'or', 'email:like' => 'test@test.com'))->selectAll('user');
- * $this->db->where(array('uid:greater' => 1))->where("OR")->like(array('email' => 'test@test.com'))->selectAll('user');
- * $this->db->where(array('name' => 'antsnet'))->exclude(array('email' => 'test@test.com', 'status' => 1))->selectAll('user');
- * $this->db->where(array('name' => 'antsnet'))->orTerms(array('email' => 'test@test.com', 'status' => 1))->selectAll('user');
- * $this->db->orTerms(array('email' => 'test@test.com', 'status' => 1))->selectAll('user');
- * $this->db->join(array("leftJoin", array("table" => 'table', 'alias' => 'a', 'on' => 'a.id=b.id')));
- * $this->db->join(" LEFT JOIN table c on c.id=a.id")->selectAll('use a');
- * $this->db->where(array('email:unequal' => 'test@test.com'))->in(array('uid:in' => array('1,2,3'), 'status' => array(1)))->selectAll('user');
- * $this->>db->where(array('uid:in' => '1,2,3', 'email' => 'test@tset.com', 'status' => 1))->selectAll('user');
- * $this->db->where(array(array('email:unequal' => 'test@test.com'), array('uid:in' => array('1,2,3'), 'status:in' => array(1))))->selectAll('user');
- * }
- * }
- */
- class Base
- {
- const VERSION = '1.3';
- use TraitDatabase;
- use TraitCache;
- //query 方法
- protected $_query = array(
- "INSERT" => "INSERT INTO %s(%s) VALUES('%s')",
- "REPLACE" => "REPLACE %s (%s) VALUES('%s')",
- "SELECT" => "SELECT %s FROM %s %s",
- "UPDATE" => "UPDATE %s SET ",
- "DELETE" => "DELETE FROM %s %s",
- "WHERE" => " WHERE %s",
- "OR" => " `%s` = '%s' ",
- "ORDER" => " ORDER BY %s %s",
- "GROUP" => " GROUP BY %s",
- "LIMIT" => " LIMIT %d, %d"
- );
- //load类
- public $load;
- //cache类
- public $cache;
- //语言包
- public $language;
- //响应内容
- public $response;
- //执行的sql语句
- public $modelSQL = "";
- /**
- * @var string sql 引用
- */
- public $executeSQL = '';
- public $operateVal = array('or', 'and', 'like');//连接条件操作;
- public $shortExpression = array(
- 'equal' => "%s`%s` = '%s'",
- 'in' => "%s`%s` in (%s)",
- 'unequal' => "%s`%s` != '%s'",
- 'greater' => "%s`%s` > '%s'",
- 'gt' => "%s`%s` > '%s'",
- 'greaterEqual' => "%s`%s` >= '%s'",
- 'gte' => "%s`%s` >= '%s'",
- 'less' => "%s`%s` < '%s'",
- 'lessEqual' => "%s`%s` <= '%s'",
- 'lte' => "%s`%s` <= '%s'",
- 'like' => "%s`%s` like '%%%s%%'"
- );
- public $operateTable = array('leftJoin', 'rightJoin', 'innerJoin');//链接表的操作
- public $faultTolerant = true;
- public $whereCondition = array();
- public $joinCondition = array();
- public $fields = "*";
- public $sets = array();
- protected $groupBy;
- protected $limit;
- protected $orderBy;
- protected $_modelAlias = array('updateRows' => 'update', 'selectRows' => 'selectAll', 'select' => 'selectRow', 'getOne' => 'selectOne', 'getRow' => 'selectRow', 'getAll' => 'selectAll', 'remove' => 'delete', 'deleteRows' => 'delete');
- public function __construct()
- {
- $this->language = Psr4::getInstance()->loadClass('Qii\Language\Loader');
- $this->load = Psr4::getInstance()->loadClass('\Qii\Autoloader\Loader');
- $this->response = new Response();
- }
- /**
- * 获取所有数据
- *
- * @param $table
- * @param null $where
- * @return mixed
- * @throws \Exception
- */
- public function selectAll($table, $where = null)
- {
- if(is_array($where) && count($where) > 0)
- {
- $this->where($where);
- }
- $sql = $this->createSelectSQL($table);
- return $this->getAll($sql);
- }
- /**
- * 返回resource资源
- * @param string $table 数据表名称
- */
- final function rs($table)
- {
- $sql = $this->createSelectSQL($table);
- return $this->setQuery($sql);
- }
- /**
- * 查询一行
- * @param $table
- * @param null $where
- * @return array | bool
- * @throws \Exception
- */
- public function selectRow($table, $where = null)
- {
- if(is_array($where) && count($where) > 0)
- {
- $this->where($where);
- }
- $sql = $this->createSelectSQL($table);
- return $this->getRow($sql);
- }
- /**
- * get row 子类去覆写
- *
- * @param $sql
- * @return false
- */
- public function getRow($sql) {
- return false;
- }
- /**
- *
- * 查询一列
- * @param string $table 表名
- * @return false | array
- * @throws TableException
- */
- final function selectOne($table)
- {
- //验证table是否合法
- if (!$this->verifyTable($table)) {
- if (gettype($table) == 'string') {
- throw new TableException("表名不能包含怪字符且不能以数字开头,获取到的是". $table);
- }
- throw new TableException("表名必须是字符串加下划线,目标字符为". gettype($table));
- }
- $sql = $this->createSelectSQL($table);
- return $this->getOne($sql);
- }
- /**
- * get one 方法, 子类去覆写
- * @param string $sql
- * @return false | array
- */
- public function getOne($sql) {
- return false;
- }
- /**
- * 格式化插入值,新增null值插入
- *
- * @param $arr
- * @return array|mixed
- */
- protected function formatInsertObject($arr) {
- if(is_array($arr)) {
- $values = array();
- foreach ($arr as $val) {
- if(strtoupper(gettype($val)) == 'NULL') {
- $values[] = 'null';
- continue;
- }
- $values[] = "'". $val . "'";
- }
- return $values;
- }
- return $arr;
- }
- /**
- * 插入数据
- * @param $table
- * @param $dataArray
- * @return int
- * @throws InvalidFormat
- */
- final function insertObject($table, $dataArray)
- {
- if (empty($table)) {
- throw new InvalidParams(_i('%s is invalid', 'table'), __LINE__);
- }
- $replaceObj = $this->createInsertReplaceObj($dataArray);
- if(empty($replaceObj['fields']) || empty($replaceObj['values']))
- {
- throw new Variable(_i('Invalid %s format', 'data'), __LINE__);
- }
- // 针对 null 值单独处理,并将值的两端加上单引号 '
- $values = $this->formatInsertObject($replaceObj['values']);
- $this->executeSQL = $this->modelSQL = $sql = "INSERT INTO " . $this->getTable($table) . "(`" . join("`, `", $replaceObj['fields']) . "`) VALUES(". join(',', $values) . ")";
- $this->setQuery($sql);
- $this->setError();
- return $this->lastInsertId();
- }
- /**
- *
- * Replace Object
- * @param String $table
- * @param Array|Object $dataArray
- */
- final function replaceObject($table, $dataArray)
- {
- if (empty($table)) {
- throw new InvalidParams(_i('%s is invalid', 'table'), __LINE__);
- }
- $replaceObj = $this->createInsertReplaceObj($dataArray);
- if(empty($replaceObj['fields']) || empty($replaceObj['values']))
- {
- throw new Variable(_i('Invalid %s format', 'data'), __LINE__);
- }
- // 针对 null 值单独处理,并将值的两端加上单引号 '
- $values = $this->formatInsertObject($replaceObj['values']);
- $this->executeSQL = $this->modelSQL = $sql = "REPLACE INTO " . $this->getTable($table) . "(`" . join("`, `", $replaceObj['fields']) . "`) VALUES(". join(',', $values) . ")";
- $rs = $this->setQuery($sql);
- $this->setError();
- return $this->AffectedRows($rs);
- }
- /**
- * 创建插入或替换的内容
- *
- * @param $dataArray
- * @return array
- * @throws InvalidFormat
- */
- protected function createInsertReplaceObj($dataArray)
- {
- if(gettype($dataArray) == 'object') {
- $dataArray = get_object_vars($dataArray);
- }
- if (sizeof($dataArray) > 0) {
- $keys = array();
- $values = array();
- foreach ($dataArray AS $key => $value) {
- $keys[] = $key;
- if (is_array($value)) {
- throw new InvalidFormat(_i('Invalid %s format', $key), __LINE__);
- }
- if(strtoupper(gettype($value)) == 'NULL') {
- $values[] = null;
- }else{
- $values[] = $this->setQuote($value);
- }
- }
- return array('fields' => $keys, 'values' => $values);
- }
- return array('fields' => array(), 'values' => array());
- }
- /**
- * 更新表中指定数据 结合set、where等方法是用
- *
- * @param string $table
- * @return string
- * @throws \Exception
- */
- public function update($table)
- {
- if(!$table) {
- throw new InvalidParams(_i('%s is invalid', '表名'), __LINE__);
- }
- $set = join(",", $this->sets);
- $this->sets = array();
- if(count($this->whereCondition) > 0 && $this->isOperator($this->whereCondition[0]))
- {
- array_shift($this->whereCondition);
- }
- $where = count($this->whereCondition) > 0 ? " WHERE ". join(" ", $this->whereCondition) : "";
- $this->whereCondition = array();
- $alias = $this->getTableAlias($table);
- $this->executeSQL = $this->modelSQL = $sql = sprintf($this->_query['UPDATE'], $alias['name'] . $alias['alias']) . $set. $where;
- return $this->exec($sql);
- }
- /**
- * 更新表的数据,同时可以使用update方法达到同样的效果
- *
- * @param $table
- * @param $dataArray
- * @param array $where [key => $val]
- * @return string
- * @throws \Exception
- */
- final function updateObject($table, $dataArray, $where = array()){
- if(!$table) {
- throw new InvalidParams(_i('%s is invalid', '表名'), __LINE__);
- }
- return $this->set($dataArray)->where($where)->update($table);
- }
- /**
- * 删除表中的数据,结合where方法使用
- *
- * @param string $table 表名
- * @return string
- * @throws \Exception
- */
- final function delete($table)
- {
- if(!$table) {
- throw new \Exception('未指定更新的表名', __LINE__);
- }
- $where = count($this->whereCondition) > 0 ? " WHERE ". join(" ", $this->whereCondition) : "";
- $this->whereCondition = array();
- $alias = $this->getTableAlias($table);
- $this->executeSQL = $this->modelSQL = $sql = sprintf($this->_query['DELETE'], $alias['name'], $where);
- return $this->exec($sql);
- }
- /**
- * 删除表中数据
- *
- * @param string $table 表名
- * @param null $where
- * @return string
- * @throws \Exception
- */
- final function deleteObject($table, $where = null)
- {
- if(!$table) {
- throw new InvalidParams(_i('%s is invalid', '表名'), __LINE__);
- }
- return $this->where($where)->delete($table);
- }
- /**
- * like语句
- * @param mix $arr
- * @return $this
- */
- final function like($arr)
- {
- if(!is_array($arr)) {
- if(!empty($arr)) {
- $this->where($arr);
- }
- return $this;
- }
- foreach($arr as $key => $val) {
- $arr[$key .":like"] = $val;
- unset($arr[$key]);
- }
- $this->where($arr);
- return $this;
- }
- /**
- *
- * Limit函数,如果省略第二个参数则第一个为0,第二个参数值取第一个
- * @param int $limit
- * @param int $offset
- */
- final function limit($limit, $offset = null)
- {
- $this->limit = null;
- if($limit === '' || $limit === null) {
- throw new InvalidParams(_i('%s is invalid', 'Limit'), __LINE__);
- }
- if ($limit !== '') {
- if ($offset === null) {
- $this->limit = sprintf($this->_query["LIMIT"], 0, $limit);
- } else {
- $this->limit = sprintf($this->_query["LIMIT"], $limit, $offset);
- }
- }
- return $this;
- }
- /**
- * sql中的set条件
- *
- * @param array $set
- * @param null $res
- * @param string $defaultOperator
- * @return $this
- */
- final public function set($set, &$res = null, $defaultOperator = 'equal')
- {
- if(!is_array($set))
- {
- if(!empty($set))
- {
- $this->sets[] = $set;
- }
- return $this;
- }
- if(count($set) == 0) {
- return $this;
- }
- $operator = array("equal" => "%s`%s` = '%s'", "unequal" => "%s`%s` != '%s'", "plus" => "%s`%s` = %s`%s`+%s", "minus" => "%s`%s` = %s`%s`-%s", "multiply" => "%s`%s` = %s`%s`*%s", "divide" => "%s`%s` = %s`%s`/%s");
- foreach($set as $key => $val)
- {
- if(strtoupper(gettype($val)) != 'NULL') {
- $val = $this->setQuote($val);
- }
- $alias = $this->getFieldAlias($key);
- $operate = $this->getFieldOperator($alias['name']);
- if($operate['operator'] == '') {
- $operate['operator'] = $defaultOperator;
- }
- $opt = $operator[$operate['operator']];
- if(strtoupper(gettype($val)) == 'NULL') {
- $val = 'NULL';
- $opt = str_replace("'", '', $opt);
- }
- if($operate['operator'] == 'equal') {
- $this->sets[] = sprintf($opt, $alias['alias'], $operate['field'], $val);
- }else{
- $this->sets[] = sprintf($opt, $alias['alias'], $operate['field'], $alias['alias'], $operate['field'], $val);
- }
- }
- return $this;
- }
- /**
- * set 字段加
- * @param $set
- * @return $this
- */
- public function upsetCounter($set)
- {
- if(!is_array($set))
- {
- if(!empty($set))
- {
- $this->sets[] = $set;
- }
- return $this;
- }
- if(count($set) == 0) {
- return $this;
- }
- foreach ($set as $key => $val) {
- if(substr($key, -5) == ':plus') {
- continue;
- }
- $set[$key . ":plus"] = $val;
- unset($set[$key]);
- }
- return $this->set($set);
- }
- /**
- * set 字段减
- * @param $set
- * @return $this
- */
- public function downsetCounter($set)
- {
- if(!is_array($set)) {
- if(!empty($set)) {
- $this->sets[] = $set;
- }
- return $this;
- }
- if(count($set) == 0) {
- return $this;
- }
- foreach ($set as $key => $val) {
- if(substr($key, -6) == ':minus') {
- continue;
- }
- $set[$key . ":minus"] = $val;
- unset($set[$key]);
- }
- return $this->set($set);
- }
- /**
- * 处理where条件
- *
- * @param $where
- * @return $this|array
- * @throws \Exception
- */
- public function handleWhereFields($where) {
- if(!is_array($where)) {
- return $this;
- }
- $fields = [];
- foreach ($where as $key => $val) {
- $arr = explode(':', $key);
- $len = count($arr);
- $maxLen = 1;
- $opt = '';
- if(!$this->isExpression($arr[$len - 1])) {
- $maxLen = 0;
- }else{
- $opt = ':' .$arr[$len - 1];
- }
- if($len > $maxLen) {
- $arr1 = array_slice($arr, 0, count($arr) - $maxLen);
- foreach ($arr1 as $key) {
- $fields[$key . $opt] = $val;
- }
- }
- }
- return $fields;
- }
- /**
- * where条件
- * @param array $where where语句
- * @param null $res
- * @return $this
- */
- public function where($where, &$res = null)
- {
- if(!is_array($where)) {
- if(!empty($where))
- {
- if(!empty($this->whereCondition) && !$this->isOperator($where)) {
- $this->whereCondition[] = "and";
- }
- if($this->isOperator($where)) {
- $this->whereCondition[] = $where;
- }else{
- $this->whereCondition[] = "(". $where . ")";
- }
- }
- return $this;
- }
- if(count($where) == 0) {
- return $this;
- }
- $where = $this->handleWhereFields($where);
- $slices = $this->groupContents($where);
- $this->handleCondition($slices, $res);
- return $this;
- }
- /**
- * OR 条件
- * 用法:
- * 1:
- * $this->orTerms(['field1:like|equal....' => val1])->orTerms(....)
- * $this->orTerms(['field1:field2...:like|equal....' => val1])
- * == (field1 like|equal.... val1) or (field2 like|equal.... val1) ....
- * 2:
- * $this->orTerm(['field1:like|equal...' => val1, 'field2:like|equal...' => val1])
- * == (field1 like|equal.... val1 AND field2 like|equal.... val1 ....)
- * @param $where
- * @param string $defaultOperater
- * @param null $res
- * @return $this
- * @throws \Exception
- */
- public function orTerms($where, $defaultOperater = 'or', &$res = null)
- {
- if(!is_array($where))
- {
- if($where != '') {
- if(!empty($this->whereCondition) && !$this->isOperator($where)) {
- $this->whereCondition[] = $defaultOperater;
- }
- $this->whereCondition[] = "(". $where . ")";
- }
- return $this;
- }
- if(count($where) == 0) {
- return $this;
- }
- $extra = [];
- foreach ($where as $key => $val) {
- $fields = explode(':', $key);
- $len = count($fields);
- $min = 2;
- $opt = '';
- if($this->isExpression($fields[$len - 1])) {
- $min = 3;
- $opt = ':'. $fields[$len - 1];
- }
- if($len >= $min) {
- $arr = array_slice($fields, 0, ($opt != '' ? $len - 1 : $len));
- foreach ($arr as $field) {
- $extra[$field . $opt] = $val;
- }
- unset($where[$key]);
- }
- }
- if(count($where) > 0) {
- $this->handleCondition(array(array($defaultOperater, $where)), $res);
- }
- if(count($extra) > 0) {
- foreach ($extra as $key => $val) {
- $this->handleCondition(array(array($defaultOperater, [$key => $val])), $res);
- }
- }
- return $this;
- }
- /**
- * in 条件
- * @param $where
- * @param $defaultOperater
- * @param $res
- * @return $this
- * @throws \Exception
- */
- public function in($where, $defaultOperater = 'or', &$res = null)
- {
- if(!is_array($where))
- {
- if($where != '') {
- if(!empty($this->whereCondition) && !$this->isOperator($where)) {
- $this->whereCondition[] = $defaultOperater;
- }
- $this->whereCondition[] = "(". $where . ")";
- }
- return $this;
- }
- if(count($where) == 0) {
- return $this;
- }
- foreach ($where as $key => $val) {
- if(substr($key, - 3) == ':in') {
- continue;
- }
- $where[$key . ":in"] = $val;
- unset($where[$key]);
- }
- $where = $this->handleWhereFields($where);
- $this->handleCondition(array(array('and', $where)), $res);
- return $this;
- }
- /**
- * 不包含
- *
- * @param mix $where 条件
- * @return $this
- */
- public function exclude($where)
- {
- if(!is_array($where))
- {
- return $this->where($where);
- }
- if(count($where) == 0) {
- return $this;
- }
- foreach($where as $key => $value) {
- if($this->getFieldOperator($key)['operator'] == '') {
- $where[$key . ":unequal"] = $value;
- unset($where[$key]);
- }
- }
- return $this->where($where);
- }
- /**
- * join语句
- *
- * @param mix $val
- * @param reference $res 用于返回值
- * @return $this
- * @throws \Exception
- */
- public function join($val, &$res = null, $joinType = 'leftJoin') {
- if(!is_array($val)) {
- if(!empty($val)) {
- $this->joinCondition[] = $val;
- }
- return $this;
- }
- if(count($val) == 0) {
- return $this;
- }
- $slices = $this->groupContents($val);
- $this->handleTableJoin($slices, $joinType, $res);
- return $this;
- }
- /**
- * left join
- * @param $table
- * @param $on
- * @return $this
- * @throws \Exception
- */
- final function leftJoinObject($table, $on)
- {
- $alias = $this->getTableAlias($table);
- return $this->join(" LEFT JOIN ". $this->getTable($alias['name']) . " " . $alias['alias'] ." ON ". $on);
- }
- /**
- * GROUP BY
- * @param mix $group
- * @return $this
- */
- public function groupBy($group)
- {
- if(!is_array($group))
- {
- if(!empty($group))
- {
- $this->groupBy = stristr($group, 'GROUP BY') === false? "GROUP BY ". $group: $group;
- }
- return $this;
- }
- if(count($group) == 0) {
- return $this;
- }
- foreach($group as $index => $val)
- {
- $alias = $this->getFieldAlias($val);
- $group[$index] = $alias['alias'] . "`". $alias['name'] ."`";
- }
- $this->groupBy = " GROUP BY ". join(",", $group);
- return $this;
- }
- /**
- * Order by
- *
- * @param array|string $order
- * @return $this
- * @throws \Exception
- */
- public function orderBy($order)
- {
- if(!is_array($order))
- {
- if(!empty($order)) {
- $this->orderBy = stristr($order, 'ORDER BY') === false ? "ORDER BY ". $order: $order;
- }
- return $this;
- }
- if(count($order) == 0) {
- return $this;
- }
- $allowSortOff = array('asc', 'desc');
- $orderBy = array();
- $i = 0;
- $countOrder = count($order);
- foreach($order as $key => $sort)
- {
- if(!in_array(strtolower($sort), $allowSortOff) && $countOrder == $i)
- {
- throw new InvalidParams(_i('%s is invalid', 'sort'), __LINE__);
- }
- $alias = $this->getFieldAlias($key);
- $orderBy[] = $alias['alias'] . "`". $alias['name'] ."` ". $sort;
- $i++;
- }
- $this->orderBy = " ORDER BY ". join(",", $orderBy);
- return $this;
- }
- /**
- * Order by sql
- *
- * @param string $orderBy
- * @return $this
- * @throws \Exception
- */
- public function orderByStr($orderBy)
- {
- return $this->orderBy($orderBy);
- }
- /**
- * 过滤值
- *
- * @param string|array $word
- * @return array|string
- */
- final function setQuote($word)
- {
- if (ini_get("magic_quotes_gpc")) {
- return $word;
- }
- if(in_array(gettype($word), array("object", "resource","resource (closed)"))) {
- throw new \Exception('期待参数为数组或字符串,获取到的是:'. gettype($word)."(". json_encode($word) .")");
- }
- return is_array($word) ? array_map('addslashes', $word) : addslashes($word);
- }
- /**
- *
- * 查询的字段
- * @param string|array $fields
- * @return $this
- */
- final function fields($fields = "*", $append = false)
- {
- if (empty($fields) && !$append) $fields = "*";
- if (is_array($fields)) {
- if(count($fields) == 0) {
- $fields = $append ? '' : '*';
- }else{
- foreach($fields as $key => $val)
- {
- $alias = explode('.', $val);
- if(count($alias) > 1)
- {
- if(strpos("*", $alias[1]) !== false) {
- $fields[$key] = $val;
- continue;
- }
- $fields[$key] = $alias[0] . ".`".join(".", array_slice($alias, 1))."`";
- }
- }
- $fields = join(',', $fields);
- }
- }
- if($append) {
- if($fields != "") $this->fields .= ','. $fields;
- }else{
- $this->fields = $fields;
- }
- return $this;
- }
- /**
- * 清空Data数据
- */
- final public function cleanCondition()
- {
- $this->fields = '*';
- $this->whereCondition = array();
- $this->joinCondition = array();
- $this->groupBy = "";
- $this->orderBy = "";
- $this->limit = null;
- $this->sets = array();
- }
- /**
- * 获取错误码
- */
- final public function getCode()
- {
- return $this->response->getCode();
- }
- /**
- * 获取错误信息
- */
- final public function getMessage()
- {
- if ($this->response->isError()) {
- return $this->response->getMessage();
- }
- }
- /**
- * 返回response对象
- *
- * @return Response
- */
- public function getResponse()
- {
- return $this->response;
- }
- /**
- * 转换字符创
- *
- * @param $str
- * @return array|string
- */
- final public function iconv($str)
- {
- if (is_array($str)) {
- return array_map(function ($n) {
- return toUtf8($n);
- }, $str);
- }
- return toUtf8($str);
- }
- /**
- * 执行Model过程中保存的相关信息
- *
- * @param string $option
- * @return mixed
- */
- final function querySQL($option = '')
- {
- $allow = array('_queryTimes', '_querySeconds', '_errorInfo', '_exeSQL');
- if (in_array($option, $allow)) {
- return $this->{$option};
- }
- return 0;
- }
- /**
- * 获取执行的sql
- *
- * @param string $sql
- * @return $this
- */
- public function fetchSql(&$sql) {
- $this->executeSQL = &$sql;
- return $this;
- }
- /**
- * 通过where\set\limit等方法自动生成SQL语句
- *
- * @param string $table 必填
- * @return string
- * @throws \Exception
- */
- public function createSelectSQL($table)
- {
- if(!$table) {
- throw new InvalidParams(_i('%s is invalid', '表名'), __LINE__);
- }
- $aliases = $this->getTableAlias($table);
- $fields = (trim($this->fields) != '') ? $this->fields : "*";
- //$this->fields = '*';
- if(count($this->whereCondition) > 0 && $this->isOperator($this->whereCondition[0])) {
- array_shift($this->whereCondition);
- }
- $where = count($this->whereCondition) > 0 ? " WHERE ". join(" ", $this->whereCondition) : "";
- //$this->whereCondition = array();
- $join = count($this->joinCondition) > 0 ? join("\n", $this->joinCondition) : "";
- //$this->joinCondition = array();
- $groupBy = " ". $this->groupBy;
- //$this->groupBy = "";
- $orderBy = " ". $this->orderBy;
- //$this->orderBy = "";
- $limit = $this->limit;
- //$this->limit = null;
- $sql = sprintf($this->_query['SELECT'], $fields, $aliases['name'], $aliases['alias']) . $join . $where . $groupBy . $orderBy . $limit;
- $this->cleanCondition();
- $this->executeSQL = $this->modelSQL = $sql;
- return $sql;
- }
- /**
- * 获取操作符
- *
- * @param string $field 字段
- * @return array
- */
- protected function getFieldOperator($field)
- {
- $operator = explode(":", $field);
- if(count($operator) == 1) {
- return array('operator' => '', 'field' => $field);
- }
- $operate = array_pop($operator);
- $field = join(":", $operator);
- return array('operator' => $operate, 'field' => $field);
- }
- /**
- * 获取字段别名
- *
- * @param string $name
- * @param string $connector
- * @return array
- */
- protected function getFieldAlias($name, $connector = ".")
- {
- $aliases = explode('.', $name, 2);
- if(count($aliases) == 1) {
- return array('alias' => '', 'name' => $name);
- }
- return array('alias' => $aliases[0] . $connector, 'name' => join(".", array_slice($aliases, 1)));
- }
- /**
- * 获取表的别名
- *
- * @param string $name 名字
- * @return array
- */
- protected function getTableAlias($name)
- {
- if (!$this->verifyTable($name)) {
- if (gettype($name) == 'string') {
- throw new TableException("表名不能包含怪字符且不能以数字开头,获取到的是". $name);
- }
- throw new TableException("表名必须是字符串加下划线,目标字符为". gettype($name));
- }
- //去掉table前后的``符号
- $name = str_replace('`', '', $name);
- $aliases = explode(' ', $name);
- //检查表名中时候含数据库名,有数据表名的时候需要单独处理
- $hasDatabaseName = false;
- if(stristr($name, '.')) {
- $hasDatabaseName = true;
- }
- if(count($aliases) == 1) {
- if($hasDatabaseName) {
- $names = explode(".", $name);
- $name = $names[0] . ".`". $names[1] . "`";
- }else{
- $name = "`". $name ."`";
- }
- return array('alias' => '', 'name' => $name);
- }
- $res = array();
- $res['alias'] = array_pop($aliases);
- $res['name'] = join(" ", array_slice($aliases, -1));
- if($hasDatabaseName) {
- $names = explode(".", $res['name']);
- $res['name'] = $names[0] . ".`". $names[1] . "`";
- }else{
- $res['name'] = "`". $res['name'] ."`";
- }
- return $res;
- }
- /**
- * 把条件根据『链接字符串,『字段:值』』等内容分组
- *
- *
- * $whereGroup = array(
- * ['id' => 1, 'name' => '名字'],
- * 'or',
- * ['status' => 1, 'create_at:greater' => '22222'],//
- * 'or',//链接字段与字段之间的操作符
- * 'like',//使用在字段与值之间的操作符,可以省略
- * 'and',//字段1与字段2之间的操作符
- * 'or',//字段2与字段3之间的操作符
- * '...',//字段n与字段n+1之间的操作符
- * //字段n与字段n+1之间的操作符可以省略
- * //子数组之间的操作符优先于上边的操作符
- * ['email' => 'antsnet@163.com', "and", 'nickname' => 'antsnet'],
- * ['uid' => 1],
- * 'and',
- * ['name' => 'ss'],
- * 'and',
- * 'and',
- * 'update_at=1',
- * );
- * @param $group
- * @return array [['or/and', 'like/equal/...', ['字段1' => '值1', '字段2' => '值2']],[...]]
- * @throws \Exception
- */
- protected function groupContents($group)
- {
- $slices = array();
- //如果是一维数组就直接操作值,不检查操作符
- if(count($group) == count($group, 1)) {
- $slices[] = array($group);
- return $slices;
- }
- $count = count($group);
- $tmpWhere = array();
- //最后一次是否是赋值
- $lastIsValue = null;
- foreach($group as $index => $val)
- {
- //in比较特殊,它可以是字符串,可以是数组,结果是数组就单独处理不走操作符的处理逻辑
- if(substr($index, -3) == ':in' && is_array($val)) {
- $tmpWhere[$index] = $val;
- continue;
- }
- if(is_array($val)) {
- // group array 的情况,每组条件之间加 and
- $slices[] = $this->groupContents($val)[0];
- if($index < $count - 1) {
- $slices[] = 'and';
- }
- continue;
- }
- $isOperator = $this->isOperator($val);//如果是操作符,上一个不是操作符就清空tmpWhere,并放入slices
- $isValue = !$isOperator;
- if($lastIsValue && $isOperator)
- {
- $slices[] = array_values($tmpWhere);
- $tmpWhere = array();
- $tmpWhere[$index] = $val;
- }
- else if($count - 1 == $index)
- {
- $tmpWhere[$index] = $val;
- $slices[] = array_values($tmpWhere);
- $tmpWhere = array();
- }else {
- $tmpWhere[$index] = $val;
- }
- $lastIsValue = $isValue;
- }
- // @todo 待测试
- if(count($tmpWhere) > 0) {
- //作为独立 slices 的条件
- if(count($slices) > 0) {
- $slices[] = "and";
- }
- $slices[][] = $tmpWhere;
- }
- return $slices;
- }
- /**
- * 判断是否是操作符号
- *
- * @param mixed $val 值
- * @return bool
- */
- protected function isOperator($val)
- {
- if(is_array($val)) {
- return false;
- }
- if(!is_array($val)) {
- if(in_array(gettype($val), array("array", "object", "resource","resource (closed)"))) {
- throw new \Exception("期待参数为字符串,获取到的为: " . gettype($val) ."(". json_encode($val) . ")");
- }
- $val = strtolower($val);
- }
- return in_array($val, $this->operateVal) || in_array($val, $this->operateTable);
- }
- /**
- * 判断是否是表达式 equal unequal ...
- *
- * @param string $val
- * @return bool
- * @throws \Exception
- */
- protected function isExpression($val) {
- if(is_array($val)) {
- return false;
- }
- if(in_array(gettype($val), array("array", "object", "resource","resource (closed)"))) {
- throw new \Exception("期待参数为字符串,获取到的为: " . gettype($val) ."(". json_encode($val) . ")");
- }
- return isset($this->shortExpression[$val]);
- }
- /**
- * 是否是操作表
- *
- * @param string $val 值
- * @return bool
- */
- protected function isOperateTable($val)
- {
- if(is_array($val)) {
- return false;
- }
- return in_array($val, $this->operateTable);
- }
- /**
- * where条件子句组合
- *
- * @param array $values ['字段1' => '值1', '字段2' => '值2', ...]
- * @param string $defaultOperate 默认字句的链接方式
- * ..... 额外的参数,用于字段与字段之间的连接
- * @return string
- * @throws \Exception
- */
- protected function handleSubCondition($values, $defaultOperate = 'equal')
- {
- $extraParams = array();
- if(func_num_args() > 2)
- {
- $extraParams = array_slice(func_get_args(), 2);
- }
- $where = array();
- $operator = $this->shortExpression;
- $lastIsOperator = false;
- $lastIsValue = null;
- $i = 0;
- foreach($values as $key => $val)
- {
- $isOperator = preg_match("/^[0-9].*/", $key) && $this->isOperator($val);//如果是操作符,上一个不是操作符就清空tmpWhere,并放入slices
- $isValue = !$isOperator;
- if($lastIsValue && $isOperator)//如果当前是操作符,上一个是值,就将操作符加入到条件中
- {
- $where[] = $val;
- $lastIsValue = $isValue;
- $lastIsOperator = $isOperator;
- continue;
- }
- //如果上一次是操作符,这次又是操作符,就是用当前的操作符,去掉上一个操作符
- if($lastIsOperator && $isOperator)
- {
- if(!$this->faultTolerant) throw new InvalidParams(_i('Unsupported operator'), __LINE__);
- array_pop($where);
- $where[] = $val;
- continue;
- }
- if($lastIsValue && $isValue)//需要添加操作符
- {
- $where[] = count($extraParams) > 0 && isset($extraParams[$i-1]) ? $extraParams[$i-1] : "and";
- }
- //$aliases = explode(".", $key);
- $aliases = $this->getFieldAlias($key);
- $alias = $aliases['alias'];
- $operate = $this->getFieldOperator($aliases['name']);
- $opt = $operate['operator'] ? $operate['operator'] : $defaultOperate;
- $name = $operate['field'];
- if($opt == 'in')
- {
- if(is_array($val)) {
- $where[] = sprintf($operator[$opt], $alias, $name, "'". join("','", $val) . "'");
- }else{
- $where[] = sprintf($operator[$opt], $alias, $name, $val);
- }
- }else{
- if(!isset($operator[$opt])) {
- throw new \Exception("Unknow operator " . $opt, __LINE__);
- }
- $where[] = sprintf($operator[$opt], $alias, $name, $this->setQuote($val));
- }
- $lastIsValue = $isValue;
- $lastIsOperator = $isOperator;
- $i++;
- }
- return join(" ", $where);
- }
- /**
- * 处理table join
- * @param array $slices [['leftJoin', ['table' => '表名', 'alias' => 'a', 'on' => 'a.id = b.id']]]
- * @param string $defaultJoin
- * @param null $res
- * @return $this
- * @throws \Exception
- */
- protected function handleTableJoin($slices, $defaultJoin = 'leftJoin', &$res = null)
- {
- foreach ($slices as $v)
- {
- if(count($v) == 0) {
- throw new \Exception('连接表操作失败,格式:"leftJoin/rightJoin/innerJoin", ["table" => "表名", "alias" => "b", "on" => "a.id=b.id"]', __LINE__);
- }
- if(count($v) == 1 && !$this->isOperateTable($v[0]))
- {
- array_unshift($v, $defaultJoin);
- }
- $joinOperator = array(
- "leftJoin" => " LEFT JOIN %s ON %s",
- "rightJoin" => " RIGHT JOIN %s ON %s",
- "innerJoin" => " INNER JOIN %s ON %s"
- );
- if(!$this->isOperateTable($v[0]))
- {
- throw new \Exception('连接表操作失败,格式:"leftJoin/rightJoin/innerJoin", ["table" => "表名", "alias" => "b", "on" => "a.id=b.id"]', __LINE__);
- }
- $joinCondition = sprintf($joinOperator[$v[0]], $v[1]['table'] . ' '. $v[1]['alias'], $v[1]['on']);
- if(!empty($this->join) && is_array($this->join))
- {
- $this->joinCondition = array_merge($this->join, array($joinCondition));
- }
- else
- {
- $this->joinCondition[] = $joinCondition;
- }
- $res[] = $joinCondition;
- }
- unset($joinCondition);
- return $this;
- }
- /**
- * 处理 where 条件
- * @param array $condition
- * @param null $res
- * @return $this
- * @throws \Exception
- */
- protected function handleCondition($condition, &$res = null)
- {
- if(!is_array($condition))
- {
- return $this;
- }
- $count = count($condition);
- $whereCondition = array();
- for($i = 0; $i < $count; $i++)
- {
- $v = $condition[$i];
- if(!is_array($v) && $this->isOperator($v)) {
- $whereCondition[] = ' and ';
- continue;
- }
- //如果有两个及上的操作符
- //默认第一个为连接其他条件的操作符,第二个位字段和值之间的操作符, 从第三个开始即为字段与字段之间的连接符
- //最里层的字段与值之间的操作符优先级最高
- //例如 1: 'or/and','like','or', 'and', ['uid' => 1, 'name' => '名字', 'status' => 激活];
- //结果 1:or/and (uid like '%1%' or name like '%名字%' and status like '%激活%')
- //例如 2: 'or/and','like','or', 'and', ['uid' => 1, 'name' => '名字', 'status:equal' => 激活];
- //结果 2:or/and (uid like '%1%' or name like '%名字%' and status = '激活')
- $operateCondition = array();
- $values = array();
- $countCondition = count($v);
- $handleTable = false;
- for($j = 0; $j < $countCondition; $j++)
- {
- $handleTable = false;
- if($this->isOperateTable($v[$j]))
- {
- /*
- $operateCondition[] = $v[$j];
- $joinTable[$v[$j]] = $this->handleTableJoin($v);
- */
- //如果是操作数据表就直接退出循环单独处理
- $handleTable = true;
- break;
- }
- if($this->isOperator($v[$j]))
- {
- $operateCondition[] = $v[$j];
- continue;
- }
- if(!$this->isOperator($v[$j]))
- {
- if(!is_array($v[$j])) {
- $whereCondition[] = $v[0];
- $whereCondition[] = "(". $v[1] . ")";
- break;
- }
- $values = is_array($v[$j]) ? array_merge($values, $v[$j]) : array_merge($values, array($v[$j]));
- }
- }
- if($handleTable)
- {
- continue;
- }
- if(count($operateCondition) > 0 && count($values) > 0)
- {
- $whereCondition[] = array_shift($operateCondition);
- }
- if(count($values) > 0) {
- if(count($operateCondition) > 0) {
- array_unshift($operateCondition, $values);
- $whereCondition[] = "(". call_user_func_array(array($this, 'handleSubCondition'), $operateCondition) .")";
- }else{
- $whereCondition[] = "(". $this->handleSubCondition($values) .")";
- }
- }
- }
- if(!empty($this->whereCondition))
- {
- $lastCondition = $this->whereCondition[count($this->whereCondition) - 1];
- if(count($whereCondition) > 0 && !$this->isOperator($whereCondition[0]) && !$this->isOperator($lastCondition)) {
- $this->whereCondition = array_merge($this->whereCondition, array('and'));
- }
- $this->whereCondition = array_merge($this->whereCondition, $whereCondition);
- }
- else
- {
- $this->whereCondition = $whereCondition;
- }
- $res = $whereCondition;
- unset($whereCondition);
- return $this;
- }
- /**
- * 验证数据表名是否符合规范
- * 表名不能以数字开头,
- *
- * @param string $name
- * @return bool
- */
- final public function verifyTable($name) {
- if (!is_string($name) || (
- // table
- !preg_match("/^[a-zA-Z_]+[a-zA-Z0-9_]{0,}$/", $name) &&
- // `table`
- !preg_match("/^`[a-zA-Z_]+[a-zA-Z0-9_]{0,}`$/", $name)) &&
- // table alias
- !preg_match("/^[a-zA-Z_]+[a-zA-Z0-9_]{0,}\s+[a-zA-Z]+[a-zA-Z0-9_]{0,}$/", $name) &&
- // `table` alias
- !preg_match("/^`[a-zA-Z_]+[a-zA-Z0-9_]{0,}`\s+[a-zA-Z]+[a-zA-Z0-9_]{0,}$/", $name) &&
- // database.table
- !preg_match("/^[a-zA-Z]+\.[a-zA-Z]+[a-zA-Z0-9_]{0,}$/", $name) &&
- !preg_match("/^[a-zA-Z]+\.[a-zA-Z]+[a-zA-Z0-9_]{0,}\s+[a-zA-Z]+[a-zA-Z0-9_]{0,}$/", $name)
- ) {
- return false;
- }
- return true;
- }
- /**
- * 如果不存在指定的方法则调用提示错误
- *
- * @param string $method
- * @param mixd $args
- * @return mixed
- */
- public function __call($method, $args)
- {
- if (isset($this->_modelAlias[$method])) {
- if (method_exists($this, $this->_modelAlias[$method])) {
- return call_user_func_array(array($this, $this->_modelAlias[$method]), $args);
- }
- return \Qii::setError(false, __LINE__, 1506, 'Alias ' . get_called_class() . '->' . $method . '() not found');
- }
- return \Qii::setError(false, __LINE__, 1506, get_called_class() . '->' . $method . '() not found');
- }
- }
|