369f3c46d2a38d1d37227a2c25c8466a763177a7.svn-base 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  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 'state':
  194. $this->config['request']['state'] = array
  195. (
  196. 'type' => 'one',
  197. 'where' => array
  198. (
  199. 'state' => 1,
  200. 'id' => 'yes'
  201. )
  202. );
  203. break;
  204. case 'list':
  205. $type = 'option';
  206. $this->config['request']['list'] = array
  207. (
  208. 'type' => 'all',
  209. 'order' => array('id', 'desc'),
  210. 'page' => array(15, 'list'),
  211. 'col' => '*|id',
  212. 'option' => array(),
  213. );
  214. if(isset($this->config['manage']['list_type']) && $this->config['manage']['list_type'] == 'parent')
  215. {
  216. $this->config['request']['list']['page'][0] = 500;
  217. }
  218. if(isset(Config::$global['base']['excel']))
  219. {
  220. unset($this->config['request']['list']['page']);
  221. }
  222. break;
  223. case 'total':
  224. $type = 'option';
  225. $this->config['request']['total'] = array
  226. (
  227. 'type' => 'all',
  228. 'col' => 'count(*) as total',
  229. 'group' => array('month'),
  230. 'option' => array(),
  231. );
  232. break;
  233. default:
  234. unset($this->config['request'][$method]);
  235. break;
  236. }
  237. if($type)
  238. {
  239. if($type == 'option')
  240. {
  241. $param['search_type'] = isset($param['search_type']) ? $param['search_type'] : Input::get('search_fulltext_type', 1);
  242. $param['search_type'] = $this->type($param['search_type']);
  243. }
  244. foreach($this->config['struct'] as $k => $v)
  245. {
  246. if(isset($v['match']))
  247. {
  248. # 这里增加value,用以区分update/select的值
  249. if(is_array($v['match']))
  250. {
  251. $v['value'] = $v['match'][1];
  252. $v['match'] = $v['match'][0];
  253. }
  254. else
  255. {
  256. $v['value'] = $v['match'];
  257. }
  258. # 首先匹配批量更新
  259. if($method == 'updatemul' && isset($v['update']) && $v['update'] == 'radio' && (is_array($v['option']) || is_object($v['option'])))
  260. {
  261. $this->config['request'][$method]['set'][$k] = $v['value'];
  262. }
  263. if($type == 'option')
  264. {
  265. # 位运算
  266. if(isset($v['bit']))
  267. {
  268. $this->config['request'][$method][$type][$k] = array('option', '&');
  269. }
  270. # 默认排序
  271. elseif(isset($v['order']))
  272. {
  273. if(isset($this->config['request'][$method]['order']))
  274. {
  275. if($this->config['request'][$method]['order'][0] && $this->config['request'][$method]['order'][0] != $k)
  276. {
  277. $this->config['request'][$method]['order'][0] = $k . '` '.(is_string($v['order']) ? $v['order'] : 'desc').',`' . $this->config['request'][$method]['order'][0];
  278. }
  279. }
  280. }
  281. # 全文检索
  282. if(isset($v['search']) && strpos($v['search'], 'fulltext') !== false)
  283. {
  284. $this->config['request'][$method][$type][$k] = array('option', $param['search_type']);
  285. }
  286. # 时间区间
  287. elseif(isset($v['search']) && (strpos($v['search'], 'time') !== false || strpos($v['search'], 'date') !== false))
  288. {
  289. $this->config['request'][$method][$type]['start_' . $k] = array('yes-' . $k, '>=');
  290. $this->config['request'][$method][$type]['end_' . $k] = array('yes-' . $k, '<=');
  291. }
  292. else
  293. {
  294. $this->config['request'][$method][$type][$k] = $v['match'];
  295. }
  296. }
  297. elseif($type != 'mul' && !isset($v['table']))
  298. {
  299. if(!empty($v['insert']) && $type == 'set')
  300. {
  301. }
  302. else
  303. {
  304. $this->config['request'][$method][$type][$k] = $v['value'];
  305. }
  306. }
  307. }
  308. }
  309. }
  310. //print_r($_POST);die;
  311. //print_r($this->config['request'][$method]);die;
  312. }
  313. /**
  314. * method
  315. *
  316. * @return mixd
  317. */
  318. public function method($method = 'one', $param = array())
  319. {
  320. if(isset($param[0]) && is_array($param[0]))
  321. {
  322. $result = array();
  323. foreach($param as $k => $v)
  324. {
  325. $result[] = $this->method($method, $v);
  326. }
  327. return $result;
  328. }
  329. if(!isset($this->config['request'][$method])) $this->init($method, $param);
  330. //print_r($this->config['request']);die;
  331. $this->config['param'] = array();
  332. if(isset($this->config['request']) && isset($this->config['request'][$method]))
  333. {
  334. $this->hack('request', 'onload');
  335. $this->hack($method, 'start');
  336. # 验证头部权限
  337. if(isset($this->config['auth']) && is_string($this->config['auth']))
  338. {
  339. $value = isset($param[$this->config['auth_key']]) ? $param[$this->config['auth_key']] : Input::get($this->config['auth_key']);
  340. if($value)
  341. {
  342. $top['value'] = $value;
  343. }
  344. else
  345. {
  346. $top = Load::get('manage/auth.getTop', array($this->config['auth']));
  347. }
  348. if($top)
  349. {
  350. if(!Input::get('where_' . $this->config['auth_key'])) Input::set('where_' . $this->config['auth_key'], $top['value']);
  351. if(!Input::get('option_' . $this->config['auth_key'])) Input::set('option_' . $this->config['auth_key'], $top['value']);
  352. if(!Input::get('set_' . $this->config['auth_key'])) Input::set('set_' . $this->config['auth_key'], $top['value']);
  353. if(!Input::get('add_' . $this->config['auth_key'])) Input::set('add_' . $this->config['auth_key'], $top['value']);
  354. }
  355. }
  356. if($param)
  357. {
  358. if(!is_array($param))
  359. {
  360. $param = array('where_id' => $param);
  361. }
  362. elseif(is_array($param) && isset($top))
  363. {
  364. if(!isset($param['where_' . $this->config['auth_key']])) $param['where_' . $this->config['auth_key']] = $top['value'];
  365. if(!isset($param['option_' . $this->config['auth_key']])) $param['option_' . $this->config['auth_key']] = $top['value'];
  366. if(!isset($param['set_' . $this->config['auth_key']])) $param['set_' . $this->config['auth_key']] = $top['value'];
  367. if(!isset($param['add_' . $this->config['auth_key']])) $param['add_' . $this->config['auth_key']] = $top['value'];
  368. }
  369. $this->config['param'] =& $param;
  370. }
  371. # 创建全局参数,给hack使用
  372. Config::$global['base']['_param'] = $this->config['param'];
  373. $this->config['response'] = $this->config['request'][$method];
  374. $this->push(array('where', 'add', 'set', 'option'))->condition(array('page', 'order', 'limit', 'group'));
  375. $type = isset($this->config['response']['type']) ? $this->config['response']['type'] : $method;
  376. $this->config['response']['col'] = isset($this->config['response']['col']) ? $this->config['response']['col'] : '';
  377. $data = $this->db()->$type($this->config['response']['col']);
  378. $this->hack($method, 'end', $data);
  379. return $data;
  380. }
  381. return array();
  382. }
  383. /**
  384. * hack 插件钩子处理
  385. * @param string $key
  386. *
  387. * @return mixd
  388. */
  389. private function hack($key, $method = 'start', $param = false)
  390. {
  391. # 不再继续执行hack,就设置这个参数
  392. if(Input::get('maze_onload') == 'no')
  393. {
  394. if($method == 'end')
  395. {
  396. Input::set('maze_onload', 'yes');
  397. }
  398. }
  399. elseif(isset($this->config[$method][$key]))
  400. {
  401. # 如果定义了auth,就要传过去
  402. if(isset($this->config['auth']) && is_array($this->config['auth']))
  403. {
  404. $param = array($param, $this->config['auth']);
  405. }
  406. if(is_array($this->config[$method][$key]))
  407. {
  408. foreach($this->config[$method][$key] as $k => $v)
  409. {
  410. Load::get($v, $param);
  411. }
  412. }
  413. else
  414. {
  415. Load::get($this->config[$method][$key], $param);
  416. }
  417. }
  418. }
  419. /**
  420. * push
  421. *
  422. * @return mixd
  423. */
  424. private function push($param)
  425. {
  426. foreach($param as $k => $v)
  427. {
  428. if(isset($this->config['response'][$v]))
  429. {
  430. # 验证传入参数与配置是否相同
  431. /*
  432. $request = Input::prefix($v . '_');
  433. if($v == 'where')
  434. {
  435. $request = Input::prefix('where_');
  436. }
  437. */
  438. $value = array();
  439. foreach($this->config['response'][$v] as $i => $j)
  440. {
  441. $t = array();
  442. if(is_array($j))
  443. {
  444. $t = $j;
  445. $j = $t[0];
  446. }
  447. $temp = $this->request($v. '_' . $i, $j, '', $i, $v);
  448. //if($temp || (($v == 'add' || $v == 'set') && $temp && $temp == 0))
  449. if($temp || (($v == 'add' || $v == 'set') && ($temp === '0' || $temp === 0)))
  450. //if($temp)
  451. {
  452. if(is_array($temp))
  453. {
  454. if(isset($this->config['struct'][$i]) && isset($this->config['struct'][$i]['bit']))
  455. {
  456. $vt = 0;
  457. foreach($temp as $ki => $vi)
  458. {
  459. if(isset($this->config['struct'][$i]['bit'][$vi]))
  460. {
  461. $vt += $this->config['struct'][$i]['bit'][$vi];
  462. }
  463. }
  464. $temp = $vt;
  465. }
  466. elseif(isset($temp[0]) && is_array($temp[0]))
  467. {
  468. $temp = base64_encode(json_encode($temp));
  469. }
  470. else
  471. {
  472. $temp = implode(',', $temp);
  473. }
  474. }
  475. if($temp == 'null')
  476. {
  477. $temp = '';
  478. }
  479. $g = array($i, $temp);
  480. if(isset($t[1]))
  481. {
  482. $g[2] = $t[1];
  483. }
  484. if(isset($t[2]))
  485. {
  486. $g[3] = $t[2];
  487. }
  488. $value[] = $g;
  489. }
  490. }
  491. if($value)
  492. {
  493. if($v == 'option')
  494. {
  495. $v = 'where';
  496. }
  497. $this->db()->$v($value);
  498. }
  499. }
  500. }
  501. return $this;
  502. }
  503. /**
  504. * condition
  505. *
  506. * @return mixd
  507. */
  508. private function condition($param)
  509. {
  510. foreach($param as $k => $v)
  511. {
  512. if(isset($this->config['response'][$v]))
  513. {
  514. if($v == 'page')
  515. {
  516. $value = $this->config['response'][$v];
  517. if(is_string($value[1]))
  518. {
  519. $temp[] = $value[1];
  520. unset($value[1]);
  521. $value[1] = $temp;
  522. }
  523. if(isset($value[2])) $value[1][2] = $value[2];
  524. if(isset($this->config['param']['page']))
  525. {
  526. $value[1] = array_merge($value[1], $this->config['param']['page']);
  527. }
  528. }
  529. else
  530. {
  531. $temp = '';
  532. $value = $this->request($v, $this->config['response'][$v], '-', $temp);
  533. if(!$value)
  534. {
  535. $value = $this->config['response'][$v];
  536. }
  537. }
  538. if(is_string($value))
  539. {
  540. $value = array($value, '');
  541. }
  542. if(empty($value[1])) $value[1] = '';
  543. $this->db()->$v($value[0], $value[1]);
  544. }
  545. }
  546. return $this;
  547. }
  548. /**
  549. * request
  550. *
  551. * @return mixd
  552. */
  553. private function request($key, $value, $split = '', &$index, $method = '')
  554. {
  555. //$index = str_replace(array('add_', 'where_', 'set_', 'option_'), '', $key);
  556. if($index && strpos($value, 'yes-') !== false)
  557. {
  558. $temp = explode('-', $value);
  559. $value = $temp[0];
  560. $index = $temp[1];
  561. }
  562. 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'])
  563. {
  564. if(is_array($this->config['struct'][$index]['match']))
  565. {
  566. $value = $this->config['struct'][$index]['match'][0];
  567. }
  568. else
  569. {
  570. $value = $this->config['struct'][$index]['match'];
  571. }
  572. }
  573. $state = false;
  574. if(isset($this->config['param'][$key]))
  575. {
  576. $request = $this->config['param'][$key];
  577. }
  578. if($value == 'option')
  579. {
  580. $value = '';
  581. $state = true;
  582. }
  583. $callback = is_string($value) && function_exists($value);
  584. if($callback)
  585. {
  586. $callback = $value;
  587. $value = '';
  588. }
  589. if(empty($request))
  590. {
  591. if(isset($request) && $request == 0)
  592. {
  593. return $request;
  594. }
  595. $request = Input::get($key, $value);
  596. }
  597. if(($method == 'set' || $method == 'add') && empty($request) && isset($this->config['struct'][$index]['default']) && $this->config['struct'][$index]['default'])
  598. {
  599. //$request = $this->config['struct'][$index]['default'];
  600. }
  601. /*
  602. if(is_array($request))
  603. {
  604. $request = implode(',', $request);
  605. }
  606. */
  607. if(is_string($value) && strpos($value, '/') !== false)
  608. {
  609. $state = preg_match($value, $request);
  610. }
  611. elseif(!empty($request))
  612. {
  613. if($callback)
  614. {
  615. $state = $callback($request);
  616. }
  617. elseif(is_string($request) && $split && strpos($request, $split) !== false)
  618. {
  619. $request = explode($split, $request);
  620. }
  621. $state = true;
  622. }
  623. //Debug::log(array('text' => 'model', 'state' => $state, 'preg' => $value, 'key' => $key, 'value' => $request));
  624. if($state)
  625. {
  626. 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)
  627. {
  628. $call = $this->config['struct'][$index]['callback'];
  629. if($call == 'maketime')
  630. {
  631. if(is_string($request))
  632. {
  633. $request = \Maze::maketime($request);
  634. }
  635. }
  636. else
  637. {
  638. $request = $call($request);
  639. }
  640. }
  641. return $request;
  642. }
  643. # error
  644. if($method != 'option' && $method != 'add' && $method != 'set')
  645. {
  646. if(isset($this->config['struct'][$index]['desc']) && $this->config['struct'][$index]['desc'])
  647. {
  648. Output::abert($this->config['struct'][$index]['desc']);
  649. }
  650. else
  651. {
  652. Output::abert('core_database_request', array($key, ($value ? $value : $callback)));
  653. }
  654. }
  655. return false;
  656. }
  657. }