1
0
mirror of https://github.com/dg/dibi.git synced 2025-08-04 13:17:58 +02:00

* added DibiTable

* new connection options: "result:objects" & "result:withtables"
* renamed DibiDriverInterface -> IDibiDriver, DibiVariableInterface -> IDibiVariable
This commit is contained in:
David Grudl
2008-01-15 03:43:03 +00:00
parent da0a239d6d
commit 5c045e58dc
21 changed files with 461 additions and 58 deletions

View File

@@ -1,6 +1,5 @@
- dibi::insertOrUpdate...
- sjednotit DibiVariable, modifier a type u DibiDriverInterface::format()
- odstranit podporu pro modifik<69>tory v kli<6C><69>ch pole?
- sjednotit DibiVariable, modifier a type u IDibiDriver::format()
- odstranit podporu pro modifik<69>tory v kl<6B><6C><EFBFBD>ch pole?
- odstranit podporu pro conditional query?
- odstranit podporu pro meta types - odstraneno
- event, log, profiler

View File

@@ -35,14 +35,15 @@ if (!class_exists('NObject', FALSE)) { require_once dirname(__FILE__) . '/libs/N
if (!class_exists('NException', FALSE)) { require_once dirname(__FILE__) . '/libs/NException.php'; }
// dibi libraries
require_once dirname(__FILE__) . '/libs/interfaces.php';
require_once dirname(__FILE__) . '/libs/DibiException.php';
require_once dirname(__FILE__) . '/libs/DibiConnection.php';
require_once dirname(__FILE__) . '/libs/DibiDriverInterface.php';
require_once dirname(__FILE__) . '/libs/DibiResult.php';
require_once dirname(__FILE__) . '/libs/DibiResultIterator.php';
require_once dirname(__FILE__) . '/libs/DibiTranslator.php';
require_once dirname(__FILE__) . '/libs/DibiLogger.php';
require_once dirname(__FILE__) . '/libs/DibiVariable.php';
require_once dirname(__FILE__) . '/libs/DibiTable.php';

View File

@@ -34,7 +34,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiMsSqlDriver extends NObject implements DibiDriverInterface
class DibiMsSqlDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -40,7 +40,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiMySqlDriver extends NObject implements DibiDriverInterface
class DibiMySqlDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -40,7 +40,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiMySqliDriver extends NObject implements DibiDriverInterface
class DibiMySqliDriver extends NObject implements IDibiDriver
{
/**
@@ -92,7 +92,7 @@ class DibiMySqliDriver extends NObject implements DibiDriverInterface
// default values
if (!isset($config['username'])) $config['username'] = ini_get('mysqli.default_user');
if (!isset($config['password'])) $config['password'] = ini_get('mysqli.default_password');
if (!isset($config['password'])) $config['password'] = ini_get('mysqli.default_pw');
if (!isset($config['socket'])) $config['socket'] = ini_get('mysqli.default_socket');
if (!isset($config['host'])) {
$config['host'] = ini_get('mysqli.default_host');

View File

@@ -33,7 +33,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiOdbcDriver extends NObject implements DibiDriverInterface
class DibiOdbcDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -33,7 +33,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiOracleDriver extends NObject implements DibiDriverInterface
class DibiOracleDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -33,7 +33,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiPdoDriver extends NObject implements DibiDriverInterface
class DibiPdoDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -33,7 +33,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiPostgreDriver extends NObject implements DibiDriverInterface
class DibiPostgreDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -34,7 +34,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
class DibiSqliteDriver extends NObject implements DibiDriverInterface
class DibiSqliteDriver extends NObject implements IDibiDriver
{
/**

View File

@@ -36,7 +36,7 @@ class DibiConnection extends NObject
private $config;
/**
* DibiDriverInterface
* IDibiDriver
* @var array
*/
private $driver;
@@ -254,7 +254,7 @@ class DibiConnection extends NObject
$time = -microtime(TRUE);
dibi::notify($this, 'beforeQuery', $sql);
$res = $this->driver->query($sql) ? new DibiResult(clone $this->driver) : TRUE; // backward compatibility - will be changed to NULL
$res = $this->driver->query($sql) ? new DibiResult(clone $this->driver, $this->config) : TRUE; // backward compatibility - will be changed to NULL
$time += microtime(TRUE);
dibi::$elapsedTime = $time;

View File

@@ -26,6 +26,7 @@
* $result = dibi::query('SELECT * FROM [table]');
*
* $row = $result->fetch();
* $obj = $result->fetch(TRUE);
* $value = $result->fetchSingle();
* $table = $result->fetchAll();
* $pairs = $result->fetchPairs();
@@ -43,7 +44,7 @@
class DibiResult extends NObject implements IteratorAggregate, Countable
{
/**
* DibiDriverInterface
* IDibiDriver
* @var array
*/
private $driver;
@@ -60,7 +61,6 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
*/
private $metaCache;
/**
* Already fetched? Used for allowance for first seek(0)
* @var bool
@@ -73,6 +73,12 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
*/
private $withTables = FALSE;
/**
* Fetch as object?
* @var bool
*/
public $asObjects = FALSE;
private static $types = array(
@@ -85,13 +91,19 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
public function __construct($driver)
/**
* @param IDibiDriver
* @param array
*/
public function __construct($driver, $config)
{
$this->driver = $driver;
$this->setWithTables(!empty($config['result:withtables']));
$this->asObjects = !empty($config['result:objects']);
}
/**
* Automatically frees the resources allocated for this result set
*
@@ -207,9 +219,10 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
* Fetches the row at current position, process optional type conversion
* and moves the internal cursor to the next position
*
* @param bool fetch as object? Overrides $this->asObjects
* @return array|FALSE array on success, FALSE if no next record
*/
final public function fetch()
final public function fetch($asObject = NULL)
{
if ($this->withTables === FALSE) {
$row = $this->getDriver()->fetch(TRUE);
@@ -232,6 +245,10 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
}
}
if ($asObject || ($asObject === NULL && $this->asObjects)) {
$row = (object) $row;
}
return $row;
}
@@ -268,7 +285,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
final function fetchAll()
{
$this->seek(0);
$row = $this->fetch();
$row = $this->fetch(FALSE);
if (!$row) return array(); // empty resultset
$data = array();
@@ -276,10 +293,10 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
$key = key($row);
do {
$data[] = $row[$key];
} while ($row = $this->fetch());
} while ($row = $this->fetch(FALSE));
} else {
if ($this->asObjects) $row = (object) $row;
do {
$data[] = $row;
} while ($row = $this->fetch());
@@ -302,7 +319,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
final function fetchAssoc($assoc)
{
$this->seek(0);
$row = $this->fetch();
$row = $this->fetch(FALSE);
if (!$row) return array(); // empty resultset
$data = NULL;
@@ -366,7 +383,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
if ($leaf === '=') $x = $row; else $x = (object) $row;
}
} while ($row = $this->fetch());
} while ($row = $this->fetch(FALSE));
unset($x);
return $data;
@@ -385,7 +402,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
final function fetchPairs($key = NULL, $value = NULL)
{
$this->seek(0);
$row = $this->fetch();
$row = $this->fetch(FALSE);
if (!$row) return array(); // empty resultset
$data = array();
@@ -412,7 +429,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
if ($key === NULL) { // indexed-array
do {
$data[] = $row[$value];
} while ($row = $this->fetch());
} while ($row = $this->fetch(FALSE));
return $data;
}
@@ -423,7 +440,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
do {
$data[ $row[$key] ] = $row[$value];
} while ($row = $this->fetch());
} while ($row = $this->fetch(FALSE));
return $data;
}
@@ -558,7 +575,7 @@ class DibiResult extends NObject implements IteratorAggregate, Countable
/**
* Safe access to property $driver
*
* @return DibiDriverInterface
* @return IDibiDriver
* @throws DibiException
*/
private function getDriver()

