From fa11260e7548ac418b27e869ee2c41454d265c76 Mon Sep 17 00:00:00 2001 From: zYne Date: Sun, 27 May 2007 18:56:04 +0000 Subject: [PATCH] --- lib/Doctrine/Cache/Array.php | 2 +- lib/Doctrine/Connection.php | 349 +++++++------------------ lib/Doctrine/Connection/UnitOfWork.php | 76 +++++- lib/Doctrine/Db.php | 12 +- lib/Doctrine/Formatter.php | 24 +- lib/Doctrine/Import/Builder.php | 4 +- lib/Doctrine/Import/Builder/Record.tpl | 4 +- lib/Doctrine/RawSql.php | 2 +- lib/Doctrine/Record.php | 6 +- lib/Doctrine/Record/Filter.php | 1 - lib/Doctrine/Sequence/Db2.php | 83 ++++++ 11 files changed, 271 insertions(+), 292 deletions(-) diff --git a/lib/Doctrine/Cache/Array.php b/lib/Doctrine/Cache/Array.php index 57936c0a9..1c3be50fb 100644 --- a/lib/Doctrine/Cache/Array.php +++ b/lib/Doctrine/Cache/Array.php @@ -31,7 +31,7 @@ * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Cache_Array implements Countable +class Doctrine_Cache_Array implements Countable, Doctrine_Cache_Interface { /** * @var array $data an array of cached data diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index 8d3a92ea6..6ba78261e 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -22,6 +22,28 @@ Doctrine::autoload('Doctrine_Configurable'); /** * Doctrine_Connection * + * A wrapper layer on top of PDO / Doctrine_Adapter + * + * Doctrine_Connection is the heart of any Doctrine based application. + * + * 1. Event listeners + * An easy to use, pluggable eventlistener architecture. Aspects such as + * logging, query profiling and caching can be easily implemented through + * the use of these listeners + * + * 2. Lazy-connecting + * Creating an instance of Doctrine_Connection does not connect + * to database. Connecting to database is only invoked when actually needed + * (for example when query() is being called) + * + * 3. Convenience methods + * Doctrine_Connection provides many convenience methods. + * + * 4. Modular structure + * Higher level functionality such as schema importing, exporting, sequence handling etc. + * is divided into modules. For a full list of connection modules see + * Doctrine_Connection::$_modules + * * @package Doctrine * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @category Object Relational Mapping @@ -70,12 +92,19 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * * sequence Doctrine_Sequence driver, handles sequential id generation and retrieval * + * unitOfWork Doctrine_Connection_UnitOfWork handles many orm functionalities such as object + * deletion and saving + * + * formatter Doctrine_Formatter handles data formatting, quoting and escaping + * * @see Doctrine_Connection::__get() * @see Doctrine_DataDict * @see Doctrine_Expression * @see Doctrine_Export * @see Doctrine_Transaction * @see Doctrine_Sequence + * @see Doctrine_Connection_UnitOfWork + * @see Doctrine_Formatter */ private $modules = array('transaction' => false, 'expression' => false, @@ -84,22 +113,18 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun 'import' => false, 'sequence' => false, 'unitOfWork' => false, + 'formatter' => false ); /** * @var array $properties an array of connection properties */ protected $properties = array('sql_comments' => array(array('start' => '--', 'end' => "\n", 'escape' => false), - array('start' => '/*', 'end' => '*/', 'escape' => false) - ), - 'identifier_quoting' => array('start' => '"', - 'end' => '"', - 'escape' => '"' - ), + array('start' => '/*', 'end' => '*/', 'escape' => false)), + 'identifier_quoting' => array('start' => '"', 'end' => '"','escape' => '"'), 'string_quoting' => array('start' => "'", 'end' => "'", 'escape' => false, - 'escape_pattern' => false - ), + 'escape_pattern' => false), 'wildcards' => array('%', '_'), 'varchar_max_length' => 255, ); @@ -179,6 +204,9 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun case 'unitOfWork': $this->modules[$name] = new Doctrine_Connection_UnitOfWork($this); break; + case 'formatter': + $this->modules[$name] = new Doctrine_Formatter($this); + break; default: $class = 'Doctrine_' . ucwords($name) . '_' . $this->getName(); $this->modules[$name] = new $class($this); @@ -187,97 +215,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun return $this->modules[$name]; } - /** - * Quotes pattern (% and _) characters in a string) - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @param string the input string to quote - * - * @return string quoted string - */ - public function escapePattern($text) - { - if ($this->string_quoting['escape_pattern']) { - $text = str_replace($this->string_quoting['escape_pattern'], $this->string_quoting['escape_pattern'] . $this->string_quoting['escape_pattern'], $text); - foreach ($this->wildcards as $wildcard) { - $text = str_replace($wildcard, $this->string_quoting['escape_pattern'] . $wildcard, $text); - } - } - return $text; - } - /** - * convertBoolean - * some drivers need the boolean values to be converted into integers - * when using DQL API - * - * This method takes care of that conversion - * - * @param array $item - * @return void - */ - public function convertBooleans($item) - { - if (is_array($item)) { - foreach ($item as $k => $value) { - if (is_bool($item)) { - $item[$k] = (int) $value; - } - } - } else { - if (is_bool($item)) { - $item = (int) $item; - } - } - return $item; - } - /** - * Quote a string so it can be safely used as a table or column name - * - * Delimiting style depends on which database driver is being used. - * - * NOTE: just because you CAN use delimited identifiers doesn't mean - * you SHOULD use them. In general, they end up causing way more - * problems than they solve. - * - * Portability is broken by using the following characters inside - * delimited identifiers: - * + backtick (`) -- due to MySQL - * + double quote (") -- due to Oracle - * + brackets ([ or ]) -- due to Access - * - * Delimited identifiers are known to generally work correctly under - * the following drivers: - * + mssql - * + mysql - * + mysqli - * + oci8 - * + pgsql - * + sqlite - * - * InterBase doesn't seem to be able to use delimited identifiers - * via PHP 4. They work fine under PHP 5. - * - * @param string $str identifier name to be quoted - * @param bool $checkOption check the 'quote_identifier' option - * - * @return string quoted identifier string - */ - public function quoteIdentifier($str, $checkOption = true) - { - if ($checkOption && ! $this->getAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER)) { - return $str; - } - $str = str_replace($this->properties['identifier_quoting']['end'], - $this->properties['identifier_quoting']['escape'] . - $this->properties['identifier_quoting']['end'], $str); - - return $this->properties['identifier_quoting']['start'] - . $str . $this->properties['identifier_quoting']['end']; - } /** * returns the manager that created this connection * @@ -313,100 +250,9 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun public function supports($feature) { return (isset($this->supported[$feature]) - && ($this->supported[$feature] === 'emulated' - || $this->supported[$feature] - ) - ); + && ($this->supported[$feature] === 'emulated' + || $this->supported[$feature])); } - /** - * quote - * quotes given input parameter - * - * @param mixed $input parameter to be quoted - * @param string $type - * @return mixed - */ - public function quote($input, $type = null) - { - if ($type == null) { - $type = gettype($input); - } - switch ($type) { - case 'integer': - case 'enum': - case 'boolean': - case 'double': - case 'float': - case 'bool': - case 'int': - return $input; - case 'array': - case 'object': - $input = serialize($input); - case 'string': - case 'char': - case 'varchar': - case 'text': - case 'gzip': - case 'blob': - case 'clob': - return $this->dbh->quote($input); - } - } - /** - * Removes any formatting in an sequence name using the 'seqname_format' option - * - * @param string $sqn string that containts name of a potential sequence - * @return string name of the sequence with possible formatting removed - */ - public function fixSequenceName($sqn) - { - $seqPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->getAttribute(Doctrine::ATTR_SEQNAME_FORMAT)).'$/i'; - $seqName = preg_replace($seqPattern, '\\1', $sqn); - - if ($seqName && ! strcasecmp($sqn, $this->getSequenceName($seqName))) { - return $seqName; - } - return $sqn; - } - /** - * Removes any formatting in an index name using the 'idxname_format' option - * - * @param string $idx string that containts name of anl index - * @return string name of the index with possible formatting removed - */ - public function fixIndexName($idx) - { - $indexPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT)).'$/i'; - $indexName = preg_replace($indexPattern, '\\1', $idx); - if ($indexName && ! strcasecmp($idx, $this->getIndexName($indexName))) { - return $indexName; - } - return $idx; - } - /** - * adds sequence name formatting to a sequence name - * - * @param string name of the sequence - * @return string formatted sequence name - */ - public function getSequenceName($sqn) - { - return sprintf($this->getAttribute(Doctrine::ATTR_SEQNAME_FORMAT), - preg_replace('/[^a-z0-9_\$.]/i', '_', $sqn)); - } - /** - * adds index name formatting to a index name - * - * @param string name of the index - * @return string formatted index name - */ - public function getIndexName($idx) - { - return sprintf($this->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT), - preg_replace('/[^a-z0-9_\$]/i', '_', $idx)); - } - /** * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT * query, except that if there is already a row in the table with the same @@ -507,6 +353,68 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun public function setCharset($charset) { + } + /** + * Quote a string so it can be safely used as a table or column name + * + * Delimiting style depends on which database driver is being used. + * + * NOTE: just because you CAN use delimited identifiers doesn't mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * Portability is broken by using the following characters inside + * delimited identifiers: + * + backtick (`) -- due to MySQL + * + double quote (") -- due to Oracle + * + brackets ([ or ]) -- due to Access + * + * Delimited identifiers are known to generally work correctly under + * the following drivers: + * + mssql + * + mysql + * + mysqli + * + oci8 + * + pgsql + * + sqlite + * + * InterBase doesn't seem to be able to use delimited identifiers + * via PHP 4. They work fine under PHP 5. + * + * @param string $str identifier name to be quoted + * @param bool $checkOption check the 'quote_identifier' option + * + * @return string quoted identifier string + */ + public function quoteIdentifier($str, $checkOption = true) + { + return $this->formatter->quoteIdentifier($str, $checkOption); + } + /** + * convertBooleans + * some drivers need the boolean values to be converted into integers + * when using DQL API + * + * This method takes care of that conversion + * + * @param array $item + * @return void + */ + public function convertBooleans($item) + { + return $this->formatter->convertBooleans($item); + } + /** + * quote + * quotes given input parameter + * + * @param mixed $input parameter to be quoted + * @param string $type + * @return mixed + */ + public function quote($input, $type = null) + { + return $this->formatter->quote($input, $type); } /** * Set the date/time format for the current connection @@ -689,7 +597,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun if ( ! empty($params)) { $stmt = $this->dbh->prepare($query); $stmt->execute($params); - return $stmt; + return $stmt; } else { return $this->dbh->query($query); } @@ -977,61 +885,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun { $this->transaction->rollback(); } - /** - * saves the given record - * - * @param Doctrine_Record $record - * @return void - */ - public function save(Doctrine_Record $record) - { - $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record); - - switch ($record->state()) { - case Doctrine_Record::STATE_TDIRTY: - $this->unitOfWork->insert($record); - break; - case Doctrine_Record::STATE_DIRTY: - case Doctrine_Record::STATE_PROXY: - $this->unitOfWork->update($record); - break; - case Doctrine_Record::STATE_CLEAN: - case Doctrine_Record::STATE_TCLEAN: - // do nothing - break; - } - - $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record); - } - /** - * deletes this data access object and all the related composites - * this operation is isolated by a transaction - * - * this event can be listened by the onPreDelete and onDelete listeners - * - * @return boolean true on success, false on failure - */ - public function delete(Doctrine_Record $record) - { - if ( ! $record->exists()) { - return false; - } - $this->beginTransaction(); - - $record->getTable()->getListener()->onPreDelete($record); - - $this->unitOfWork->deleteComposites($record); - - $this->transaction->addDelete($record); - - $record->getTable()->getListener()->onDelete($record); - - $record->state(Doctrine_Record::STATE_TCLEAN); - - $this->commit(); - - return true; - } /** * returns a string representation of this object * @return string diff --git a/lib/Doctrine/Connection/UnitOfWork.php b/lib/Doctrine/Connection/UnitOfWork.php index 5806ae7f4..18874b7fc 100644 --- a/lib/Doctrine/Connection/UnitOfWork.php +++ b/lib/Doctrine/Connection/UnitOfWork.php @@ -40,8 +40,8 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module * 'correct' order. Basically this means that the records of those * components can be saved safely in the order specified by the returned array. * - * @param array $tables - * @return array + * @param array $tables an array of Doctrine_Table objects or component names + * @return array an array of component names in flushing order */ public function buildFlushTree(array $tables) { @@ -131,6 +131,61 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module } return array_values($tree); } + /** + * saves the given record + * + * @param Doctrine_Record $record + * @return void + */ + public function save(Doctrine_Record $record) + { + $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record); + + switch ($record->state()) { + case Doctrine_Record::STATE_TDIRTY: + $this->insert($record); + break; + case Doctrine_Record::STATE_DIRTY: + case Doctrine_Record::STATE_PROXY: + $this->update($record); + break; + case Doctrine_Record::STATE_CLEAN: + case Doctrine_Record::STATE_TCLEAN: + // do nothing + break; + } + + $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record); + } + /** + * deletes this data access object and all the related composites + * this operation is isolated by a transaction + * + * this event can be listened by the onPreDelete and onDelete listeners + * + * @return boolean true on success, false on failure + */ + public function delete(Doctrine_Record $record) + { + if ( ! $record->exists()) { + return false; + } + $this->conn->beginTransaction(); + + $record->getTable()->getListener()->onPreDelete($record); + + $this->deleteComposites($record); + + $this->conn->transaction->addDelete($record); + + $record->getTable()->getListener()->onDelete($record); + + $record->state(Doctrine_Record::STATE_TCLEAN); + + $this->conn->commit(); + + return true; + } /** * saveRelated * saves all related records to $record @@ -241,7 +296,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $table = $this->conn->getTable($name); foreach ($table->getRepository() as $record) { - $this->conn->save($record); + $this->save($record); } } @@ -275,19 +330,16 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module $set[] = $name . ' = ?'; if ($value instanceof Doctrine_Record) { - switch ($value->state()) { - case Doctrine_Record::STATE_TCLEAN: - case Doctrine_Record::STATE_TDIRTY: - $record->save($this->conn); - default: - $array[$name] = $value->getIncremented(); - $record->set($name, $value->getIncremented()); + if ( ! $value->exists()) { + $record->save($this->conn); } + $array[$name] = $value->getIncremented(); + $record->set($name, $value->getIncremented()); } } - $params = array_values($array); - $id = $record->obtainIdentifier(); + $params = array_values($array); + $id = $record->obtainIdentifier(); if ( ! is_array($id)) { $id = array($id); diff --git a/lib/Doctrine/Db.php b/lib/Doctrine/Db.php index 8bf00ad2c..ae2bc5e92 100644 --- a/lib/Doctrine/Db.php +++ b/lib/Doctrine/Db.php @@ -20,19 +20,11 @@ */ /** * Doctrine_Db - * A thin wrapper layer on top of PDO / Doctrine_Adapter + * * * Doctrine_Db provides the following things to underlying database hanlder * - * 1. Event listeners - * An easy to use, pluggable eventlistener architecture. Aspects such as - * logging, query profiling and caching can be easily implemented through - * the use of these listeners - * - * 2. Lazy-connecting - * Creating an instance of Doctrine_Db does not connect - * to database. Connecting to database is only invoked when actually needed - * (for example when query() is being called) + * * @author Konsta Vesterinen * @license http://www.opensource.org/licenses/lgpl-license.php LGPL diff --git a/lib/Doctrine/Formatter.php b/lib/Doctrine/Formatter.php index 9203290c8..a0947d370 100644 --- a/lib/Doctrine/Formatter.php +++ b/lib/Doctrine/Formatter.php @@ -58,7 +58,7 @@ class Doctrine_Formatter extends Doctrine_Connection_Module return $text; } /** - * convertBoolean + * convertBooleans * some drivers need the boolean values to be converted into integers * when using DQL API * @@ -116,15 +116,15 @@ class Doctrine_Formatter extends Doctrine_Connection_Module */ public function quoteIdentifier($str, $checkOption = true) { - if ($checkOption && ! $this->getAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER)) { + if ($checkOption && ! $this->conn->getAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER)) { return $str; } - $str = str_replace($this->properties['identifier_quoting']['end'], - $this->properties['identifier_quoting']['escape'] . - $this->properties['identifier_quoting']['end'], $str); + $tmp = $this->conn->identifier_quoting; + $str = str_replace($tmp['end'], + $tmp['escape'] . + $tmp['end'], $str); - return $this->properties['identifier_quoting']['start'] - . $str . $this->properties['identifier_quoting']['end']; + return $tmp['start'] . $str . $tmp['end']; } /** * quote @@ -158,7 +158,7 @@ class Doctrine_Formatter extends Doctrine_Connection_Module case 'gzip': case 'blob': case 'clob': - return $this->dbh->quote($input); + return $this->conn->getDbh()->quote($input); } } /** @@ -169,7 +169,7 @@ class Doctrine_Formatter extends Doctrine_Connection_Module */ public function fixSequenceName($sqn) { - $seqPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->getAttribute(Doctrine::ATTR_SEQNAME_FORMAT)).'$/i'; + $seqPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->conn->getAttribute(Doctrine::ATTR_SEQNAME_FORMAT)).'$/i'; $seqName = preg_replace($seqPattern, '\\1', $sqn); if ($seqName && ! strcasecmp($sqn, $this->getSequenceName($seqName))) { @@ -185,7 +185,7 @@ class Doctrine_Formatter extends Doctrine_Connection_Module */ public function fixIndexName($idx) { - $indexPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT)).'$/i'; + $indexPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->conn->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT)).'$/i'; $indexName = preg_replace($indexPattern, '\\1', $idx); if ($indexName && ! strcasecmp($idx, $this->getIndexName($indexName))) { return $indexName; @@ -200,7 +200,7 @@ class Doctrine_Formatter extends Doctrine_Connection_Module */ public function getSequenceName($sqn) { - return sprintf($this->getAttribute(Doctrine::ATTR_SEQNAME_FORMAT), + return sprintf($this->conn->getAttribute(Doctrine::ATTR_SEQNAME_FORMAT), preg_replace('/[^a-z0-9_\$.]/i', '_', $sqn)); } /** @@ -211,7 +211,7 @@ class Doctrine_Formatter extends Doctrine_Connection_Module */ public function getIndexName($idx) { - return sprintf($this->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT), + return sprintf($this->conn->getAttribute(Doctrine::ATTR_IDXNAME_FORMAT), preg_replace('/[^a-z0-9_\$]/i', '_', $idx)); } } diff --git a/lib/Doctrine/Import/Builder.php b/lib/Doctrine/Import/Builder.php index 4647a2b66..b8fcecc1e 100644 --- a/lib/Doctrine/Import/Builder.php +++ b/lib/Doctrine/Import/Builder.php @@ -140,9 +140,9 @@ class Doctrine_Import_Builder $i++; } - $content = sprintf(self::$tpl, $created, $className, implode("\n", $columns)); + $content = sprintf(self::$tpl, $created, $className, implode("\n", $columns)); - $bytes = file_put_contents($fileName, $content); + $bytes = file_put_contents($fileName, $content); if ($bytes === false) { throw new Doctrine_Import_Builder_Exception("Couldn't write file " . $fileName); diff --git a/lib/Doctrine/Import/Builder/Record.tpl b/lib/Doctrine/Import/Builder/Record.tpl index 1cd9b1abd..0e4536b8b 100644 --- a/lib/Doctrine/Import/Builder/Record.tpl +++ b/lib/Doctrine/Import/Builder/Record.tpl @@ -4,7 +4,7 @@ * Created: %s */ class %s extends Doctrine_Record -{ +{%s public function setTableDefinition() { %s @@ -12,5 +12,5 @@ class %s extends Doctrine_Record public function setUp() { - } + }%s } diff --git a/lib/Doctrine/RawSql.php b/lib/Doctrine/RawSql.php index 78afcadec..e9e1a21ce 100644 --- a/lib/Doctrine/RawSql.php +++ b/lib/Doctrine/RawSql.php @@ -158,7 +158,7 @@ class Doctrine_RawSql extends Doctrine_Query_Abstract // force-add all primary key fields - foreach ($this->getAliases() as $tableAlias => $componentAlias) { + foreach ($this->getTableAliases() as $tableAlias => $componentAlias) { $map = $this->_aliasMap[$componentAlias]; foreach ($map['table']->getPrimaryKeys() as $key) { diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 4ec7fe50d..17a940b05 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -890,7 +890,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $saveLater = $conn->unitOfWork->saveRelated($this); if ($this->isValid()) { - $conn->save($this); + $conn->unitOfWork->save($this); } else { $conn->transaction->addInvalid($this); } @@ -1106,7 +1106,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite if ($conn == null) { $conn = $this->_table->getConnection(); } - return $conn->delete($this); + return $conn->unitOfWork->delete($this); } /** * copy @@ -1152,7 +1152,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite * @param integer $id * @return void */ - final public function assignIdentifier($id = false) + public function assignIdentifier($id = false) { if ($id === false) { $this->_id = array(); diff --git a/lib/Doctrine/Record/Filter.php b/lib/Doctrine/Record/Filter.php index 534f7185c..abaca42d3 100644 --- a/lib/Doctrine/Record/Filter.php +++ b/lib/Doctrine/Record/Filter.php @@ -171,7 +171,6 @@ class Doctrine_Record_Filter } } - return $data; } /** diff --git a/lib/Doctrine/Sequence/Db2.php b/lib/Doctrine/Sequence/Db2.php index 04deae53b..d6e51cc47 100644 --- a/lib/Doctrine/Sequence/Db2.php +++ b/lib/Doctrine/Sequence/Db2.php @@ -32,5 +32,88 @@ Doctrine::autoload('Doctrine_Sequence'); */ class Doctrine_Sequence_Db2 extends Doctrine_Sequence { + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return integer + * @throws Doctrine_Adapter_Db2_Exception + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $sql = 'SELECT PREVVAL FOR '.$this->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); + if ($result) { + return $result[0]['VAL']; + } else { + return null; + } + } + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return integer + * @throws Doctrine_Adapter_Db2_Exception + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $sql = 'SELECT NEXTVAL FOR '.$this->quoteIdentifier($sequenceName).' AS VAL FROM SYSIBM.SYSDUMMY1'; + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); + if ($result) { + return $result[0]['VAL']; + } else { + return null; + } + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * The IDENTITY_VAL_LOCAL() function gives the last generated identity value + * in the current process, even if it was for a GENERATED column. + * + * @param string $tableName OPTIONAL + * @param string $primaryKey OPTIONAL + * @return integer + * @throws Doctrine_Adapter_Db2_Exception + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $this->_connect(); + + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + + $sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM SYSIBM.SYSDUMMY1'; + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); + if ($result) { + return $result[0]['VAL']; + } else { + return null; + } + } }