bf8254ee9da556c4452705b0f3c75b84ed6d05b6.svn-base 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. <?php namespace Maze\Data;
  2. use Maze\Debug\Process as Debug;
  3. use Maze\Config\Load as Config;
  4. use Maze\Http\Output;
  5. use Maze\Http\Input;
  6. use Maze\Routing\Load;
  7. class Model
  8. {
  9. /**
  10. * database
  11. *
  12. * @var array
  13. */
  14. protected $database;
  15. /**
  16. * config
  17. *
  18. * @var array
  19. */
  20. protected $config;
  21. /**
  22. * db
  23. *
  24. * @var Object
  25. */
  26. protected $db;
  27. /**
  28. * __construct
  29. *
  30. * @return mixd
  31. */
  32. public function __construct($config)
  33. {
  34. $this->config =& $config;
  35. $this->database = Config::get('database', $config['project']);
  36. }
  37. /**
  38. * db
  39. *
  40. * @return mixd
  41. */
  42. protected function db($key = '')
  43. {
  44. if(!$key)
  45. {
  46. $key = isset($this->config['project']) ? $this->config['project'] : MAZE_PROJECT_NAME;
  47. }
  48. if(empty($this->database[$key]))
  49. {
  50. if(empty($this->database['default']))
  51. {
  52. Output::abert('core_database_exists', $key);
  53. }
  54. $this->database[$key] = $this->database['default'];
  55. }
  56. if(empty($this->db[$key]))
  57. {
  58. //$this->config['name'] = $key . '_' . $this->config['name'];
  59. $method = 'Maze\\Data\\' . ucwords($this->database[$key]['type']) . '\\Store';
  60. $this->db[$key] = new $method($this->database[$key]);
  61. $this->db[$key]->table($key . '_' . $this->config['name']);
  62. # 建表
  63. if(isset($this->config['struct']))
  64. {
  65. $create = $this->db[$key]->create($this->config['struct']);
  66. if($create === true)
  67. {
  68. # 写入默认值
  69. if(isset($this->config['default']))
  70. {
  71. $this->db[$key]->inserts($this->config['default']);
  72. }
  73. }
  74. else
  75. {
  76. if(isset($create['struct']))
  77. {
  78. if(count($create['struct']) < count($this->config['struct']))
  79. {
  80. $alter = array_diff_key($this->config['struct'], $create['struct']);
  81. if($alter)
  82. {
  83. $this->db[$key]->alter($alter, $this->config['struct']);
  84. }
  85. }
  86. }
  87. # 更改表结构
  88. if(isset($this->config['alter']))
  89. {
  90. $this->db[$key]->alter($this->config['alter']);
  91. }
  92. }
  93. # 建立索引
  94. if(isset($this->config['index']))
  95. {
  96. $this->db[$key]->index($this->config['index']);
  97. }
  98. }
  99. }
  100. return $this->db[$key];
  101. }
  102. /**
  103. * 获取匹配的类型
  104. *
  105. * @return mixd
  106. */
  107. private function type($method)
  108. {
  109. switch($method)
  110. {
  111. case 1:
  112. $method = '=';
  113. break;
  114. case 2:
  115. $method = 'like';
  116. break;
  117. case 3:
  118. $method = '>';
  119. break;
  120. case 4:
  121. $method = '>=';
  122. break;
  123. case 5:
  124. $method = '<';
  125. break;
  126. case 6:
  127. $method = '<=';
  128. break;
  129. }
  130. return $method;
  131. }
  132. /**
  133. * # 初始化默认方法one、list、update、insert、delete
  134. *
  135. * @return mixd
  136. */
  137. private function init($method, $param = array())
  138. {
  139. $array = array();
  140. $type = '';
  141. $this->config['request'][$method] = array
  142. (
  143. 'type' => $method,
  144. 'where' => array('id' => 'yes'),
  145. );
  146. # 支持单独字段更新
  147. $key = '';
  148. if(strpos($method, 'update_') !== false)
  149. {
  150. $key = str_replace('update_', '', $method);
  151. if($key && isset($this->config['struct'][$key]))
  152. {
  153. $match = $this->config['struct'][$key]['match'];
  154. if(is_array($this->config['struct'][$key]['match']))
  155. {
  156. $match = $this->config['struct'][$key]['match'][0];
  157. }
  158. $this->config['request'][$method]['type'] = 'update';
  159. $this->config['request'][$method]['set'][$key] = $match;
  160. $this->config['request'][$method]['where']['id'] = 'yes';
  161. return;
  162. }
  163. }
  164. switch($method)
  165. {
  166. case 'one':
  167. case 'delete':
  168. break;
  169. case 'updatemul':
  170. #批量更新操作,仅仅开启了mul_type配置或者后台可用
  171. if(isset(Config::$global['base']['mul_type']) && Config::$global['base']['mul_type'] > 0)
  172. {
  173. $this->config['request'][$method]['type'] = 'update';
  174. if(Config::$global['base']['mul_type'] == 2)
  175. {
  176. unset($this->config['request'][$method]['where']);
  177. $type = 'option';
  178. }
  179. else
  180. {
  181. $type = 'mul';
  182. $this->config['request'][$method]['where']['id'] = array('yes', 'in');
  183. }
  184. }
  185. break;
  186. case 'update':
  187. $type = 'set';
  188. break;
  189. case 'insert':
  190. unset($this->config['request'][$method]['where']);
  191. $type = 'add';
  192. break;
  193. case 'list':
  194. $type = 'option';
  195. $this->config['request']['list'] = array
  196. (
  197. 'type' => 'all',
  198. 'order' => array('id', 'desc'),
  199. 'page' => array(15, 'list'),
  200. 'col' => '*|id',
  201. 'option' => array(),
  202. );
  203. if(isset($this->config['manage']['list_type']) && $this->config['manage']['list_type'] == 'parent')
  204. {
  205. $this->config['request']['list']['page'][0] = 500;
  206. }
  207. if(isset(Config::$global['base']['excel']))
  208. {
  209. unset($this->config['request']['list']['page']);
  210. }
  211. break;
  212. case 'total':
  213. $type = 'option';
  214. $this->config['request']['total'] = array
  215. (
  216. 'type' => 'all',
  217. 'col' => 'count(*) as total',
  218. 'group' => array('month'),
  219. 'option' => array(),
  220. );
  221. break;
  222. default:
  223. unset($this->config['request'][$method]);
  224. break;
  225. }
  226. if($type)
  227. {
  228. if($type == 'option')
  229. {
  230. $param['search_type'] = isset($param['search_type']) ? $param['search_type'] : Input::get('search_fulltext_type', 1);
  231. $param['search_type'] = $this->type($param['search_type']);
  232. }
  233. foreach($this->config['struct'] as $k => $v)
  234. {
  235. if(isset($v['match']))
  236. {
  237. # 这里增加value,用以区分update/select的值
  238. if(is_array($v['match']))
  239. {
  240. $v['value'] = $v['match'][1];
  241. $v['match'] = $v['match'][0];
  242. }
  243. else
  244. {
  245. $v['value'] = $v['match'];
  246. }
  247. # 首先匹配批量更新
  248. if($method == 'updatemul' && isset($v['update']) && $v['update'] == 'radio' && (is_array($v['option']) || is_object($v['option'])))
  249. {
  250. $this->config['request'][$method]['set'][$k] = $v['value'];
  251. }
  252. if($type == 'option')
  253. {
  254. # 位运算
  255. if(isset($v['bit']))
  256. {
  257. $this->config['request'][$method][$type][$k] = array('option', '&');
  258. }
  259. # 默认排序
  260. elseif(isset($v['order']))
  261. {
  262. if(isset($this->config['request'][$method]['order']))
  263. {
  264. if($this->config['request'][$method]['order'][0] && $this->config['request'][$method]['order'][0] != $k)
  265. {
  266. $this->config['request'][$method]['order'][0] = $k . '` '.(is_string($v['order']) ? $v['order'] : 'desc').',`' . $this->config['request'][$method]['order'][0];
  267. }
  268. }
  269. }
  270. # 全文检索
  271. if(isset($v['search']) && strpos($v['search'], 'fulltext') !== false)
  272. {
  273. $this->config['request'][$method][$type][$k] = array('option', $param['search_type']);
  274. }
  275. # 时间区间
  276. elseif(isset($v['search']) && (strpos($v['search'], 'time') !== false || strpos($v['search'], 'date') !== false))
  277. {
  278. $this->config['request'][$method][$type]['start_' . $k] = array('yes-' . $k, '>=');
  279. $this->config['request'][$method][$type]['end_' . $k] = array('yes-' . $k, '<=');
  280. }
  281. else
  282. {
  283. $this->config['request'][$method][$type][$k] = $v['match'];
  284. }
  285. }
  286. elseif($type != 'mul' && !isset($v['table']))
  287. {
  288. if(!empty($v['insert']) && $type == 'set')
  289. {
  290. }
  291. else
  292. {
  293. $this->config['request'][$method][$type][$k] = $v['value'];
  294. }
  295. }
  296. }
  297. }
  298. }
  299. //print_r($_POST);die;
  300. //print_r($this->config['request'][$method]);die;
  301. }
  302. /**
  303. * method
  304. *
  305. * @return mixd
  306. */
  307. public function method($method = 'one', $param = array())
  308. {
  309. if(isset($param[0]) && is_array($param[0]))
  310. {
  311. $result = array();
  312. foreach($param as $k => $v)
  313. {
  314. $result[] = $this->method($method, $v);
  315. }
  316. return $result;
  317. }
  318. if(!isset($this->config['request'][$method])) $this->init($method, $param);
  319. //print_r($this->config['request']);die;
  320. $this->config['param'] = array();
  321. if(isset($this->config['request']) && isset($this->config['request'][$method]))
  322. {
  323. $this->hack('request', 'onload');
  324. $this->hack($method, 'start');
  325. # 验证头部权限
  326. if(isset($this->config['auth']) && is_string($this->config['auth']))
  327. {
  328. $value = isset($param[$this->config['auth_key']]) ? $param[$this->config['auth_key']] : Input::get($this->config['auth_key']);
  329. if($value)
  330. {
  331. $top['value'] = $value;
  332. }
  333. else
  334. {
  335. $top = Load::get('manage/auth.getTop', array($this->config['auth']));
  336. }
  337. if($top)
  338. {
  339. if(!Input::get('where_' . $this->config['auth_key'])) Input::set('where_' . $this->config['auth_key'], $top['value']);
  340. if(!Input::get('option_' . $this->config['auth_key'])) Input::set('option_' . $this->config['auth_key'], $top['value']);
  341. if(!Input::get('set_' . $this->config['auth_key'])) Input::set('set_' . $this->config['auth_key'], $top['value']);
  342. if(!Input::get('add_' . $this->config['auth_key'])) Input::set('add_' . $this->config['auth_key'], $top['value']);
  343. }
  344. }
  345. if($param)
  346. {
  347. if(!is_array($param))
  348. {
  349. $param = array('where_id' => $param);
  350. }
  351. elseif(is_array($param) && isset($top))
  352. {
  353. if(!isset($param['where_' . $this->config['auth_key']])) $param['where_' . $this->config['auth_key']] = $top['value'];
  354. if(!isset($param['option_' . $this->config['auth_key']])) $param['option_' . $this->config['auth_key']] = $top['value'];
  355. if(!isset($param['set_' . $this->config['auth_key']])) $param['set_' . $this->config['auth_key']] = $top['value'];
  356. if(!isset($param['add_' . $this->config['auth_key']])) $param['add_' . $this->config['auth_key']] = $top['value'];
  357. }
  358. $this->config['param'] =& $param;
  359. }
  360. # 创建全局参数,给hack使用
  361. Config::$global['base']['_param'] = $this->config['param'];
  362. $this->config['response'] = $this->config['request'][$method];
  363. $this->push(array('where', 'add', 'set', 'option'))->condition(array('page', 'order', 'limit', 'group'));
  364. $type = isset($this->config['response']['type']) ? $this->config['response']['type'] : $method;
  365. $this->config['response']['col'] = isset($this->config['response']['col']) ? $this->config['response']['col'] : '';
  366. $data = $this->db()->$type($this->config['response']['col']);
  367. $this->hack($method, 'end', $data);
  368. return $data;
  369. }
  370. return array();
  371. }
  372. /**
  373. * hack 插件钩子处理
  374. * @param string $key
  375. *
  376. * @return mixd
  377. */
  378. private function hack($key, $method = 'start', $param = false)
  379. {
  380. # 不再继续执行hack,就设置这个参数
  381. if(Input::get('maze_onload') == 'no')
  382. {
  383. if($method == 'end')
  384. {
  385. Input::set('maze_onload', 'yes');
  386. }
  387. }
  388. elseif(isset($this->config[$method][$key]))
  389. {
  390. # 如果定义了auth,就要传过去
  391. if(isset($this->config['auth']) && is_array($this->config['auth']))
  392. {
  393. $param = array($param, $this->config['auth']);
  394. }
  395. if(is_array($this->config[$method][$key]))
  396. {
  397. foreach($this->config[$method][$key] as $k => $v)
  398. {
  399. Load::get($v, $param);
  400. }
  401. }
  402. else
  403. {
  404. Load::get($this->config[$method][$key], $param);
  405. }
  406. }
  407. }
  408. /**
  409. * push
  410. *
  411. * @return mixd
  412. */
  413. private function push($param)
  414. {
  415. foreach($param as $k => $v)
  416. {
  417. if(isset($this->config['response'][$v]))
  418. {
  419. # 验证传入参数与配置是否相同
  420. /*
  421. $request = Input::prefix($v . '_');
  422. if($v == 'where')
  423. {
  424. $request = Input::prefix('where_');
  425. }
  426. */
  427. $value = array();
  428. foreach($this->config['response'][$v] as $i => $j)
  429. {
  430. $t = array();
  431. if(is_array($j))
  432. {
  433. $t = $j;
  434. $j = $t[0];
  435. }
  436. $temp = $this->request($v. '_' . $i, $j, '', $i, $v);
  437. //if($temp || (($v == 'add' || $v == 'set') && $temp && $temp == 0))
  438. if($temp || (($v == 'add' || $v == 'set') && ($temp === '0' || $temp === 0)))
  439. //if($temp)
  440. {
  441. if(is_array($temp))
  442. {
  443. if(isset($this->config['struct'][$i]) && isset($this->config['struct'][$i]['bit']))
  444. {
  445. $vt = 0;
  446. foreach($temp as $ki => $vi)
  447. {
  448. if(isset($this->config['struct'][$i]['bit'][$vi]))
  449. {
  450. $vt += $this->config['struct'][$i]['bit'][$vi];
  451. }
  452. }
  453. $temp = $vt;
  454. }
  455. elseif(isset($temp[0]) && is_array($temp[0]))
  456. {
  457. $temp = base64_encode(json_encode($temp));
  458. }
  459. else
  460. {
  461. $temp = implode(',', $temp);
  462. }
  463. }
  464. if($temp == 'null')
  465. {
  466. $temp = '';
  467. }
  468. $g = array($i, $temp);
  469. if(isset($t[1]))
  470. {
  471. $g[2] = $t[1];
  472. }
  473. if(isset($t[2]))
  474. {
  475. $g[3] = $t[2];
  476. }
  477. $value[] = $g;
  478. }
  479. }
  480. if($value)
  481. {
  482. if($v == 'option')
  483. {
  484. $v = 'where';
  485. }
  486. $this->db()->$v($value);
  487. }
  488. }
  489. }
  490. return $this;
  491. }
  492. /**
  493. * condition
  494. *
  495. * @return mixd
  496. */
  497. private function condition($param)
  498. {
  499. foreach($param as $k => $v)
  500. {
  501. if(isset($this->config['response'][$v]))
  502. {
  503. if($v == 'page')
  504. {
  505. $value = $this->config['response'][$v];
  506. if(is_string($value[1]))
  507. {
  508. $temp[] = $value[1];
  509. unset($value[1]);
  510. $value[1] = $temp;
  511. }
  512. if(isset($value[2])) $value[1][2] = $value[2];
  513. if(isset($this->config['param']['page']))
  514. {
  515. $value[1] = array_merge($value[1], $this->config['param']['page']);
  516. }
  517. }
  518. else
  519. {
  520. $temp = '';
  521. $value = $this->request($v, $this->config['response'][$v], '-', $temp);
  522. if(!$value)
  523. {
  524. $value = $this->config['response'][$v];
  525. }
  526. }
  527. if(is_string($value))
  528. {
  529. $value = array($value, '');
  530. }
  531. if(empty($value[1])) $value[1] = '';
  532. $this->db()->$v($value[0], $value[1]);
  533. }
  534. }
  535. return $this;
  536. }
  537. /**
  538. * request
  539. *
  540. * @return mixd
  541. */
  542. private function request($key, $value, $split = '', &$index, $method = '')
  543. {
  544. //$index = str_replace(array('add_', 'where_', 'set_', 'option_'), '', $key);
  545. if($index && strpos($value, 'yes-') !== false)
  546. {
  547. $temp = explode('-', $value);
  548. $value = $temp[0];
  549. $index = $temp[1];
  550. }
  551. if($index && $value == 'yes' && isset($this->config['struct'][$index]) && is_array($this->config['struct'][$index]) && isset($this->config['struct'][$index]['match']) && $this->config['struct'][$index]['match'])
  552. {
  553. if(is_array($this->config['struct'][$index]['match']))
  554. {
  555. $value = $this->config['struct'][$index]['match'][0];
  556. }
  557. else
  558. {
  559. $value = $this->config['struct'][$index]['match'];
  560. }
  561. }
  562. $state = false;
  563. if(isset($this->config['param'][$key]))
  564. {
  565. $request = $this->config['param'][$key];
  566. }
  567. if($value == 'option')
  568. {
  569. $value = '';
  570. $state = true;
  571. }
  572. $callback = is_string($value) && function_exists($value);
  573. if($callback)
  574. {
  575. $callback = $value;
  576. $value = '';
  577. }
  578. if(empty($request))
  579. {
  580. if(isset($request) && $request == 0)
  581. {
  582. return $request;
  583. }
  584. $request = Input::get($key, $value);
  585. }
  586. if(($method == 'set' || $method == 'add') && empty($request) && isset($this->config['struct'][$index]['default']) && $this->config['struct'][$index]['default'])
  587. {
  588. //$request = $this->config['struct'][$index]['default'];
  589. }
  590. /*
  591. if(is_array($request))
  592. {
  593. $request = implode(',', $request);
  594. }
  595. */
  596. if(is_string($value) && strpos($value, '/') !== false)
  597. {
  598. $state = preg_match($value, $request);
  599. }
  600. elseif(!empty($request))
  601. {
  602. if($callback)
  603. {
  604. $state = $callback($request);
  605. }
  606. elseif(is_string($request) && $split && strpos($request, $split) !== false)
  607. {
  608. $request = explode($split, $request);
  609. }
  610. $state = true;
  611. }
  612. //Debug::log(array('text' => 'model', 'state' => $state, 'preg' => $value, 'key' => $key, 'value' => $request));
  613. if($state)
  614. {
  615. if($index && isset($this->config['struct'][$index]) && is_array($this->config['struct'][$index]) && isset($this->config['struct'][$index]['callback']) && $this->config['struct'][$index]['callback'] && $request)
  616. {
  617. $call = $this->config['struct'][$index]['callback'];
  618. if($call == 'maketime')
  619. {
  620. if(is_string($request))
  621. {
  622. $request = \Maze::maketime($request);
  623. }
  624. }
  625. else
  626. {
  627. $request = $call($request);
  628. }
  629. }
  630. return $request;
  631. }
  632. # error
  633. if($method != 'option' && $method != 'add' && $method != 'set')
  634. {
  635. if(isset($this->config['struct'][$index]['desc']) && $this->config['struct'][$index]['desc'])
  636. {
  637. Output::abert($this->config['struct'][$index]['desc']);
  638. }
  639. else
  640. {
  641. Output::abert('core_database_request', array($key, ($value ? $value : $callback)));
  642. }
  643. }
  644. return false;
  645. }
  646. }