PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ezQuery.php

http://github.com/jv2222/ezSQL
PHP | 992 lines | 791 code | 115 blank | 86 comment | 124 complexity | c7e538940af7ee9a4f919c35b27a2e2c MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. namespace ezsql;
  3. use ezsql\ezSchema;
  4. use ezsql\ezQueryInterface;
  5. use function ezsql\functions\{column, get_vendor};
  6. class ezQuery implements ezQueryInterface
  7. {
  8. protected $select_result = true;
  9. protected $prepareActive = false;
  10. protected $preparedValues = array();
  11. /**
  12. * ID generated from the AUTO_INCREMENT of the previous INSERT operation (if any)
  13. * @var int
  14. */
  15. protected $insertId = null;
  16. /**
  17. * The table `name` to use on calls to `ing` ending
  18. * `CRUD` methods/functions.
  19. *
  20. * @var string
  21. */
  22. protected $table = '';
  23. /**
  24. * A `prefix` to append to `table` on calls to `ing` ending
  25. * `CRUD` methods/functions.
  26. *
  27. * @var string
  28. */
  29. protected $prefix = '';
  30. private $fromTable = null;
  31. private $isWhere = true;
  32. private $isInto = false;
  33. private $whereSQL = null;
  34. private $combineWith = null;
  35. public function __construct()
  36. {
  37. }
  38. /**
  39. * Return status of prepare function availability in shortcut method calls
  40. */
  41. protected function isPrepareOn()
  42. {
  43. return $this->prepareActive;
  44. }
  45. /**
  46. * Returns array of parameter values for prepare function
  47. * @return array
  48. */
  49. protected function prepareValues()
  50. {
  51. return $this->preparedValues;
  52. }
  53. /**
  54. * Add values to array variable for prepare function.
  55. * @param mixed $value
  56. *
  57. * @return int array count
  58. */
  59. protected function addPrepare($value = null)
  60. {
  61. return \array_push($this->preparedValues, $value);
  62. }
  63. /**
  64. * Clear out prepare parameter values
  65. *
  66. * @return bool false
  67. */
  68. protected function clearPrepare()
  69. {
  70. $this->preparedValues = array();
  71. return false;
  72. }
  73. public function prepareOn()
  74. {
  75. $this->prepareActive = true;
  76. }
  77. public function prepareOff()
  78. {
  79. $this->prepareActive = $this->clearPrepare();
  80. }
  81. /**
  82. * Convert array to string, and attach '`,`' for separation, if none is provided.
  83. *
  84. * @return string
  85. */
  86. public static function to_string($arrays, $separation = ',')
  87. {
  88. if (\is_array($arrays)) {
  89. $columns = '';
  90. foreach ($arrays as $val) {
  91. $columns .= $val . $separation . ' ';
  92. }
  93. $columns = \rtrim($columns, $separation . ' ');
  94. } else
  95. $columns = $arrays;
  96. return $columns;
  97. }
  98. public function groupBy($column)
  99. {
  100. if (empty($column)) {
  101. return false;
  102. }
  103. $columns = $this->to_string($column);
  104. return 'GROUP BY ' . $columns;
  105. }
  106. public function having(...$conditions)
  107. {
  108. $this->isWhere = false;
  109. return $this->where(...$conditions);
  110. }
  111. public function innerJoin(
  112. string $leftTable = null,
  113. string $rightTable = null,
  114. string $leftColumn = null,
  115. string $rightColumn = null,
  116. string $tableAs = null,
  117. $condition = \EQ
  118. ) {
  119. return $this->joining(
  120. 'INNER',
  121. $leftTable,
  122. $rightTable,
  123. $leftColumn,
  124. $rightColumn,
  125. $tableAs,
  126. $condition
  127. );
  128. }
  129. public function leftJoin(
  130. string $leftTable = null,
  131. string $rightTable = null,
  132. string $leftColumn = null,
  133. string $rightColumn = null,
  134. string $tableAs = null,
  135. $condition = \EQ
  136. ) {
  137. return $this->joining(
  138. 'LEFT',
  139. $leftTable,
  140. $rightTable,
  141. $leftColumn,
  142. $rightColumn,
  143. $tableAs,
  144. $condition
  145. );
  146. }
  147. public function rightJoin(
  148. string $leftTable = null,
  149. string $rightTable = null,
  150. string $leftColumn = null,
  151. string $rightColumn = null,
  152. string $tableAs = null,
  153. $condition = \EQ
  154. ) {
  155. return $this->joining(
  156. 'RIGHT',
  157. $leftTable,
  158. $rightTable,
  159. $leftColumn,
  160. $rightColumn,
  161. $tableAs,
  162. $condition
  163. );
  164. }
  165. public function fullJoin(
  166. string $leftTable = null,
  167. string $rightTable = null,
  168. string $leftColumn = null,
  169. string $rightColumn = null,
  170. string $tableAs = null,
  171. $condition = \EQ
  172. ) {
  173. return $this->joining(
  174. 'FULL',
  175. $leftTable,
  176. $rightTable,
  177. $leftColumn,
  178. $rightColumn,
  179. $tableAs,
  180. $condition
  181. );
  182. }
  183. /**
  184. * For multiple select joins, combine rows from tables where `on` condition is met
  185. *
  186. * - Will perform an equal on tables by left column key,
  187. * left column key and left table, left column key and right table,
  188. * if `rightColumn` is null.
  189. *
  190. * - Will perform an equal on tables by,
  191. * left column key and left table, right column key and right table,
  192. * if `rightColumn` not null, and `$condition` not changed.
  193. *
  194. * - Will perform the `condition` on passed in arguments, for left column, and right column.
  195. * if `$condition`, is in the array
  196. *
  197. * @param string $type - Either `INNER`, `LEFT`, `RIGHT`, `FULL`
  198. * @param string $leftTable -
  199. * @param string $rightTable -
  200. *
  201. * @param string $leftColumn -
  202. * @param string $rightColumn -
  203. * @param string $tableAs -
  204. *
  205. * @param string $condition -
  206. *
  207. * @return bool|string JOIN sql statement, false for error
  208. */
  209. private function joining(
  210. String $type = \_INNER,
  211. string $leftTable = null,
  212. string $rightTable = null,
  213. string $leftColumn = null,
  214. string $rightColumn = null,
  215. string $tableAs = null,
  216. $condition = \EQ
  217. ) {
  218. if (
  219. !\in_array($type, \_JOINERS)
  220. || !\in_array($condition, \_BOOLEAN)
  221. || empty($leftTable)
  222. || empty($rightTable)
  223. || empty($leftColumn)
  224. ) {
  225. return false;
  226. }
  227. if (empty($tableAs))
  228. $tableAs = $rightTable;
  229. if (\is_string($leftColumn) && empty($rightColumn))
  230. $onCondition = ' ON ' . $leftTable . '.' . $leftColumn . ' = ' . $tableAs . '.' . $leftColumn;
  231. elseif ($condition !== \EQ)
  232. $onCondition = ' ON ' . $leftTable . '.' . $leftColumn . ' ' . $condition . ' ' . $tableAs . '.' . $rightColumn;
  233. else
  234. $onCondition = ' ON ' . $leftTable . '.' . $leftColumn . ' = ' . $tableAs . '.' . $rightColumn;
  235. return ' ' . $type . ' JOIN ' . $rightTable . ' AS ' . $tableAs . ' ' . $onCondition;
  236. }
  237. public function orderBy($column, $order)
  238. {
  239. if (empty($column)) {
  240. return false;
  241. }
  242. $columns = $this->to_string($column);
  243. $by = \strtoupper($order);
  244. $order = (\in_array($by, array('ASC', 'DESC'))) ? $by : 'ASC';
  245. return 'ORDER BY ' . $columns . ' ' . $order;
  246. }
  247. public function limit($numberOf, $offset = null)
  248. {
  249. if (empty($numberOf)) {
  250. return false;
  251. }
  252. $rows = (int) $numberOf;
  253. $value = !empty($offset) ? ' OFFSET ' . (int) $offset : '';
  254. return 'LIMIT ' . $rows . $value;
  255. }
  256. private function conditions($key, $condition, $value, $combine, $extra)
  257. {
  258. $groupStart = (!empty($extra) && $extra === '(') ? $extra : '';
  259. $groupEnd = (!empty($extra) && $extra === ')') ? $extra : '';
  260. if ($this->isPrepareOn()) {
  261. $this->whereSQL .= "$groupStart $key $condition " . \_TAG . " $groupEnd $combine ";
  262. $this->addPrepare($value);
  263. } else
  264. $this->whereSQL .= "$groupStart $key $condition '" . $this->escape($value) . "' $groupEnd $combine ";
  265. }
  266. private function conditionBetween($key, $condition, $valueOne, $valueTwo, $combine)
  267. {
  268. $_valueTwo = $this->escape($valueTwo);
  269. $andCombineWith = \_AND;
  270. if (\in_array(\strtoupper($combine), \_COMBINERS))
  271. $andCombineWith = \strtoupper($combine);
  272. if ($this->isPrepareOn()) {
  273. $this->whereSQL .= "$key " . $condition . ' ' . \_TAG . " AND " . \_TAG . " $andCombineWith ";
  274. $this->addPrepare($valueOne);
  275. $this->addPrepare($valueTwo);
  276. } else
  277. $this->whereSQL .= "$key $condition '" . $this->escape($valueOne) . "' AND '" . $_valueTwo . "' $andCombineWith ";
  278. $this->combineWith = $andCombineWith;
  279. }
  280. private function conditionIn($key, $condition, $valueRow, $combine)
  281. {
  282. $value = '';
  283. foreach ($valueRow as $splitValue) {
  284. if ($this->isPrepareOn()) {
  285. $value .= \_TAG . ', ';
  286. $this->addPrepare($splitValue);
  287. } else
  288. $value .= "'" . $this->escape($splitValue) . "', ";
  289. }
  290. $this->whereSQL .= "$key $condition ( " . \rtrim($value, ', ') . " ) $combine ";
  291. }
  292. private function conditionIs($key, $condition, $combine)
  293. {
  294. $isCondition = (($condition == 'IS') || ($condition == 'IS NOT')) ? $condition : 'IS';
  295. $this->whereSQL .= "$key $isCondition NULL $combine ";
  296. }
  297. private function flattenWhereConditions($whereConditions)
  298. {
  299. $whereConditionsReturn = [];
  300. foreach ($whereConditions as $whereCondition) {
  301. if (!empty($whereCondition[0]) && is_array($whereCondition[0])) {
  302. $whereConditionsReturn = \array_merge($whereConditionsReturn, $this->flattenWhereConditions($whereCondition));
  303. } else {
  304. $whereConditionsReturn[] = $whereCondition;
  305. }
  306. }
  307. return $whereConditionsReturn;
  308. }
  309. private function retrieveConditions($whereConditions)
  310. {
  311. $whereConditions = $this->flattenWhereConditions($whereConditions);
  312. $whereKey = [];
  313. $whereValue = [];
  314. $operator = [];
  315. $extra = [];
  316. $combiner = [];
  317. foreach ($whereConditions as $checkFields) {
  318. $operator[] = (isset($checkFields[1])) ? $checkFields[1] : '';
  319. if (empty($checkFields[1])) {
  320. $this->clearPrepare();
  321. return [[], [], [], [], []];
  322. }
  323. if (\strtoupper($checkFields[1]) == 'IN') {
  324. $whereKey[] = $checkFields[0];
  325. $whereValue[] = \array_slice((array) $checkFields, 2);
  326. $combiner[] = \_AND;
  327. $extra[] = null;
  328. } else {
  329. if (!empty($checkFields[0])) {
  330. $whereKey[] = $checkFields[0];
  331. $whereValue[] = (isset($checkFields[2])) ? $checkFields[2] : '';
  332. $combiner[] = (isset($checkFields[3])) ? $checkFields[3] : \_AND;
  333. $extra[] = (isset($checkFields[4])) ? $checkFields[4] : null;
  334. }
  335. }
  336. }
  337. return [$operator, $whereKey, $whereValue, $combiner, $extra];
  338. }
  339. private function processConditions($column, $condition, $value, $valueOrCombine, $extraCombine)
  340. {
  341. if (!\in_array($condition, \_BOOLEAN_OPERATORS))
  342. return $this->clearPrepare();
  343. if (($condition == \_BETWEEN) || ($condition == \_notBETWEEN)) {
  344. $this->conditionBetween($column, $condition, $value, $valueOrCombine, $extraCombine);
  345. } elseif ($condition == \_IN) {
  346. $this->conditionIn($column, $condition, $value, $valueOrCombine);
  347. } elseif (((\strtolower($value) == 'null') || ($condition == 'IS') || ($condition == 'IS NOT'))) {
  348. $this->conditionIs($column, $condition, $valueOrCombine);
  349. } elseif ((($condition == \_LIKE) || ($condition == \_notLIKE)) && !\preg_match('/[_%?]/', $value)) {
  350. return $this->clearPrepare();
  351. } else {
  352. $this->conditions($column, $condition, $value, $valueOrCombine, $extraCombine);
  353. }
  354. }
  355. public function grouping(...$whereConditions)
  356. {
  357. if (empty($whereConditions))
  358. return false;
  359. $whereOrHaving = ($this->isWhere) ? 'WHERE' : 'HAVING';
  360. if (\is_string($whereConditions[0]) && \strpos($whereConditions[0], $whereOrHaving) !== false)
  361. return $whereConditions[0];
  362. $totalConditions = \count($whereConditions) - 1;
  363. if ($totalConditions > 0) {
  364. if (!\in_array('(', $whereConditions[0]))
  365. $whereConditions[0][\count($whereConditions[0])] = '(';
  366. if (!\in_array(')', $whereConditions[$totalConditions]))
  367. $whereConditions[$totalConditions][\count($whereConditions[$totalConditions])] = ')';
  368. }
  369. return $whereConditions;
  370. }
  371. public function where(...$conditions)
  372. {
  373. if (empty($conditions))
  374. return false;
  375. $whereOrHaving = ($this->isWhere) ? 'WHERE' : 'HAVING';
  376. $this->isWhere = true;
  377. $this->combineWith = '';
  378. if (\is_string($conditions[0]) && \strpos($conditions[0], $whereOrHaving) !== false)
  379. return $conditions[0];
  380. list($operator, $whereKeys, $whereValues, $combiner, $extra) = $this->retrieveConditions($conditions);
  381. if (empty($operator))
  382. return false;
  383. $where = '1';
  384. if (!empty($whereKeys)) {
  385. $this->whereSQL = '';
  386. $i = 0;
  387. foreach ($whereKeys as $key) {
  388. $isCondition = \strtoupper($operator[$i]);
  389. $combine = $combiner[$i];
  390. $this->combineWith = \_AND;
  391. if (\in_array(\strtoupper($combine), \_COMBINERS) || isset($extra[$i]))
  392. $this->combineWith = isset($extra[$i]) ? $combine : \strtoupper($combine);
  393. if ($this->processConditions($key, $isCondition, $whereValues[$i], $this->combineWith, $extra[$i]) === false)
  394. return false;
  395. $i++;
  396. }
  397. $where = \rtrim($this->whereSQL, " $this->combineWith ");
  398. $this->whereSQL = null;
  399. }
  400. if (($this->isPrepareOn()) && !empty($this->prepareValues()) && ($where != '1'))
  401. return " $whereOrHaving $where ";
  402. return ($where != '1') ? " $whereOrHaving $where " : ' ';
  403. }
  404. public function select(string $table = null, $columnFields = '*', ...$conditions)
  405. {
  406. $getFromTable = $this->fromTable;
  407. $getSelect_result = $this->select_result;
  408. $getIsInto = $this->isInto;
  409. $this->fromTable = null;
  410. $this->select_result = true;
  411. $this->isInto = false;
  412. $skipWhere = false;
  413. $whereKeys = $conditions;
  414. $where = '';
  415. if (empty($table)) {
  416. return $this->clearPrepare();
  417. }
  418. $columns = $this->to_string($columnFields);
  419. if (isset($getFromTable) && !$getIsInto)
  420. $sql = "CREATE TABLE $table AS SELECT $columns FROM " . $getFromTable;
  421. elseif (isset($getFromTable) && $getIsInto)
  422. $sql = "SELECT $columns INTO $table FROM " . $getFromTable;
  423. else
  424. $sql = "SELECT $columns FROM " . $table;
  425. if (!empty($conditions)) {
  426. if (\is_string($conditions[0])) {
  427. $args_by = '';
  428. $joinSet = false;
  429. $groupBySet = false;
  430. $havingSet = false;
  431. $orderBySet = false;
  432. $limitSet = false;
  433. $unionSet = false;
  434. foreach ($conditions as $checkFor) {
  435. if (\strpos($checkFor, 'JOIN') !== false) {
  436. $args_by .= $checkFor;
  437. $joinSet = true;
  438. } elseif (\strpos($checkFor, 'WHERE') !== false) {
  439. $args_by .= $checkFor;
  440. $skipWhere = true;
  441. } elseif (\strpos($checkFor, 'GROUP BY') !== false) {
  442. $args_by .= ' ' . $checkFor;
  443. $groupBySet = true;
  444. } elseif (\strpos($checkFor, 'HAVING') !== false) {
  445. if ($groupBySet) {
  446. $args_by .= ' ' . $checkFor;
  447. $havingSet = true;
  448. } else {
  449. return $this->clearPrepare();
  450. }
  451. } elseif (\strpos($checkFor, 'ORDER BY') !== false) {
  452. $args_by .= ' ' . $checkFor;
  453. $orderBySet = true;
  454. } elseif (\strpos($checkFor, 'LIMIT') !== false) {
  455. $args_by .= ' ' . $checkFor;
  456. $limitSet = true;
  457. } elseif (\strpos($checkFor, 'UNION') !== false) {
  458. $args_by .= ' ' . $checkFor;
  459. $unionSet = true;
  460. }
  461. }
  462. if ($joinSet || $skipWhere || $groupBySet || $havingSet || $orderBySet || $limitSet || $unionSet) {
  463. $where = $args_by;
  464. $skipWhere = true;
  465. }
  466. }
  467. } else {
  468. $skipWhere = true;
  469. }
  470. if (!$skipWhere)
  471. $where = $this->where(...$whereKeys);
  472. if (\is_string($where)) {
  473. $sql .= $where;
  474. if ($getSelect_result)
  475. return (($this->isPrepareOn()) && !empty($this->prepareValues()))
  476. ? $this->get_results($sql, \OBJECT, true)
  477. : $this->get_results($sql);
  478. return $sql;
  479. }
  480. return $this->clearPrepare();
  481. }
  482. /**
  483. * Get SQL statement string from `select` method instead of executing get_result
  484. * @return string
  485. */
  486. private function select_sql($table = '', $columnFields = '*', ...$conditions)
  487. {
  488. $this->select_result = false;
  489. return $this->select($table, $columnFields, ...$conditions);
  490. }
  491. public function union(string $table = null, $columnFields = '*', ...$conditions)
  492. {
  493. return 'UNION ' . $this->select_sql($table, $columnFields, ...$conditions);
  494. }
  495. public function unionAll(string $table = null, $columnFields = '*', ...$conditions)
  496. {
  497. return 'UNION ALL ' . $this->select_sql($table, $columnFields, ...$conditions);
  498. }
  499. public function create_select(string $newTable, $fromColumns = '*', $oldTable = null, ...$fromWhereConditions)
  500. {
  501. if (isset($oldTable))
  502. $this->fromTable = $oldTable;
  503. else {
  504. return $this->clearPrepare();
  505. }
  506. $newTableFromTable = $this->select_sql($newTable, $fromColumns, ...$fromWhereConditions);
  507. if (is_string($newTableFromTable))
  508. return (($this->isPrepareOn()) && !empty($this->prepareValues()))
  509. ? $this->query($newTableFromTable, true)
  510. : $this->query($newTableFromTable);
  511. return $this->clearPrepare();
  512. }
  513. /**
  514. * @codeCoverageIgnore
  515. */
  516. public function select_into(string $newTable, $fromColumns = '*', string $oldTable = null, ...$fromWhereConditions)
  517. {
  518. $this->isInto = true;
  519. if (isset($oldTable))
  520. $this->fromTable = $oldTable;
  521. else
  522. return $this->clearPrepare();
  523. $newTableFromTable = $this->select_sql($newTable, $fromColumns, ...$fromWhereConditions);
  524. if (\is_string($newTableFromTable))
  525. return (($this->isPrepareOn()) && !empty($this->prepareValues()))
  526. ? $this->query($newTableFromTable, true)
  527. : $this->query($newTableFromTable);
  528. return $this->clearPrepare();
  529. }
  530. public function update(string $table = null, $keyValue, ...$whereConditions)
  531. {
  532. if (!\is_array($keyValue) || empty($table)) {
  533. return $this->clearPrepare();
  534. }
  535. $sql = "UPDATE $table SET ";
  536. foreach ($keyValue as $key => $val) {
  537. if (\strtolower($val) == 'null') {
  538. $sql .= "$key = NULL, ";
  539. } elseif (\in_array(\strtolower($val), array('current_timestamp()', 'date()', 'now()'))) {
  540. $sql .= "$key = CURRENT_TIMESTAMP(), ";
  541. } else {
  542. if ($this->isPrepareOn()) {
  543. $sql .= "$key = " . \_TAG . ", ";
  544. $this->addPrepare($val);
  545. } else
  546. $sql .= "$key = '" . $this->escape($val) . "', ";
  547. }
  548. }
  549. $where = $this->where(...$whereConditions);
  550. if (\is_string($where)) {
  551. $sql = \rtrim($sql, ', ') . $where;
  552. return (($this->isPrepareOn()) && !empty($this->prepareValues()))
  553. ? $this->query($sql, true)
  554. : $this->query($sql);
  555. }
  556. return $this->clearPrepare();
  557. }
  558. public function delete(string $table = null, ...$whereConditions)
  559. {
  560. if (empty($table)) {
  561. return $this->clearPrepare();
  562. }
  563. $sql = "DELETE FROM $table";
  564. $where = $this->where(...$whereConditions);
  565. if (\is_string($where)) {
  566. $sql .= $where;
  567. return (($this->isPrepareOn()) && !empty($this->prepareValues()))
  568. ? $this->query($sql, true)
  569. : $this->query($sql);
  570. }
  571. return $this->clearPrepare();
  572. }
  573. /**
  574. * Helper does the actual insert or replace query with an array
  575. * @return mixed bool/results - false for error
  576. */
  577. private function _query_insert_replace($table = '', $keyValue = null, $type = '', $execute = true)
  578. {
  579. if ((!\is_array($keyValue) && ($execute)) || empty($table)) {
  580. return $this->clearPrepare();
  581. }
  582. if (!\in_array(strtoupper($type), array('REPLACE', 'INSERT'))) {
  583. return $this->clearPrepare();
  584. }
  585. $sql = "$type INTO $table";
  586. $value = '';
  587. $index = '';
  588. if ($execute) {
  589. foreach ($keyValue as $key => $val) {
  590. $index .= "$key, ";
  591. if (\strtolower($val) == 'null')
  592. $value .= "NULL, ";
  593. elseif (\in_array(\strtolower($val), array('current_timestamp()', 'date()', 'now()')))
  594. $value .= "CURRENT_TIMESTAMP(), ";
  595. else {
  596. if ($this->isPrepareOn()) {
  597. $value .= _TAG . ", ";
  598. $this->addPrepare($val);
  599. } else
  600. $value .= "'" . $this->escape($val) . "', ";
  601. }
  602. }
  603. $sql .= "(" . \rtrim($index, ', ') . ") VALUES (" . \rtrim($value, ', ') . ");";
  604. if (($this->isPrepareOn()) && !empty($this->prepareValues()))
  605. $ok = $this->query($sql, true);
  606. else
  607. $ok = $this->query($sql);
  608. if ($ok)
  609. return $this->insertId;
  610. return $this->clearPrepare();
  611. } else {
  612. if (\is_array($keyValue)) {
  613. if (\array_keys($keyValue) === \range(0, \count($keyValue) - 1)) {
  614. foreach ($keyValue as $key) {
  615. $index .= "$key, ";
  616. }
  617. $sql .= " (" . \rtrim($index, ', ') . ") ";
  618. } else {
  619. return false;
  620. }
  621. }
  622. return $sql;
  623. }
  624. }
  625. public function replace(string $table = null, $keyValue)
  626. {
  627. return $this->_query_insert_replace($table, $keyValue, 'REPLACE');
  628. }
  629. public function insert(string $table = null, $keyValue)
  630. {
  631. return $this->_query_insert_replace($table, $keyValue, 'INSERT');
  632. }
  633. public function insert_select(string $toTable = null, $toColumns = '*', $fromTable = null, $fromColumns = '*', ...$conditions)
  634. {
  635. $putToTable = $this->_query_insert_replace($toTable, $toColumns, 'INSERT', false);
  636. $getFromTable = $this->select_sql($fromTable, $fromColumns, ...$conditions);
  637. if (\is_string($putToTable) && \is_string($getFromTable))
  638. return (($this->isPrepareOn()) && !empty($this->prepareValues()))
  639. ? $this->query($putToTable . " " . $getFromTable, true)
  640. : $this->query($putToTable . " " . $getFromTable);
  641. return $this->clearPrepare();
  642. }
  643. // get_results call template
  644. public function get_results(string $query = null, $output = \OBJECT, bool $use_prepare = false)
  645. {
  646. return array();
  647. }
  648. //
  649. /**
  650. * query call template
  651. *
  652. * @param string $query
  653. * @param bool $use_prepare
  654. * @return bool|mixed
  655. */
  656. public function query(string $query, bool $use_prepare = false)
  657. {
  658. return false;
  659. }
  660. // escape call template if not available by vendor
  661. public function escape(string $str)
  662. {
  663. if (empty($str))
  664. return '';
  665. if (\is_numeric($str))
  666. return $str;
  667. $nonDisplayable = array(
  668. '/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15
  669. '/%1[0-9a-f]/', // url encoded 16-31
  670. '/[\x00-\x08]/', // 00-08
  671. '/\x0b/', // 11
  672. '/\x0c/', // 12
  673. '/[\x0e-\x1f]/' // 14-31
  674. );
  675. foreach ($nonDisplayable as $regex)
  676. $str = \preg_replace($regex, '', $str);
  677. $search = array("\\", "\x00", "\n", "\r", "'", '"', "\x1a");
  678. $replace = array("\\\\", "\\0", "\\n", "\\r", "\'", '\"', "\\Z");
  679. return \str_replace($search, $replace, $str);
  680. }
  681. /**
  682. * Creates an database schema from array
  683. * - column, datatype, value/options/key arguments.
  684. * @param array ...$columnDataOptions
  685. * @return string|bool - SQL schema string, or false for error
  686. */
  687. private function create_schema(array ...$columnDataOptions)
  688. {
  689. if (empty($columnDataOptions))
  690. return false;
  691. $columnData = '';
  692. foreach ($columnDataOptions as $datatype) {
  693. $column = \array_shift($datatype);
  694. $type = \array_shift($datatype);
  695. if (!empty($column) && !empty($type))
  696. $columnData .= column($column, $type, ...$datatype);
  697. }
  698. $schemaColumns = !empty($columnData) ? \rtrim($columnData, ', ') : null;
  699. if (\is_string($schemaColumns))
  700. return $schemaColumns;
  701. return false;
  702. }
  703. public function create(string $table = null, ...$schemas)
  704. {
  705. $vendor = get_vendor();
  706. if (empty($table) || empty($schemas) || empty($vendor))
  707. return false;
  708. $sql = 'CREATE TABLE IF NOT EXISTS ' . $table . '( ';
  709. $skipSchema = false;
  710. if (\is_string($schemas[0])) {
  711. $data = '';
  712. $stringTypes = ezSchema::STRINGS['common'];
  713. $stringTypes += ezSchema::STRINGS[$vendor];
  714. $numericTypes = ezSchema::NUMERICS['common'];
  715. $numericTypes += ezSchema::NUMERICS[$vendor];
  716. $numberTypes = ezSchema::NUMBERS['common'];
  717. $numberTypes += ezSchema::NUMBERS[$vendor];
  718. $dateTimeTypes = ezSchema::DATE_TIME['common'];
  719. $dateTimeTypes += ezSchema::DATE_TIME[$vendor];
  720. $objectTypes = ezSchema::OBJECTS[$vendor];
  721. $allowedTypes = ezSchema::OPTIONS;
  722. $stringPattern = "/" . \implode('|', $stringTypes) . "/i";
  723. $numericPattern = "/" . \implode('|', $numericTypes) . "/i";
  724. $numberPattern = "/" . \implode('|', $numberTypes) . "/i";
  725. $dateTimePattern = "/" . \implode('|', $dateTimeTypes) . "/i";
  726. $objectPattern = "/" . \implode('|', $objectTypes) . "/i";
  727. $patternOther = "/" . \implode('|', $allowedTypes) . "/i";
  728. foreach ($schemas as $types) {
  729. if (\preg_match($stringPattern, $types)) {
  730. $data .= $types;
  731. $skipSchema = true;
  732. } elseif (\preg_match($numericPattern, $types)) {
  733. $data .= $types;
  734. $skipSchema = true;
  735. } elseif (\preg_match($numberPattern, $types)) {
  736. $data .= $types;
  737. $skipSchema = true;
  738. } elseif (\preg_match($dateTimePattern, $types)) {
  739. $data .= $types;
  740. $skipSchema = true;
  741. } elseif (\preg_match($objectPattern, $types)) {
  742. $data .= $types;
  743. $skipSchema = true;
  744. } elseif (\preg_match($patternOther, $types)) {
  745. $data .= $types;
  746. $skipSchema = true;
  747. }
  748. }
  749. $schema = $skipSchema ? \rtrim($data, ', ') : $data;
  750. }
  751. if (!$skipSchema) {
  752. $schema = $this->create_schema(...$schemas);
  753. }
  754. $createTable = !empty($schema) ? $sql . $schema . ' );' : null;
  755. if (\is_string($createTable))
  756. return $this->query($createTable);
  757. return false;
  758. }
  759. public function alter(string $table = null, ...$alteringSchema)
  760. {
  761. if (empty($table) || empty($alteringSchema))
  762. return false;
  763. $sql = 'ALTER TABLE ' . $table . ' ';
  764. $skipSchema = false;
  765. if (\is_string($alteringSchema[0])) {
  766. $data = '';
  767. $allowedTypes = ezSchema::ALTERS;
  768. $pattern = "/" . \implode('|', $allowedTypes) . "/i";
  769. foreach ($alteringSchema as $types) {
  770. if (\preg_match($pattern, $types)) {
  771. $data .= $types;
  772. $skipSchema = true;
  773. }
  774. }
  775. $schema = $skipSchema ? \rtrim($data, ', ') : $data;
  776. }
  777. if (!$skipSchema)
  778. $schema = $this->create_schema(...$alteringSchema);
  779. $alterTable = !empty($schema) ? $sql . $schema . ';' : null;
  780. if (\is_string($alterTable))
  781. return $this->query($alterTable);
  782. return false;
  783. }
  784. public function drop(string $table = null)
  785. {
  786. if (empty($table))
  787. return false;
  788. $drop = 'DROP TABLE IF EXISTS ' . $table . ';';
  789. return $this->query($drop);
  790. }
  791. public function selecting($columns = '*', ...$conditions)
  792. {
  793. $table = $this->table_prefix();
  794. return ($table === false) ? false : $this->select($table, $columns, ...$conditions);
  795. }
  796. public function inserting(array $keyValue)
  797. {
  798. $table = $this->table_prefix();
  799. return ($table === false) ? false : $this->insert($table, $keyValue);
  800. }
  801. public function replacing(array $keyValue)
  802. {
  803. $table = $this->table_prefix();
  804. return ($table === false) ? false : $this->replace($table, $keyValue);
  805. }
  806. public function updating(array $keyValue, ...$whereConditions)
  807. {
  808. $table = $this->table_prefix();
  809. return ($table === false) ? false : $this->update($table, $keyValue, ...$whereConditions);
  810. }
  811. public function deleting(...$whereConditions)
  812. {
  813. $table = $this->table_prefix();
  814. return ($table === false) ? false : $this->delete($table, ...$whereConditions);
  815. }
  816. public function creating(...$schemas)
  817. {
  818. $table = $this->table_prefix();
  819. return ($table === false) ? false : $this->create($table, ...$schemas);
  820. }
  821. public function dropping()
  822. {
  823. $table = $this->table_prefix();
  824. return ($table === false) ? false : $this->drop($table);
  825. }
  826. public function altering(...$alteringSchema)
  827. {
  828. $table = $this->table_prefix();
  829. return ($table === false) ? false : $this->alter($table, ...$alteringSchema);
  830. }
  831. /**
  832. * Check and return the stored database `table` preset with any `prefix`.
  833. *
  834. * @return boolean|string `false` if no preset.
  835. */
  836. protected function table_prefix()
  837. {
  838. if (empty($this->table) || !\is_string($this->table))
  839. return $this->clearPrepare();
  840. $table = (!empty($this->prefix) && \is_string($this->prefix))
  841. ? $this->prefix . $this->table
  842. : $this->table;
  843. return $table;
  844. }
  845. }