From 81a21344bd644df090bf063a42ec7feeefc1f1a9 Mon Sep 17 00:00:00 2001 From: zYne Date: Sat, 10 Feb 2007 21:51:53 +0000 Subject: [PATCH] --- lib/Doctrine/Connection.php | 12 +-- lib/Doctrine/Export.php | 181 ++++++++++++++++++++++++++++++++-- lib/Doctrine/Import.php | 17 ++++ lib/Doctrine/Import/Mssql.php | 10 +- lib/Doctrine/Record.php | 4 +- 5 files changed, 198 insertions(+), 26 deletions(-) diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index 5bdd6dd42..7cdc37835 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -463,17 +463,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun return true; } - /** - * returns the next value in the given sequence - * - * @param string $sequence - * @throws PDOException if something went wrong at database level - * @return integer - */ - public function nextId($sequence) - { - throw new Doctrine_Connection_Exception('NextId() for sequences not supported by this driver.'); - } /** * Set the charset on the current connection * @@ -483,6 +472,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun */ public function setCharset($charset) { + } /** * Set the date/time format for the current connection diff --git a/lib/Doctrine/Export.php b/lib/Doctrine/Export.php index 4d7bb8d8e..f730b30c0 100644 --- a/lib/Doctrine/Export.php +++ b/lib/Doctrine/Export.php @@ -131,9 +131,9 @@ class Doctrine_Export extends Doctrine_Connection_Module * ); * @param array $options An associative array of table options: * - * @return void + * @return string */ - public function createTable($name, array $fields, array $options = array()) + public function createTableSql($name, array $fields, array $options = array()) { if ( ! $name) { throw new Doctrine_Export_Exception('no valid table name specified'); @@ -145,27 +145,56 @@ class Doctrine_Export extends Doctrine_Connection_Module $queryFields = $this->getFieldDeclarationList($fields); if (isset($options['primary']) && ! empty($options['primary'])) { - $queryFields.= ', PRIMARY KEY(' . implode(', ', array_values($options['primary'])) . ')'; + $queryFields .= ', PRIMARY KEY(' . implode(', ', array_values($options['primary'])) . ')'; + } + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach($options['indexes'] as $index => $definition) { + $queryFields .= ', ' . $this->getIndexDeclaration($index, $definition); + } } $name = $this->conn->quoteIdentifier($name, true); $query = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')'; - return $this->conn->exec($query); + return $query; + } + /** + * create a new table + * + * @param string $name Name of the database that should be created + * @param array $fields Associative array that contains the definition of each field of the new table + * @param array $options An associative array of table options: + * @see Doctrine_Export::createTableSql() + * + * @return void + */ + public function createTable($name, array $fields, array $options = array()) + { + return $this->conn->execute($this->createTableSql($name, $fields, $options)); } /** * create sequence - * (this method is implemented by the drivers) * * @param string $seqName name of the sequence to be created * @param string $start start value of the sequence; default is 1 * @return void */ public function createSequence($seqName, $start = 1) + { + return $this->conn->execute($this->createSequenceSql($seqName, $start = 1)); + } + /** + * return RDBMS specific create sequence statement + * (this method is implemented by the drivers) + * + * @param string $seqName name of the sequence to be created + * @param string $start start value of the sequence; default is 1 + * @return string + */ + public function createSequenceSql($seqName, $start = 1) { throw new Doctrine_Export_Exception('Create sequence not supported by this driver.'); } - /** * create a constraint on a table * @@ -253,7 +282,7 @@ class Doctrine_Export extends Doctrine_Connection_Module $table = $this->conn->quoteIdentifier($table); $name = $this->conn->quoteIdentifier($name); $type = ''; - + if(isset($definition['type'])) { switch (strtolower($definition['type'])) { case 'unique': @@ -479,7 +508,7 @@ class Doctrine_Export extends Doctrine_Connection_Module $default = ' DEFAULT ' . $this->conn->quote($field['default'], $field['type']); } elseif (empty($field['notnull'])) { - $default = ' DEFAULT NULL'; + //$default = ' DEFAULT NULL'; } $charset = (isset($field['charset']) && $field['charset']) ? @@ -502,6 +531,142 @@ class Doctrine_Export extends Doctrine_Connection_Module } return $this->conn->quoteIdentifier($name, true) . ' ' . $dec . $charset . $default . $notnull . $unique . $collation; } + /** + * Obtain DBMS specific SQL code portion needed to set an index + * declaration to be used in statements like CREATE TABLE. + * + * @param string $charset name of the index + * @param array $definition index definition + * @return string DBMS specific SQL code portion needed to set an index + */ + public function getIndexDeclaration($name, array $definition) + { + $name = $this->conn->quoteIdentifier($name); + $type = ''; + + if (isset($definition['type'])) { + if (strtolower($definition['type']) == 'unique') { + $type = strtoupper($definition['type']) . ' '; + } else { + throw new Doctrine_Export_Exception('Unknown index type ' . $definition['type']); + } + } + + if ( ! isset($definition['fields']) || ! is_array($definition['fields'])) { + throw new Doctrine_Export_Exception('No index columns given.'); + } + + $query = $type . 'INDEX ' . $name; + + $query .= ' (' . $this->getIndexFieldDeclarationList($definition['fields']) . ')'; + + return $query; + } + /** + * getIndexFieldDeclarationList + * Obtain DBMS specific SQL code portion needed to set an index + * declaration to be used in statements like CREATE TABLE. + * + * @return string + */ + public function getIndexFieldDeclarationList(array $fields) + { + foreach ($fields as $field => $definition) { + if(is_array($definition)) { + $fields[] = $this->conn->quoteIdentifier($field); + } else { + $fields[] = $definition; + } + } + return implode(', ', $fields); + } + /** + * getForeignKeyDeclaration + * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param array $definition an associative array with the following structure: + * name optional constraint name + * + * local the local field(s) + * + * foreign the foreign reference field(s) + * + * foreignTable the name of the foreign table + * + * onDelete referential delete action + * + * onUpdate referential update action + * + * The onDelete and onUpdate keys accept the following values: + * + * CASCADE: Delete or update the row from the parent table and automatically delete or + * update the matching rows in the child table. Both ON DELETE CASCADE and ON UPDATE CASCADE are supported. + * Between two tables, you should not define several ON UPDATE CASCADE clauses that act on the same column + * in the parent table or in the child table. + * + * SET NULL: Delete or update the row from the parent table and set the foreign key column or columns in the + * child table to NULL. This is valid only if the foreign key columns do not have the NOT NULL qualifier + * specified. Both ON DELETE SET NULL and ON UPDATE SET NULL clauses are supported. + * + * NO ACTION: In standard SQL, NO ACTION means no action in the sense that an attempt to delete or update a primary + * key value is not allowed to proceed if there is a related foreign key value in the referenced table. + * + * RESTRICT: Rejects the delete or update operation for the parent table. NO ACTION and RESTRICT are the same as + * omitting the ON DELETE or ON UPDATE clause. + * + * SET DEFAULT + * + * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a field declaration. + */ + public function getForeignKeyDeclaration($definition) + { + $sql = ''; + if (isset($definition['name'])) { + $sql .= 'CONSTRAINT ' . $definition['name']; + } + if ( ! isset($definition['local'])) { + throw new Doctrine_Export_Exception('Local reference field missing from definition.'); + } + if ( ! isset($definition['foreign'])) { + throw new Doctrine_Export_Exception('Foreign reference field missing from definition.'); + } + if ( ! isset($definition['foreignTable'])) { + throw new Doctrine_Export_Exception('Foreign reference table missing from definition.'); + } + + if ( ! is_array($definition['local'])) { + $definition['local'] = array($definition['local']); + } + if ( ! is_array($definition['foreign'])) { + $definition['foreign'] = array($definition['foreign']); + } + $sql .= implode(', ', array_map(array($this->conn, 'quoteIdentifier'), $definition['local'])) + . ' REFERENCES ' + . $definition['foreignTable'] . '(' + . implode(', ', array_map(array($this->conn, 'quoteIdentifier'), $definition['foreign'])) . ')'; + + $a = array('onUpdate', 'onDelete'); + foreach($a as $v) { + $keyword = ($v == 'onUpdate') ? ' ON UPDATE ' : ' ON DELETE '; + + if (isset($definition[$v])) { + switch ($definition[$v]) { + case 'CASCADE': + case 'SET NULL': + case 'NO ACTION': + case 'RESTRICT': + case 'SET DEFAULT': + $sql .= $keyword . $definition[$v]; + break; + default: + throw new Doctrine_Export_Exception('Unknown foreign key referential action option given.'); + } + } + } + return $sql; + } /** * Obtain DBMS specific SQL code portion needed to set the UNIQUE constraint * of a field declaration to be used in statements like CREATE TABLE. diff --git a/lib/Doctrine/Import.php b/lib/Doctrine/Import.php index ca0603d4b..12d53d7a0 100644 --- a/lib/Doctrine/Import.php +++ b/lib/Doctrine/Import.php @@ -174,4 +174,21 @@ class Doctrine_Import extends Doctrine_Connection_Module return $this->conn->fetchColumn($this->sql['listViews']); } + /** + * import + * + * method for importing existing schema to Doctrine_Record classes + * + * @param string $directory + * @param array $databases + */ + public function import($directory, array $databases = array()) + { + $builder = new Doctrine_Import_Builder(); + $builder->setTargetPath($directory); + + foreach ($this->listTables() as $table) { + $builder->buildRecord($table, $this->listTableColumns($table)); + } + } } diff --git a/lib/Doctrine/Import/Mssql.php b/lib/Doctrine/Import/Mssql.php index 55bd387fc..21b9b61f5 100644 --- a/lib/Doctrine/Import/Mssql.php +++ b/lib/Doctrine/Import/Mssql.php @@ -73,15 +73,15 @@ class Doctrine_Import_Mssql extends Doctrine_Import $decl = $this->conn->dataDict->getPortableDeclaration($val); $description = array( - 'name' => $val['column_name'], - 'type' => $type, + 'name' => $val['column_name'], + 'type' => $type, 'ptype' => $decl['type'], 'length' => $decl['length'], 'fixed' => $decl['fixed'], 'unsigned' => $decl['unsigned'], - 'notnull' => (bool) ($val['is_nullable'] === 'NO'), - 'default' => $val['column_def'], - 'primary' => (strtolower($identity) == 'identity'), + 'notnull' => (bool) ($val['is_nullable'] === 'NO'), + 'default' => $val['column_def'], + 'primary' => (strtolower($identity) == 'identity'), ); $columns[$val['column_name']] = $description; } diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index de08d50e8..2731ed550 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -1067,8 +1067,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $a[$v] = $this->_data[$v]; } } - - foreach ($this->_table->inheritanceMap as $k => $v) { + $map = $this->_table->inheritanceMap; + foreach ($map as $k => $v) { $old = $this->get($k, false); if ((string) $old !== (string) $v || $old === null) {