View File

@@ -129,7 +129,7 @@ final class DibiResultIterator implements Iterator
*/
public function valid()
{
return is_array($this->row) && ($this->limit < 0 || $this->pointer < $this->limit);
return !empty($this->row) && ($this->limit < 0 || $this->pointer < $this->limit);
}

248
dibi/libs/DibiTable.php Normal file
View File

@@ -0,0 +1,248 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2008 David Grudl aka -dgx- (http://www.dgx.cz)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com/
*
* @copyright Copyright (c) 2005, 2008 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com/
* @package dibi
*/
/**
* Experimental object-oriented interface to database tables.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2008 David Grudl
* @package dibi
* @version $Revision$ $Date$
*/
abstract class DibiTable extends NObject
{
/** @var string primary key mask */
public static $primaryMask = 'id';
/** @var bool */
public static $lowerCase = TRUE;
/** @var DibiConnection */
private $connection;
/** @var array */
private $options;
/** @var string table name */
protected $name;
/** @var string primary key name */
protected $primary;
/** @var string primary key type */
protected $primaryModifier = '%i';
/**
* Table constructor
* @param array
* @return void
*/
public function __construct(array $options = array())
{
$this->options = $options;
$this->setup();
if ($this->connection === NULL) {
$this->connection = dibi::getConnection();
}
}
/**
* Returns the table name
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns the primary key name
* @return string
*/
public function getPrimary()
{
return $this->primary;
}
/**
* Returns the dibi connection
* @return DibiConnection
*/
public function getConnection()
{
return $this->connection;
}
/**
* Setup object
* @return void
*/
protected function setup()
{
// autodetect table name
if ($this->name === NULL) {
$name = $this->getClass();
if (FALSE !== ($pos = strrpos($name, ':'))) {
$name = substr($name, $pos + 1);
}
if (self::$lowerCase) {
$name = strtolower($name);
}
$this->name = $name;
}
// autodetect primary key name
if ($this->primary === NULL) {
$this->primary = str_replace(
array('%p', '%s'),
array($this->name, trim($this->name, 's')), // the simplest inflector in the world :-))
self::$primaryMask
);
}
}
/**
* Inserts row into a table
* @param array|object
* @return int new primary key
*/
public function insert($data)
{
if (is_object($data)) {
$data = (array) $data;
} elseif (!is_array($data)) {
throw new DibiException('Dataset must be array or anonymous object');
}
$this->connection->query(
'INSERT INTO %n', $this->name, '%v', $data
);
return $this->connection->insertId();
}
/**
* Updates rows in a table
* @param mixed primary key value(s)
* @param array|object
* @return int number of updated rows
*/
public function update($where, $data)
{
if (is_object($data)) {
$data = (array) $data;
} elseif (!is_array($data)) {
throw new DibiException('Dataset must be array or anonymous object');
}
$this->connection->query(
'UPDATE %n', $this->name,
'SET %a', $data,
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
);
return $this->connection->affectedRows();
}
/**
* Deletes rows from a table by primary key
* @param mixed primary key value(s)
* @return int number of deleted rows
*/
public function delete($where)
{
$this->connection->query(
'DELETE FROM %n', $this->name,
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $where, ')'
);
return $this->connection->affectedRows();
}
/**
* Finds rows by primary key
* @param mixed primary key value(s)
* @return DibiResult
*/
public function find($what)
{
if (!is_array($what)) {
$what = func_get_args();
}
return $this->connection->query(
'SELECT * FROM %n', $this->name,
'WHERE %n', $this->primary, 'IN (' . $this->primaryModifier, $what, ')'
);
}
/**
* Selects all rows
* @param string column to order by
* @return DibiResult
*/
public function findAll($order = NULL)
{
if ($order === NULL) {
return $this->connection->query(
'SELECT * FROM %n', $this->name
);
} else {
$order = func_get_args();
return $this->connection->query(
'SELECT * FROM %n', $this->name,
'ORDER BY %n', $order
);
}
}
/**
* Fetches single row
* @param scalar primary key value
* @return array row
*/
public function fetch($what)
{
$this->connection->query(
'SELECT * FROM %n', $this->name,
'WHERE %n', $this->primary, '=' . $this->primaryModifier, $what
)->fetch();
}
}

View File

@@ -35,7 +35,7 @@ final class DibiTranslator extends NObject
/** @var string NOT USED YET */
public $mask;
/** @var DibiDriverInterface */
/** @var IDibiDriver */
private $driver;
/** @var string last modifier */
@@ -55,7 +55,7 @@ final class DibiTranslator extends NObject
public function __construct(DibiDriverInterface $driver)
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
@@ -207,7 +207,7 @@ final class DibiTranslator extends NObject
return 'NULL';
}
if ($value instanceof DibiVariableInterface) {
if ($value instanceof IDibiVariable) {
return $value->toSql($this->driver, $modifier);
}
@@ -311,7 +311,7 @@ final class DibiTranslator extends NObject
if ($value === NULL)
return 'NULL';
if ($value instanceof DibiVariableInterface)
if ($value instanceof IDibiVariable)
return $value->toSql($this->driver, NULL);
$this->hasError = TRUE;

View File

@@ -20,26 +20,10 @@
/**
* Interface for user variable, used for generating SQL
* Default implemenation of IDibiVariable
* @package dibi
*/
interface DibiVariableInterface
{
/**
* Format for SQL
*
* @param object destination DibiDriverInterface
* @param string optional modifier
* @return string SQL code
*/
public function toSql(DibiDriverInterface $driver, $modifier);
}
class DibiVariable extends NObject implements DibiVariableInterface
class DibiVariable extends NObject implements IDibiVariable
{
/** @var mixed */
public $value;
@@ -55,7 +39,7 @@ class DibiVariable extends NObject implements DibiVariableInterface
}
public function toSql(DibiDriverInterface $driver, $modifier)
public function toSql(IDibiDriver $driver, $modifier)
{
return $driver->format($this->value, $this->type);
}

View File

@@ -25,8 +25,9 @@
*
* It defines some handful methods and enhances object core of PHP:
* - access to undeclared members throws exceptions
* - ability to add new methods to class (extension methods)
* - support for conventional properties with getters and setters
* - support for event raising functionality
* - ability to add new methods to class (extension methods)
*
* Properties is a syntactic sugar which allows access public getter and setter
* methods as normal object variables. A property is defined by a getter method
@@ -38,6 +39,15 @@
* Property names are case-sensitive, and they are written in the camelCaps
* or PascalCaps.
*
* Event functionality is provided by declaration using pseudo-keyword 'event'.
* Multiple handlers are allowed.
* <code>
* public $onClick = event; // declaration in class
* $this->onClick[] = 'callback'; // attaching event handler
* if (empty($this->onClick)) ... // are there any handler?
* $this->onClick($sender, $arg); // raises the event with arguments
* </code>
*
* Adding method to class (i.e. to all instances) works similar to JavaScript
* prototype property. The syntax for adding a new method is:
* <code>
@@ -93,9 +103,23 @@ abstract class NObject
throw new BadMethodCallException("Call to method without name");
}
$class = get_class($this);
// event functionality
if (self::hasEvent($class, $name)) {
$list = $this->$name;
if (is_array($list) || $list instanceof Traversable) {
foreach ($list as $handler) {
if ($handler === '') continue;
call_user_func_array($handler, $args);
}
}
return;
}
// object prototypes support Class__method()
// (or use class Class__method { static function ... } with autoloading?)
$cl = $class = get_class($this);
$cl = $class;
do {
if (function_exists($nm = $cl . '_prototype_' . $name)) {
array_unshift($args, $this);
@@ -199,7 +223,7 @@ abstract class NObject
/**
* Has property accessor?
* Has property an accessor?
*
* @param string class name
* @param string method name
@@ -221,4 +245,26 @@ abstract class NObject
return isset($cache[$c][$m]);
}
/**
* Is property an event?
*
* @param string class name
* @param string method name
* @return bool
*/
private static function hasEvent($c, $m)
{
if (strncmp($m, 'on', 2)) return FALSE;
static $cache;
if (!isset($cache[$c])) {
// get_class_vars returns ONLY PUBLIC properties
// but returns static methods too (nothing doing...)
$cache[$c] = get_class_vars($c);
}
return isset($cache[$c][$m]) && $cache[$c][$m] === '';
}
}

View File

@@ -19,6 +19,26 @@
/**
* Interface for user variable, used for generating SQL
* @package dibi
*/
interface IDibiVariable
{
/**
* Format for SQL
*
* @param object destination IDibiDriver
* @param string optional modifier
* @return string SQL code
*/
public function toSql(IDibiDriver $driver, $modifier);
}
/**
* dibi driver interface
*
@@ -27,7 +47,7 @@
* @package dibi
* @version $Revision$ $Date$
*/
interface DibiDriverInterface
interface IDibiDriver
{
/**

View File

@@ -10,6 +10,7 @@ try {
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
'result:objects' => TRUE, // fetch rows as objects
));
echo 'OK';

View File

@@ -1,4 +1,4 @@
<h1>DibiVariableInterface example</h1>
<h1>IDibiVariable example</h1>
<?php
require_once '../dibi/dibi.php';

87
examples/dibi.table.php Normal file
View File

@@ -0,0 +1,87 @@
<h1>DibiTable demo</h1>
<pre>
<?php
require_once '../dibi/dibi.php';
copy('sample.sdb', 'sample_tmp.sdb');
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample_tmp.sdb',
));
// table products
class Products extends DibiTable
{
// rely on autodetection...
// protected $name = 'products';
// protected $primary = 'product_id';
}
// autodetection: primary keys are customer_id, order_id, ...
DibiTable::$primaryMask = '%s_id';
// create table object
$products = new Products();
echo "Table name: $products->name\n";
echo "Primary key: $products->primary\n";
// Finds rows by primary key
foreach ($products->find(1, 3) as $row) {
...
}
// select all
$products->findAll()->dump();
// select all, order by title, product_id
$products->findAll('title', $products->primary)->dump();
// fetches single row with id 3
$row = $products->fetch(3);
// deletes row from a table
$count = $products->delete(1);
// deletes multiple rows
$count = $products->delete(array(1, 2, 3));
var_dump($count); // number of deleted rows
// update row #2 in a table
$data = (object) NULL;
$data->title = 'New title';
$count = $products->update(2, $data);
var_dump($count); // number of updated rows
// update multiple rows in a table
$count = $products->update(array(3, 5), $data);
var_dump($count); // number of updated rows
// inserts row into a table
$data = array();
$data['title'] = 'New product';
$id = $products->insert($data);
var_dump($id); // generated id
// is absolutely SQL injection safe
$key = '3 OR 1=1';
$products->delete($key);
// --> DELETE FROM [products] WHERE [product_id] IN ( 3 )