Easy.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. <?php
  2. /**
  3. * 简易数据库操作类
  4. *
  5. * @author Jinhui Zhu<jinhui.zhu@live.cn>2015-12-10 14:35
  6. *
  7. * usage:
  8. * $user = (new \Qii\Driver\Easy())->_initialize();
  9. * $user->setRules(new \Qii\Driver\Rules($rules));
  10. * $user->setPrivateKey(array());
  11. * $user->uid = 1;
  12. * $user->email = 'antsnet@163.com';
  13. * $user->nick = 'Jinhui Zhu';
  14. * $user->add_time = time();
  15. * $user->update_time = time();
  16. * 保存数据
  17. * $user->_save();
  18. * 检查指定数据是否存在,以privateKey为准
  19. * $user->_exist();
  20. * 删除指定数据,以privateKey为准
  21. * $user->_remove()
  22. * 更新数据,以privateKey为准
  23. * $user->_update();
  24. * if($user->isError())
  25. * {
  26. * //todo 如果执行操作有问题,错误详情 $user->getErrors()
  27. * }
  28. * else
  29. * {
  30. * //todo 对返回结果进行处理
  31. * }
  32. *
  33. * //获取所有
  34. * $user->_getRowsByEmail('antsnet@163.com');
  35. * $user->_getRowByFileds($this->_privateKey);
  36. * $user->_getRowsByFileds($this->_privateKey);
  37. * $user->getEmailByUid(1);
  38. * $user->_getAllByUid(1);
  39. */
  40. namespace Qii\Driver;
  41. \Qii\Autoloader\Import::requires(dirname(__FILE__) . DS . 'Response.php');
  42. class Easy
  43. {
  44. const VERSION = '1.2';
  45. /**
  46. * @var Fields $fields
  47. */
  48. private $fields = null;
  49. /**
  50. * 数据表主键
  51. * @var array $privateKeys
  52. */
  53. private $privateKeys = array();
  54. /**
  55. * 保存或更新的时候验证的规则
  56. * @var array $rules
  57. */
  58. private $easyRules = array();
  59. /**
  60. * @var string $databaseName 数据库名称
  61. * 如果没有指定数据库名称将使用当前连接的数据库
  62. */
  63. private $databaseName;
  64. /**
  65. * @var string $tableName 表名,
  66. * 如果要指定操作的数据库名需要将数据库名和表名合在一起,如:database.table
  67. */
  68. private $tableName = '';
  69. /**
  70. * @var book $isInstance 是否实例化对象了
  71. */
  72. private $isInstance = false;
  73. /**
  74. * @var array $_response 操作出错保存数据到此数组
  75. */
  76. private $_response;
  77. /**
  78. * @var bool 是否需要重置privateKeys
  79. */
  80. private $needResetPrivatekey = true;
  81. private $db;
  82. public function __construct()
  83. {
  84. $this->db = \Qii\Autoloader\Psr4::loadClass('Qii\Model')->db;
  85. $this->clean();
  86. return $this;
  87. }
  88. /**
  89. * 初始化数据库对象
  90. *
  91. */
  92. final public function _initialize()
  93. {
  94. $this->isInstance = true;
  95. $this->clean();
  96. return $this;
  97. }
  98. /**
  99. * 设置表字段
  100. *
  101. * @param array $fields
  102. * @return $this
  103. */
  104. final public function setFields(array $fields)
  105. {
  106. $this->fields = new Fields($fields);
  107. return $this;
  108. }
  109. /**
  110. * 设置主键
  111. *
  112. * @param array|string $privateKeys
  113. */
  114. final public function setPrivateKey(array $privateKeys)
  115. {
  116. if(count($privateKeys) == 0) return $this;
  117. $this->needResetPrivatekey = false;
  118. $this->privateKeys = $privateKeys;
  119. return $this;
  120. }
  121. /**
  122. * 重置主键,主要用于查询、更新、删除操作
  123. *
  124. * @param string | null $opt
  125. * @return array
  126. */
  127. final public function resetPrivateKey($opt = null)
  128. {
  129. if ($this->needResetPrivatekey && $opt) {
  130. $valid = $this->easyRules->getOperateValidFields($opt);
  131. if (!empty($valid)) $this->privateKeys = array_values($valid);
  132. }
  133. return $this->privateKeys;
  134. }
  135. /**
  136. * 设置规则
  137. * @param array $rules {_save:{}, _update:{}, _remove:{}}
  138. */
  139. final public function setRules(\Qii\Driver\Rules $rules)
  140. {
  141. $this->setFields($rules->getFields());
  142. $this->tableName = $rules->getTableName();
  143. $this->databaseName = $rules->getDatabase();
  144. if (!$this->privateKeys) $this->privateKeys = $rules->getPrivateKey();
  145. $this->easyRules = $rules;
  146. return $this;
  147. }
  148. /**
  149. * 设置表字段
  150. *
  151. * @param $name
  152. * @param $val
  153. * @return $this
  154. */
  155. public function __set($name, $val)
  156. {
  157. $this->fields->$name = $val;
  158. return $this;
  159. }
  160. /**
  161. * 批量设置字段的值
  162. * @param array $data
  163. * @return $this
  164. */
  165. public function setFieldsVal(array $data)
  166. {
  167. foreach ($data AS $name => $val) {
  168. $this->fields->$name = $val;
  169. }
  170. return $this;
  171. }
  172. /**
  173. * 获取当前使用的rules的字段
  174. *
  175. * @return mixed
  176. */
  177. public function getFields()
  178. {
  179. return $this->easyRules->getFields();
  180. }
  181. /**
  182. * 获取当前使用的fields的值
  183. *
  184. * @return mixed
  185. */
  186. public function getValues()
  187. {
  188. return $this->fields->getValues();
  189. }
  190. /**
  191. * 如果没有调用parent::__construct()方法就报错
  192. *
  193. */
  194. public function checkInstance()
  195. {
  196. if (!$this->isInstance) {
  197. $this->_response = Response::Fail('checkInstance', array('msg' => \Qii::i(1507, 'parent::__construct()'), 'code' => __LINE__));
  198. throw new \Qii\Exceptions\TableException(\Qii::i(1507, 'parent::__construct()'), __LINE__);
  199. }
  200. return $this;
  201. }
  202. /**
  203. * 重置Fields及相关条件
  204. *
  205. */
  206. final protected function clean()
  207. {
  208. $this->fields = null;
  209. $this->privateKeys = array();
  210. $this->easyRules = array();
  211. $this->tableName = '';
  212. $this->_response = new Response();
  213. return $this;
  214. }
  215. /**
  216. * 验证保存的数据
  217. *
  218. * @param $rules
  219. * @return bool
  220. */
  221. final protected function validateFields($rules)
  222. {
  223. if (empty($rules)) return true;
  224. $validateCls = _loadClass('Qii_Library_Validate');
  225. $result = $validateCls->verify($this->fields->getValues(), $rules, $this->easyRules->getInvalidMessage());
  226. if ($result === true) {
  227. return true;
  228. }
  229. $error = $validateCls->getErrors();
  230. $this->_response = Response::FailValidate('validate', array('_result' => $error['msg'], 'fields' => array('field' => $error['field'], 'message' => $error['msg'])));
  231. return false;
  232. }
  233. /**
  234. * 获取用户表
  235. */
  236. final public function getTableName()
  237. {
  238. if (!$this->tableName) throw new \Qii\Exceptions\Errors(\Qii::i(1510), true);
  239. return $this->databaseName ? $this->databaseName . '.' . $this->tableName : $this->tableName;
  240. }
  241. /**
  242. * 对指定字段执行指定方法 同时校验值的有效性
  243. *
  244. * @param String $func
  245. * @param String $field
  246. * @param String $val
  247. * @return Object
  248. */
  249. final public function func($func, $key, $val)
  250. {
  251. $rule = $this->getValidateField($key);
  252. //如果字段需要用到函数编码字符,如果没有通过验证就不将值放入fields中
  253. $validateCls = _loadClass('Qii\Library\Validate');
  254. $result = $validateCls->verify(array($key => $val), array($key => $rule), $this->easyRules->getInvalidMessage());
  255. if ($result === true) {
  256. $this->fields->$key = $func($val);
  257. return $this;
  258. }
  259. $error = $validateCls->getErrors();
  260. $this->_response = Response::FailValidate('validate', array('_result' => $error['msg'], 'fields' => array('field' => $error['field'], 'message' => $error['msg'])));
  261. return $this;
  262. }
  263. /**
  264. * 检查数据是否已经存在,并返回一行,只能根据主键查询
  265. *
  266. * @return array
  267. */
  268. final public function _exist()
  269. {
  270. $this->checkInstance();
  271. if (!$this->privateKeys) {
  272. $this->_response = Response::FAIL('privateKey', \Qii::i(1513));
  273. return $this->_response;
  274. }
  275. $where = array();
  276. foreach ($this->privateKeys AS $key) {
  277. $rule = $this->getValidateField($key);
  278. if (count($rule) > 0 && !$this->validateFields(array($key => $rule))) {
  279. return $this->_response;
  280. }
  281. if ($this->fields->isField($key)) $where[] = "`{$key}` = '" . $this->db->setQuote($this->fields->getField($key)) . "'";
  282. }
  283. $result = (array)$this->db->limit(1)->where(join(' AND ', $where))->select($this->getTableName());
  284. if ($this->db->isError()) {
  285. $this->_response = $this->db->getResponse();
  286. }
  287. return $this->_response = Response::Success('_exist', array('_result' => $result));
  288. }
  289. /**
  290. * 获取主键对应的值
  291. * @return array
  292. */
  293. final protected function getPrivateValue()
  294. {
  295. $data = array();
  296. foreach ($this->privateKeys AS $key) {
  297. $data[$key] = $this->fields->getField($key);
  298. }
  299. return $data;
  300. }
  301. /**
  302. * 保存数据
  303. *
  304. * @return string 如果是自动增长的行返回插入数据的id
  305. */
  306. final public function _save()
  307. {
  308. $this->checkInstance();
  309. if (!$this->validateFields($this->easyRules->getRulesByOperate('save'))) return $this->_response;
  310. $this->resetPrivateKey('save');
  311. if ($this->privateKeys && count($this->_exist()->getResult()) > 0) {
  312. $this->_response = Response::Exist('_save', array('_result' => \Qii::i(1511, join(',', $this->getPrivateValue()))));
  313. return $this->_response;
  314. }
  315. $result = $this->db->insertObject($this->getTableName(), $this->fields->getValues());
  316. if ($this->db->isError()) {
  317. return $this->db->getResponse();
  318. }
  319. return $this->_response = Response::Success('_save', array_merge($this->fields->getValueAsArray(), array('_result' => $result)));
  320. }
  321. /**
  322. * 更新数据
  323. *
  324. * @return int 更新数据影响的行数
  325. */
  326. final public function _update()
  327. {
  328. $this->checkInstance();
  329. if (!$this->validateFields($this->easyRules->getRulesByOperate('update'))) return $this->_response;
  330. $this->resetPrivateKey('update');
  331. if (count($this->_exist()) == 0) {
  332. return $this->_response = Response::NotExist('_update', \Qii::i(1512, join(',', $this->getPrivateValue())));
  333. }
  334. $result = $this->db->updateObject($this->getTableName(), $this->fields->getValues(), $this->privateKeys);
  335. if ($this->db->isError()) {
  336. return $this->_response = $this->db->getResponse();
  337. }
  338. return $this->_response = Response::Success('_update', array('_result' => $result));
  339. }
  340. /**
  341. * 删除数据
  342. * @return int 删除数据影响的行数
  343. */
  344. final public function _remove()
  345. {
  346. $this->checkInstance();
  347. if (!$this->validateFields($this->easyRules->getRulesByOperate('remove'))) return $this->_response;
  348. $this->resetPrivateKey('remove');
  349. if (count($this->_exist()) == 0) {
  350. return $this->_response = Response::NotExist('_remove', \Qii::i(1512, join(',', $this->getPrivateValue())));
  351. }
  352. $result = $this->db->deleteObject($this->getTableName(), $this->fields->getValues());
  353. if ($this->db->isError()) {
  354. return $this->_response = $this->db->getResponse();
  355. }
  356. return $this->_response = Response::Success('_remove', array('_result' => $result));
  357. }
  358. /**
  359. * 获取操作数据返回的错误
  360. */
  361. final public function getErrors()
  362. {
  363. if ($this->_response) {
  364. if (!$this->_response->isError()) return false;
  365. return $this->_response;
  366. }
  367. return $this->db->getError();
  368. }
  369. /**
  370. * 是否有错误
  371. */
  372. final public function isError()
  373. {
  374. if ($this->_response) {
  375. return $this->_response->isError();
  376. }
  377. return $this->db->isError();
  378. }
  379. /**
  380. * 获取response对象
  381. */
  382. final public function getResponse()
  383. {
  384. return $this->_response;
  385. }
  386. /**
  387. * 使用此方法用于查询某一条数据的某一个字段
  388. * @useage getXxxByXxx
  389. * getNameById:通过id获取name的值; getEmailById:通过id获取email;
  390. * _getRowById:返回所有字段; _getRowsById:通过id获取所有匹配的数据
  391. * 备注:以_开头的才会去走getRow, getRows方法去取所有字段,目前仅支持All, Row, Rows这几个方法
  392. * @param String $method [description]
  393. * @param Mix $args 请求的参数
  394. * @return Mix [description]
  395. */
  396. final public function __call($method, $args)
  397. {
  398. $this->checkInstance();
  399. $selectType = 'normal';
  400. if (substr($method, 0, 1) == '_') {
  401. $selectType = 'system';
  402. $method = substr($method, 1);
  403. }
  404. preg_match('/^(get)(.*)(By)(.*)/', $method, $matches);
  405. if ($matches && count($matches) == 5 && $matches[1] == 'get') {
  406. //大写字母匹配下划线,字段中统一用小写字母,在查询的时候使用驼峰结构
  407. //如:getEmailAddressByUserId 通过user_id查询email_address
  408. $field = strtolower(preg_replace('/(?<!^)([A-Z])/', '_$1', $matches[2]));
  409. if (isset($this->_relationMap[$field])) $field = $this->_relationMap[$field];
  410. $method = 'selectRow';
  411. if ($field == 'rows' && $selectType == 'system') $method = 'selectRows';
  412. if ($field == 'row' && $selectType == 'system') $method = 'selectRow';
  413. if (in_array($field, array('all', 'row', 'rows')) && $selectType == 'system') {
  414. $field = '*';
  415. }
  416. $value = $this->db->setQuote(array_shift($args));
  417. $name = strtolower(strtolower(preg_replace('/(?<!^)([A-Z])/', '_$1', $matches[4])));
  418. $whereArray = array();
  419. if ($selectType == 'system' && $name == 'fields') {
  420. foreach ($value AS $val) {
  421. $whereArray[$val] = $this->fields->isField($val) ? $this->fields->getField($val) : '';
  422. }
  423. } else {
  424. if (!$this->fields->isField($name)) $this->fields->$name = $value;
  425. $whereArray[$name] = $this->fields->getField($name);
  426. }
  427. foreach ($whereArray AS $key => $val) {
  428. $rule = $this->getValidateField($key);
  429. if (count($rule) > 0 && !$this->validateFields(array($key => $rule))) {
  430. return $this->_response;
  431. }
  432. }
  433. $result = $this->db->fields($field)->whereArray($whereArray)->$method($this->getTableName());
  434. if ($this->db->isError()) {
  435. return $this->_response = $this->db->getResponse();
  436. }
  437. return $this->_response = Response::Success($method, array('_result' => $result));
  438. }
  439. //exec{$method}
  440. preg_match('/^(exec)(.*)/', $method, $matches);
  441. if ($matches && count($matches) == 3) {
  442. $alias = lcfirst($matches[2]);
  443. if (method_exists($this->db, $alias)) {
  444. $result = $this->db->{$matches[2]}($this->getTableName(), $this->getFields());
  445. if ($this->db->isError()) {
  446. return $this->_response = $this->db->getResponse();
  447. }
  448. return $this->_response = Response::Success($matches[2], array('_result' => $result));
  449. }
  450. if ($this->db->getAlias($method) && method_exists($this->db, $this->db->getAlias($method))) {
  451. $this->db->whereArray($this->getFields());
  452. $result = $this->db->{$this->db->getAlias($method)}($this->getTableName());
  453. if ($this->db->isError()) {
  454. return $this->_response = $this->db->getResponse();
  455. }
  456. return $this->_response = Response::Success($this->db->getAlias($method), array('_result' => $result));
  457. }
  458. }
  459. //访问方法的别名
  460. if ($this->db->getAlias($method)) {
  461. if (method_exists($this->db, $this->db->getAlias($method))) {
  462. $result = call_user_func_array(array($this->db, $this->db->getAlias($method)), $args);
  463. if ($this->db->isError()) {
  464. return $this->_response = $this->db->getResponse();
  465. }
  466. return $this->_response = Response::Success($this->db->getAlias($method), array('_result' => $result));
  467. }
  468. $this->_response = Response::UndefinedMethod('__call', $this->db->getAlias($method));
  469. \Qii::setError(false, __LINE__, 1106, 'Model', 'Alias ' . $this->db->getAlias($method) . ' does not exist.', print_r($args, true));
  470. }
  471. $this->_response = Response::UndefinedMethod('__call', $method);
  472. \Qii::setError(false, __LINE__, 1106, 'Model', $method, print_r($args, true));
  473. }
  474. /**
  475. * 获取单个字段的验证规则
  476. * @param String $fieldName 字段名
  477. * @return Array
  478. */
  479. protected function getValidateField($fieldName)
  480. {
  481. return $this->easyRules->getRulesByField($fieldName);
  482. }
  483. }