PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/app/code/core/Xedin/Core/Model/Db/Adapter.php

https://bitbucket.org/aukhanev/xdn-wordpress31
PHP | 854 lines | 580 code | 135 blank | 139 comment | 97 complexity | 1a139c9473b9046796f3699f076bb59e MD5 | raw file
  1. <?php
  2. /**
  3. * This is an object-oriended wrapper for the native WordPress wpdb class
  4. * that provides an ActiveRecord-style database interface.
  5. *
  6. * Using andWhere/orWhere functions with two-dimensional arrays, it is possible
  7. * to execute queries with very complex conditions.
  8. *
  9. * To retreive all records from a table, just use the from(), where() and
  10. * execute() functions consecutively.
  11. *
  12. * Results are provided in a form of multidimensional arrays.
  13. * Automatic table prefixing.
  14. *
  15. * @version 0.1.2
  16. * + Added join() and group() functions
  17. *
  18. * @author Xedin Unknown <xedin.unknown@gmail.com>
  19. */
  20. class Xedin_Core_Model_Db_Adapter {
  21. protected $_connection;
  22. protected $_result;
  23. protected $_lastResult;
  24. protected $_lastQuery;
  25. protected $_insertId;
  26. protected $_affectedRows;
  27. protected $_parts = array();
  28. protected $_isDebugMode = false;
  29. protected $_isAutoPrefix = true;
  30. const MYSQL_FIELD_NAME_KEY = 'Field';
  31. protected $_joinTypes = array(
  32. 'join',
  33. 'left join',
  34. 'right join',
  35. 'left outer join',
  36. 'right outer join',
  37. 'natural left join',
  38. 'natural right join',
  39. 'natural left outer join',
  40. 'natural right outer join',
  41. 'inner join',
  42. 'cross join'
  43. );
  44. public function __construct() {
  45. global $wpdb;
  46. $this->_connection = $wpdb->dbh;
  47. }
  48. public function isDebug($isDebug = null) {
  49. if (is_null($isDebug)) {
  50. return $this->_isDebugMode;
  51. }
  52. $this->_isDebugMode = $isDebug;
  53. return $this;
  54. }
  55. protected function _debug($text) {
  56. if ($this->isDebug()) {
  57. echo $text . "\n";
  58. }
  59. }
  60. public function isAutoPrefix($autoPrefix = null) {
  61. if( is_null($autoPrefix) ) {
  62. return $this->_isAutoPrefix;
  63. }
  64. $this->_isAutoPrefix = $autoPrefix;
  65. return $this;
  66. }
  67. protected function _addPart($partName, $value, $section = null, $explicitArray = false) {
  68. if ( ($value instanceof Zend_Db_Expr) || (!is_array($value) || $explicitArray) ) {
  69. if (empty($section)) {
  70. if (strtolower($partName) == 'from' && in_array($value, $this->_parts[$partName])) {
  71. return $this;
  72. }
  73. $this->_debug('adding ' . $partName . ' part "' . $value . '"');
  74. $this->_parts[$partName][] = $value;
  75. } else {
  76. $this->_parts[$partName][$section][] = $value;
  77. }
  78. return $this;
  79. }
  80. foreach ($value as $idx => $_value) {
  81. $this->_addPart($partName, $_value, $section, false);
  82. }
  83. return $this;
  84. }
  85. protected function _getPart($partName) {
  86. if (!isset($this->_parts[$partName]) || empty($this->_parts[$partName])) {
  87. return null;
  88. }
  89. return $this->_parts[$partName];
  90. }
  91. /**
  92. * @param <type> $fieldNames
  93. * @return Xedin_Core_Model_Db_Adapter
  94. */
  95. public function select($fieldNames) {
  96. $this->_debug('selecting "' . implode(',', (array) $fieldNames) . '"');
  97. $this->_addPart('select', $fieldNames);
  98. return $this;
  99. }
  100. /**
  101. * @param <type> $tableName
  102. * @param <type> $fieldNames
  103. * @return Xedin_Core_Model_Db_Adapter
  104. */
  105. public function update($tableName, $fieldNames) {
  106. $this->_addPart('update', $tableName);
  107. $this->_parts['set'] = $fieldNames;
  108. return $this;
  109. }
  110. /**
  111. * @param <type> $tableName
  112. * @param <type> $values
  113. * @param <type> $fieldNames
  114. * @return Xedin_Core_Model_Db_Adapter
  115. */
  116. public function insert($tableName, $values, $fieldNames = null) {
  117. $this->_addPart('into', $tableName);
  118. $this->_addPart('values', $values);
  119. if (!is_null($fieldNames)) {
  120. $this->_addPart('_fields', $fieldNames);
  121. }
  122. return $this;
  123. }
  124. /**
  125. * @param <type> $tableName
  126. * @param <type> $tableAlias
  127. * @return Xedin_Core_Model_Db_Adapter
  128. */
  129. public function from($tableName, $tableAlias = null) {
  130. if (!is_array($tableName)) {
  131. $fromEntry = array('table_name' => $tableName);
  132. if (!is_null($tableAlias)) {
  133. $fromEntry['alias'] = $tableAlias;
  134. }
  135. $this->_parts['from'][] = $fromEntry;
  136. return $this;
  137. }
  138. foreach ($tableName as $idx => $value) {
  139. // If numeric index, add with no alias
  140. if (is_number($idx)) {
  141. $this->from($value);
  142. } else {
  143. $this->from($idx, $value);
  144. }
  145. }
  146. return $this;
  147. }
  148. /**
  149. * @param <type> $conditions
  150. * @param <type> $all
  151. * @return Xedin_Core_Model_Db_Adapter
  152. */
  153. public function where($conditions, $all = false) {
  154. $this->andWhere($conditions, $all);
  155. return $this;
  156. }
  157. /**
  158. * @param array $conditions
  159. * @param bool $all
  160. * @return Xedin_Core_Model_Db_Adapter
  161. */
  162. public function andWhere($conditions, $all = false) {
  163. if (isset($conditions['field']) || (isset($conditions[0]) && !is_array($conditions[0]))) {
  164. $conditions = array($conditions);
  165. }
  166. $this->_parts['where']['and'][] = array('conditions' => $conditions, 'all' => $all);
  167. return $this;
  168. }
  169. /**
  170. * @param <type> $conditions
  171. * @param <type> $all
  172. * @return Xedin_Core_Model_Db_Adapter
  173. */
  174. public function orWhere($conditions, $all = false) {
  175. if (isset($conditions['field']) || (isset($conditions[0]) && !is_array($conditions[0])) || $conditions instanceof Zend_Db_Expr ) {
  176. $conditions = array($conditions);
  177. }
  178. $this->_parts['where']['or'][] = array('conditions' => $conditions, 'all' => $all);
  179. return $this;
  180. }
  181. /**
  182. * @return Xedin_Core_Model_Db_Adapter
  183. */
  184. public function delete() {
  185. $this->_addPart('delete', true);
  186. return $this;
  187. }
  188. /**
  189. * @param string|Zend_Db_Expression $fieldName
  190. * @param bool $ascending
  191. * @return Xedin_Core_Model_Db_Adapter
  192. */
  193. public function orderBy($fieldName, $ascending = true) {
  194. if( $fieldName instanceof Zend_Db_Expr ) {
  195. /* @var $fieldName Zend_Db_Expr */
  196. $this->_parts['order'] = $fieldName;
  197. return $this;
  198. }
  199. $order = $ascending ? 'asc' : 'desc';
  200. foreach ($fieldName as $idx => $_fieldName) {
  201. $this->_parts['order'][$order][$field][] = $_fieldName;
  202. }
  203. return $this;
  204. }
  205. /**
  206. * @param <type> $limit
  207. * @param <type> $offset
  208. * @return Xedin_Core_Model_Db_Adapter
  209. */
  210. public function limit($limit, $offset = 0) {
  211. $this->_parts['limit'] = array('limit' => $limit, 'offset' => $offset);
  212. return $this;
  213. }
  214. public function quoteField($fieldName) {
  215. if (!is_array($fieldName)) {
  216. $fieldName = array($fieldName);
  217. }
  218. foreach ($fieldName as $idx => $_fieldName) {
  219. if (stripos($_fieldName, '.')) {
  220. $complexName = explode('.', $_fieldName);
  221. // if (!$this->hasFrom($complexName[0])) {
  222. // $this->from($complexName[0]);
  223. // }
  224. $tableName = $complexName[0];
  225. if( $this->isAutoPrefix() ) {
  226. $tableName = $this->getPrefix($tableName);
  227. }
  228. $complexName[0] = $this->_surround($tableName, '`', null);
  229. if (trim($complexName[1]) != '*') {
  230. $complexName[1] = $this->_surround($complexName[1], '`', null);
  231. }
  232. $fieldName[$idx] = implode('.', $complexName);
  233. } else {
  234. $fieldName[$idx] = $this->_surround($_fieldName, '`');
  235. }
  236. }
  237. return implode(', ', $fieldName);
  238. }
  239. public function hasFrom($tableName) {
  240. $fromPart = $this->_getPart('from');
  241. foreach ($fromPart as $idx => $_from) {
  242. if ($_from['table_name'] == $tableName) {
  243. return true;
  244. }
  245. }
  246. return false;
  247. }
  248. public function quoteValue($value) {
  249. return $this->_surround($value, '\'', null, ', ');
  250. }
  251. protected function _surround($string, $before, $after = null, $delimiter = null) {
  252. if (is_null($string)) {
  253. return 'NULL';
  254. }
  255. if (is_null($after)) {
  256. $after = $before;
  257. }
  258. if (!is_array($string)) {
  259. return $before . $string . $after;
  260. }
  261. $surroundedStrings = array();
  262. foreach ($string as $idx => $_string) {
  263. $surroundedStrings[] = $this->_surround($_string, $before, $after);
  264. }
  265. if (!is_null($delimiter)) {
  266. $surroundedStrings = implode($delimiter, $surroundedStrings);
  267. }
  268. return $surroundedStrings;
  269. }
  270. /**
  271. * @return string The complete query string from the current parts.
  272. */
  273. public function getQueryString() {
  274. $queryString = '';
  275. $hasPart = false;
  276. foreach (array('update', 'values', 'from', 'delete') as $idx => $_queryType) {
  277. if ($this->hasPart($_queryType)) {
  278. $hasPart = $_queryType;
  279. }
  280. }
  281. if (!$hasPart) {
  282. $this->_debug(print_r(debug_backtrace(), true));
  283. throw new Exception(get_class($this) . ': Query must be one of the following types: SELECT, INSERT, UPDATE, DELETE.');
  284. }
  285. switch ($hasPart) {
  286. case 'delete':
  287. $conditionString = $this->_getConditionString();
  288. $fromString = $this->_getFromString();
  289. $queryString .= $this->_getDeleteString() . $fromString . $conditionString;
  290. break;
  291. case 'from':
  292. $selectString = $this->_getSelectString();
  293. if (empty($selectString)) {
  294. $selectString = 'SELECT *' . "\n";
  295. }
  296. $conditionString = $this->_getConditionString();
  297. $joinString = $this->_getJoinString();
  298. $fromString = $this->_getFromString();
  299. $queryString .= $this->_getSelectString() . $fromString . $joinString . $conditionString . $this->_getGroupByString() . $this->_getOrderByString() . $this->_getLimitString();
  300. break;
  301. case 'values':
  302. $queryString .= $this->_getInsertString();
  303. break;
  304. case 'update':
  305. $queryString .= $this->_getUpdateString() . $this->_getConditionString();
  306. break;
  307. }
  308. return $queryString;
  309. }
  310. /**
  311. * @return string
  312. */
  313. protected function _getSelectString() {
  314. $selectString = '';
  315. $part = $this->_getPart('select');
  316. if (is_null($part)) {
  317. return 'SELECT *' . "\n";
  318. }
  319. $this->_debug('building select "' . implode(', ', (array) $part) . '"');
  320. $selectString = 'SELECT ' . $this->quoteField($part) . "\n";
  321. return $selectString;
  322. }
  323. /**
  324. * @return string
  325. */
  326. protected function _getInsertString() {
  327. $insertString = 'INSERT';
  328. $valuesPart = $this->_getPart('values');
  329. if (is_null($valuesPart)) {
  330. return '';
  331. }
  332. $intoPart = $this->_getPart('into');
  333. if (is_null($intoPart)) {
  334. return '';
  335. }
  336. $insertString .= ' INTO ' . $this->quoteField($this->getPrefix($intoPart)) . ' ';
  337. $fieldsPart = $this->_getPart('_fields');
  338. if (!is_null($fieldsPart)) {
  339. $insertString .= '(' . $this->quoteField($fieldsPart) . ')' . "\n";
  340. }
  341. $insertString .= 'VALUES (' . $this->quoteValue($valuesPart) . ')' . "\n";
  342. return $insertString;
  343. }
  344. /**
  345. * @return string
  346. */
  347. protected function _getFromString() {
  348. $fromString = 'FROM';
  349. $fromPart = $this->_getPart('from');
  350. if (is_null($fromPart)) {
  351. return '';
  352. }
  353. $fromEntries = array();
  354. foreach ($fromPart as $idx => $_from) {
  355. $fromEntry = '';
  356. if( $this->isAutoPrefix() ) {
  357. $_from['table_name'] = $this->getPrefix($_from['table_name']);
  358. }
  359. $fromEntry .= "\t" . $this->quoteField($_from['table_name']);
  360. if (isset($_from['alias']) && !empty($_form['alias'])) {
  361. $fromEntry .= '.' . $this->quoteField($_from['alias']);
  362. }
  363. $fromEntries[] = $fromEntry;
  364. }
  365. $fromString .= implode(', ', $fromEntries) . "\n";
  366. return $fromString;
  367. }
  368. /**
  369. * @return string
  370. */
  371. protected function _getUpdateString() {
  372. $updateString = '';
  373. $updatePart = $this->_getPart('update');
  374. $setPart = $this->_getPart('set');
  375. if (is_null($updatePart) || is_null($setPart)) {
  376. return '';
  377. }
  378. $updateString .= 'UPDATE ' . $this->quoteField($this->getPrefix($updatePart)) . "\n";
  379. $updateString .= 'SET ';
  380. $setEntries = array();
  381. foreach ($setPart as $field => $value) {
  382. $setEntries[] = $this->quoteField($field) . ' = ' . $this->quoteValue($value);
  383. }
  384. $updateString .= implode(', ', $setEntries) . "\n";
  385. return $updateString;
  386. }
  387. /**
  388. * @return string
  389. */
  390. protected function _getDeleteString() {
  391. $deleteString = '';
  392. $deletePart = $this->_getPart('delete');
  393. if (!$deletePart) {
  394. return '';
  395. }
  396. $deleteString = 'DELETE ';
  397. return $deleteString;
  398. }
  399. /**
  400. * @return string
  401. */
  402. protected function _getOrderByString() {
  403. $orderString = '';
  404. $orderPart = $this->_getPart('order');
  405. if (!$orderPart) {
  406. return '';
  407. }
  408. if( $orderPart instanceof Zend_Db_Expr ) {
  409. return 'ORDER BY ' . (string)$orderPart . "\n";
  410. }
  411. foreach ($orderPart as $idx => $_order) {
  412. $orderEntries = array();
  413. foreach ($_order as $idx2 => $_fieldName) {
  414. $orderEntries[] = $this->quoteField($_fieldName) . ' ' . ( (strtolower($_order) == 'asc') ? 'ASC' : 'DESC' );
  415. }
  416. $orderString .= implode(', ', $orderEntries);
  417. }
  418. return 'ORDER BY ' . $orderString . "\n";
  419. }
  420. /**
  421. * @return string
  422. */
  423. protected function _getLimitString() {
  424. $limitString = '';
  425. $limitPart = $this->_getPart('limit');
  426. if (!$limitPart) {
  427. return '';
  428. }
  429. if ($limitPart['offset']) {
  430. $limitString .= $limitPart['offset'] . ',';
  431. }
  432. $limitString .= $limitPart['limit'];
  433. return 'LIMIT ' . $limitString . "\n";
  434. }
  435. /**
  436. * @return string
  437. */
  438. protected function _getConditionString() {
  439. $conditionString = '';
  440. $wherePart = $this->_getPart('where');
  441. if (is_null($wherePart) || empty($wherePart)) {
  442. return 'WHERE 1 ';
  443. }
  444. $k = 0;
  445. foreach ($wherePart as $_typeKey => $_type) {
  446. /**
  447. * @var string $_typeKey either 'and' or 'or'
  448. * @var array $_type contains numbered sections
  449. */
  450. $i = 0;
  451. if( $k>0 ) {
  452. $conditionString .= ' AND ';
  453. }
  454. $whereEntry = '';
  455. foreach ($_type as $_sectionIndex => $_section) {
  456. /**
  457. * @var int $_sectionIndex Numeric index of section
  458. * @var array $_section Array
  459. */
  460. $conditionSections = array();
  461. // <editor-fold defaultstate="collapsed" desc="Inner conditions loop">
  462. foreach ($_section['conditions'] as $_conditionIndex => $_condition) {
  463. if (!is_array($_condition)) {
  464. $conditionSections[] = $_condition;
  465. continue;
  466. }
  467. $field = '';
  468. if (isset($_condition['field'])) {
  469. $field = $_condition['field'];
  470. } elseif (!isset($_condition['field']) && isset($_condition[0])) {
  471. $field = $_condition[0];
  472. } else {
  473. throw new Exception(get_class($this) . ': Field is not set in condition.');
  474. }
  475. $operator = '';
  476. $value = '';
  477. if (isset($_condition['operator'])) {
  478. $operator = $_condition['operator'];
  479. } elseif (!isset($_condition['operator']) && isset($_condition[1]) && isset($_condition[2])) {
  480. $operator = $_condition[1];
  481. } elseif (!isset($_codition['operator']) && isset($_condition[1]) && !isset($_condition[2])) {
  482. $operator = '=';
  483. $value = $_condition[1];
  484. } else {
  485. throw new Exception(get_class($this) . ': Operator not set in condition.');
  486. }
  487. if (isset($_condition['value'])) {
  488. $value = $_condition['value'];
  489. } elseif (!isset($_condition['value']) && isset($_condition[2])) {
  490. $value = $_condition[2];
  491. } else {
  492. if (!isset($_condition[1]))
  493. throw new Exception(get_class($this) . ': Value not set in condition.');
  494. }
  495. $field = $this->quoteField($field);
  496. $value = $this->quoteValue($value);
  497. if ($operator == 'IN' || $operator == 'NOT IN') {
  498. $value = '(' . $value . ')';
  499. }
  500. $conditionSections[] = $field . ' ' . $operator . ' ' . $value;
  501. }// </editor-fold>
  502. $logicalOperator = $_section['all'] ? ' AND ' : ' OR ';
  503. $whereEntry = implode($logicalOperator, $conditionSections);
  504. if (count($conditionSections) > 1) {
  505. $whereEntry = '(' . $whereEntry . ')';
  506. }
  507. if ($i > 0) {
  508. switch (strtolower($_typeKey)) {
  509. case 'and':
  510. $conditionString .= ' AND ';
  511. break;
  512. case 'or':
  513. $conditionString .= ' OR ';
  514. break;
  515. }
  516. }
  517. $conditionString .= $whereEntry;
  518. $i++;
  519. }
  520. $k++;
  521. }
  522. return 'WHERE ' . $conditionString . "\n";
  523. }
  524. /**
  525. * @return wpdb The wordpress database instance
  526. */
  527. public function getConnection() {
  528. return $this->_connection;
  529. }
  530. /**
  531. * @param string $part
  532. * @param bool $all
  533. * @return bool
  534. */
  535. public function hasPart($part, $all = false) {
  536. if (!is_array($part)) {
  537. $part = strtolower($part);
  538. return ( isset($this->_parts[$part]) && !empty($this->_parts[$part]) );
  539. }
  540. foreach ($part as $idx => $_part) {
  541. if ($all && !$this->hasPart($part)) {
  542. return false;
  543. } elseif (!$all && $this->hasPart($part)) {
  544. return true;
  545. }
  546. }
  547. return!$all;
  548. }
  549. public function execute() {
  550. $string = $this->getQueryString();
  551. $this->reset();
  552. $this->query($string);
  553. $result = $this->getResults();
  554. return $result;
  555. }
  556. public function reset() {
  557. $this->_parts = array();
  558. }
  559. public function flush() {
  560. @mysql_free_result($this->_result);
  561. $this->_result = null;
  562. $this->_lastResult = null;
  563. $this->_affectedRows = null;
  564. $this->_insertId = null;
  565. return $this;
  566. }
  567. /**
  568. * @param string $query
  569. * @return Xedin_Wordpress_Db
  570. */
  571. public function query($query) {
  572. $this->_debug($query);
  573. $this->flush();
  574. $this->_lastQuery = $query;
  575. $this->_result = mysql_query($query, $this->getConnection());if ( preg_match( '/^\s*(insert|delete|update|replace) /i', $query ) ) {
  576. $this->_affectedRows = mysql_affected_rows( $this->getConnection() );
  577. if ( preg_match( '/^\s*(insert|replace) /i', $query ) ) {
  578. $this->_insertId = mysql_insert_id($this->getConnection() );
  579. }
  580. }
  581. if ($this->getLastError()) {
  582. throw new Exception(get_class($this) . ': ' . $this->getLastError() . ' in query "' . $this->getLastQuery() . '".');
  583. }
  584. return $this;
  585. }
  586. /**
  587. * @param string $query
  588. * @return array Result array with rows.
  589. */
  590. public function getResults() {
  591. if( empty($this->_lastResult) ) {
  592. $this->_lastResult = array();
  593. while( $_row = mysql_fetch_assoc($this->_result) ) {
  594. $this->_lastResult[] = $_row;
  595. }
  596. }
  597. return $this->_lastResult;
  598. }
  599. public function getPrefix($tableName = '') {
  600. global $wpdb;
  601. if (empty($tableName)) {
  602. return $wpdb->prefix;
  603. }
  604. if (!is_array($tableName)) {
  605. return $wpdb->prefix . $tableName;
  606. }
  607. $prefixedTableNames = array();
  608. foreach ($tableName as $idx => $_tableName) {
  609. $prefixedTableNames[] = $wpdb->prefix . $_tableName;
  610. }
  611. return $prefixedTableNames;
  612. }
  613. public function getAffectedRows() {
  614. return $this->getConnection()->_affectedRows;
  615. }
  616. public function getInsertId() {
  617. return $this->_insertId;
  618. }
  619. public function getLastQuery() {
  620. return $this->_lastQuery;
  621. }
  622. public function getLastResult() {
  623. return $this->getConnection()->_lastResult;
  624. }
  625. public function getNumRows() {
  626. return mysql_num_rows($this->_result);
  627. }
  628. /**
  629. *
  630. * @return string|null Error text if error occured; null otherwise.
  631. */
  632. public function getLastError() {
  633. $lastError = mysql_error($this->getConnection());
  634. return empty($lastError) ? null : $lastError;
  635. }
  636. public function getQueries() {
  637. return $this->getConnection()->queries;
  638. }
  639. /**
  640. * Gets a list of table fields.
  641. * The table name will not be prefixed.
  642. * If the second parameter is false, returns an array containing arrays with field info.
  643. * Otherwise, returns an array containing field names.
  644. *
  645. * @see http://dev.mysql.com/doc/refman/5.0/en/show-columns.html
  646. * @param string $tableName Name of the table for which to list fields.
  647. * @param type $namesOnly Whether or not to exclude field info, leaving only field names. Default: false.
  648. * @return array Field information or list of field names.
  649. */
  650. public function getFieldList($tableName, $namesOnly = false) {
  651. $fields = $this->query('SHOW FIELDS FROM ' . $this->quoteField($tableName));
  652. if (!$namesOnly) {
  653. return $fields;
  654. }
  655. $fieldNames = array();
  656. foreach ($fields as $idx => $_fieldInfo) {
  657. $fieldNames[] = $_fieldInfo[self::MYSQL_FIELD_NAME_KEY];
  658. }
  659. return $fieldNames;
  660. }
  661. public function getOne($index = 0) {
  662. $result = $this->execute();
  663. // Temporary test
  664. if (!isset($result[$index])) {
  665. return array();
  666. }
  667. return $result[$index];
  668. }
  669. public function join($tables, $fields) {
  670. $tables = (array) $tables;
  671. $fields = (array) $fields;
  672. $this->_addPart('join', $tables, 'tables', true);
  673. $this->_addPart('join', $fields, 'fields', true);
  674. return $this;
  675. }
  676. protected function _getJoinString() {
  677. $string = '';
  678. foreach ($this->_joinTypes as $idx => $_joinType) {
  679. if (!$this->hasPart($_joinType)) {
  680. continue;
  681. }
  682. $_joinPart = $this->_getPart($_joinType);
  683. foreach ($_joinPart['tables'] as $i => $_tables) {
  684. if( $this->isAutoPrefix() ) {
  685. $_tables = $this->getPrefix($_tables);
  686. }
  687. $string .= strtoupper($_joinType) . ' ';
  688. $string .= '(' . $this->quoteField( $_tables ) . ')';
  689. $string .= ' ON ';
  690. $string .= '(';
  691. $fields = $_joinPart['fields'][$i];
  692. foreach ($fields as $k => $_conditions) {
  693. foreach ($_conditions as $_field1 => $_field2) {
  694. $string .= $this->quoteField($_field1) . ' = ' . $this->quoteField($_field2) . ' AND';
  695. }
  696. }
  697. $string = substr($string, 0, strlen($string) - 4); // Remove the " AND" from the end
  698. $string .= ')';
  699. $string .= "\n";
  700. }
  701. }
  702. return $string;
  703. }
  704. public function groupBy($fields) {
  705. $this->_addPart('group by', $fields);
  706. return $this;
  707. }
  708. public function group($fields) {
  709. $this->groupBy($fields);
  710. return $this;
  711. }
  712. protected function _getGroupByString() {
  713. if( !$this->hasPart('group by') ) {
  714. return '';
  715. }
  716. return 'GROUP BY ' . $this->quoteField($this->_getPart('group by')) . "\n";
  717. }
  718. }
  719. ?>