diff --git a/dibi/drivers/postgre.php b/dibi/drivers/postgre.php index cc633e45..18a4bc22 100644 --- a/dibi/drivers/postgre.php +++ b/dibi/drivers/postgre.php @@ -249,6 +249,7 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver } case dibi::IDENTIFIER: + // @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS $a = strrpos($value, '.'); if ($a === FALSE) { return '"' . str_replace('"', '""', $value) . '"'; diff --git a/dibi/libs/DibiConnection.php b/dibi/libs/DibiConnection.php index 316e05ea..fe37915d 100644 --- a/dibi/libs/DibiConnection.php +++ b/dibi/libs/DibiConnection.php @@ -92,7 +92,7 @@ class DibiConnection extends DibiObject $driver = preg_replace('#[^a-z0-9_]#', '_', $config['driver']); $class = "Dibi" . $driver . "Driver"; if (!class_exists($class, FALSE)) { - include_once __FILE__ . "/../../drivers/$driver.php"; + include_once dirname(__FILE__) . "/../drivers/$driver.php"; if (!class_exists($class, FALSE)) { throw new DibiException("Unable to create instance of dibi driver class '$class'."); diff --git a/dibi/libs/DibiFluent.php b/dibi/libs/DibiFluent.php index 3bcbf75b..bf5b514e 100644 --- a/dibi/libs/DibiFluent.php +++ b/dibi/libs/DibiFluent.php @@ -259,12 +259,11 @@ class DibiFluent extends DibiObject * Fetches all records from table. * @param int offset * @param int limit - * @param bool simplify one-column result set? * @return array */ - public function fetchAll($offset = NULL, $limit = NULL, $simplify = TRUE) + public function fetchAll($offset = NULL, $limit = NULL) { - return $this->execute()->fetchAll($offset, $limit, $simplify); + return $this->execute()->fetchAll($offset, $limit); } diff --git a/dibi/libs/DibiResult.php b/dibi/libs/DibiResult.php index fdb24c79..b7e532a2 100644 --- a/dibi/libs/DibiResult.php +++ b/dibi/libs/DibiResult.php @@ -312,10 +312,9 @@ class DibiResult extends DibiObject implements IDataSource * * @param int offset * @param int limit - * @param bool simplify one-column result set? * @return array */ - final public function fetchAll($offset = NULL, $limit = NULL, $simplify = TRUE) + final public function fetchAll($offset = NULL, $limit = NULL) { $limit = $limit === NULL ? -1 : (int) $limit; $this->seek((int) $offset); @@ -323,22 +322,11 @@ class DibiResult extends DibiObject implements IDataSource if (!$row) return array(); // empty result set $data = array(); - if ($simplify && !$this->objects && count($row) === 1) { - // special case: one-column result set - $key = key($row); - do { - if ($limit === 0) break; - $limit--; - $data[] = $row[$key]; - } while ($row = $this->fetch()); - - } else { - do { - if ($limit === 0) break; - $limit--; - $data[] = $row; - } while ($row = $this->fetch()); - } + do { + if ($limit === 0) break; + $limit--; + $data[] = $row; + } while ($row = $this->fetch()); return $data; } @@ -456,13 +444,16 @@ class DibiResult extends DibiObject implements IDataSource throw new InvalidArgumentException("Either none or both columns must be specified."); } - if (count($row) < 2) { - throw new UnexpectedValueException("Result must have at least two columns."); - } - // autodetect $tmp = array_keys($row); $key = $tmp[0]; + if (count($row) < 2) { // indexed-array + do { + $data[] = $row[$key]; + } while ($row = $this->fetch(FALSE)); + return $data; + } + $value = $tmp[1]; } else { @@ -633,7 +624,7 @@ class DibiResult extends DibiObject implements IDataSource */ final public function getIterator($offset = NULL, $limit = NULL) { - return new ArrayIterator($this->fetchAll($offset, $limit, FALSE)); + return new ArrayIterator($this->fetchAll($offset, $limit)); } diff --git a/dibi/libs/DibiTable.php b/dibi/libs/DibiTable.php index 13204661..fc0d1ef0 100644 --- a/dibi/libs/DibiTable.php +++ b/dibi/libs/DibiTable.php @@ -162,9 +162,15 @@ abstract class DibiTable extends DibiObject */ public function update($where, $data) { + $data = $this->prepare($data); + if ($where === NULL && isset($data[$this->primary])) {; + $where = $data[$this->primary]; + unset($data[$this->primary]); + } + $this->connection->query( 'UPDATE %n', $this->name, - 'SET %a', $this->prepare($data), + 'SET %a', $data, 'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')' ); return $this->connection->affectedRows(); @@ -172,6 +178,36 @@ abstract class DibiTable extends DibiObject + /** + * Inserts or updates rows in a table. + * @param array|object + * @return int (new) primary key + */ + public function insertOrUpdate($data) + { + $data = $this->prepare($data); + if (!isset($data[$this->primary])) { + throw new InvalidArgumentException("Missing primary key '$this->primary' in dataset."); + } + + try { + $this->connection->query( + 'INSERT INTO %n', $this->name, '%v', $data + ); + + } catch (DibiDriverException $e) { + $where = $data[$this->primary]; + unset($data[$this->primary]); + $this->connection->query( + 'UPDATE %n', $this->name, + 'SET %a', $data, + 'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')' + ); + } + } + + + /** * Deletes rows from a table by primary key. * @param mixed primary key value(s) diff --git a/dibi/libs/DibiTranslator.php b/dibi/libs/DibiTranslator.php index cd3063f8..4b9d9196 100644 --- a/dibi/libs/DibiTranslator.php +++ b/dibi/libs/DibiTranslator.php @@ -198,11 +198,11 @@ final class DibiTranslator extends DibiObject if (is_array($value)) { $vx = $kx = array(); - $separator = ', '; + $operator = ', '; switch ($modifier) { case 'and': case 'or': // key=val AND key IS NULL AND ... - $separator = ' ' . strtoupper($modifier) . ' '; + $operator = ' ' . strtoupper($modifier) . ' '; if (empty($value)) { return '1'; @@ -215,21 +215,12 @@ final class DibiTranslator extends DibiObject foreach ($value as $k => $v) { $pair = explode('%', $k, 2); // split into identifier & modifier $k = $this->delimite($pair[0]); - if (isset($pair[1])) { - $pair = explode(' ', $pair[1], 2); // split into modifier & operator - $op = isset($pair[1]) ? $pair[1] : '='; - $v = $this->formatValue($v, $pair[0]); - } else { - $op = '='; - $v = $this->formatValue($v, FALSE); - } - if ($v === 'NULL') { - $op = 'IS'; - } + $v = $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE); + $op = isset($pair[1]) && $pair[1] === 'l' ? 'IN' : ($v === 'NULL' ? 'IS' : '='); $vx[] = $k . ' ' . $op . ' ' . $v; } } - return implode($separator, $vx); + return implode($operator, $vx); case 'a': // key=val, key=val, ... foreach ($value as $k => $v) { @@ -237,7 +228,7 @@ final class DibiTranslator extends DibiObject $vx[] = $this->delimite($pair[0]) . '=' . $this->formatValue($v, isset($pair[1]) ? $pair[1] : FALSE); } - return implode($separator, $vx); + return implode($operator, $vx); case 'l': // (val, val, ...) @@ -256,6 +247,13 @@ final class DibiTranslator extends DibiObject } return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')'; + case 'by': // key ASC, key DESC + foreach ($value as $k => $v) { + $v = (is_string($v) && strcasecmp($v, 'desc')) || $v > 0 ? 'ASC' : 'DESC'; + $vx[] = $this->delimite($k) . ' ' . $v; + } + return implode(', ', $vx); + default: // value, value, value - all with the same modifier foreach ($value as $v) { $vx[] = $this->formatValue($v, $modifier); diff --git a/examples/dibi.table.php b/examples/dibi.table.php index 01a1ea5c..6d27dd29 100644 --- a/examples/dibi.table.php +++ b/examples/dibi.table.php @@ -31,7 +31,7 @@ class Products extends DibiTable // create table object -$products = new Products(); +$products = new Products; echo "Table name: $products->name\n"; echo "Primary key: $products->primary\n"; @@ -83,6 +83,13 @@ $id = $products->insert($data); var_dump($id); // generated id +// inserts or updates row into a table +$data = array(); +$data['title'] = 'New product'; +$data[$products->primary] = 5; +$products->insertOrUpdate($data); + + // is absolutely SQL injection safe $key = '3 OR 1=1'; $products->delete($key); diff --git a/examples/sql-builder.php b/examples/sql-builder.php index 256c8dcf..18047cb8 100644 --- a/examples/sql-builder.php +++ b/examples/sql-builder.php @@ -64,3 +64,15 @@ SELECT * FROM [people] WHERE [id] IN (", $array, ") "); + + +// ORDER BY array +$order = array( + 'field1' => 'asc', + 'field2' => 'desc', +); +dibi::test(" +SELECT * +FROM [people] +ORDER BY %by", $order, " +"); diff --git a/icons/example.html b/icons/example.html index f6e0e7f2..560423ed 100644 --- a/icons/example.html +++ b/icons/example.html @@ -1,2 +1,16 @@ + + + +