From dd6ffc3d0e608cdda0aef32917cb78d08f1db0fc Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 5 Feb 2009 21:10:50 +0000 Subject: [PATCH] - DibiTranslator: modifiers %ex, %by, %n improved, %SQL added - DibiDataSource: allows select columns, sorting and conditions --- dibi/libs/DibiDataSource.php | 122 +++++++++++++++++++++++++++++++---- dibi/libs/DibiTranslator.php | 19 ++++-- 2 files changed, 122 insertions(+), 19 deletions(-) diff --git a/dibi/libs/DibiDataSource.php b/dibi/libs/DibiDataSource.php index 20ad30e6..7390177d 100644 --- a/dibi/libs/DibiDataSource.php +++ b/dibi/libs/DibiDataSource.php @@ -38,6 +38,15 @@ class DibiDataSource extends DibiObject implements IDataSource /** @var int */ private $count; + /** @var array */ + private $cols = array(); + + /** @var array */ + private $sorting = array(); + + /** @var array */ + private $conds = array(); + /** @@ -46,14 +55,7 @@ class DibiDataSource extends DibiObject implements IDataSource */ public function __construct($sql, DibiConnection $connection = NULL) { - if (strpos($sql, ' ') === FALSE) { - // table name - $this->sql = $sql; - } else { - // SQL command - $this->sql = '(' . $sql . ') AS [source]'; - } - + $this->sql = $sql; $this->connection = $connection === NULL ? dibi::getConnection() : $connection; } @@ -63,15 +65,17 @@ class DibiDataSource extends DibiObject implements IDataSource * @param int offset * @param int limit * @param array columns - * @return ArrayIterator + * @return DibiResultIterator */ public function getIterator($offset = NULL, $limit = NULL) { return $this->connection->query(' - SELECT * - FROM', $this->sql, ' + SELECT %n', (empty($this->cols) ? '*' : $this->cols), ' + FROM (%SQL) AS [t]', $this->sql, ' + WHERE %and', $this->conds, ' + ORDER BY %by', $this->sorting, ' %ofs %lmt', $offset, $limit - ); + )->getIterator(); } @@ -82,11 +86,101 @@ class DibiDataSource extends DibiObject implements IDataSource public function count() { if ($this->count === NULL) { - $this->count = $this->connection->query(' - SELECT COUNT(*) FROM', $this->sql + $this->count = $this->connection->nativeQuery( + 'SELECT COUNT(*) FROM (' . $this->sql . ') AS t' )->fetchSingle(); } return $this->count; } + + + + /** + * Returns SQL wrapped as DibiFluent. + * @return DibiFluent + * @throws DibiException + */ + public function toFluent() + { + return $this->connection->select('*')->from('(%SQL) AS [t]', $this->__toString()); + } + + + + /** + * @return DibiDataSource + */ + public function toDataSource() + { + return new self($this->__toString(), $this->connection); + } + + + + /** + * Returns SQL query. + * @return string + */ + final public function __toString() + { + return $this->connection->sql(' + SELECT %n', (empty($this->cols) ? '*' : $this->cols), ' + FROM (%SQL) AS [t]', $this->sql, ' + WHERE %and', $this->conds, ' + ORDER BY %by', $this->sorting, ' + '); + } + + + + /** + */ + public function select($col, $as = NULL) + { + if (is_array($col)) { + $this->cols = $col; + } else { + $this->cols[$col] = $as; + } + } + + + + /** + */ + public function where($cond) + { + if (is_array($cond)) { + // TODO: not consistent with select and orderBy + $this->conds[] = $cond; + } else { + $this->conds[] = func_get_args(); + } + } + + + + /** + */ + public function orderBy($row, $sorting = 'ASC') + { + if (is_array($row)) { + $this->sorting = $row; + } else { + $this->sorting[$row] = $sorting; + } + } + + + + /** + * Returns the dibi connection. + * @return DibiConnection + */ + final public function getConnection() + { + return $this->connection; + } + } diff --git a/dibi/libs/DibiTranslator.php b/dibi/libs/DibiTranslator.php index 0b249693..d278752c 100644 --- a/dibi/libs/DibiTranslator.php +++ b/dibi/libs/DibiTranslator.php @@ -213,8 +213,8 @@ final class DibiTranslator extends DibiObject $v = $this->formatValue($v, FALSE); $vx[] = $k . ($v === 'NULL' ? 'IS ' : '= ') . $v; - } elseif ($pair[1] === 'ex') { - $vx[] = $k . $this->formatValue($v, 'sql'); + } elseif ($pair[1] === 'ex') { // TODO: this will be removed + $vx[] = $k . $this->formatValue($v, 'ex'); } else { $v = $this->formatValue($v, $pair[1]); @@ -222,7 +222,7 @@ final class DibiTranslator extends DibiObject } } else { - $vx[] = $this->formatValue($v, 'sql'); + $vx[] = $this->formatValue($v, 'ex'); } } return implode(' ' . strtoupper($modifier) . ' ', $vx); @@ -264,6 +264,10 @@ final class DibiTranslator extends DibiObject return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')'; case 'by': // key ASC, key DESC + if (empty($value)) { + return '1'; + } + foreach ($value as $k => $v) { if (is_string($k)) { $v = (is_string($v) && strncasecmp($v, 'd', 1)) || $v > 0 ? 'ASC' : 'DESC'; @@ -274,6 +278,7 @@ final class DibiTranslator extends DibiObject } return implode(', ', $vx); + case 'ex': case 'sql': $translator = new self($this->driver); return $translator->translate($value); @@ -337,7 +342,8 @@ final class DibiTranslator extends DibiObject case 'n': // identifier name return $this->delimite($value); - case 'sql':// preserve as SQL + case 'ex': + case 'sql': // preserve as dibi-SQL (TODO: leave only %ex) $value = (string) $value; // speed-up - is regexp required? $toSkip = strcspn($value, '`[\'"'); @@ -351,6 +357,9 @@ final class DibiTranslator extends DibiObject ); } + case 'SQL': // preserve as real SQL (TODO: rename to %sql) + return (string) $value; + case 'and': case 'or': case 'a': @@ -496,7 +505,7 @@ final class DibiTranslator extends DibiObject */ private function delimite($value) { - return $this->driver->escape(dibi::substitute($value), dibi::IDENTIFIER); + return $value === '*' ? '*' : $this->driver->escape(dibi::substitute($value), dibi::IDENTIFIER); }