pivotstate.class.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575
  1. <?php
  2. class pivotState
  3. {
  4. /**
  5. * Pivot state ID.
  6. *
  7. * @var int
  8. * @access public
  9. */
  10. public $id;
  11. /**
  12. * Pivot state dimension.
  13. *
  14. * @var string
  15. * @access public
  16. */
  17. public $dimension;
  18. /**
  19. * Pivot state group.
  20. *
  21. * @var string
  22. * @access public
  23. */
  24. public $group;
  25. /**
  26. * Pivot state code.
  27. *
  28. * @var string
  29. * @access public
  30. */
  31. public $code;
  32. /**
  33. * Pivot state driver.
  34. *
  35. * @var string
  36. * @access public
  37. */
  38. public $driver;
  39. /**
  40. * Pivot state mode.
  41. *
  42. * @var string
  43. * @access public
  44. */
  45. public $mode;
  46. /**
  47. * Pivot state name.
  48. *
  49. * @var string
  50. * @access public
  51. */
  52. public $name;
  53. /**
  54. * Pivot state names.
  55. *
  56. * @var array
  57. * @access public
  58. */
  59. public $names;
  60. /**
  61. * Pivot state description.
  62. *
  63. * @var string
  64. * @access public
  65. */
  66. public $desc;
  67. /**
  68. * Pivot state descriptions.
  69. *
  70. * @var array
  71. * @access public
  72. */
  73. public $descs;
  74. /**
  75. * Pivot state SQL.
  76. *
  77. * @var string
  78. * @access public
  79. */
  80. public $sql;
  81. /**
  82. * Pivot state fields.
  83. *
  84. * @var array
  85. * @access public
  86. */
  87. public $fields;
  88. /**
  89. * Pivot state fieldSettings.
  90. *
  91. * @var array
  92. * @access public
  93. */
  94. public $fieldSettings;
  95. /**
  96. * Pivot state relatedObject.
  97. * e.g array('id' => 'action')
  98. *
  99. * @var array
  100. * @access public
  101. */
  102. public $relatedObject;
  103. /**
  104. * Pivot state languages.
  105. *
  106. * @var array
  107. * @access public
  108. */
  109. public $langs;
  110. /**
  111. * client languages.
  112. *
  113. * @var array
  114. * @access public
  115. */
  116. public $clientLang;
  117. /**
  118. * Pivot state variables.
  119. *
  120. * @var array
  121. * @access public
  122. */
  123. public $vars;
  124. /**
  125. * Pivot state objects.
  126. *
  127. * @var array
  128. * @access public
  129. */
  130. public $objects;
  131. /**
  132. * Pivot state settings.
  133. *
  134. * @var array
  135. * @access public
  136. */
  137. public $settings;
  138. /**
  139. * Pivot state filters.
  140. *
  141. * @var array
  142. * @access public
  143. */
  144. public $filters;
  145. /**
  146. * Pivot state default drill.
  147. *
  148. * @var array
  149. * @access public
  150. */
  151. public $defaultDrill;
  152. /**
  153. * Pivot state drills.
  154. *
  155. * @var array
  156. * @access public
  157. */
  158. public $drills;
  159. /**
  160. * Pivot state step.
  161. *
  162. * @var int
  163. * @access public
  164. */
  165. public $step;
  166. /**
  167. * Pivot state stage.
  168. *
  169. * @var string
  170. * @access public
  171. */
  172. public $stage;
  173. /**
  174. * Pivot state version.
  175. *
  176. * @var string
  177. * @access public
  178. */
  179. public $version;
  180. /**
  181. * Pivot state acl.
  182. *
  183. * @var string
  184. * @access public
  185. */
  186. public $acl;
  187. /**
  188. * Pivot state used.
  189. *
  190. * @var string
  191. * @access public
  192. */
  193. public $used;
  194. /**
  195. * Pivot state whitelist.
  196. *
  197. * @var string
  198. * @access public
  199. */
  200. public $whitelist;
  201. /**
  202. * Pivot stage action.
  203. *
  204. * @var string
  205. * @access public
  206. */
  207. public $action = 'design';
  208. /**
  209. * error
  210. *
  211. * @var bool
  212. * @access public
  213. */
  214. public $error = false;
  215. /**
  216. * errorMsg
  217. *
  218. * @var string
  219. * @access public
  220. */
  221. public $errorMsg = '';
  222. /**
  223. * queryCols
  224. *
  225. * @var array
  226. * @access public
  227. */
  228. public $queryCols = array();
  229. /**
  230. * queryData
  231. *
  232. * @var array
  233. * @access public
  234. */
  235. public $queryData = array();
  236. /**
  237. * pivotCols
  238. *
  239. * @var array
  240. * @access public
  241. */
  242. public $pivotCols = array();
  243. /**
  244. * pivotData
  245. *
  246. * @var array
  247. * @access public
  248. */
  249. public $pivotData = array();
  250. /**
  251. * pivotCellSpan
  252. *
  253. * @var array
  254. * @access public
  255. */
  256. public $pivotCellSpan = array();
  257. /**
  258. * pivotFilters
  259. *
  260. * @var array
  261. * @access public
  262. */
  263. public $pivotFilters = array();
  264. /**
  265. * pager
  266. *
  267. * @var int
  268. * @access public
  269. */
  270. public $pager;
  271. /**
  272. * sqlChanged
  273. *
  274. * @var bool
  275. * @access public
  276. */
  277. public $sqlChanged = false;
  278. /**
  279. * filterChanged.
  280. *
  281. * @var bool
  282. * @access public
  283. */
  284. public $filterChanged = false;
  285. /**
  286. * addQueryFilter
  287. *
  288. * @var array
  289. * @access public
  290. */
  291. public $addQueryFilter = array();
  292. /**
  293. * step2 finish with Sql, used to judge if step1 sql changed
  294. *
  295. * @var string
  296. * @access public
  297. */
  298. public $step2FinishSql = '';
  299. /**
  300. * First enter design.
  301. *
  302. * @var bool
  303. * @access public
  304. */
  305. public $firstEnterDesign = false;
  306. /**
  307. * Auto gen drills.
  308. *
  309. * @var bool
  310. * @access public
  311. */
  312. public $autoGenDrills = false;
  313. /**
  314. * Check step design.
  315. *
  316. * @var bool
  317. * @access public
  318. */
  319. public $checkStepDesign = false;
  320. public $triggerQuery = false;
  321. public $canChangeMode = true;
  322. public $sqlbuilder = array();
  323. /**
  324. * __construct method.
  325. *
  326. * @param pivot object
  327. * @param drills array
  328. * @param clientLang string
  329. * @access public
  330. * @return void
  331. */
  332. public function __construct($pivot, $drills = array(), $clientLang = 'zh-cn', $sqlbuilder = array())
  333. {
  334. $this->id = $pivot->id;
  335. $this->dimension = $pivot->dimension;
  336. $this->group = $pivot->group;
  337. $this->code = $pivot->code;
  338. $this->driver = $pivot->driver;
  339. $this->mode = $pivot->mode;
  340. $this->name = $pivot->name;
  341. $this->desc = $pivot->desc;
  342. $this->names = $pivot->names;
  343. $this->descs = $pivot->descs;
  344. $this->sql = $pivot->sql;
  345. $this->step = 'query';
  346. $this->stage = $pivot->stage;
  347. $this->version = $pivot->version;
  348. $this->acl = $pivot->acl;
  349. $this->whitelist = $pivot->whitelist;
  350. $this->drills = $drills;
  351. $this->defaultDrill = $this->initDrill();
  352. $this->sqlbuilder = $sqlbuilder;
  353. $this->fields = $this->json2Array($pivot->fieldSettings);
  354. $this->langs = $this->json2Array($pivot->langs);
  355. $this->vars = $this->json2Array($pivot->vars);
  356. $this->objects = $this->json2Array($pivot->objects);
  357. $this->settings = $this->json2Array($pivot->settings);
  358. $this->filters = $this->json2Array($pivot->filters);
  359. $this->clientLang = $clientLang;
  360. $this->fieldSettings = array_merge_recursive($this->fields, $this->langs);
  361. $this->setPager();
  362. $this->formatSettingColumns();
  363. $this->setStep2FinishSql();
  364. }
  365. /**
  366. * Process query filters.
  367. *
  368. * @access public
  369. * @return void
  370. */
  371. public function processQueryFilters()
  372. {
  373. if($this->mode == 'text') return;
  374. $querys = $this->sqlbuilder->querys;
  375. $this->clearFilters();
  376. if(empty($querys)) return;
  377. if($this->sqlbuilder->checkQuerys() !== true) return;
  378. foreach($querys as $index => $query)
  379. {
  380. $filter = $this->getDefaultQueryFilter();
  381. $field = "var$index";
  382. foreach(array_keys($filter) as $key)
  383. {
  384. if($key == 'field') $filter[$key] = $field;
  385. elseif(isset($query[$key])) $filter[$key] = $query[$key];
  386. }
  387. $filter['from'] = 'query';
  388. $this->filters[] = $filter;
  389. }
  390. }
  391. /**
  392. * Match field setting from builder.
  393. *
  394. * @param string $key
  395. * @param array $setting
  396. * @access public
  397. * @return array
  398. */
  399. public function matchFieldSettingFromBuilder($key, $setting)
  400. {
  401. if($this->mode == 'text') return $setting;
  402. $selects = array_merge($this->sqlbuilder->getSelects(), $this->sqlbuilder->getFuncSelects());
  403. foreach($selects as $select)
  404. {
  405. list($table, $field, $alias) = $select;
  406. if($key != $alias) continue;
  407. $fieldList = $this->sqlbuilder->getTableDescList($table);
  408. $name = zget($fieldList, $field, $field);
  409. $setting[$this->clientLang] = $name;
  410. $setting['field'] = $field;
  411. }
  412. return $setting;
  413. }
  414. /**
  415. * Clear fieldSettings.
  416. *
  417. * @access public
  418. * @return void
  419. */
  420. public function clearFieldSettings()
  421. {
  422. $this->fields = array();
  423. $this->langs = array();
  424. $this->fieldSettings = array();
  425. $this->relatedObject = array();
  426. }
  427. /**
  428. * Clear settings.
  429. *
  430. * @param int $init
  431. * @access public
  432. * @return void
  433. */
  434. public function clearSettings($init = false)
  435. {
  436. $this->settings = array();
  437. if($init) $this->completeSettings();
  438. }
  439. /**
  440. * Clear column drill.
  441. *
  442. * @access public
  443. * @return void
  444. */
  445. public function clearColumnDrill()
  446. {
  447. if(empty($this->settings)) return;
  448. if(!isset($this->settings['columns']) || empty($this->settings['columns'])) return;
  449. $columns = $this->settings['columns'];
  450. foreach($columns as $index => $column)
  451. {
  452. if(isset($column['drill'])) unset($this->settings['columns'][$index]['drill']);
  453. }
  454. }
  455. /**
  456. * Clear filters.
  457. *
  458. * @access public
  459. * @return void
  460. */
  461. public function clearFilters()
  462. {
  463. $this->filters = array();
  464. $this->pivotFilters = array();
  465. }
  466. /**
  467. * Clear drills.
  468. *
  469. * @access public
  470. * @return void
  471. */
  472. public function clearDrills()
  473. {
  474. $this->drills = array();
  475. }
  476. /**
  477. * Sql changed.
  478. *
  479. * @access public
  480. * @return void
  481. */
  482. public function sqlChanged()
  483. {
  484. $this->queryCols = array();
  485. $this->queryData = array();
  486. }
  487. /**
  488. * Get filters.
  489. *
  490. * @access public
  491. * @return array
  492. */
  493. public function getFilters()
  494. {
  495. $filters = array();
  496. $filterValues = array();
  497. if(!empty($this->pivotFilters))
  498. {
  499. $pivotFilters = array();
  500. foreach($this->pivotFilters as $pivotFilter) $pivotFilters = array_merge($pivotFilters, $pivotFilter);
  501. foreach($pivotFilters as $pivotFilter) $filterValues[$pivotFilter['name']] = $pivotFilter['value'];
  502. }
  503. foreach($this->filters as $filter)
  504. {
  505. $value = zget($filterValues, $filter['field'], $filter['default']);
  506. if(is_array($value)) $value = array_filter($value);
  507. if(isset($filterValues[$filter['field']])) $filter['default'] = $value;
  508. $filters[$filter['field']] = $filter;
  509. }
  510. return $filters;
  511. }
  512. /**
  513. * Add filter.
  514. *
  515. * @access public
  516. * @return void
  517. */
  518. public function addFilter()
  519. {
  520. $firstKey = key($this->fieldSettings);
  521. $firstField = current($this->fieldSettings);
  522. $lang = $this->clientLang;
  523. $this->filters[] = array('field' => $firstKey, 'saveAs' => '', 'type' => 'input', 'name' => $firstField[$lang], 'default' => '');
  524. }
  525. /**
  526. * Judge is query filter or not.
  527. *
  528. * @param array $filters
  529. * @access public
  530. * @return bool
  531. */
  532. public function isQueryFilter($filters = array())
  533. {
  534. $filters = empty($filters) ? $this->filters : $filters;
  535. if(empty($filters)) return false;
  536. $filter = current($filters);
  537. return isset($filter['from']) && $filter['from'] == 'query';
  538. }
  539. /**
  540. * Save query filter.
  541. *
  542. * @access public
  543. * @return void
  544. */
  545. public function saveQueryFilter()
  546. {
  547. $filter = $this->addQueryFilter;
  548. $filter['from'] = 'query';
  549. $this->filters[] = $filter;
  550. $this->addQueryFilter = array();
  551. }
  552. /**
  553. * Add variable to sql.
  554. *
  555. * @access public
  556. * @return void
  557. */
  558. public function addVariableToSql()
  559. {
  560. $variable = $this->addQueryFilter['field'];
  561. $this->sql .= "\$$variable";
  562. }
  563. /**
  564. * Complete filters default.
  565. *
  566. * @access public
  567. * @return void
  568. */
  569. public function completeFiltersDefault()
  570. {
  571. $queryDefaults = array('select' => '', 'input' => '', 'date' => '', 'datetime' => '');
  572. $resultDefaults = array('select' => array(), 'input' => '', 'date' => array('begin' => '', 'end' => ''), 'datetime' => array('begin' => '', 'end' => ''));
  573. foreach($this->filters as $index => $filter)
  574. {
  575. if(isset($filter['default'])) continue;
  576. $from = zget($filter, 'from', 'result');
  577. $type = $filter['type'];
  578. $defaults = $from == 'query' ? $queryDefaults : $resultDefaults;
  579. $filter['default'] = $defaults[$type];
  580. $this->filters[$index] = $filter;
  581. }
  582. }
  583. /**
  584. * Convert filters to where conditions.
  585. *
  586. * @param array $filters
  587. * @access public
  588. * @return array
  589. */
  590. public function convertFiltersToWhere($filters)
  591. {
  592. if($this->isQueryFilter($filters)) return array_values($filters);
  593. $filterWheres = array();
  594. foreach($filters as $filter)
  595. {
  596. $field = $filter['field'];
  597. $default = zget($filter, 'default', '');
  598. $type = $filter['type'];
  599. if(empty($default)) continue;
  600. switch($type)
  601. {
  602. case 'select':
  603. if(is_string($default) && strpos($default, ',') !== false) $default = explode(',', $default);
  604. if(is_array($default)) $default = implode("', '", array_filter($default, function($val){return trim($val) != '';}));
  605. if(empty($default)) break;
  606. $value = "('" . $default . "')";
  607. $filterWheres[$field] = array('operator' => 'IN', 'type' => $type, 'value' => $value);
  608. break;
  609. case 'input':
  610. $filterWheres[$field] = array('operator' => 'LIKE', 'type' => $type, 'value' => "'%$default%'");
  611. break;
  612. case 'date':
  613. case 'datetime':
  614. $begin = $default['begin'];
  615. $end = $default['end'];
  616. if(!empty($begin)) $begin = date('Y-m-d 00:00:00', strtotime($begin));
  617. if(!empty($end)) $end = date('Y-m-d 23:59:59', strtotime($end));
  618. if(!empty($begin) && empty($end)) $filterWheres[$field] = array('operator' => '>=', 'type' => $type, 'value' => "'{$begin}'");
  619. if( empty($begin) && !empty($end)) $filterWheres[$field] = array('operator' => '<=', 'type' => $type, 'value' => "'{$end}'");
  620. if(!empty($begin) && !empty($end)) $filterWheres[$field] = array('operator' => 'BETWEEN', 'type' => $type, 'value' => "'{$begin}' AND '{$end}'");
  621. break;
  622. default:
  623. break;
  624. }
  625. }
  626. return $filterWheres;
  627. }
  628. /**
  629. * Set filters default value.
  630. *
  631. * @param array $filterValues
  632. * @access public
  633. * @return void
  634. */
  635. public function setFiltersDefaultValue($filterValues)
  636. {
  637. $filters = array();
  638. foreach($this->filters as $index => $filter)
  639. {
  640. if(!isset($filterValues[$index])) continue;
  641. $default = $filterValues[$index];
  642. $type = $filter['type'];
  643. $from = zget($filter, 'from', 'result');
  644. if($type == 'select' && is_array($default)) $default = array_filter($default);
  645. if($type == 'date' || $type == 'datetime')
  646. {
  647. if($from == 'query')
  648. {
  649. $format = $type == 'datetime' ? 'Y-m-d H:i:s' : 'Y-m-d';
  650. switch($default)
  651. {
  652. case '$MONDAY': $default = date($format, time() - (date('N') - 1) * 24 * 3600); break;
  653. case '$SUNDAY': $default = date($format, time() + (7 - date('N')) * 24 * 3600); break;
  654. case '$MONTHBEGIN': $default = date($format, time() - (date('j') - 1) * 24 * 3600); break;
  655. case '$MONTHEND': $default = date($format, time() + (date('t') - date('j')) * 24 * 3600); break;
  656. default:
  657. if(is_numeric($default)) $default = date('Y-m-d H:i:s', $default / 1000);
  658. break;
  659. }
  660. }
  661. else
  662. {
  663. if(is_array($default))
  664. {
  665. $begin = $default['begin'];
  666. $end = $default['end'];
  667. if(is_numeric($begin)) $begin = date('Y-m-d H:i:s', $begin / 1000);
  668. if(is_numeric($end)) $end = date('Y-m-d H:i:s', $end / 1000);
  669. $default = array('begin' => $begin, 'end' => $end);
  670. }
  671. else
  672. {
  673. $default = array('begin' => '', 'end' => '');
  674. }
  675. }
  676. }
  677. $filter['default'] = $default;
  678. $filters[] = $filter;
  679. }
  680. return $filters;
  681. }
  682. /**
  683. * Complete settings.
  684. *
  685. * @access public
  686. * @return void
  687. */
  688. public function isSummaryNotUse()
  689. {
  690. return (isset($this->settings['summary']) && $this->settings['summary'] === 'notuse');
  691. }
  692. /**
  693. * Complete settings.
  694. *
  695. * @access public
  696. * @return void
  697. */
  698. public function completeSettings()
  699. {
  700. if($this->isSummaryNotUse())
  701. {
  702. $this->settings['drills'] = array_column($this->drills, 'condition', 'field');
  703. return;
  704. }
  705. $settings = $this->settings;
  706. if(!isset($settings['summary']) || $settings['summary'] !== 'notuse') $this->settings['summary'] = 'use';
  707. if(!isset($settings['group1'])) $this->settings['group1'] = '';
  708. if(!isset($settings['columns']) || empty($settings['columns'])) $this->addColumn();
  709. if(!isset($settings['columnTotal'])) $this->settings['columnTotal'] = 'noShow';
  710. if(!isset($settings['columnPosition'])) $this->settings['columnPosition'] = 'bottom';
  711. foreach($this->settings['columns'] as $index => $column)
  712. {
  713. $this->settings['columns'][$index] = array_merge($this->getDefaultColumn(), $column);
  714. unset($this->settings['columns'][$index]['drill']);
  715. foreach($this->drills as $drill)
  716. {
  717. if(empty($drill)) continue;
  718. if($drill['field'] == $column['field']) $this->settings['columns'][$index]['drill'] = $drill;
  719. }
  720. }
  721. }
  722. /**
  723. * Process column show origin.
  724. *
  725. * @access public
  726. * @return void
  727. */
  728. public function processColumnShowOrigin()
  729. {
  730. if(empty($this->settings['columns'])) return;
  731. $columns = $this->settings['columns'];
  732. foreach($columns as $index => $column)
  733. {
  734. $showOrigin = $column['showOrigin'];
  735. $defaultColumn = $this->getDefaultColumn();
  736. $columns[$index] = $showOrigin ? array('field' => $column['field'], 'showOrigin' => 1) : array_merge($defaultColumn, $column);
  737. }
  738. $this->settings['columns'] = $columns;
  739. }
  740. /**
  741. * Get field options.
  742. *
  743. * @access public
  744. * @return array
  745. */
  746. public function getFieldOptions()
  747. {
  748. $options = array();
  749. $lang = $this->clientLang;
  750. foreach($this->fieldSettings as $field => $settings)
  751. {
  752. $name = zget($settings, 'name', $field);
  753. $text = zget($settings, $lang, $name);
  754. $options[] = array('text' => $text, 'value' => $field, 'key' => $field);
  755. }
  756. return $options;
  757. }
  758. /**
  759. * Get setting groups.
  760. *
  761. * @access public
  762. * @return array
  763. */
  764. public function getSettingGroups()
  765. {
  766. $groups = array();
  767. $settings = $this->settings;
  768. $keys = array_keys($settings);
  769. foreach($keys as $key) if(strpos($key, 'group') === 0) $groups[$key] = $settings[$key];
  770. return $groups;
  771. }
  772. /**
  773. * Get setting columns.
  774. *
  775. * @access public
  776. * @return array
  777. */
  778. public function getSettingColumns()
  779. {
  780. return $this->settings['columns'];
  781. }
  782. /**
  783. * Add column.
  784. *
  785. * @access public
  786. * @return void
  787. */
  788. public function addColumn()
  789. {
  790. $this->settings['columns'][] = $this->getDefaultColumn();
  791. }
  792. /**
  793. * Init drill.
  794. *
  795. * @access public
  796. * @return void
  797. */
  798. public function initDrill()
  799. {
  800. return array('field' => '', 'object' => '', 'referSQL' => '', 'whereSQL' => '', 'type' => 'manual', 'condition' => array($this->addCondition()));
  801. }
  802. /**
  803. * Add drill.
  804. *
  805. * @access public
  806. * @return void
  807. */
  808. public function addDrill($drill)
  809. {
  810. $this->drills[] = $drill;
  811. }
  812. /**
  813. * Add condition.
  814. *
  815. * @access public
  816. * @return void
  817. */
  818. public function addCondition()
  819. {
  820. return array('drillObject' => '', 'drillAlias' => '', 'drillField' => '', 'queryField' => '');
  821. }
  822. /**
  823. * Get default column.
  824. *
  825. * @param string|null $field
  826. * @access public
  827. * @return void
  828. */
  829. public function getDefaultColumn($field = null)
  830. {
  831. if(empty($field))
  832. {
  833. $field = key($this->fieldSettings);
  834. }
  835. return array('field' => $field, 'slice' => 'noSlice', 'stat' => 'count', 'showTotal' => 'noShow', 'showMode' => 'default', 'monopolize' => 0, 'showOrigin' => 0);
  836. }
  837. /**
  838. * Get default query filter.
  839. *
  840. * @access public
  841. * @return array
  842. */
  843. public function getDefaultQueryFilter()
  844. {
  845. return array('field' => '', 'name' => '', 'type' => 'input', 'typeOption' => '', 'default' => '', 'items' => array());
  846. }
  847. /**
  848. * Update from $_POST.
  849. *
  850. * @param array $post
  851. * @access public
  852. * @return void
  853. */
  854. public function updateFromPost($post)
  855. {
  856. if(!isset($post['data'])) return;
  857. $data = json_decode($post['data'], true);
  858. foreach($data as $key => $value)
  859. {
  860. if(!empty($value['sql'])) $value['sql'] = base64_encode($value['sql']);
  861. $this->$key = $key == 'sql' ? base64_decode($value) : $value;
  862. }
  863. $this->formatSettingColumns();
  864. $this->processFieldSettingsLang();
  865. $this->completeFiltersDefault();
  866. $this->canChangeMode = $this->setCanChangeMode();
  867. }
  868. /**
  869. * Set can change mode.
  870. *
  871. * @access public
  872. * @return bool
  873. */
  874. public function setCanChangeMode()
  875. {
  876. if($this->mode == 'builder') return true;
  877. if($this->mode == 'text' && empty($this->sql)) return true;
  878. return false;
  879. }
  880. /**
  881. * Update from cache.
  882. *
  883. * @param object $cache
  884. * @access public
  885. * @return void
  886. */
  887. public function updateFromCache($cache)
  888. {
  889. if($cache === false) return;
  890. foreach($cache as $key => $value)
  891. {
  892. if(is_array($value) || is_object($value)) $value = json_decode(json_encode($value), true);
  893. $this->$key = $value;
  894. }
  895. $this->formatSettingColumns();
  896. $this->processFieldSettingsLang();
  897. $this->completeFiltersDefault();
  898. $this->canChangeMode = $this->setCanChangeMode();
  899. }
  900. /**
  901. * Format setting columns.
  902. *
  903. * @access public
  904. * @return void
  905. */
  906. public function formatSettingColumns()
  907. {
  908. if(empty($this->settings->columns)) return;
  909. foreach($this->settings->columns as $id => $column)
  910. {
  911. $column['monopolize'] = (int)$column['monopolize'];
  912. $column['showOrigin'] = (int)$column['showOrigin'];
  913. $this->settings->columns[$id] = $column;
  914. }
  915. }
  916. /**
  917. * Clear properies before query sql.
  918. *
  919. * @access public
  920. * @return void
  921. */
  922. public function beforeQuerySql()
  923. {
  924. $this->error = false;
  925. $this->errorMsg = '';
  926. $this->queryCols = array();
  927. $this->queryData = array();
  928. $this->pivotCols = array();
  929. $this->pivotData = array();
  930. $this->pivotCellSpan = array();
  931. }
  932. /**
  933. * Set fieldSettings with merge.
  934. *
  935. * @param array $settings
  936. * @access public
  937. * @return void
  938. */
  939. public function setFieldSettings($settings)
  940. {
  941. $settings = (array)$settings;
  942. $oldFieldSettings = !empty($this->fieldSettings) ? $this->fieldSettings : array();
  943. $newFieldSettings = array();
  944. foreach($settings as $field => $setting)
  945. {
  946. $oldSetting = isset($oldFieldSettings[$field]) ? $oldFieldSettings[$field] : array();
  947. if(!empty($oldSetting))
  948. {
  949. $newFieldSettings[$field] = $this->processFieldSettingLang($field, $oldSetting, $setting);
  950. if($setting['type'] != $oldSetting['type'] && in_array($setting['type'], array('user', 'type'))) $newFieldSettings[$field]['type'] = $setting['type'];
  951. }
  952. else
  953. {
  954. // $newFieldSettings[$field] = $setting;
  955. $newFieldSettings[$field] = $this->matchFieldSettingFromBuilder($field, $setting);
  956. }
  957. }
  958. $this->fields = $this->json2Array($newFieldSettings);
  959. $this->fieldSettings = $newFieldSettings;
  960. }
  961. /**
  962. * Set drills.
  963. *
  964. * @param array $drills
  965. * @access public
  966. * @return void
  967. */
  968. public function setDrills($drills)
  969. {
  970. $this->drills = json_decode(json_encode($drills), true);
  971. }
  972. /**
  973. * Set filters.
  974. *
  975. * @param array $drills
  976. * @access public
  977. * @return void
  978. */
  979. public function setFilters($filters)
  980. {
  981. $this->filters = json_decode(json_encode($filters), true);
  982. }
  983. /**
  984. * Set field related object.
  985. *
  986. * @param array $relatedObject
  987. * @access public
  988. * @return void
  989. */
  990. public function setFieldRelatedObject($relatedObject)
  991. {
  992. $this->relatedObject = $relatedObject;
  993. }
  994. /**
  995. * Set step2 finishsql.
  996. *
  997. * @access public
  998. * @return void
  999. */
  1000. public function setStep2FinishSql()
  1001. {
  1002. if($this->issetSettings()) $this->step2FinishSql = $this->sql;
  1003. }
  1004. /**
  1005. * isset pivot setting.
  1006. *
  1007. * @access public
  1008. * @return void
  1009. */
  1010. public function issetSettings()
  1011. {
  1012. if($this->isSummaryNotUse()) return true;
  1013. if(empty($this->getSettingGroups())) return false;
  1014. $columns = $this->getSettingColumns();
  1015. if(count($columns) == 1 && empty($columns[0]['field'])) return false;
  1016. return true;
  1017. }
  1018. /**
  1019. * Process fieldSettings lang.
  1020. *
  1021. * @access public
  1022. * @return void
  1023. */
  1024. public function processFieldSettingsLang()
  1025. {
  1026. if(empty($this->fieldSettings)) return;
  1027. foreach($this->fieldSettings as $field => $fieldSetting)
  1028. {
  1029. $this->fieldSettings[$field] = $this->processFieldSettingLang($field, $fieldSetting);
  1030. }
  1031. }
  1032. /**
  1033. * Process fieldSetting lang.
  1034. *
  1035. * @param string $field
  1036. * @param array $fieldSetting
  1037. * @param array $newSetting
  1038. * @access public
  1039. * @return array
  1040. */
  1041. public function processFieldSettingLang($field, $oldSetting, $newSetting = array())
  1042. {
  1043. $lang = $this->clientLang;
  1044. if(!empty($oldSetting[$lang])) return $oldSetting;
  1045. if(!empty($newSetting[$lang]))
  1046. {
  1047. $oldSetting[$lang] = $newSetting[$lang];
  1048. return $oldSetting;
  1049. }
  1050. $oldSetting[$lang] = isset($oldSetting['name']) ? $oldSetting['name'] : $field;
  1051. return $oldSetting;
  1052. }
  1053. /**
  1054. * Build cols for query sql with lang.
  1055. *
  1056. * @access public
  1057. * @return object
  1058. */
  1059. public function buildQuerySqlCols()
  1060. {
  1061. $cols = array();
  1062. $lang = $this->clientLang;
  1063. foreach($this->fieldSettings as $field => $settings)
  1064. {
  1065. $settings = (array)$settings;
  1066. $title = isset($settings[$lang]) ? $settings[$lang] : $field;
  1067. $cols[] = array('name' => $field, 'title' => $title, 'sortType' => false);
  1068. }
  1069. $this->queryCols = $cols;
  1070. return $this;
  1071. }
  1072. /**
  1073. * Get langs.
  1074. *
  1075. * @param string $type
  1076. * @access public
  1077. * @return object|string
  1078. */
  1079. public function getFields($type = 'object')
  1080. {
  1081. $fieldSettings = $this->fieldSettings;
  1082. if(empty($fieldSettings)) return null;
  1083. $fields = array();
  1084. $keys = array('object', 'field', 'type');
  1085. foreach($fieldSettings as $fieldKey => $fieldSetting)
  1086. {
  1087. $field = array();
  1088. foreach($keys as $key)
  1089. {
  1090. if(isset($fieldSetting[$key])) $field[$key] = $fieldSetting[$key];
  1091. }
  1092. $fields[$fieldKey] = $field;
  1093. }
  1094. return $type == 'object' ? $fields : json_encode($fields);
  1095. }
  1096. /**
  1097. * Get langs.
  1098. *
  1099. * @param string $type
  1100. * @access public
  1101. * @return object|string
  1102. */
  1103. public function getLangs($type = 'object')
  1104. {
  1105. $fieldSettings = $this->fieldSettings;
  1106. if(empty($fieldSettings)) return null;
  1107. $langs = array();
  1108. $keys = array('object', 'field', 'type');
  1109. foreach($fieldSettings as $fieldKey => $fieldSetting)
  1110. {
  1111. $lang = array();
  1112. foreach($fieldSetting as $key => $value)
  1113. {
  1114. if(!in_array($key, $keys)) $lang[$key] = $value;
  1115. }
  1116. $langs[$fieldKey] = $lang;
  1117. }
  1118. return $type == 'object' ? $langs : json_encode($langs);
  1119. }
  1120. /**
  1121. * Get filters.
  1122. *
  1123. * @param string $type
  1124. * @access public
  1125. * @return object|string
  1126. */
  1127. public function getFiltersForSave($type = 'object')
  1128. {
  1129. $filters = $this->filters;
  1130. foreach($filters as $index => $filter)
  1131. {
  1132. if(isset($filter['items'])) unset($filters[$index]['items']);
  1133. }
  1134. if($type == 'object') return $filters;
  1135. return json_encode($filters);
  1136. }
  1137. /**
  1138. * Judge is queried.
  1139. *
  1140. * @access public
  1141. * @return bool
  1142. */
  1143. public function isQueried()
  1144. {
  1145. return !empty($this->sql) && !$this->isError() && !empty($this->queryCols);
  1146. }
  1147. /**
  1148. * Check fields with setting.
  1149. *
  1150. * @param bool $removeUnused
  1151. * @access public
  1152. * @return bool
  1153. */
  1154. public function checkFieldsWithSetting($removeUnused = false)
  1155. {
  1156. $settings = $this->settings;
  1157. $fields = $this->fieldSettings;
  1158. $isChanged = false;
  1159. foreach($settings as $key => $value)
  1160. {
  1161. if(strpos($key, 'group') === 0 && !isset($fields[$value]))
  1162. {
  1163. $isChanged = true;
  1164. if($removeUnused) unset($this->settings[$key]);
  1165. }
  1166. if($key === 'columns')
  1167. {
  1168. foreach($value as $index => $column)
  1169. {
  1170. if(!isset($fields[$column['field']]) || !isset($fields[$column['slice']]))
  1171. {
  1172. $isChanged = true;
  1173. if($removeUnused) unset($this->settings['columns'][$index]);
  1174. }
  1175. }
  1176. }
  1177. }
  1178. $filters = $this->filters;
  1179. foreach($filters as $index => $filter)
  1180. {
  1181. $from = zget($filter, 'from', 'result');
  1182. if($from == 'query') continue;
  1183. if(!isset($fields[$filter['field']]))
  1184. {
  1185. $isChanged = true;
  1186. if($removeUnused) unset($this->filters[$index]);
  1187. }
  1188. }
  1189. $drills = $this->drills;
  1190. foreach($drills as $index => $drill)
  1191. {
  1192. if(!isset($fields[$drill['field']]))
  1193. {
  1194. $isChanged = true;
  1195. if($removeUnused) unset($this->drills[$index]);
  1196. }
  1197. foreach($drill['condition'] as $conditionIndex => $condition)
  1198. {
  1199. if(!isset($fields[$condition['queryField']]))
  1200. {
  1201. $isChanged = true;
  1202. if($removeUnused) unset($this->drills[$index]['condition'][$conditionIndex]);
  1203. }
  1204. }
  1205. }
  1206. if($removeUnused) $this->completeSettings();
  1207. return $isChanged;
  1208. }
  1209. /**
  1210. * Check settings.
  1211. *
  1212. * @access public
  1213. * @return array
  1214. */
  1215. public function checkSettings()
  1216. {
  1217. if($this->isSummaryNotUse()) return array();
  1218. $errors = array();
  1219. foreach($this->settings as $key => $value)
  1220. {
  1221. if(strpos($key, 'group') === 0 && empty($value))
  1222. {
  1223. $errors[$key] = true;
  1224. continue;
  1225. }
  1226. if($key === 'columns')
  1227. {
  1228. foreach($value as $index => $column)
  1229. {
  1230. if(empty($column['field'])) $errors[$key][$index]['field'] = true;
  1231. if($column['showOrigin'] === 0 && empty($column['stat'])) $errors[$key][$index]['stat'] = true;
  1232. }
  1233. }
  1234. }
  1235. return $errors;
  1236. }
  1237. /**
  1238. * Check query filter.
  1239. *
  1240. * @access public
  1241. * @return array
  1242. */
  1243. public function checkQueryFilter()
  1244. {
  1245. $errors = array();
  1246. foreach($this->filters as $index => $filter)
  1247. {
  1248. if(empty($filter['field'])) $errors[$index]['field'] = true;
  1249. if(empty($filter['name'])) $errors[$index]['name'] = true;
  1250. }
  1251. $addFilter = $this->addQueryFilter;
  1252. if(empty($addFilter['field'])) $errors[$index]['field'] = true;
  1253. if(empty($addFilter['name'])) $errors[$index]['name'] = true;
  1254. return $errors;
  1255. }
  1256. /**
  1257. * Match query filte from sql.
  1258. *
  1259. * @access public
  1260. * @return void
  1261. */
  1262. public function matchQueryFilterFromSql()
  1263. {
  1264. if(!$this->isQueryFilter()) return;
  1265. $keepFilters = array();
  1266. $keepPivotFilters = array();
  1267. foreach($this->filters as $index => $filter)
  1268. {
  1269. $field = $filter['field'];
  1270. if(strpos($this->sql, "\$$field") !== false)
  1271. {
  1272. $keepFilters[] = $filter;
  1273. $keepPivotFilters[] = $this->pivotFilters[0][$index];
  1274. }
  1275. }
  1276. $this->filters = $keepFilters;
  1277. $this->pivotFilters[0] = $keepPivotFilters;
  1278. }
  1279. /**
  1280. * Set action.
  1281. *
  1282. * @param string $action
  1283. * @access public
  1284. * @return void
  1285. */
  1286. public function setAction($action)
  1287. {
  1288. if($action == 'enterDesign') $action = 'design';
  1289. $this->action = $action;
  1290. }
  1291. /**
  1292. * Set step.
  1293. *
  1294. * @param int $step
  1295. * @access public
  1296. * @return void
  1297. */
  1298. public function setStep($step)
  1299. {
  1300. $this->step = $step;
  1301. }
  1302. /**
  1303. * Judge is publish action.
  1304. *
  1305. * @access public
  1306. * @return bool
  1307. */
  1308. public function isPublish()
  1309. {
  1310. return $this->action == 'publish';
  1311. }
  1312. /**
  1313. * Judge is design action.
  1314. *
  1315. * @access public
  1316. * @return bool
  1317. */
  1318. public function isDesign()
  1319. {
  1320. return $this->action == 'design';
  1321. }
  1322. /**
  1323. * Judge is first design action.
  1324. *
  1325. * @access public
  1326. * @return bool
  1327. */
  1328. public function isFirstDesign()
  1329. {
  1330. return $this->isDesign() && empty($this->sql);
  1331. }
  1332. /**
  1333. * Judge is error.
  1334. *
  1335. * @access public
  1336. * @return bool
  1337. */
  1338. public function isError()
  1339. {
  1340. return $this->error;
  1341. }
  1342. /**
  1343. * Get error message.
  1344. *
  1345. * @access public
  1346. * @return string
  1347. */
  1348. public function getError()
  1349. {
  1350. return $this->errorMsg;
  1351. }
  1352. /**
  1353. * Set error.
  1354. *
  1355. * @param string $msg
  1356. * @access public
  1357. * @return object
  1358. */
  1359. public function setError($msg)
  1360. {
  1361. $this->error = true;
  1362. $this->errorMsg = $msg;
  1363. return $this;
  1364. }
  1365. /**
  1366. * Set pager
  1367. *
  1368. * @param int $total
  1369. * @param int $recPerPage
  1370. * @param int $pageID
  1371. * @access public
  1372. * @return void
  1373. */
  1374. public function setPager($total = 0, $recPerPage = 10, $pageID = 1)
  1375. {
  1376. $this->pager = array();
  1377. $this->pager['total'] = $total;
  1378. $this->pager['recPerPage'] = $recPerPage;
  1379. $this->pager['pageID'] = $pageID;
  1380. $this->pager['pageTotal'] = $total % $recPerPage == 0 ? (int)($total / $recPerPage) : (int)($total / $recPerPage) + 1;
  1381. }
  1382. /**
  1383. * Convert json string to array.
  1384. *
  1385. * @param string|object|array|null $json
  1386. * @access public
  1387. * @return array
  1388. */
  1389. private function json2Array($json)
  1390. {
  1391. if(empty($json)) return array();
  1392. if(is_string($json)) return json_decode($json, true);
  1393. if(is_object($json) || is_array($json)) return json_decode(json_encode($json), true);
  1394. return $json;
  1395. }
  1396. }