From d97336373d3591306ed1dc9d12faf03ace4b9a89 Mon Sep 17 00:00:00 2001 From: romanb Date: Wed, 7 Jan 2009 17:46:02 +0000 Subject: [PATCH] Finally first, very basic, running CRUD tests for Doctrine 2 --- lib/Doctrine/DBAL/Connection.php | 21 +- lib/Doctrine/DBAL/Driver/Connection.php | 3 +- lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php | 2 +- lib/Doctrine/DBAL/Driver/PDOStatement.php | 4 +- lib/Doctrine/DBAL/Driver/Statement.php | 4 +- .../DBAL/Platforms/AbstractPlatform.php | 96 ++++-- lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 42 ++- .../DBAL/Platforms/SqlitePlatform.php | 158 ++++++++- ...aManager.php => AbstractSchemaManager.php} | 9 +- .../DBAL/Schema/MySqlSchemaManger.php | 9 +- .../DBAL/Schema/OracleSchemaManager.php | 9 +- .../DBAL/Schema/PostgreSqlSchemaManager.php | 14 +- .../DBAL/Schema/SqliteSchemaManager.php | 130 +------- lib/Doctrine/DBAL/Types/ArrayType.php | 3 +- lib/Doctrine/DBAL/Types/BigIntType.php | 16 + lib/Doctrine/DBAL/Types/BooleanType.php | 1 - lib/Doctrine/DBAL/Types/CharType.php | 11 + lib/Doctrine/DBAL/Types/IntegerType.php | 17 +- lib/Doctrine/DBAL/Types/MediumIntType.php | 15 + lib/Doctrine/DBAL/Types/SmallIntType.php | 15 + lib/Doctrine/DBAL/Types/StringType.php | 28 -- lib/Doctrine/DBAL/Types/TextType.php | 10 +- lib/Doctrine/DBAL/Types/TinyIntType.php | 15 + lib/Doctrine/DBAL/Types/Type.php | 35 +- lib/Doctrine/DBAL/Types/VarcharType.php | 27 ++ lib/Doctrine/ORM/EntityManager.php | 16 +- lib/Doctrine/ORM/EntityRepository.php | 12 +- lib/Doctrine/ORM/Export/ClassExporter.php | 142 ++++++++ lib/Doctrine/ORM/Export/Export.php | 311 ------------------ lib/Doctrine/ORM/Mapping/ClassMetadata.php | 4 +- .../ORM/Mapping/Driver/AnnotationDriver.php | 14 +- .../Mapping/Driver/addendum/annotations.php | 12 +- .../Persisters/AbstractEntityPersister.php | 41 +-- lib/Doctrine/ORM/UnitOfWork.php | 20 +- tests/Orm/Functional/AllTests.php | 35 ++ tests/Orm/Functional/BasicCRUDTest.php | 38 +++ tests/Orm/Functional/Ticket/1Test.php | 10 + tests/Orm/Functional/Ticket/AllTests.php | 30 ++ tests/lib/Doctrine_OrmFunctionalTestCase.php | 31 +- .../mocks/Doctrine_DatabasePlatformMock.php | 21 ++ .../mocks/Doctrine_DriverConnectionMock.php | 2 +- tests/models/cms/CmsArticle.php | 4 +- tests/models/cms/CmsComment.php | 4 +- tests/models/cms/CmsPhonenumber.php | 2 +- tests/models/cms/CmsUser.php | 6 +- tests/models/forum/ForumCategory.php | 2 +- tests/models/forum/ForumEntry.php | 2 +- tests/models/forum/ForumUser.php | 4 +- 48 files changed, 801 insertions(+), 656 deletions(-) rename lib/Doctrine/DBAL/Schema/{SchemaManager.php => AbstractSchemaManager.php} (98%) create mode 100644 lib/Doctrine/DBAL/Types/BigIntType.php create mode 100644 lib/Doctrine/DBAL/Types/CharType.php create mode 100644 lib/Doctrine/DBAL/Types/MediumIntType.php create mode 100644 lib/Doctrine/DBAL/Types/SmallIntType.php delete mode 100644 lib/Doctrine/DBAL/Types/StringType.php create mode 100644 lib/Doctrine/DBAL/Types/TinyIntType.php create mode 100644 lib/Doctrine/DBAL/Types/VarcharType.php create mode 100644 lib/Doctrine/ORM/Export/ClassExporter.php delete mode 100644 lib/Doctrine/ORM/Export/Export.php create mode 100644 tests/Orm/Functional/AllTests.php create mode 100644 tests/Orm/Functional/BasicCRUDTest.php create mode 100644 tests/Orm/Functional/Ticket/1Test.php create mode 100644 tests/Orm/Functional/Ticket/AllTests.php diff --git a/lib/Doctrine/DBAL/Connection.php b/lib/Doctrine/DBAL/Connection.php index 2887fa56e..771027794 100644 --- a/lib/Doctrine/DBAL/Connection.php +++ b/lib/Doctrine/DBAL/Connection.php @@ -216,9 +216,7 @@ class Doctrine_DBAL_Connection */ public function connect() { - if ($this->_isConnected) { - return false; - } + if ($this->_isConnected) return false; $driverOptions = isset($this->_params['driverOptions']) ? $this->_params['driverOptions'] : array(); @@ -259,6 +257,7 @@ class Doctrine_DBAL_Connection */ public function delete($tableName, array $identifier) { + $this->connect(); $criteria = array(); foreach (array_keys($identifier) as $id) { $criteria[] = $this->quoteIdentifier($id) . ' = ?'; @@ -282,6 +281,7 @@ class Doctrine_DBAL_Connection */ public function update($tableName, array $data, array $identifier) { + $this->connect(); if (empty($data)) { return false; } @@ -316,6 +316,7 @@ class Doctrine_DBAL_Connection */ public function insert($tableName, array $data) { + $this->connect(); if (empty($data)) { return false; } @@ -326,7 +327,7 @@ class Doctrine_DBAL_Connection $a = array(); foreach ($data as $columnName => $value) { $cols[] = $this->quoteIdentifier($columnName); - if ($value instanceof Doctrine_Expression) { + if ($value instanceof Doctrine_DBAL_Expression) { $a[] = $value->getSql(); unset($data[$columnName]); } else { @@ -395,6 +396,7 @@ class Doctrine_DBAL_Connection */ public function quote($input, $type = null) { + $this->connect(); return $this->_conn->quote($input, $type); } @@ -492,10 +494,10 @@ class Doctrine_DBAL_Connection */ public function prepare($statement) { + echo $statement; $this->connect(); try { - $stmt = $this->_conn->prepare($statement); - return new Doctrine_DBAL_Statement($this, $stmt); + return $this->_conn->prepare($statement); } catch (PDOException $e) { $this->rethrowException($e, $this); } @@ -530,6 +532,7 @@ class Doctrine_DBAL_Connection { $this->connect(); try { + echo $query . PHP_EOL; if ( ! empty($params)) { $stmt = $this->prepare($query); $stmt->execute($params); @@ -566,7 +569,7 @@ class Doctrine_DBAL_Connection return $count; } } catch (PDOException $e) { - $this->rethrowException($e, $this); + throw $e; } } @@ -577,7 +580,7 @@ class Doctrine_DBAL_Connection */ public function rethrowException(Exception $e, $invoker) { - throw $exc; + throw $e; } /** @@ -667,6 +670,7 @@ class Doctrine_DBAL_Connection */ public function lastInsertId($seqName = null) { + $this->connect(); return $this->_conn->lastInsertId($seqName); } @@ -680,6 +684,7 @@ class Doctrine_DBAL_Connection */ public function beginTransaction() { + $this->connect(); if ($this->_transactionNestingLevel == 0) { return $this->_conn->beginTransaction(); } diff --git a/lib/Doctrine/DBAL/Driver/Connection.php b/lib/Doctrine/DBAL/Driver/Connection.php index 15d58046e..ca6c019a4 100644 --- a/lib/Doctrine/DBAL/Driver/Connection.php +++ b/lib/Doctrine/DBAL/Driver/Connection.php @@ -11,7 +11,7 @@ interface Doctrine_DBAL_Driver_Connection { public function prepare($prepareString); - public function query($queryString); + public function query(); public function quote($input); public function exec($statement); public function lastInsertId(); @@ -22,4 +22,3 @@ interface Doctrine_DBAL_Driver_Connection public function errorInfo(); } -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php index 2d68704d6..689ac791c 100644 --- a/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php +++ b/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -59,7 +59,7 @@ class Doctrine_DBAL_Driver_PDOSqlite_Driver implements Doctrine_DBAL_Driver * Gets the schema manager that is relevant for this driver. * * @param Doctrine\DBAL\Connection $conn - * @return Doctrine\DBAL\Schema\AbstractSchemaManager + * @return Doctrine\DBAL\Schema\SqliteSchemaManager */ public function getSchemaManager(Doctrine_DBAL_Connection $conn) { diff --git a/lib/Doctrine/DBAL/Driver/PDOStatement.php b/lib/Doctrine/DBAL/Driver/PDOStatement.php index 47f6e805e..4d3b88c84 100644 --- a/lib/Doctrine/DBAL/Driver/PDOStatement.php +++ b/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -1,4 +1,6 @@ getFieldDeclarationList($columns); + $queryFields = $this->getFieldDeclarationListSql($columns); if (isset($options['primary']) && ! empty($options['primary'])) { $queryFields .= ', PRIMARY KEY(' . implode(', ', array_values($options['primary'])) . ')'; @@ -1193,7 +1193,7 @@ abstract class Doctrine_DBAL_Platforms_AbstractPlatform } /** - * Get declaration of a number of field in bulk + * Get declaration of a number of fields in bulk * * @param array $fields a multidimensional associative array. * The first dimension determines the field name, while the second @@ -1223,9 +1223,9 @@ abstract class Doctrine_DBAL_Platforms_AbstractPlatform */ public function getFieldDeclarationListSql(array $fields) { + $queryFields = array(); foreach ($fields as $fieldName => $field) { $query = $this->getDeclarationSql($fieldName, $field); - $queryFields[] = $query; } return implode(', ', $queryFields); @@ -1265,33 +1265,64 @@ abstract class Doctrine_DBAL_Platforms_AbstractPlatform */ public function getDeclarationSql($name, array $field) { - $default = $this->getDefaultFieldDeclarationSql($field); - - $charset = (isset($field['charset']) && $field['charset']) ? - ' ' . $this->getCharsetFieldDeclarationSql($field['charset']) : ''; - + $default = $this->getDefaultFieldDeclarationSql($field); + $charset = (isset($field['charset']) && $field['charset']) ? + ' ' . $this->getCharsetFieldDeclarationSql($field['charset']) : ''; $collation = (isset($field['collation']) && $field['collation']) ? - ' ' . $this->getCollationFieldDeclarationSql($field['collation']) : ''; + ' ' . $this->getCollationFieldDeclarationSql($field['collation']) : ''; + $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; + $unique = (isset($field['unique']) && $field['unique']) ? + ' ' . $this->getUniqueFieldDeclarationSql() : ''; + $check = (isset($field['check']) && $field['check']) ? + ' ' . $field['check'] : ''; - $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; - - $unique = (isset($field['unique']) && $field['unique']) ? - ' ' . $this->getUniqueFieldDeclarationSql() : ''; - - $check = (isset($field['check']) && $field['check']) ? - ' ' . $field['check'] : ''; - - $method = 'get' . $field['type'] . 'Declaration'; - - if (method_exists($this, $method)) { - return $this->$method($name, $field); - } else { - $dec = $this->getNativeDeclaration($field); - } - - return $this->quoteIdentifier($name, true) . ' ' . $dec . $charset . $default . $notnull . $unique . $check . $collation; + $typeDecl = $field['type']->getSqlDeclaration($field, $this); + + return $this->quoteIdentifier($name, true) . ' ' . $typeDecl . $charset . $default . $notnull . $unique . $check . $collation; } + /** + * + * @param $name + * @param $field + */ + abstract public function getIntegerTypeDeclarationSql(array $columnDef); + + /** + * Gets the SQL snippet that declares a BIGINT column. + * + * @return string + */ + abstract public function getBigIntTypeDeclarationSql(array $columnDef); + + /** + * Gets the SQL snippet that declares a TINYINT column. + * + * @return string + */ + abstract public function getTinyIntTypeDeclarationSql(array $columnDef); + + /** + * Gets the SQL snippet that declares a SMALLINT column. + * + * @return string + */ + abstract public function getSmallIntTypeDeclarationSql(array $columnDef); + + /** + * Gets the SQL snippet that declares a MEDIUMINT column. + * + * @return string + */ + abstract public function getMediumIntTypeDeclarationSql(array $columnDef); + + /** + * Gets the SQL snippet that declares common properties of an integer column. + * + * @return string + */ + abstract protected function _getCommonIntegerTypeDeclarationSql(array $columnDef); + /** * getDefaultDeclaration * Obtain DBMS specific SQL code portion needed to set a default value @@ -1858,7 +1889,18 @@ abstract class Doctrine_DBAL_Platforms_AbstractPlatform { return true; } + + public function getIdentityColumnNullInsertSql() + { + return ""; + } + + /** + * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform. + * + * @params array $field + */ + abstract public function getVarcharDeclarationSql(array $field); } -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php index 01356846b..1e8a30eab 100644 --- a/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -230,7 +230,9 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst } /** - * @TEST + * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform. + * + * @params array $field */ public function getVarcharDeclarationSql(array $field) { @@ -243,7 +245,7 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst } $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false; - $fixed = (isset($field['fixed'])) ? $field['fixed'] : false; + $fixed = (isset($field['fixed'])) ? $field['fixed'] : false; return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); @@ -1037,7 +1039,37 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst * declare the specified field. * @override */ - public function getIntegerDeclarationSql($name, $field) + public function getIntegerTypeDeclarationSql(array $field) + { + return 'INT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getBigIntTypeDeclarationSql(array $field) + { + return 'BIGINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getTinyIntTypeDeclarationSql(array $field) + { + return 'TINYINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getSmallIntDeclarationSql(array $field) + { + return 'SMALLINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getMediumIntDeclarationSql(array $field) + { + return 'MEDIUMINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) { $default = $autoinc = ''; if ( ! empty($field['autoincrement'])) { @@ -1058,9 +1090,7 @@ class Doctrine_DBAL_Platforms_MySqlPlatform extends Doctrine_DBAL_Platforms_Abst $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; $unsigned = (isset($field['unsigned']) && $field['unsigned']) ? ' UNSIGNED' : ''; - $name = $this->quoteIdentifier($name, true); - - return $name . ' ' . $this->getNativeDeclaration($field) . $unsigned . $default . $notnull . $autoinc; + return $unsigned . $default . $notnull . $autoinc; } /** diff --git a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php index 76ec77919..afb26aae8 100644 --- a/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +++ b/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -391,6 +391,162 @@ class Doctrine_DBAL_Platforms_SqlitePlatform extends Doctrine_DBAL_Platforms_Abs { return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSql($level); } + + /** @override */ + public function prefersIdentityColumns() { + return true; + } + + /** @override */ + public function getIntegerTypeDeclarationSql(array $field) + { + return 'INT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getBigIntTypeDeclarationSql(array $field) + { + return 'BIGINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getTinyIntTypeDeclarationSql(array $field) + { + return 'TINYINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getSmallIntTypeDeclarationSql(array $field) + { + return 'SMALLINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + public function getMediumIntTypeDeclarationSql(array $field) + { + return 'MEDIUMINT ' . $this->_getCommonIntegerTypeDeclarationSql($field); + } + + /** @override */ + protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) + { + $default = $autoinc = ''; + if ( ! empty($columnDef['autoincrement'])) { + $autoinc = ' AUTO_INCREMENT'; + } else if (array_key_exists('default', $columnDef)) { + if ($field['default'] === '') { + $field['default'] = empty($columnDef['notnull']) ? null : 0; + } + if (is_null($columnDef['default'])) { + $default = ' DEFAULT NULL'; + } else { + $default = ' DEFAULT ' . $this->quote($columnDef['default']); + } + } else if (empty($columnDef['notnull'])) { + $default = ' DEFAULT NULL'; + } + + $notnull = (isset($columnDef['notnull']) && $columnDef['notnull']) ? ' NOT NULL' : ''; + $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : ''; + + return $unsigned . $default . $notnull . $autoinc; + } + + /** + * 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 + * The indexes of the array entries are the names of the fields of the table an + * the array entry values are associative arrays like those that are meant to be + * passed with the field definitions to get[Type]Declaration() functions. + * array( + * 'id' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * 'notnull' => 1 + * 'default' => 0 + * ), + * 'name' => array( + * 'type' => 'text', + * 'length' => 12 + * ), + * 'password' => array( + * 'type' => 'text', + * 'length' => 12 + * ) + * ); + * @param array $options An associative array of table options: + * + * @return void + * @override + */ + public function getCreateTableSql($name, array $fields, array $options = array()) + { + if ( ! $name) { + throw new Doctrine_Exception('no valid table name specified'); + } + + if (empty($fields)) { + throw new Doctrine_Exception('no fields specified for table '.$name); + } + $queryFields = $this->getFieldDeclarationListSql($fields); + + $autoinc = false; + foreach($fields as $field) { + if (isset($field['autoincrement']) && $field['autoincrement'] || + (isset($field['autoinc']) && $field['autoinc'])) { + $autoinc = true; + break; + } + } + + if ( ! $autoinc && isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_values($options['primary']); + $keyColumns = array_map(array($this->_conn, 'quoteIdentifier'), $keyColumns); + $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')'; + } + + $name = $this->quoteIdentifier($name, true); + $sql = 'CREATE TABLE ' . $name . ' (' . $queryFields; + + if ($check = $this->getCheckDeclarationSql($fields)) { + $sql .= ', ' . $check; + } + + if (isset($options['checks']) && $check = $this->getCheckDeclarationSql($options['checks'])) { + $sql .= ', ' . $check; + } + + $sql .= ')'; + + $query[] = $sql; + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index => $definition) { + $query[] = $this->createIndexSql($name, $index, $definition); + } + } + return $query; + } + + /** + * {@inheritdoc} + */ + public function getVarcharDeclarationSql(array $field) + { + if ( ! isset($field['length'])) { + if (array_key_exists('default', $field)) { + $field['length'] = $this->getVarcharMaxLength(); + } else { + $field['length'] = false; + } + } + $length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false; + $fixed = (isset($field['fixed'])) ? $field['fixed'] : false; + + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); + } } -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Schema/SchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php similarity index 98% rename from lib/Doctrine/DBAL/Schema/SchemaManager.php rename to lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index 34a4643ae..92656ae7f 100644 --- a/lib/Doctrine/DBAL/Schema/SchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -19,7 +19,7 @@ * . */ -#namespace Doctrine::DBAL::Schema; +#namespace Doctrine\DBAL\Schema; /** * Base class for schema managers. Schema managers are used to inspect and/or @@ -28,14 +28,19 @@ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @author Konsta Vesterinen * @author Lukas Smith (PEAR MDB2 library) + * @author Roman Borschel * @version $Revision$ * @since 2.0 - * @todo Rename to AbstractSchemaManager */ abstract class Doctrine_DBAL_Schema_AbstractSchemaManager { protected $_conn; + public function __construct(Doctrine_DBAL_Connection $conn) + { + $this->_conn = $conn; + } + /** * lists all databases * diff --git a/lib/Doctrine/DBAL/Schema/MySqlSchemaManger.php b/lib/Doctrine/DBAL/Schema/MySqlSchemaManger.php index 5d06541de..ad7fe6b6a 100644 --- a/lib/Doctrine/DBAL/Schema/MySqlSchemaManger.php +++ b/lib/Doctrine/DBAL/Schema/MySqlSchemaManger.php @@ -19,7 +19,7 @@ * . */ -#namespace Doctrine::DBAL::Schema; +#namespace Doctrine\DBAL\Schema; /** * xxx @@ -31,12 +31,7 @@ * @since 2.0 */ class Doctrine_DBAL_Schema_MySqlSchemaManager extends Doctrine_DBAL_Schema_AbstractSchemaManager -{ - public function __construct(Doctrine_Connection $conn) - { - $this->_conn = $conn; - } - +{ /** * lists all database sequences * diff --git a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php index 6b725eaa3..79ce29e14 100644 --- a/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -19,7 +19,7 @@ * . */ -#namespace Doctrine::DBAL::Schema; +#namespace Doctrine\DBAL\Schema; /** * xxx @@ -31,12 +31,7 @@ * @since 2.0 */ class Doctrine_DBAL_Schema_OracleSchemaManager extends Doctrine_DBAL_Schema_AbstractSchemaManager -{ - public function __construct(Doctrine_Connection_Oracle $conn) - { - $this->_conn = $conn; - } - +{ /** * create a new database * diff --git a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php index c797e64ca..7840d2555 100644 --- a/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php @@ -19,7 +19,7 @@ * . */ -#namespace Doctrine::DBAL::Schema; +#namespace Doctrine\DBAL\Schema; /** * xxx @@ -31,17 +31,7 @@ * @since 2.0 */ class Doctrine_DBAL_Schema_PostgreSqlSchemaManager extends Doctrine_DBAL_Schema_AbstractSchemaManager -{ - /** - * Enter description here... - * - * @param Doctrine_Connection_Pgsql $conn - */ - public function __construct(Doctrine_Connection_Pgsql $conn) - { - $this->_conn = $conn; - } - +{ /** * alter an existing table * diff --git a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php index 29c2c63e5..467ae2c6f 100644 --- a/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -19,7 +19,7 @@ * . */ -#namespace Doctrine::DBAL::Schema; +#namespace Doctrine\DBAL\Schema; /** * xxx @@ -31,12 +31,7 @@ * @since 2.0 */ class Doctrine_DBAL_Schema_SqliteSchemaManager extends Doctrine_DBAL_Schema_AbstractSchemaManager -{ - public function __construct(Doctrine_Connection_Sqlite $conn) - { - $this->_conn = $conn; - } - +{ /** * lists all databases * @@ -44,11 +39,11 @@ class Doctrine_DBAL_Schema_SqliteSchemaManager extends Doctrine_DBAL_Schema_Abst */ public function listDatabases() { - + } /** - * lists all availible database functions + * lists all available database functions * * @return array */ @@ -371,123 +366,6 @@ class Doctrine_DBAL_Schema_SqliteSchemaManager extends Doctrine_DBAL_Schema_Abst return implode(', ', $declFields); } - /** - * 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 - * The indexes of the array entries are the names of the fields of the table an - * the array entry values are associative arrays like those that are meant to be - * passed with the field definitions to get[Type]Declaration() functions. - * array( - * 'id' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * 'notnull' => 1 - * 'default' => 0 - * ), - * 'name' => array( - * 'type' => 'text', - * 'length' => 12 - * ), - * 'password' => array( - * 'type' => 'text', - * 'length' => 12 - * ) - * ); - * @param array $options An associative array of table options: - * - * @return void - */ - public function createTableSql($name, array $fields, array $options = array()) - { - if ( ! $name) { - throw new Doctrine_Export_Exception('no valid table name specified'); - } - - if (empty($fields)) { - throw new Doctrine_Export_Exception('no fields specified for table '.$name); - } - $queryFields = $this->getFieldDeclarationList($fields); - - $autoinc = false; - foreach($fields as $field) { - if (isset($field['autoincrement']) && $field['autoincrement'] || - (isset($field['autoinc']) && $field['autoinc'])) { - $autoinc = true; - break; - } - } - - if ( ! $autoinc && isset($options['primary']) && ! empty($options['primary'])) { - $keyColumns = array_values($options['primary']); - $keyColumns = array_map(array($this->_conn, 'quoteIdentifier'), $keyColumns); - $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')'; - } - - $name = $this->_conn->quoteIdentifier($name, true); - $sql = 'CREATE TABLE ' . $name . ' (' . $queryFields; - - if ($check = $this->getCheckDeclaration($fields)) { - $sql .= ', ' . $check; - } - - if (isset($options['checks']) && $check = $this->getCheckDeclaration($options['checks'])) { - $sql .= ', ' . $check; - } - - $sql .= ')'; - - $query[] = $sql; - - if (isset($options['indexes']) && ! empty($options['indexes'])) { - foreach ($options['indexes'] as $index => $definition) { - $query[] = $this->createIndexSql($name, $index, $definition); - } - } - return $query; - - - /** - try { - - if ( ! empty($fk)) { - $this->_conn->beginTransaction(); - } - - $ret = $this->_conn->exec($query); - - if ( ! empty($fk)) { - foreach ($fk as $definition) { - - $query = 'CREATE TRIGGER doctrine_' . $name . '_cscd_delete ' - . 'AFTER DELETE ON ' . $name . ' FOR EACH ROW ' - . 'BEGIN ' - . 'DELETE FROM ' . $definition['foreignTable'] . ' WHERE '; - - $local = (array) $definition['local']; - foreach((array) $definition['foreign'] as $k => $field) { - $query .= $field . ' = old.' . $local[$k] . ';'; - } - - $query .= 'END;'; - - $this->_conn->exec($query); - } - - $this->_conn->commit(); - } - - - } catch(Doctrine_Exception $e) { - - $this->_conn->rollback(); - - throw $e; - } - */ - } - /** * getAdvancedForeignKeyOptions * Return the FOREIGN KEY query section dealing with non-standard options diff --git a/lib/Doctrine/DBAL/Types/ArrayType.php b/lib/Doctrine/DBAL/Types/ArrayType.php index f1a847628..3c4dbabe5 100644 --- a/lib/Doctrine/DBAL/Types/ArrayType.php +++ b/lib/Doctrine/DBAL/Types/ArrayType.php @@ -11,8 +11,7 @@ class Doctrine_DBAL_Types_ArrayType extends Doctrine_DBAL_Types_Type public function getName() { - return 'array'; + return 'Array'; } } -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/BigIntType.php b/lib/Doctrine/DBAL/Types/BigIntType.php new file mode 100644 index 000000000..44ea32275 --- /dev/null +++ b/lib/Doctrine/DBAL/Types/BigIntType.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/CharType.php b/lib/Doctrine/DBAL/Types/CharType.php new file mode 100644 index 000000000..b198c5d98 --- /dev/null +++ b/lib/Doctrine/DBAL/Types/CharType.php @@ -0,0 +1,11 @@ +getIntegerTypeDeclarationSql($fieldDeclaration); + } + + public function convertToPHPValue($value) + { + return (int)$value; } } -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/MediumIntType.php b/lib/Doctrine/DBAL/Types/MediumIntType.php new file mode 100644 index 000000000..0b827e618 --- /dev/null +++ b/lib/Doctrine/DBAL/Types/MediumIntType.php @@ -0,0 +1,15 @@ + diff --git a/lib/Doctrine/DBAL/Types/StringType.php b/lib/Doctrine/DBAL/Types/StringType.php deleted file mode 100644 index a919688c4..000000000 --- a/lib/Doctrine/DBAL/Types/StringType.php +++ /dev/null @@ -1,28 +0,0 @@ -getVarcharDeclaration($fieldDeclaration); - } - - public function getDefaultLength(Doctrine_DatabasePlatform $platform) - { - return $platform->getVarcharDefaultLength(); - } - - public function getName() - { - return 'string'; - } -} - -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/TextType.php b/lib/Doctrine/DBAL/Types/TextType.php index d31da7496..b0132330b 100644 --- a/lib/Doctrine/DBAL/Types/TextType.php +++ b/lib/Doctrine/DBAL/Types/TextType.php @@ -7,14 +7,7 @@ */ class Doctrine_DBAL_Types_TextType extends Doctrine_DBAL_Types_Type { - /** - * Enter description here... - * - * @param array $fieldDeclaration - * @param Doctrine_DatabasePlatform $platform - * @return unknown - * @override - */ + /** @override */ public function getSqlDeclaration(array $fieldDeclaration, Doctrine_DatabasePlatform $platform) { return $platform->getClobDeclarationSql($fieldDeclaration); @@ -22,4 +15,3 @@ class Doctrine_DBAL_Types_TextType extends Doctrine_DBAL_Types_Type } -?> \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/TinyIntType.php b/lib/Doctrine/DBAL/Types/TinyIntType.php new file mode 100644 index 000000000..c00542a17 --- /dev/null +++ b/lib/Doctrine/DBAL/Types/TinyIntType.php @@ -0,0 +1,15 @@ + 'Doctrine_DataType_IntegerType', - 'string' => 'Doctrine_DataType_StringType', - 'text' => 'Doctrine_DataType_TextType', - 'datetime' => 'Doctrine_DataType_DateTimeType', - 'decimal' => 'Doctrine_DataType_DecimalType', - 'double' => 'Doctrine_DataType_DoubleType' + 'integer' => 'Doctrine_DBAL_Types_IntegerType', + 'int' => 'Doctrine_DBAL_Types_IntegerType', + 'tinyint' => 'Doctrine_DBAL_Types_TinyIntType', + 'smallint' => 'Doctrine_DBAL_Types_SmallIntType', + 'mediumint' => 'Doctrine_DBAL_Types_MediumIntType', + 'bigint' => 'Doctrine_DBAL_Types_BigIntType', + 'varchar' => 'Doctrine_DBAL_Types_VarcharType', + 'text' => 'Doctrine_DBAL_Types_TextType', + 'datetime' => 'Doctrine_DBAL_Types_DateTimeType', + 'decimal' => 'Doctrine_DBAL_Types_DecimalType', + 'double' => 'Doctrine_DBAL_Types_DoubleType' ); - public function convertToDatabaseValue($value, Doctrine_DBAL_Platforms_AbstractDatabasePlatform $platform) + public function convertToDatabaseValue($value, Doctrine_DBAL_Platforms_AbstractPlatform $platform) + { + return $value; + } + + public function convertToPHPValue($value) { return $value; } - public function convertToObjectValue($value) + public function getDefaultLength(Doctrine_DBAL_Platforms_AbstractPlatform $platform) { - return $value; + return null; } - - abstract public function getDefaultLength(Doctrine_DBAL_Platforms_AbstractDatabasePlatform $platform); - abstract public function getSqlDeclaration(array $fieldDeclaration, Doctrine_DBAL_Platforms_AbstractDatabasePlatform $platform); + + abstract public function getSqlDeclaration(array $fieldDeclaration, Doctrine_DBAL_Platforms_AbstractPlatform $platform); abstract public function getName(); /** @@ -35,7 +44,7 @@ abstract class Doctrine_DBAL_Types_Type * Type instances are implemented as flyweights. * * @param string $name The name of the type (as returned by getName()). - * @return Doctrine::DBAL::Types::Type + * @return Doctrine\DBAL\Types\Type */ public static function getType($name) { diff --git a/lib/Doctrine/DBAL/Types/VarcharType.php b/lib/Doctrine/DBAL/Types/VarcharType.php new file mode 100644 index 000000000..e5d0a56f2 --- /dev/null +++ b/lib/Doctrine/DBAL/Types/VarcharType.php @@ -0,0 +1,27 @@ +getVarcharDeclarationSql($fieldDeclaration); + } + + /** @override */ + public function getDefaultLength(Doctrine_DBAL_Platforms_AbstractPlatform $platform) + { + return $platform->getVarcharDefaultLength(); + } + + /** @override */ + public function getName() { return 'Varchar'; } +} + diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index be7253366..a3606d0b0 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -429,12 +429,12 @@ class Doctrine_ORM_EntityManager /** * Saves the given entity, persisting it's state. * - * @param Doctrine\ORM\Entity $entity + * @param object $object */ - public function save(Doctrine_ORM_Entity $entity) + public function save($object) { $this->_errorIfNotActiveOrClosed(); - $this->_unitOfWork->save($entity); + $this->_unitOfWork->save($object); if ($this->_flushMode == self::FLUSHMODE_IMMEDIATE) { $this->flush(); } @@ -496,7 +496,7 @@ class Doctrine_ORM_EntityManager if ($customRepositoryClassName !== null) { $repository = new $customRepositoryClassName($entityName, $metadata); } else { - $repository = new Doctrine_ORM_EntityRepository($entityName, $metadata); + $repository = new Doctrine_ORM_EntityRepository($this, $metadata); } $this->_repositories[$entityName] = $repository; @@ -506,11 +506,11 @@ class Doctrine_ORM_EntityManager /** * Checks if the instance is managed by the EntityManager. * - * @param Doctrine\ORM\Entity $entity + * @param object $entity * @return boolean TRUE if this EntityManager currently manages the given entity * (and has it in the identity map), FALSE otherwise. */ - public function contains(Doctrine_ORM_Entity $entity) + public function contains($entity) { return $this->_unitOfWork->isInIdentityMap($entity) && ! $this->_unitOfWork->isRegisteredRemoved($entity); @@ -543,8 +543,8 @@ class Doctrine_ORM_EntityManager */ private function _errorIfNotActiveOrClosed() { - if ( ! $this->isActive() || $this->_closed) { - throw Doctrine_EntityManagerException::notActiveOrClosed($this->_name); + if ($this->_closed) { + throw Doctrine_ORM_Exceptions_EntityManagerException::notActiveOrClosed($this->_name); } } diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php index 13c45c180..389959c03 100644 --- a/lib/Doctrine/ORM/EntityRepository.php +++ b/lib/Doctrine/ORM/EntityRepository.php @@ -38,10 +38,10 @@ class Doctrine_ORM_EntityRepository protected $_em; protected $_classMetadata; - public function __construct($entityName, Doctrine_ORM_Mapping_ClassMetadata $classMetadata) + public function __construct($em, Doctrine_ORM_Mapping_ClassMetadata $classMetadata) { - $this->_entityName = $entityName; - $this->_em = $classMetadata->getConnection(); + $this->_entityName = $classMetadata->getClassName(); + $this->_em = $em; $this->_classMetadata = $classMetadata; } @@ -77,7 +77,6 @@ class Doctrine_ORM_EntityRepository * @param $id The identifier. * @param int $hydrationMode The hydration mode to use. * @return mixed Array or Doctrine_Entity or false if no result - * @todo Remove. Move to EntityRepository. */ public function find($id, $hydrationMode = null) { @@ -94,7 +93,10 @@ class Doctrine_ORM_EntityRepository $keys = $this->_classMetadata->getIdentifier(); } - //TODO: check identity map? + // Check identity map first + if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_classMetadata->getRootClassName())) { + return $entity; // Hit! + } return $this->_createQuery() ->where(implode(' = ? AND ', $keys) . ' = ?') diff --git a/lib/Doctrine/ORM/Export/ClassExporter.php b/lib/Doctrine/ORM/Export/ClassExporter.php new file mode 100644 index 000000000..e36d55c56 --- /dev/null +++ b/lib/Doctrine/ORM/Export/ClassExporter.php @@ -0,0 +1,142 @@ +. + */ + +#namespace Doctrine\ORM\Export; + +/** + * The ClassExporter can generate database schemas/structures from ClassMetadata + * class descriptors. + * + * @package Doctrine + * @subpackage Export + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 4805 $ + */ +class Doctrine_ORM_Export_ClassExporter +{ + /** The SchemaManager */ + private $_sm; + /** The EntityManager */ + private $_em; + + public function __construct(Doctrine_ORM_EntityManager $em) + { + $this->_em = $em; + $this->_sm = $em->getConnection()->getSchemaManager(); + } + + /** + * Exports entity classes to a schema. + * + * FIXME: This method is a big huge hack. The sql needs to be executed in the correct order. I have some stupid logic to + * make sure they are in the right order. + * + * @param array $classes + * @return void + */ + public function exportClasses(array $classes) + { + //TODO: order them + foreach ($classes as $class) { + $columns = array(); + $options = array(); + + foreach ($class->getFieldMappings() as $fieldName => $mapping) { + $column = array(); + $column['name'] = $mapping['columnName']; + $column['type'] = $mapping['type']; + $column['length'] = $mapping['length']; + + if ($class->isIdentifier($fieldName)) { + if ($class->isIdGeneratorIdentity()) { + $column['autoincrement'] = true; + } + } + + $columns[$mapping['columnName']] = $column; + } + + $this->_sm->createTable($class->getTableName(), $columns, $options); + } + } + + /** + * exportClassesSql + * method for exporting entity classes to a schema + * + * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS + * occurred during the create table operation + * @param array $classes + * @return void + */ + public function exportClassesSql(array $classes) + { + $models = Doctrine::filterInvalidModels($classes); + + $sql = array(); + $finishedClasses = array(); + + foreach ($models as $name) { + if (in_array($name, $finishedClasses)) { + continue; + } + + $classMetadata = $this->conn->getClassMetadata($name); + + // In Class Table Inheritance we have to make sure that ALL tables of parent classes + // are exported, too as soon as ONE table is exported, because the data of one class is stored + // across many tables. + if ($classMetadata->getInheritanceType() == Doctrine::INHERITANCE_TYPE_JOINED) { + $parents = $classMetadata->getParentClasses(); + foreach ($parents as $parent) { + $data = $classMetadata->getConnection()->getClassMetadata($parent)->getExportableFormat(); + $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']); + $sql = array_merge($sql, (array) $query); + $finishedClasses[] = $parent; + } + } + + $data = $classMetadata->getExportableFormat(); + $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']); + + if (is_array($query)) { + $sql = array_merge($sql, $query); + } else { + $sql[] = $query; + } + + if ($classMetadata->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_PLUGINS) { + $sql = array_merge($sql, $this->exportGeneratorsSql($classMetadata)); + } + } + + $sql = array_unique($sql); + + rsort($sql); + + return $sql; + } +} diff --git a/lib/Doctrine/ORM/Export/Export.php b/lib/Doctrine/ORM/Export/Export.php deleted file mode 100644 index b93c0a7a9..000000000 --- a/lib/Doctrine/ORM/Export/Export.php +++ /dev/null @@ -1,311 +0,0 @@ -. - */ - -#namespace Doctrine::DBAL::Export; - -/** - * Doctrine_Export - * - * @package Doctrine - * @subpackage Export - * @author Konsta Vesterinen - * @author Lukas Smith (PEAR MDB2 library) - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.phpdoctrine.org - * @since 1.0 - * @version $Revision: 4805 $ - * @todo Rename to ExportManager. Subclasses: MySqlExportManager, PgSqlExportManager etc. - */ -class Doctrine_Export extends Doctrine_Connection_Module -{ - - /** - * exportSchema - * method for exporting Doctrine_Entity classes to a schema - * - * if the directory parameter is given this method first iterates - * recursively trhough the given directory in order to find any model classes - * - * Then it iterates through all declared classes and creates tables for the ones - * that extend Doctrine_Entity and are not abstract classes - * - * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS - * occurred during the create table operation - * @param string $directory optional directory parameter - * @return void - */ - public function exportSchema($directory = null) - { - if ($directory !== null) { - $models = Doctrine::loadModels($directory); - } else { - $models = Doctrine::getLoadedModels(); - } - - $this->exportClasses($models); - } - - /** - * exportClasses - * - * FIXME: This method is a big huge hack. The sql needs to be executed in the correct order. I have some stupid logic to - * make sure they are in the right order. - * - * method for exporting Doctrine_Entity classes to a schema - * - * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS - * occurred during the create table operation - * @param array $classes - * @return void - * @todo ORM stuff - */ - public function exportClasses(array $classes) - { - $connections = array(); - foreach ($classes as $class) { - $record = new $class(); - $connection = $record->getTable()->getConnection(); - $connectionName = Doctrine_Manager::getInstance()->getConnectionName($connection); - - if ( ! isset($connections[$connectionName])) { - $connections[$connectionName] = array( - 'create_tables' => array(), - 'create_sequences' => array(), - 'alters' => array() - ); - } - - $sql = $this->exportClassesSql(array($class)); - - // Build array of all the creates - // We need these to happen first - foreach ($sql as $key => $query) { - if (strstr($query, 'CREATE TABLE')) { - $connections[$connectionName]['create_tables'][] = $query; - - unset($sql[$key]); - } - - if (strstr($query, 'CREATE SEQUENCE')) { - $connections[$connectionName]['create_sequences'][] = $query; - - unset($sql[$key]); - } - } - - $connections[$connectionName]['alters'] = array_merge($connections[$connectionName]['alters'], $sql); - } - - // Loop over all the sql again to merge the creates and alters in to the same array, but so that the alters are at the bottom - $build = array(); - foreach ($connections as $connectionName => $sql) { - $build[$connectionName] = array_unique(array_merge($sql['create_tables'], $sql['create_sequences'], $sql['alters'])); - } - - foreach ($build as $connectionName => $sql) { - $connection = Doctrine_Manager::getInstance()->getConnection($connectionName); - - $connection->beginTransaction(); - - foreach ($sql as $query) { - try { - $connection->exec($query); - } catch (Doctrine_Connection_Exception $e) { - // we only want to silence table already exists errors - if ($e->getPortableCode() !== Doctrine::ERR_ALREADY_EXISTS) { - $connection->rollback(); - throw new Doctrine_Export_Exception($e->getMessage() . '. Failing Query: ' . $query); - } - } - } - - $connection->commit(); - } - } - - /** - * exportClassesSql - * method for exporting Doctrine_Entity classes to a schema - * - * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS - * occurred during the create table operation - * @param array $classes - * @return void - * @todo package:orm - */ - public function exportClassesSql(array $classes) - { - $models = Doctrine::filterInvalidModels($classes); - - $sql = array(); - $finishedClasses = array(); - - foreach ($models as $name) { - if (in_array($name, $finishedClasses)) { - continue; - } - - $classMetadata = $this->conn->getClassMetadata($name); - - // In Class Table Inheritance we have to make sure that ALL tables of parent classes - // are exported, too as soon as ONE table is exported, because the data of one class is stored - // across many tables. - if ($classMetadata->getInheritanceType() == Doctrine::INHERITANCE_TYPE_JOINED) { - $parents = $classMetadata->getParentClasses(); - foreach ($parents as $parent) { - $data = $classMetadata->getConnection()->getClassMetadata($parent)->getExportableFormat(); - $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']); - $sql = array_merge($sql, (array) $query); - $finishedClasses[] = $parent; - } - } - - $data = $classMetadata->getExportableFormat(); - $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']); - - if (is_array($query)) { - $sql = array_merge($sql, $query); - } else { - $sql[] = $query; - } - - if ($classMetadata->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_PLUGINS) { - $sql = array_merge($sql, $this->exportGeneratorsSql($classMetadata)); - } - } - - $sql = array_unique($sql); - - rsort($sql); - - return $sql; - } - - /** - * fetches all generators recursively for given table - * - * @param Doctrine_Table $table table object to retrieve the generators from - * @return array an array of Doctrine_Record_Generator objects - * @todo package:orm - */ - public function getAllGenerators(Doctrine_ClassMetadata $table) - { - $generators = array(); - - foreach ($table->getGenerators() as $name => $generator) { - if ($generator === null) { - continue; - } - - $generators[] = $generator; - - $generatorTable = $generator->getTable(); - - if ($generatorTable instanceof Doctrine_Table) { - $generators = array_merge($generators, $this->getAllGenerators($generatorTable)); - } - } - - return $generators; - } - - /** - * exportGeneratorsSql - * exports plugin tables for given table - * - * @param Doctrine_Table $table the table in which the generators belong to - * @return array an array of sql strings - * @todo package:orm - */ - public function exportGeneratorsSql(Doctrine_ClassMetadata $class) - { - $sql = array(); - foreach ($this->getAllGenerators($class) as $name => $generator) { - $table = $generator->getTable(); - - // Make sure plugin has a valid table - if ($table instanceof Doctrine_Table) { - $data = $table->getExportableFormat(); - $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']); - $sql = array_merge($sql, (array) $query); - } - } - - return $sql; - } - - /** - * exportSql - * returns the sql for exporting Doctrine_Entity classes to a schema - * - * if the directory parameter is given this method first iterates - * recursively trhough the given directory in order to find any model classes - * - * Then it iterates through all declared classes and creates tables for the ones - * that extend Doctrine_Entity and are not abstract classes - * - * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS - * occurred during the create table operation - * @param string $directory optional directory parameter - * @return void - */ - public function exportSql($directory = null) - { - if ($directory !== null) { - $models = Doctrine::loadModels($directory); - } else { - $models = Doctrine::getLoadedModels(); - } - - return $this->exportClassesSql($models); - } - - /** - * exportTable - * exports given table into database based on column and option definitions - * - * @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS - * occurred during the create table operation - * @return boolean whether or not the export operation was successful - * false if table already existed in the database - * @todo ORM stuff - */ - public function exportTable(Doctrine_ClassMetadata $metadata) - { - /** - TODO: maybe there should be portability option for the following check - if ( ! Doctrine::isValidClassname($table->getOption('declaringClass')->getName())) { - throw new Doctrine_Export_Exception('Class name not valid.'); - } - */ - - try { - $data = $metadata->getExportableFormat(); - - $this->conn->export->createTable($data['tableName'], $data['columns'], $data['options']); - } catch (Doctrine_Connection_Exception $e) { - // we only want to silence table already exists errors - if ($e->getPortableCode() !== Doctrine::ERR_ALREADY_EXISTS) { - throw $e; - } - } - } -} diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index 01cbf187f..719324910 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -616,7 +616,9 @@ class Doctrine_ORM_Mapping_ClassMetadata if ( ! isset($mapping['type'])) { throw Doctrine_ORM_Exceptions_MappingException::missingType(); } - + + $mapping['type'] = Doctrine_DBAL_Types_Type::getType($mapping['type']); + // Complete fieldName and columnName mapping if ( ! isset($mapping['columnName'])) { $mapping['columnName'] = $mapping['fieldName']; diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 0c3f129f5..86c289522 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -2,14 +2,10 @@ #namespace Doctrine\ORM\Mapping\Driver; -/* Addendum annotation API */ -require_once dirname(__FILE__) . '/addendum/annotations.php'; -Addendum::setRawMode(false); -Addendum::setParsedAnnotations(array('DoctrineEntity', 'DoctrineInheritanceType', - 'DoctrineDiscriminatorColumn', 'DoctrineDiscriminatorMap', - 'DoctrineSubClasses', 'DoctrineTransient', 'DoctrineId', - 'DoctrineIdGenerator', 'DoctrineColumn', 'DoctrineOneToOne', - 'DoctrineOneToMany', 'DoctrineManyToOne', 'DoctrineManyToMany')); +/* Addendum annotation reflection extensions */ +if ( ! class_exists('Addendum', false)) { + require_once dirname(__FILE__) . '/addendum/annotations.php'; +} /** * The AnnotationDriver reads the mapping metadata from docblock annotations. @@ -122,7 +118,7 @@ final class DoctrineColumn extends Annotation { public $type; public $length; public $unique; - public $notnull; + public $nullable; } final class DoctrineOneToOne extends Annotation { public $targetEntity; diff --git a/lib/Doctrine/ORM/Mapping/Driver/addendum/annotations.php b/lib/Doctrine/ORM/Mapping/Driver/addendum/annotations.php index d8498f6ed..1895f1d3c 100755 --- a/lib/Doctrine/ORM/Mapping/Driver/addendum/annotations.php +++ b/lib/Doctrine/ORM/Mapping/Driver/addendum/annotations.php @@ -75,7 +75,7 @@ class AnnotationsBuilder { $data = $this->parse($targetReflection); $annotations = array(); foreach($data as $class => $parameters) { - if(Addendum::parses($class)) { + if(is_subclass_of($class, 'Annotation')) { foreach($parameters as $params) { $annotationReflection = new ReflectionClass($class); $annotations[$class][] = $annotationReflection->newInstance($params, $targetReflection); @@ -296,7 +296,7 @@ class ReflectionAnnotatedProperty extends ReflectionProperty { class Addendum { private static $rawMode; - private static $parsedAnnotations; + private static $ignored; public static function getDocComment($reflection) { if(self::checkRawDocCommentParsingNeeded()) { @@ -324,12 +324,12 @@ class Addendum { self::$rawMode = $enabled; } - public static function setParsedAnnotations(array $annotations) { - self::$parsedAnnotations = array_combine($annotations, array_fill(0, count($annotations), true)); + public static function ignore(array $annotations) { + self::$ignored = array_combine($annotations, array_fill(0, count($annotations), true)); } - public static function parses($annotation) { - return isset(self::$parsedAnnotations[$annotation]); + public static function ignores($annotation) { + return isset(self::$ignored[$annotation]); } } diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php index 1d55515a3..0a9ae2fdc 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php @@ -65,11 +65,6 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister * @var Doctrine\ORM\EntityManager */ protected $_em; - - /** - * Null object. - */ - //private $_nullObject; /** * Initializes a new instance of a class derived from AbstractEntityPersister @@ -238,48 +233,36 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister protected function _prepareData($entity, array &$result, $isInsert = false) { foreach ($this->_em->getUnitOfWork()->getDataChangeSet($entity) as $field => $change) { - list ($oldVal, $newVal) = each($change); + if (is_array($change)) { + list ($oldVal, $newVal) = each($change); + } else { + $oldVal = null; + $newVal = $change; + } + $type = $this->_classMetadata->getTypeOfField($field); $columnName = $this->_classMetadata->getColumnName($field); - if (is_null($newVal)) { - $result[$columnName] = null; - } else if (is_object($newVal)) { + if ($this->_classMetadata->hasAssociation($field)) { $assocMapping = $this->_classMetadata->getAssociationMapping($field); if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) { //echo "NOT TO-ONE OR INVERSE!"; continue; } foreach ($assocMapping->getSourceToTargetKeyColumns() as $sourceColumn => $targetColumn) { - //TODO: What if both join columns (local/foreign) are just db-only - // columns (no fields in models) ? Currently we assume the foreign column - // is mapped to a field in the foreign entity. //TODO: throw exc if field not set $otherClass = $this->_em->getClassMetadata($assocMapping->getTargetEntityName()); $result[$sourceColumn] = $otherClass->getReflectionProperty( $otherClass->getFieldName($targetColumn))->getValue($newVal); } + } else if (is_null($newVal)) { + $result[$columnName] = null; } else { - switch ($type) { - case 'array': - case 'object': - $result[$columnName] = serialize($newVal); - break; - case 'gzip': - $result[$columnName] = gzcompress($newVal, 5); - break; - case 'boolean': - $result[$columnName] = $this->_em->getConnection()->convertBooleans($newVal); - break; - default: - $result[$columnName] = $newVal; - } + $result[$columnName] = $type->convertToDatabaseValue($newVal, $this->_conn->getDatabasePlatform()); } - /*$result[$columnName] = $type->convertToDatabaseValue( - $newVal, $this->_em->getConnection()->getDatabasePlatform());*/ } - // Populate the discriminator column on insert in Single & Class Table Inheritance + // Populate the discriminator column on insert in JOINED & SINGLE_TABLE inheritance if ($isInsert && ($this->_classMetadata->isInheritanceTypeJoined() || $this->_classMetadata->isInheritanceTypeSingleTable())) { $discColumn = $this->_classMetadata->getDiscriminatorColumn(); diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 3124f3a00..6b6be76bd 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -279,12 +279,13 @@ class Doctrine_ORM_UnitOfWork } else { $entitySet = $this->_identityMap; } - + foreach ($entitySet as $className => $entities) { $class = $this->_em->getClassMetadata($className); foreach ($entities as $entity) { $oid = spl_object_hash($entity); - if ($this->getEntityState($entity) == self::STATE_MANAGED) { + $state = $this->getEntityState($entity); + if ($state == self::STATE_MANAGED || $state == self::STATE_NEW) { if ( ! $class->isInheritanceTypeNone()) { $class = $this->_em->getClassMetadata(get_class($entity)); } @@ -294,7 +295,7 @@ class Doctrine_ORM_UnitOfWork $actualData[$name] = $refProp->getValue($entity); } - if ( ! isset($this->_originalEntityData[$oid])) { + if ($state == self::STATE_NEW) { $this->_dataChangeSets[$oid] = $actualData; } else { $originalData = $this->_originalEntityData[$oid]; @@ -904,7 +905,6 @@ class Doctrine_ORM_UnitOfWork $class = $this->_em->getClassMetadata(get_class($entity)); foreach ($class->getAssociationMappings() as $assocMapping) { if ( ! $assocMapping->isCascadeSave()) { - echo "NOT cascade " . $assocMapping->getSourceFieldName(); continue; } $relatedEntities = $class->getReflectionProperty($assocMapping->getSourceFieldName()) @@ -1157,6 +1157,18 @@ class Doctrine_ORM_UnitOfWork { return $this->_entityIdentifiers[spl_object_hash($entity)]; } + + /** + * + */ + public function tryGetById($id, $rootClassName) + { + $idHash = $this->getIdentifierHash((array)$id); + if (isset($this->_identityMap[$rootClassName][$idHash])) { + return $this->_identityMap[$rootClassName][$idHash]; + } + return false; + } } diff --git a/tests/Orm/Functional/AllTests.php b/tests/Orm/Functional/AllTests.php new file mode 100644 index 000000000..c39bd43af --- /dev/null +++ b/tests/Orm/Functional/AllTests.php @@ -0,0 +1,35 @@ +addTestSuite('Orm_Functional_BasicCRUDTest'); + + $suite->addTest(Orm_Functional_Ticket_AllTests::suite()); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'Orm_Functional_AllTests::main') { + Orm_Functional_AllTests::main(); +} \ No newline at end of file diff --git a/tests/Orm/Functional/BasicCRUDTest.php b/tests/Orm/Functional/BasicCRUDTest.php new file mode 100644 index 000000000..cad1cf0bf --- /dev/null +++ b/tests/Orm/Functional/BasicCRUDTest.php @@ -0,0 +1,38 @@ +_getEntityManager(); + + $exporter = new Doctrine_ORM_Export_ClassExporter($em); + $exporter->exportClasses(array($em->getClassMetadata('CmsUser'))); + + // Create + $user = new CmsUser; + $user->name = 'romanb'; + $em->save($user); + $this->assertTrue(is_numeric($user->id)); + $this->assertTrue($em->contains($user)); + + $user2 = new CmsUser; + $user2->name = 'jwage'; + $em->save($user2); + $this->assertTrue(is_numeric($user2->id)); + $this->assertTrue($em->contains($user2)); + + // Read + $user3 = $em->find('CmsUser', $user->id); + $this->assertTrue($user === $user3); + + $user4 = $em->find('CmsUser', $user2->id); + $this->assertTrue($user2 === $user4); + } +} + diff --git a/tests/Orm/Functional/Ticket/1Test.php b/tests/Orm/Functional/Ticket/1Test.php new file mode 100644 index 000000000..0dcea441b --- /dev/null +++ b/tests/Orm/Functional/Ticket/1Test.php @@ -0,0 +1,10 @@ +assertEquals(0, 0); + } +} \ No newline at end of file diff --git a/tests/Orm/Functional/Ticket/AllTests.php b/tests/Orm/Functional/Ticket/AllTests.php new file mode 100644 index 000000000..6225d58a5 --- /dev/null +++ b/tests/Orm/Functional/Ticket/AllTests.php @@ -0,0 +1,30 @@ +addTestSuite('Orm_Functional_Ticket_1Test'); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'Orm_Functional_Ticket_AllTests::main') { + Ticket_AllTests::main(); +} \ No newline at end of file diff --git a/tests/lib/Doctrine_OrmFunctionalTestCase.php b/tests/lib/Doctrine_OrmFunctionalTestCase.php index 32735f758..c298e2a33 100644 --- a/tests/lib/Doctrine_OrmFunctionalTestCase.php +++ b/tests/lib/Doctrine_OrmFunctionalTestCase.php @@ -56,19 +56,18 @@ class Doctrine_OrmFunctionalTestCase extends Doctrine_OrmTestCase } $fixture = self::$_fixtures[$uniqueName]; - $this->_loadedFixtures[] = $fixture['model']; + $this->_loadedFixtures[] = $fixture['table']; - $em = $this->sharedFixture['em']; - $classMetadata = $em->getClassMetadata($fixture['model']); - $tableName = $classMetadata->getTableName(); + $conn = $this->sharedFixture['conn']; + $tableName = $fixture['table']; if ( ! in_array($tableName, self::$_exportedTables)) { - $em->getConnection()->getSchemaManager()->exportClasses(array($fixture['model'])); + $conn->getSchemaManager()->exportClasses(array($fixture['model'])); self::$_exportedTables[] = $tableName; } foreach ($fixture['rows'] as $row) { - $em->getConnection()->insert($tableName, $row); + $conn->insert($tableName, $row); } } @@ -100,9 +99,23 @@ class Doctrine_OrmFunctionalTestCase extends Doctrine_OrmTestCase */ protected function tearDown() { - $em = $this->sharedFixture['em']; - foreach (array_reverse($this->_loadedFixtures) as $model) { - $conn->exec("DELETE FROM " . $em->getClassMetadata($model)->getTableName()); + $conn = $this->sharedFixture['conn']; + foreach (array_reverse($this->_loadedFixtures) as $table) { + $conn->exec("DELETE FROM " . $table); } } + + protected function setUp() + { + if ( ! isset($this->sharedFixture['conn'])) { + $this->sharedFixture['conn'] = Doctrine_TestUtil::getConnection(); + } + } + + protected function _getEntityManager($config = null, $eventManager = null) { + $config = new Doctrine_ORM_Configuration(); + $eventManager = new Doctrine_Common_EventManager(); + $conn = $this->sharedFixture['conn']; + return Doctrine_ORM_EntityManager::create($conn, 'em', $config, $eventManager); + } } \ No newline at end of file diff --git a/tests/lib/mocks/Doctrine_DatabasePlatformMock.php b/tests/lib/mocks/Doctrine_DatabasePlatformMock.php index b21edbefa..42b983d33 100644 --- a/tests/lib/mocks/Doctrine_DatabasePlatformMock.php +++ b/tests/lib/mocks/Doctrine_DatabasePlatformMock.php @@ -24,6 +24,27 @@ class Doctrine_DatabasePlatformMock extends Doctrine_DBAL_Platforms_AbstractPlat public function prefersIdentityColumns() { return $this->_prefersIdentityColumns; } + + /** @override */ + public function getIntegerTypeDeclarationSql(array $field) {} + + /** @override */ + public function getBigIntTypeDeclarationSql(array $field) {} + + /** @override */ + public function getTinyIntTypeDeclarationSql(array $field) {} + + /** @override */ + public function getSmallIntTypeDeclarationSql(array $field) {} + + /** @override */ + public function getMediumIntTypeDeclarationSql(array $field) {} + + /** @override */ + protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) {} + + /** @override */ + public function getVarcharDeclarationSql(array $field) {} /* MOCK API */ diff --git a/tests/lib/mocks/Doctrine_DriverConnectionMock.php b/tests/lib/mocks/Doctrine_DriverConnectionMock.php index ff2a035cd..d326dddc4 100644 --- a/tests/lib/mocks/Doctrine_DriverConnectionMock.php +++ b/tests/lib/mocks/Doctrine_DriverConnectionMock.php @@ -5,7 +5,7 @@ class Doctrine_DriverConnectionMock implements Doctrine_DBAL_Driver_Connection { public function prepare($prepareString) {} - public function query($queryString) {} + public function query() {} public function quote($input) {} public function exec($statement) {} public function lastInsertId() {} diff --git a/tests/models/cms/CmsArticle.php b/tests/models/cms/CmsArticle.php index 7496481e7..74b34e58f 100755 --- a/tests/models/cms/CmsArticle.php +++ b/tests/models/cms/CmsArticle.php @@ -14,11 +14,11 @@ class CmsArticle */ public $id; /** - * @DoctrineColumn(type="string", length=255) + * @DoctrineColumn(type="varchar", length=255) */ public $topic; /** - * @DoctrineColumn(type="string") + * @DoctrineColumn(type="varchar") */ public $text; /** diff --git a/tests/models/cms/CmsComment.php b/tests/models/cms/CmsComment.php index 2a8863cfc..165787581 100755 --- a/tests/models/cms/CmsComment.php +++ b/tests/models/cms/CmsComment.php @@ -14,11 +14,11 @@ class CmsComment */ public $id; /** - * @DoctrineColumn(type="string", length=255) + * @DoctrineColumn(type="varchar", length=255) */ public $topic; /** - * @DoctrineColumn(type="string") + * @DoctrineColumn(type="varchar") */ public $text; /** diff --git a/tests/models/cms/CmsPhonenumber.php b/tests/models/cms/CmsPhonenumber.php index ad8f01eb6..3ff3d342a 100755 --- a/tests/models/cms/CmsPhonenumber.php +++ b/tests/models/cms/CmsPhonenumber.php @@ -6,7 +6,7 @@ class CmsPhonenumber implements Doctrine_ORM_Entity { /** - * @DoctrineColumn(type="string", length=50) + * @DoctrineColumn(type="varchar", length=50) * @DoctrineId */ public $phonenumber; diff --git a/tests/models/cms/CmsUser.php b/tests/models/cms/CmsUser.php index 6e0e993cc..65665a400 100644 --- a/tests/models/cms/CmsUser.php +++ b/tests/models/cms/CmsUser.php @@ -14,15 +14,15 @@ class CmsUser */ public $id; /** - * @DoctrineColumn(type="string", length=50) + * @DoctrineColumn(type="varchar", length=50) */ public $status; /** - * @DoctrineColumn(type="string", length=255) + * @DoctrineColumn(type="varchar", length=255) */ public $username; /** - * @DoctrineColumn(type="string", length=255) + * @DoctrineColumn(type="varchar", length=255) */ public $name; /** diff --git a/tests/models/forum/ForumCategory.php b/tests/models/forum/ForumCategory.php index c09be4a8f..77bba3638 100755 --- a/tests/models/forum/ForumCategory.php +++ b/tests/models/forum/ForumCategory.php @@ -17,7 +17,7 @@ class ForumCategory */ public $position; /** - * @DoctrineColumn(type="string", length=255) + * @DoctrineColumn(type="varchar", length=255) */ public $name; /** diff --git a/tests/models/forum/ForumEntry.php b/tests/models/forum/ForumEntry.php index d0de7596d..c26640d4d 100644 --- a/tests/models/forum/ForumEntry.php +++ b/tests/models/forum/ForumEntry.php @@ -14,7 +14,7 @@ class ForumEntry */ public $id; /** - * @DoctrineColumn(type="string", length=50) + * @DoctrineColumn(type="varchar", length=50) */ public $topic; } diff --git a/tests/models/forum/ForumUser.php b/tests/models/forum/ForumUser.php index c97d30941..56a71bebe 100644 --- a/tests/models/forum/ForumUser.php +++ b/tests/models/forum/ForumUser.php @@ -7,7 +7,7 @@ /** * @DoctrineEntity * @DoctrineInheritanceType("joined") - * @DoctrineDiscriminatorColumn(name="dtype", type="string", length=20) + * @DoctrineDiscriminatorColumn(name="dtype", type="varchar", length=20) * @DoctrineDiscriminatorMap({"user" = "ForumUser", "admin" = "ForumAdministrator"}) * @DoctrineSubclasses({"ForumAdministrator"}) */ @@ -20,7 +20,7 @@ class ForumUser */ public $id; /** - * @DoctrineColumn(type="string", length=50) + * @DoctrineColumn(type="varchar", length=50) */ public $username; /**