Commit 87979219 authored by romanb's avatar romanb

[2.0] Removed AssociationMappings from ResultSetMapping for improved caching....

[2.0] Removed AssociationMappings from ResultSetMapping  for improved caching. Fixed caching issue with reflection classes and properties. Reimplemented and leaned up broken identifier quoting. Added support for named (native) queries. Fixed small hydration memory leak.
parent 103cdf57
......@@ -22,7 +22,7 @@
namespace Doctrine\Common;
/**
* Simple generic lexical scanner
* Simple generic lexical scanner.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
......
......@@ -48,8 +48,7 @@ class Configuration
protected $_attributes = array();
/**
* Creates a new configuration that can be used for Doctrine.
*
* Creates a new DBAL configuration instance.
*/
public function __construct()
{
......
......@@ -21,8 +21,8 @@
namespace Doctrine\DBAL;
use Doctrine\Common\EventManager;
use Doctrine\Common\DoctrineException;
use Doctrine\Common\EventManager,
Doctrine\Common\DoctrineException;
/**
* A wrapper around a Doctrine\DBAL\Driver\Connection that adds features like
......@@ -376,11 +376,10 @@ class Connection
$criteria = array();
foreach (array_keys($identifier) as $id) {
$criteria[] = $this->quoteIdentifier($id) . ' = ?';
$criteria[] = $id . ' = ?';
}
$query = 'DELETE FROM ' . $this->quoteIdentifier($tableName)
. ' WHERE ' . implode(' AND ', $criteria);
$query = 'DELETE FROM ' . $tableName . ' WHERE ' . implode(' AND ', $criteria);
return $this->executeUpdate($query, array_values($identifier));
}
......@@ -439,13 +438,12 @@ class Connection
$set = array();
foreach ($data as $columnName => $value) {
$set[] = $this->quoteIdentifier($columnName) . ' = ?';
$set[] = $columnName . ' = ?';
}
$params = array_merge(array_values($data), array_values($identifier));
$sql = 'UPDATE ' . $this->quoteIdentifier($tableName)
. ' SET ' . implode(', ', $set)
$sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', array_keys($identifier))
. ' = ?';
......@@ -473,11 +471,11 @@ class Connection
$a = array();
foreach ($data as $columnName => $value) {
$cols[] = $this->quoteIdentifier($columnName);
$cols[] = $columnName;
$a[] = '?';
}
$query = 'INSERT INTO ' . $this->quoteIdentifier($tableName)
$query = 'INSERT INTO ' . $tableName
. ' (' . implode(', ', $cols) . ')'
. ' VALUES (' . implode(', ', $a) . ')';
......
......@@ -21,9 +21,9 @@
namespace Doctrine\DBAL\Platforms;
use Doctrine\Common\DoctrineException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types;
use Doctrine\Common\DoctrineException,
Doctrine\DBAL\Connection,
Doctrine\DBAL\Types;
/**
* Base class for all DatabasePlatforms. The DatabasePlatforms are the central
......@@ -114,8 +114,6 @@ abstract class AbstractPlatform
*/
public function getAvgExpression($column)
{
$column = $this->quoteIdentifier($column);
return 'AVG(' . $column . ')';
}
......@@ -130,8 +128,6 @@ abstract class AbstractPlatform
*/
public function getCountExpression($column)
{
$column = $this->quoteIdentifier($column);
return 'COUNT(' . $column . ')';
}
......@@ -143,8 +139,6 @@ abstract class AbstractPlatform
*/
public function getMaxExpression($column)
{
$column = $this->quoteIdentifier($column);
return 'MAX(' . $column . ')';
}
......@@ -156,8 +150,6 @@ abstract class AbstractPlatform
*/
public function getMinExpression($column)
{
$column = $this->quoteIdentifier($column);
return 'MIN(' . $column . ')';
}
......@@ -169,8 +161,6 @@ abstract class AbstractPlatform
*/
public function getSumExpression($column)
{
$column = $this->quoteIdentifier($column);
return 'SUM(' . $column . ')';
}
......@@ -185,8 +175,6 @@ abstract class AbstractPlatform
*/
public function getMd5Expression($column)
{
$column = $this->quoteIdentifier($column);
return 'MD5(' . $column . ')';
}
......@@ -199,8 +187,6 @@ abstract class AbstractPlatform
*/
public function getLengthExpression($column)
{
$column = $this->quoteIdentifier($column);
return 'LENGTH(' . $column . ')';
}
......@@ -213,8 +199,6 @@ abstract class AbstractPlatform
*/
public function getRoundExpression($column, $decimals = 0)
{
$column = $this->quoteIdentifier($column);
return 'ROUND(' . $column . ', ' . $decimals . ')';
}
......@@ -228,9 +212,6 @@ abstract class AbstractPlatform
*/
public function getModExpression($expression1, $expression2)
{
$expression1 = $this->quoteIdentifier($expression1);
$expression2 = $this->quoteIdentifier($expression2);
return 'MOD(' . $expression1 . ', ' . $expression2 . ')';
}
......@@ -333,11 +314,9 @@ abstract class AbstractPlatform
*/
public function getSubstringExpression($value, $from, $len = null)
{
$value = $this->quoteIdentifier($value);
if ($len === null)
return 'SUBSTRING(' . $value . ' FROM ' . $from . ')';
else {
$len = $this->quoteIdentifier($len);
return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')';
}
}
......@@ -371,7 +350,7 @@ abstract class AbstractPlatform
*/
public function getNotExpression($expression)
{
return 'NOT(' . $this->quoteIdentifier($expression) . ')';
return 'NOT(' . $expression . ')';
}
/**
......@@ -401,7 +380,6 @@ abstract class AbstractPlatform
$values = array($values);
}
$values = $this->getIdentifiers($values);
$column = $this->quoteIdentifier($column);
if (count($values) == 0) {
throw DoctrineException::updateMe('Values array for IN operator should not be empty.');
......@@ -425,8 +403,6 @@ abstract class AbstractPlatform
*/
public function getIsNullExpression($expression)
{
$expression = $this->quoteIdentifier($expression);
return $expression . ' IS NULL';
}
......@@ -446,8 +422,6 @@ abstract class AbstractPlatform
*/
public function getIsNotNullExpression($expression)
{
$expression = $this->quoteIdentifier($expression);
return $expression . ' IS NOT NULL';
}
......@@ -476,10 +450,6 @@ abstract class AbstractPlatform
*/
public function getBetweenExpression($expression, $value1, $value2)
{
$expression = $this->quoteIdentifier($expression);
$value1 = $this->quoteIdentifier($value1);
$value2 = $this->quoteIdentifier($value2);
return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2;
}
......@@ -525,17 +495,11 @@ abstract class AbstractPlatform
public function getDropConstraintSql($table, $name, $primary = false)
{
$table = $this->quoteIdentifier($table);
$name = $this->quoteIdentifier($name);
return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $name;
}
public function getDropForeignKeySql($table, $name)
{
$table = $this->quoteIdentifier($table);
$name = $this->quoteIdentifier($name);
return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $name;
}
......@@ -562,7 +526,7 @@ abstract class AbstractPlatform
}
}
$query = 'CREATE TABLE ' . $this->quoteIdentifier($table, true) . ' (' . $columnListSql;
$query = 'CREATE TABLE ' . $table . ' (' . $columnListSql;
$check = $this->getCheckDeclarationSql($columns);
if ( ! empty($check)) {
......@@ -682,12 +646,9 @@ abstract class AbstractPlatform
*/
public function quoteIdentifier($str)
{
if ($str[0] != '`') {
return $str;
}
$c = $this->getIdentifierQuoteCharacter();
return $c . trim($str, '`') . $c;
return $c . $str . $c;
}
/**
......@@ -699,7 +660,6 @@ abstract class AbstractPlatform
*/
public function getCreateForeignKeySql($table, array $definition)
{
$table = $this->quoteIdentifier($table);
$query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSql($definition);
return $query;
......@@ -811,7 +771,7 @@ abstract class AbstractPlatform
$typeDecl = $field['type']->getSqlDeclaration($field, $this);
return $this->quoteIdentifier($name) . ' ' . $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
return $name . ' ' . $typeDecl . $charset . $default . $notnull . $unique . $check . $collation;
}
/**
......@@ -855,7 +815,7 @@ abstract class AbstractPlatform
$default = empty($field['notnull']) ? ' DEFAULT NULL' : '';
if (isset($field['default'])) {
$default = ' DEFAULT ' . $this->quoteIdentifier($field['default'], $field['type']);
$default = ' DEFAULT ' . $field['default'];
}
return $default;
}
......@@ -897,7 +857,6 @@ abstract class AbstractPlatform
*/
public function getIndexDeclarationSql($name, array $definition)
{
$name = $this->quoteIdentifier($name);
$type = '';
if (isset($definition['type'])) {
......@@ -931,9 +890,9 @@ abstract class AbstractPlatform
$ret = array();
foreach ($fields as $field => $definition) {
if (is_array($definition)) {
$ret[] = $this->quoteIdentifier($field);
$ret[] = $field;
} else {
$ret[] = $this->quoteIdentifier($definition);
$ret[] = $definition;
}
}
return implode(', ', $ret);
......@@ -1072,7 +1031,7 @@ abstract class AbstractPlatform
{
$sql = '';
if (isset($definition['name'])) {
$sql .= ' CONSTRAINT ' . $this->quoteIdentifier($definition['name']) . ' ';
$sql .= ' CONSTRAINT ' . $definition['name'] . ' ';
}
$sql .= 'FOREIGN KEY (';
......@@ -1093,10 +1052,10 @@ abstract class AbstractPlatform
$definition['foreign'] = array($definition['foreign']);
}
$sql .= implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['local']))
$sql .= implode(', ', $definition['local'])
. ') REFERENCES '
. $this->quoteIdentifier($definition['foreignTable']) . '('
. implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['foreign'])) . ')';
. $definition['foreignTable'] . '('
. implode(', ', $definition['foreign']) . ')';
return $sql;
}
......@@ -1492,6 +1451,16 @@ abstract class AbstractPlatform
return true;
}
/**
* Whether the platform supports database schemas.
*
* @return boolean
*/
public function supportsSchemas()
{
return false;
}
/**
* Whether the platform supports getting the affected rows of a recent
* update/delete type query.
......@@ -1574,4 +1543,9 @@ abstract class AbstractPlatform
* @return string
*/
abstract public function getName();
public function getSqlResultCasing($column)
{
return $column;
}
}
\ No newline at end of file
......@@ -105,7 +105,7 @@ class MsSqlPlatform extends AbstractPlatform
$query = '';
if ( ! empty($changes['name'])) {
$change_name = $this->quoteIdentifier($changes['name']);
$change_name = $changes['name'];
$query .= 'RENAME TO ' . $change_name;
}
......@@ -123,7 +123,6 @@ class MsSqlPlatform extends AbstractPlatform
if ($query) {
$query .= ', ';
}
$field_name = $this->quoteIdentifier($fieldName, true);
$query .= 'DROP COLUMN ' . $fieldName;
}
}
......@@ -146,7 +145,6 @@ class MsSqlPlatform extends AbstractPlatform
} else {
$oldFieldName = $fieldName;
}
$oldFieldName = $this->quoteIdentifier($oldFieldName, true);
$query .= 'CHANGE ' . $oldFieldName . ' '
. $this->getColumnDeclarationSql($fieldName, $field['definition']);
}
......@@ -158,7 +156,6 @@ class MsSqlPlatform extends AbstractPlatform
$query.= ', ';
}
$field = $changes['rename'][$renamedField];
$renamedField = $this->quoteIdentifier($renamedField, true);
$query .= 'CHANGE ' . $renamedField . ' '
. $this->getColumnDeclarationSql($field['name'], $field['definition']);
}
......@@ -168,22 +165,9 @@ class MsSqlPlatform extends AbstractPlatform
return false;
}
$name = $this->quoteIdentifier($name, true);
return 'ALTER TABLE ' . $name . ' ' . $query;
}
/**
* Gets the character used for identifier quoting.
*
* @return string
* @override
*/
public function getIdentifierQuoteCharacter()
{
return '`';
}
/**
* Returns the regular expression operator.
*
......@@ -321,7 +305,7 @@ class MsSqlPlatform extends AbstractPlatform
*/
public function getCreateDatabaseSql($name)
{
return 'CREATE DATABASE ' . $this->quoteIdentifier($name);
return 'CREATE DATABASE ' . $name;
}
/**
......@@ -333,7 +317,7 @@ class MsSqlPlatform extends AbstractPlatform
*/
public function getDropDatabaseSql($name)
{
return 'DROP DATABASE ' . $this->quoteIdentifier($name);
return 'DROP DATABASE ' . $name;
}
public function getSetTransactionIsolationSql($level)
......@@ -481,7 +465,7 @@ class MsSqlPlatform extends AbstractPlatform
}
$query = preg_replace('/^'.$selectRegExp.'/i', $selectReplace . 'TOP ' . ($count + $offset) . ' ', $query);
$query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS ' . $this->quoteIdentifier('inner_tbl');
$query = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $query . ') AS ' . 'inner_tbl';
if ($orderby !== false) {
$query .= ' ORDER BY ';
......@@ -491,12 +475,12 @@ class MsSqlPlatform extends AbstractPlatform
$query .= ', ';
}
$query .= $this->quoteIdentifier('inner_tbl') . '.' . $aliases[$i] . ' ';
$query .= 'inner_tbl' . '.' . $aliases[$i] . ' ';
$query .= (stripos($sorts[$i], 'ASC') !== false) ? 'DESC' : 'ASC';
}
}
$query .= ') AS ' . $this->quoteIdentifier('outer_tbl');
$query .= ') AS ' . 'outer_tbl';
if ($orderby !== false) {
$query .= ' ORDER BY ';
......@@ -506,7 +490,7 @@ class MsSqlPlatform extends AbstractPlatform
$query .= ', ';
}
$query .= $this->quoteIdentifier('outer_tbl') . '.' . $aliases[$i] . ' ' . $sorts[$i];
$query .= 'outer_tbl' . '.' . $aliases[$i] . ' ' . $sorts[$i];
}
}
}
......
......@@ -156,19 +156,19 @@ class MySqlPlatform extends AbstractPlatform
{
$query = 'SHOW TABLES';
if ( ! is_null($database)) {
$query .= ' FROM ' . $this->quoteIdentifier($database);
$query .= ' FROM ' . $database;
}
return $query;
}
public function getListTableConstraintsSql($table)
{
return 'SHOW INDEX FROM ' . $this->quoteIdentifier($table);
return 'SHOW INDEX FROM ' . $table;
}
public function getListTableIndexesSql($table)
{
return 'SHOW INDEX FROM ' . $this->quoteIdentifier($table);
return 'SHOW INDEX FROM ' . $table;
}
public function getListUsersSql()
......@@ -335,7 +335,7 @@ class MySqlPlatform extends AbstractPlatform
public function getListTableColumnsSql($table)
{
return 'DESCRIBE ' . $this->quoteIdentifier($table);
return 'DESCRIBE ' . $table;
}
/**
......@@ -347,7 +347,7 @@ class MySqlPlatform extends AbstractPlatform
*/
public function getCreateDatabaseSql($name)
{
return 'CREATE DATABASE ' . $this->quoteIdentifier($name);
return 'CREATE DATABASE ' . $name;
}
/**
......@@ -359,7 +359,7 @@ class MySqlPlatform extends AbstractPlatform
*/
public function getDropDatabaseSql($name)
{
return 'DROP DATABASE ' . $this->quoteIdentifier($name);
return 'DROP DATABASE ' . $name;
}
/**
......@@ -445,7 +445,6 @@ class MySqlPlatform extends AbstractPlatform
// attach all primary keys
if (isset($options['primary']) && ! empty($options['primary'])) {
$keyColumns = array_unique(array_values($options['primary']));
$keyColumns = array_map(array($this, 'quoteIdentifier'), $keyColumns);
$queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
}
......@@ -453,7 +452,7 @@ class MySqlPlatform extends AbstractPlatform
if (!empty($options['temporary'])) {
$query .= 'TEMPORARY ';
}
$query.= 'TABLE ' . $this->quoteIdentifier($name, true) . ' (' . $queryFields . ')';
$query.= 'TABLE ' . $name . ' (' . $queryFields . ')';
$optionStrings = array();
......@@ -609,8 +608,7 @@ class MySqlPlatform extends AbstractPlatform
$query = '';
if ( ! empty($changes['name'])) {
$change_name = $this->quoteIdentifier($changes['name']);
$query .= 'RENAME TO ' . $change_name;
$query .= 'RENAME TO ' . $changes['name'];
}
if ( ! empty($changes['add']) && is_array($changes['add'])) {
......@@ -627,7 +625,6 @@ class MySqlPlatform extends AbstractPlatform
if ($query) {
$query .= ', ';
}
$fieldName = $this->quoteIdentifier($fieldName);
$query .= 'DROP ' . $fieldName;
}
}
......@@ -650,7 +647,6 @@ class MySqlPlatform extends AbstractPlatform
} else {
$oldFieldName = $fieldName;
}
$oldFieldName = $this->quoteIdentifier($oldFieldName, true);
$query .= 'CHANGE ' . $oldFieldName . ' '
. $this->getColumnDeclarationSql($fieldName, $field['definition']);
}
......@@ -662,7 +658,6 @@ class MySqlPlatform extends AbstractPlatform
$query.= ', ';
}
$field = $changes['rename'][$renamedField];
$renamedField = $this->quoteIdentifier($renamedField, true);
$query .= 'CHANGE ' . $renamedField . ' '
. $this->getColumnDeclarationSql($field['name'], $field['definition']);
}
......@@ -672,8 +667,6 @@ class MySqlPlatform extends AbstractPlatform
return false;
}
$name = $this->quoteIdentifier($name, true);
return 'ALTER TABLE ' . $name . ' ' . $query;
}
......@@ -715,7 +708,6 @@ class MySqlPlatform extends AbstractPlatform
public function getCreateIndexSql($table, $name, array $definition)
{
$table = $table;
$name = $this->quoteIdentifier($name);
$type = '';
if (isset($definition['type'])) {
switch (strtolower($definition['type'])) {
......@@ -818,7 +810,7 @@ class MySqlPlatform extends AbstractPlatform
$definition['fields'] = array($definition['fields']);
}
$query = $type . 'INDEX ' . $this->quoteIdentifier($name);
$query = $type . 'INDEX ' . $name;
$query .= ' (' . $this->getIndexFieldDeclarationListSql($definition['fields']) . ')';
......@@ -838,7 +830,7 @@ class MySqlPlatform extends AbstractPlatform
$declFields = array();
foreach ($fields as $fieldName => $field) {
$fieldString = $this->quoteIdentifier($fieldName);
$fieldString = $fieldName;
if (is_array($field)) {
if (isset($field['length'])) {
......@@ -857,7 +849,7 @@ class MySqlPlatform extends AbstractPlatform
}
}
} else {
$fieldString = $this->quoteIdentifier($field);
$fieldString = $field;
}
$declFields[] = $fieldString;
}
......@@ -896,8 +888,6 @@ class MySqlPlatform extends AbstractPlatform
*/
public function getDropIndexSql($table, $name)
{
$table = $this->quoteIdentifier($table);
$name = $this->quoteIdentifier($name);
return 'DROP INDEX ' . $name . ' ON ' . $table;
}
......@@ -909,7 +899,7 @@ class MySqlPlatform extends AbstractPlatform
*/
public function getDropTableSql($table)
{
return 'DROP TABLE ' . $this->quoteIdentifier($table);
return 'DROP TABLE ' . $table;
}
public function getSetTransactionIsolationSql($level)
......
......@@ -112,7 +112,7 @@ class OraclePlatform extends AbstractPlatform
*/
public function getCreateSequenceSql($sequenceName, $start = 1, $allocationSize = 1)
{
return 'CREATE SEQUENCE ' . $this->quoteIdentifier($sequenceName)
return 'CREATE SEQUENCE ' . $sequenceName
. ' START WITH ' . $start . ' INCREMENT BY ' . $allocationSize;
}
......@@ -124,7 +124,7 @@ class OraclePlatform extends AbstractPlatform
*/
public function getSequenceNextValSql($sequenceName)
{
return 'SELECT ' . $this->quoteIdentifier($sequenceName) . '.nextval FROM DUAL';
return 'SELECT ' . $sequenceName . '.nextval FROM DUAL';
}
/**
......@@ -323,9 +323,7 @@ END;';
$sequenceName = $table . '_SEQ';
$sql[] = $this->getCreateSequenceSql($sequenceName, $start);
$triggerName = $this->quoteIdentifier($table . '_AI_PK', true);
$table = $this->quoteIdentifier($table, true);
$name = $this->quoteIdentifier($name, true);
$triggerName = $table . '_AI_PK';
$sql[] = 'CREATE TRIGGER ' . $triggerName . '
BEFORE INSERT
ON ' . $table . '
......@@ -334,16 +332,16 @@ DECLARE
last_Sequence NUMBER;
last_InsertID NUMBER;
BEGIN
SELECT ' . $this->quoteIdentifier($sequenceName) . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
IF (:NEW.' . $name . ' IS NULL OR :NEW.'.$name.' = 0) THEN
SELECT ' . $this->quoteIdentifier($sequenceName) . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL;
ELSE
SELECT NVL(Last_Number, 0) INTO last_Sequence
FROM User_Sequences
WHERE Sequence_Name = \'' . $sequenceName . '\';
SELECT :NEW.' . $name . ' INTO last_InsertID FROM DUAL;
WHILE (last_InsertID > last_Sequence) LOOP
SELECT ' . $this->quoteIdentifier($sequenceName) . '.NEXTVAL INTO last_Sequence FROM DUAL;
SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL;
END LOOP;
END IF;
END;';
......@@ -380,7 +378,7 @@ END;';
public function getDropSequenceSql($sequenceName)
{
return 'DROP SEQUENCE ' . $this->quoteIdentifier($sequenceName);
return 'DROP SEQUENCE ' . $sequenceName;
}
public function getDropDatabaseSql($database)
......@@ -410,8 +408,6 @@ END;';
return false;
}
$name = $this->quoteIdentifier($name);
if ( ! empty($changes['add']) && is_array($changes['add'])) {
$fields = array();
foreach ($changes['add'] as $fieldName => $field) {
......@@ -430,21 +426,21 @@ END;';
if ( ! empty($changes['rename']) && is_array($changes['rename'])) {
foreach ($changes['rename'] as $fieldName => $field) {
$sql[] = 'ALTER TABLE ' . $name . ' RENAME COLUMN ' . $this->quoteIdentifier($fieldName)
. ' TO ' . $this->quoteIdentifier($field['name']);
$sql[] = 'ALTER TABLE ' . $name . ' RENAME COLUMN ' . $fieldName
. ' TO ' . $field['name'];
}
}
if ( ! empty($changes['remove']) && is_array($changes['remove'])) {
$fields = array();
foreach ($changes['remove'] as $fieldName => $field) {
$fields[] = $this->quoteIdentifier($fieldName);
$fields[] = $fieldName;
}
$sql[] = 'ALTER TABLE ' . $name . ' DROP COLUMN ' . implode(', ', $fields);
}
if ( ! empty($changes['name'])) {
$changeName = $this->quoteIdentifier($changes['name']);
$changeName = $changes['name'];
$sql[] = 'ALTER TABLE ' . $name . ' RENAME TO ' . $changeName;
}
......@@ -504,4 +500,9 @@ END;';
}
return $query;
}
public function getSqlResultCasing($column)
{
return strtoupper($column);
}
}
\ No newline at end of file
......@@ -61,7 +61,6 @@ class PostgreSqlPlatform extends AbstractPlatform
*/
public function getMd5Expression($column)
{
$column = $this->quoteIdentifier($column);
if ($this->_version > 7) {
return 'MD5(' . $column . ')';
} else {
......@@ -82,10 +81,7 @@ class PostgreSqlPlatform extends AbstractPlatform
*/
public function getSubstringExpression($value, $from, $len = null)
{
$value = $this->quoteIdentifier($value);
if ($len === null) {
$len = $this->quoteIdentifier($len);
return 'SUBSTR(' . $value . ', ' . $from . ')';
} else {
return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
......@@ -238,6 +234,16 @@ class PostgreSqlPlatform extends AbstractPlatform
return true;
}
/**
* Whether the platform supports database schemas.
*
* @return boolean
*/
public function supportsSchemas()
{
return true;
}
/**
* Whether the platform supports identity columns.
* Postgres supports these through the SERIAL keyword.
......@@ -321,7 +327,7 @@ class PostgreSqlPlatform extends AbstractPlatform
WHERE trg.tgrelid = tbl.oid';
if ( ! is_null($table)) {
$sql .= " AND tbl.relname = ".$this->quoteIdentifier($table);
$sql .= " AND tbl.relname = " . $table;
}
return $sql;
......@@ -428,7 +434,7 @@ class PostgreSqlPlatform extends AbstractPlatform
*/
public function getCreateDatabaseSql($name)
{
return 'CREATE DATABASE ' . $this->quoteIdentifier($name);
return 'CREATE DATABASE ' . $name;
}
/**
......@@ -440,7 +446,7 @@ class PostgreSqlPlatform extends AbstractPlatform
*/
public function getDropDatabaseSql($name)
{
return 'DROP DATABASE ' . $this->quoteIdentifier($name);
return 'DROP DATABASE ' . $name;
}
/**
......@@ -519,7 +525,6 @@ class PostgreSqlPlatform extends AbstractPlatform
if (isset($changes['remove']) && is_array($changes['remove'])) {
foreach ($changes['remove'] as $fieldName => $field) {
$fieldName = $this->quoteIdentifier($fieldName, true);
$query = 'DROP ' . $fieldName;
$sql[] = 'ALTER TABLE ' . $name . ' ' . $query;
}
......@@ -527,7 +532,6 @@ class PostgreSqlPlatform extends AbstractPlatform
if (isset($changes['change']) && is_array($changes['change'])) {
foreach ($changes['change'] as $fieldName => $field) {
$fieldName = $this->quoteIdentifier($fieldName, true);
if (isset($field['type'])) {
$serverInfo = $this->getServerVersion();
......@@ -550,15 +554,12 @@ class PostgreSqlPlatform extends AbstractPlatform
if (isset($changes['rename']) && is_array($changes['rename'])) {
foreach ($changes['rename'] as $fieldName => $field) {
$fieldName = $this->quoteIdentifier($fieldName, true);
$sql[] = 'ALTER TABLE ' . $name . ' RENAME COLUMN ' . $fieldName . ' TO ' . $this->quoteIdentifier($field['name'], true);
$sql[] = 'ALTER TABLE ' . $name . ' RENAME COLUMN ' . $fieldName . ' TO ' . $field['name'];
}
}
$name = $this->quoteIdentifier($name, true);
if (isset($changes['name'])) {
$changeName = $this->quoteIdentifier($changes['name'], true);
$sql[] = 'ALTER TABLE ' . $name . ' RENAME TO ' . $changeName;
$sql[] = 'ALTER TABLE ' . $name . ' RENAME TO ' . $changes['name'];
}
return $sql;
......@@ -572,7 +573,7 @@ class PostgreSqlPlatform extends AbstractPlatform
*/
public function getCreateSequenceSql($sequenceName, $start = 1, $allocationSize = 1)
{
return 'CREATE SEQUENCE ' . $this->quoteIdentifier($sequenceName)
return 'CREATE SEQUENCE ' . $sequenceName
. ' INCREMENT BY ' . $allocationSize . ' START ' . $start;
}
......@@ -584,7 +585,7 @@ class PostgreSqlPlatform extends AbstractPlatform
*/
public function getDropSequenceSql($sequenceName)
{
return 'DROP SEQUENCE ' . $this->quoteIdentifier($sequenceName);
return 'DROP SEQUENCE ' . $sequenceName;
}
/**
......@@ -601,11 +602,10 @@ class PostgreSqlPlatform extends AbstractPlatform
if (isset($options['primary']) && ! empty($options['primary'])) {
$keyColumns = array_unique(array_values($options['primary']));
$keyColumns = array_map(array($this, 'quoteIdentifier'), $keyColumns);
$queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
}
$query = 'CREATE TABLE ' . $this->quoteIdentifier($name) . ' (' . $queryFields . ')';
$query = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')';
$sql[] = $query;
......@@ -746,4 +746,9 @@ class PostgreSqlPlatform extends AbstractPlatform
{
return 'postgresql';
}
public function getSqlResultCasing($column)
{
return strtolower($column);
}
}
\ No newline at end of file
......@@ -298,7 +298,6 @@ class SqlitePlatform extends AbstractPlatform
$queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')';
}
$name = $this->quoteIdentifier($name, true);
$sql = 'CREATE TABLE ' . $name . ' (' . $queryFields;
/*if ($check = $this->getCheckDeclarationSql($fields)) {
......
......@@ -40,7 +40,6 @@ class MsSqlSchemaManager extends AbstractSchemaManager
*/
public function createDatabase($name)
{
$name = $this->conn->quoteIdentifier($name, true);
$query = "CREATE DATABASE $name";
if ($this->conn->options['database_device']) {
$query.= ' ON '.$this->conn->options['database_device'];
......@@ -58,7 +57,6 @@ class MsSqlSchemaManager extends AbstractSchemaManager
*/
public function dropDatabase($name)
{
$name = $this->conn->quoteIdentifier($name, true);
return $this->conn->standaloneQuery('DROP DATABASE ' . $name, null, true);
}
......@@ -181,7 +179,6 @@ class MsSqlSchemaManager extends AbstractSchemaManager
if ($query) {
$query .= ', ';
}
$field_name = $this->conn->quoteIdentifier($fieldName, true);
$query .= 'DROP COLUMN ' . $fieldName;
}
}
......@@ -190,7 +187,6 @@ class MsSqlSchemaManager extends AbstractSchemaManager
return false;
}
$name = $this->conn->quoteIdentifier($name, true);
return $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query);
}
......@@ -199,9 +195,8 @@ class MsSqlSchemaManager extends AbstractSchemaManager
*/
public function createSequence($seqName, $start = 1, $allocationSize = 1)
{
$sequenceName = $this->conn->quoteIdentifier($this->conn->getSequenceName($seqName), true);
$seqcolName = $this->conn->quoteIdentifier($this->conn->options['seqcol_name'], true);
$query = 'CREATE TABLE ' . $sequenceName . ' (' . $seqcolName .
$seqcolName = 'seq_col';
$query = 'CREATE TABLE ' . $seqName . ' (' . $seqcolName .
' INT PRIMARY KEY CLUSTERED IDENTITY(' . $start . ', 1) NOT NULL)';
$res = $this->conn->exec($query);
......@@ -228,8 +223,7 @@ class MsSqlSchemaManager extends AbstractSchemaManager
*/
public function dropSequenceSql($seqName)
{
$sequenceName = $this->conn->quoteIdentifier($this->conn->getSequenceName($seqName), true);
return 'DROP TABLE ' . $sequenceName;
return 'DROP TABLE ' . $seqName;
}
/**
......@@ -254,7 +248,7 @@ class MsSqlSchemaManager extends AbstractSchemaManager
*/
public function listTableColumns($table)
{
$sql = 'EXEC sp_columns @table_name = ' . $this->conn->quoteIdentifier($table, true);
$sql = 'EXEC sp_columns @table_name = ' . $table;
$result = $this->conn->fetchAssoc($sql);
$columns = array();
......
......@@ -278,7 +278,6 @@ class MySqlSchemaManager extends AbstractSchemaManager
*/
public function createSequence($sequenceName, $start = 1, $allocationSize = 1)
{
$sequenceName = $this->_conn->quoteIdentifier($sequenceName);
$seqColumnName = 'mysql_sequence';
/* No support for options yet. Might add 4th options parameter later
......
......@@ -412,7 +412,7 @@ abstract class AbstractQuery
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
{
return $this->_em->getHydrator($this->_hydrationMode)->iterate(
$this->_execute($params, $hydrationMode), $this->_resultSetMapping
$this->_doExecute($params, $hydrationMode), $this->_resultSetMapping
);
}
......
......@@ -46,7 +46,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
'metadataDriverImpl' => null,
'cacheDir' => null,
'allowPartialObjects' => true,
'useCExtension' => false
'useCExtension' => false,
'namedQueries' => array(),
'namedNativeQueries' => array()
));
//TODO: Move this to client code to avoid unnecessary work when a different metadata
......@@ -203,4 +205,50 @@ class Configuration extends \Doctrine\DBAL\Configuration
{
$this->_attributes['useCExtension'] = $boolean;
}
/**
* Adds a named DQL query to the configuration.
*
* @param string $name The name of the query.
* @param string $dql The DQL query string.
*/
public function addNamedQuery($name, $dql)
{
$this->_attributes['namedQueries'][$name] = $dql;
}
/**
* Gets a previously registered named DQL query.
*
* @param string $name The name of the query.
* @return string The DQL query.
*/
public function getNamedQuery($name)
{
return $this->_attributes['namedQueries'][$name];
}
/**
* Adds a named native query to the configuration.
*
* @param string $name The name of the query.
* @param string $sql The native SQL query string.
* @param ResultSetMapping $rsm The ResultSetMapping used for the results of the SQL query.
*/
public function addNamedNativeQuery($name, $sql, Query\ResultSetMapping $rsm)
{
$this->_attributes['namedNativeQueries'][$name] = array($sql, $rsm);
}
/**
* Gets the components of a previously registered named native query.
*
* @param string $name The name of the query.
* @return array A tuple with the first element being the SQL string and the second
* element being the ResultSetMapping.
*/
public function getNamedNativeQuery($name)
{
return $this->_attributes['namedNativeQueries'][$name];
}
}
\ No newline at end of file
......@@ -228,14 +228,14 @@ class EntityManager
}
/**
* Creates a DQL query with the specified name.
* Creates a Query from a named query.
*
* @param string $name
* @todo Implementation.
* @throws DoctrineException If there is no query registered with the given name.
*/
public function createNamedQuery($name)
{
//...
return $this->createQuery($this->_config->getNamedQuery($name));
}
/**
......@@ -254,11 +254,15 @@ class EntityManager
}
/**
* Creates a NativeQuery from a named native query.
*
* @param string $name
* @todo Implementation.
*/
public function createNamedNativeQuery($name)
{
//...
list($sql, $rsm) = $this->_config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
/**
......
......@@ -32,6 +32,7 @@ use Doctrine\DBAL\Connection;
*/
class ArrayHydrator extends AbstractHydrator
{
private $_ce = array();
private $_rootAliases = array();
private $_isSimpleQuery = false;
private $_identifierMap = array();
......@@ -104,10 +105,8 @@ class ArrayHydrator extends AbstractHydrator
continue;
}
$relation = $this->_rsm->relationMap[$dqlAlias];
$relationAlias = $relation->sourceFieldName;
//$relationAlias = $this->_rsm->relationMap[$dqlAlias];
//$relation = $this->_ce[$parentClass]->associationMappings[$relationField];
$relationAlias = $this->_rsm->relationMap[$dqlAlias];
$relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
// Check the type of the relation (many or single-valued)
if ( ! $relation->isOneToOne()) {
......@@ -222,6 +221,14 @@ class ArrayHydrator extends AbstractHydrator
}
}
private function _getClassMetadata($className)
{
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
return $this->_ce[$className];
}
/** {@inheritdoc} */
protected function _getRowContainer()
{
......
......@@ -91,15 +91,16 @@ class ObjectHydrator extends AbstractHydrator
// Remember which associations are "fetch joined"
if (isset($this->_rsm->relationMap[$dqlAlias])) {
$assoc = $this->_rsm->relationMap[$dqlAlias];
//$assoc = $class->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
$targetClass = $this->_em->getClassMetadata($targetClassName);
$this->_ce[$targetClassName] = $targetClass;
$assoc = $targetClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_fetchedAssociations[$assoc->sourceEntityName][$assoc->sourceFieldName] = true;
if ($assoc->mappedByFieldName) {
$this->_fetchedAssociations[$assoc->targetEntityName][$assoc->mappedByFieldName] = true;
} else {
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
if (isset($targetClass->inverseMappings[$assoc->sourceFieldName])) {
$inverseAssoc = $targetClass->inverseMappings[$assoc->sourceFieldName];
if (isset($targetClass->inverseMappings[$className][$assoc->sourceFieldName])) {
$inverseAssoc = $targetClass->inverseMappings[$className][$assoc->sourceFieldName];
$this->_fetchedAssociations[$assoc->targetEntityName][$inverseAssoc->sourceFieldName] = true;
}
}
......@@ -107,6 +108,13 @@ class ObjectHydrator extends AbstractHydrator
}
}
protected function _cleanup()
{
parent::_cleanup();
$this->_identifierMap =
$this->_resultPointers = array();
}
/**
* {@inheritdoc}
*
......@@ -141,7 +149,7 @@ class ObjectHydrator extends AbstractHydrator
$class = $this->_ce[get_class($entity)];
$relation = $class->associationMappings[$name];
$pColl = new PersistentCollection($this->_em, $this->_getClassMetadata($relation->targetEntityName),
$pColl = new PersistentCollection($this->_em, $this->_ce[$relation->targetEntityName],
$class->reflFields[$name]->getValue($entity) ?: new ArrayCollection);
$pColl->setOwner($entity, $relation);
......@@ -193,8 +201,9 @@ class ObjectHydrator extends AbstractHydrator
} else {
// Inject collection
$reflField = $this->_ce[$className]->reflFields[$field];
$pColl = new PersistentCollection($this->_em, $this->_getClassMetadata(
$assoc->targetEntityName), $reflField->getValue($entity) ?: new ArrayCollection
$pColl = new PersistentCollection($this->_em,
$this->_getClassMetadata($assoc->targetEntityName),
$reflField->getValue($entity) ?: new ArrayCollection
);
$pColl->setOwner($entity, $assoc);
$reflField->setValue($entity, $pColl);
......@@ -271,10 +280,8 @@ class ObjectHydrator extends AbstractHydrator
$parentClass = get_class($baseElement);
$oid = spl_object_hash($baseElement);
$relation = $this->_rsm->relationMap[$dqlAlias];
//$relationField = $this->_rsm->relationMap[$dqlAlias];
//$relation = $this->_ce[$parentClass]->associationMappings[$relationField];
$relationField = $relation->sourceFieldName;
$relationField = $this->_rsm->relationMap[$dqlAlias];
$relation = $this->_ce[$parentClass]->associationMappings[$relationField];
$reflField = $this->_ce[$parentClass]->reflFields[$relationField];
$reflFieldValue = $reflField->getValue($baseElement);
......@@ -296,12 +303,11 @@ class ObjectHydrator extends AbstractHydrator
// If it's a bi-directional many-to-many, also initialize the reverse collection.
if ($relation->isManyToMany()) {
if ($relation->isOwningSide && isset($this->_ce[$entityName]->inverseMappings[$relationField])) {
$inverseFieldName = $this->_ce[$entityName]->inverseMappings[$relationField]->sourceFieldName;
if ($relation->isOwningSide && isset($this->_ce[$entityName]->inverseMappings[$relation->sourceEntityName][$relationField])) {
$inverseFieldName = $this->_ce[$entityName]->inverseMappings[$relation->sourceEntityName][$relationField]->sourceFieldName;
// Only initialize reverse collection if it is not yet initialized.
if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $inverseFieldName])) {
$this->initRelatedCollection($element, $this->_ce[$entityName]
->inverseMappings[$relationField]->sourceFieldName);
$this->initRelatedCollection($element, $inverseFieldName);
}
} else if ($relation->mappedByFieldName) {
// Only initialize reverse collection if it is not yet initialized.
......@@ -345,8 +351,8 @@ class ObjectHydrator extends AbstractHydrator
$targetClass = $this->_ce[$relation->targetEntityName];
if ($relation->isOwningSide) {
// If there is an inverse mapping on the target class its bidirectional
if (isset($targetClass->inverseMappings[$relationField])) {
$sourceProp = $targetClass->inverseMappings[$relationField]->sourceFieldName;
if (isset($targetClass->inverseMappings[$relation->sourceEntityName][$relationField])) {
$sourceProp = $targetClass->inverseMappings[$relation->sourceEntityName][$relationField]->sourceFieldName;
$targetClass->reflFields[$sourceProp]->setValue($element, $base);
} else if ($this->_ce[$parentClass] === $targetClass && $relation->mappedByFieldName) {
// Special case: bi-directional self-referencing one-one on the same class
......
......@@ -57,12 +57,7 @@ abstract class AssociationMapping
* @var array
*/
protected static $_cascadeTypes = array(
'all',
'none',
'save',
'delete',
'refresh',
'merge'
'all', 'none', 'save', 'delete', 'refresh', 'merge'
);
public $cascades = array();
......@@ -173,6 +168,10 @@ abstract class AssociationMapping
if ( ! isset($mapping['mappedBy'])) {
// Optional
if (isset($mapping['joinTable'])) {
if ($mapping['joinTable']['name'][0] == '`') {
$mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
$mapping['joinTable']['quoted'] = true;
}
$this->joinTable = $mapping['joinTable'];
}
} else {
......@@ -404,14 +403,14 @@ abstract class AssociationMapping
abstract public function load($sourceEntity, $target, $em, array $joinColumnValues = array());
/**
* Uses reflection to access internal data of entities.
* @param ClassMetadata $class
* @param $entity a domain object
* @param $column name of private field
* @return mixed
*
* @param $platform
* @return unknown_type
*/
protected function _getPrivateValue(ClassMetadata $class, $entity, $column)
public function getQuotedJoinTableName($platform)
{
return $class->reflFields[$class->fieldNames[$column]]->getValue($entity);
return isset($this->joinTable['quoted']) ?
$platform->quoteIdentifier($this->joinTable['name']) :
$this->joinTable['name'];
}
}
......@@ -665,25 +665,31 @@ final class ClassMetadata
}
/**
* Gets the inverse association mapping for the given fieldname.
* Gets the inverse association mapping for the given target class name and
* owning fieldname.
*
* @param string $mappedByFieldName
* @return Doctrine\ORM\Mapping\AssociationMapping The mapping.
* @param string $mappedByFieldName The field on the
* @return Doctrine\ORM\Mapping\AssociationMapping The mapping or NULL if there is no such
* inverse association mapping.
*/
public function getInverseAssociationMapping($mappedByFieldName)
public function getInverseAssociationMapping($targetClassName, $mappedByFieldName)
{
return $this->inverseMappings[$mappedByFieldName];
return isset($this->inverseMappings[$targetClassName][$mappedByFieldName]) ?
$this->inverseMappings[$targetClassName][$mappedByFieldName] : null;
}
/**
* Whether the class has an inverse association mapping on the given fieldname.
* Checks whether the class has an inverse association mapping that points to the
* specified class and ha the specified mappedBy field.
*
* @param string $mappedByFieldName
* @param string $targetClassName The name of the target class.
* @param string $mappedByFieldName The name of the mappedBy field that points to the field on
* the target class that owns the association.
* @return boolean
*/
public function hasInverseAssociationMapping($mappedByFieldName)
public function hasInverseAssociationMapping($targetClassName, $mappedByFieldName)
{
return isset($this->inverseMappings[$mappedByFieldName]);
return isset($this->inverseMappings[$targetClassName][$mappedByFieldName]);
}
/**
......@@ -740,6 +746,11 @@ final class ClassMetadata
// Complete fieldName and columnName mapping
if ( ! isset($mapping['columnName'])) {
$mapping['columnName'] = $mapping['fieldName'];
} else {
if ($mapping['columnName'][0] == '`') {
$mapping['columnName'] = trim($mapping['columnName'], '`');
$mapping['quoted'] = true;
}
}
$this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
......@@ -762,36 +773,15 @@ final class ClassMetadata
$this->reflFields[$mapping['fieldName']] = $refProp;
}
/**
* @todo Implementation of Optimistic Locking.
*/
public function mapVersionField(array $mapping)
{
//...
}
/**
* Overrides an existant field mapping.
* Used i.e. by Entity classes deriving from another Entity class that acts
* as a mapped superclass to refine the basic mapping.
*
* @param array $newMapping
* @todo Implementation.
*/
public function overrideFieldMapping(array $newMapping)
{
//...
}
/**
* Maps an embedded value object.
*
* @todo Implementation.
*/
public function mapEmbeddedValue()
/*public function mapEmbeddedValue()
{
//...
}
}*/
/**
* Gets the identifier (primary key) field names of the class.
......@@ -964,7 +954,15 @@ final class ClassMetadata
*/
public function getIdentifierColumnNames()
{
return $this->getColumnNames((array)$this->getIdentifierFieldNames());
if ($this->isIdentifierComposite) {
$columnNames = array();
foreach ($this->identifier as $idField) {
$columnNames[] = $this->fieldMappings[$idField]['columnName'];
}
return $columnNames;
} else {
return array($this->fieldMappings[$this->identifier[0]]['columnName']);
}
}
/**
......@@ -1007,7 +1005,7 @@ final class ClassMetadata
/**
*
* @return <type>
* @return boolean
*/
public function isInheritanceTypeNone()
{
......@@ -1110,14 +1108,6 @@ final class ClassMetadata
return $this->getTypeOfField($this->getFieldName($columnName));
}
/**
* Gets the (maximum) length of a field.
*/
public function getFieldLength($fieldName)
{
return $this->fieldMappings[$fieldName]['length'];
}
/**
* Gets the name of the primary table.
*
......@@ -1138,23 +1128,6 @@ final class ClassMetadata
return $this->primaryTable['name'] . '_id_tmp';
}
public function getInheritedFields()
{
}
/**
* Adds a named query.
*
* @param string $name The name under which the query gets registered.
* @param string $query The DQL query.
* @todo Implementation.
*/
public function addNamedQuery($name, $query)
{
//...
}
/**
* Gets the inheritance mapping type used by the mapped class.
*
......@@ -1339,7 +1312,7 @@ final class ClassMetadata
/**
* Adds a field mapping.
*
* @param array $mapping
* @param array $mapping The field mapping.
*/
public function mapField(array $mapping)
{
......@@ -1374,7 +1347,7 @@ final class ClassMetadata
/**
* INTERNAL:
* Adds an association mapping without completing/validating it.
* Adds a field mapping without completing/validating it.
* This is mainly used to add inherited field mappings to derived classes.
*
* @param array $mapping
......@@ -1409,7 +1382,7 @@ final class ClassMetadata
private function _registerMappingIfInverse(AssociationMapping $assoc)
{
if ($assoc->isInverseSide()) {
$this->inverseMappings[$assoc->getMappedByFieldName()] = $assoc;
$this->inverseMappings[$assoc->targetEntityName][$assoc->mappedByFieldName] = $assoc;
}
}
......@@ -1455,7 +1428,7 @@ final class ClassMetadata
*/
private function _storeAssociationMapping(AssociationMapping $assocMapping)
{
$sourceFieldName = $assocMapping->getSourceFieldName();
$sourceFieldName = $assocMapping->sourceFieldName;
if (isset($this->associationMappings[$sourceFieldName])) {
throw MappingException::duplicateFieldMapping();
}
......@@ -1499,10 +1472,10 @@ final class ClassMetadata
* @param boolean $bool
* @see getJoinSubClasses()
*/
public function setJoinSubClasses($bool)
/*public function setJoinSubClasses($bool)
{
$this->joinSubclasses = (bool)$bool;
}
}*/
/**
* Gets whether the class mapped by this instance should OUTER JOIN sub classes
......@@ -1511,10 +1484,10 @@ final class ClassMetadata
* @return <type>
* @see setJoinSubClasses()
*/
public function getJoinSubClasses()
/*public function getJoinSubClasses()
{
return $this->joinSubclasses;
}
}*/
/**
* Dispatches the lifecycle event of the given entity to the registered
......@@ -1781,6 +1754,49 @@ final class ClassMetadata
$this->versionField = $versionField;
}
/**
* Gets the (possibly quoted) column name of a mapped field for safe use
* in an SQL statement.
*
* @param string $field
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedColumnName($field, $platform)
{
return isset($this->fieldMappings[$field]['quoted']) ?
$platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) :
$this->fieldMappings[$field]['columnName'];
}
/**
* Gets the (possibly quoted) primary table name of this class for safe use
* in an SQL statement.
*
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedTableName($platform)
{
return isset($this->primaryTable['quoted']) ?
$platform->quoteIdentifier($this->primaryTable['name']) :
$this->primaryTable['name'];
}
/**
* Gets the (possibly quoted) name of the discriminator column for safe use
* in an SQL statement.
*
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedDiscriminatorColumnName($platform)
{
return isset($this->discriminatorColumn['quoted']) ?
$platform->quoteIdentifier($this->discriminatorColumn['name']) :
$this->discriminatorColumn['name'];
}
/**
* Creates a string representation of this instance.
*
......@@ -1791,4 +1807,65 @@ final class ClassMetadata
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* Parts that are NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
return array(
'associationMappings',
'changeTrackingPolicy',
'columnNames',
'customRepositoryClassName',
'discriminatorColumn',
'discriminatorValue',
'fieldMappings',
'fieldNames',
'generatorType',
'identifier',
'idGenerator',
'inheritanceType',
'inheritedAssociationFields',
'insertSql',
'inverseMappings',
'isIdentifierComposite',
'isMappedSuperclass',
'isVersioned',
'lifecycleCallbacks',
'name',
'namespace',
'parentClasses',
'primaryTable',
'rootEntityName',
'sequenceGeneratorDefinition',
'subClasses',
'versionField'
);
}
/**
* Restores some state that could not be serialized/unserialized.
*
* @return void
*/
public function __wakeup()
{
// Restore ReflectionClass and properties
$this->reflClass = new \ReflectionClass($this->name);
foreach ($this->fieldNames as $field) {
$this->reflFields[$field] = $this->reflClass->getProperty($field);
$this->reflFields[$field]->setAccessible(true);
}
foreach ($this->associationMappings as $field => $mapping) {
$this->reflFields[$field] = $this->reflClass->getProperty($field);
$this->reflFields[$field]->setAccessible(true);
}
}
}
......@@ -98,8 +98,8 @@ class ClassMetadataFactory
if ( ! isset($this->_loadedMetadata[$className])) {
$cacheKey = "$className\$CLASSMETADATA";
if ($this->_cacheDriver) {
if ($this->_cacheDriver->contains($cacheKey)) {
$this->_loadedMetadata[$className] = $this->_cacheDriver->fetch($cacheKey);
if (($cached = $this->_cacheDriver->fetch($cacheKey)) !== false) {
$this->_loadedMetadata[$className] = $cached;
} else {
$this->_loadMetadata($className);
$this->_cacheDriver->save($cacheKey, $this->_loadedMetadata[$className], null);
......@@ -298,12 +298,12 @@ class ClassMetadataFactory
$assoc = $class->associationMappings[$name];
if ($assoc->isOneToOne() && $assoc->isOwningSide) {
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
$columns[] = $this->_targetPlatform->quoteIdentifier($sourceCol);
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform);
$values[] = '?';
}
}
} else if ($class->name != $class->rootEntityName || ! $class->isIdGeneratorIdentity() || $class->identifier[0] != $name) {
$columns[] = $this->_targetPlatform->quoteIdentifier($class->columnNames[$name]);
$columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform);
$values[] = '?';
}
}
......@@ -317,12 +317,12 @@ class ClassMetadataFactory
$assoc = $class->associationMappings[$name];
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
$columns[] = $this->_targetPlatform->quoteIdentifier($sourceCol);
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform);
$values[] = '?';
}
}
} else if ($class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $class->identifier[0] != $name) {
$columns[] = $this->_targetPlatform->quoteIdentifier($class->columnNames[$name]);
$columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform);
$values[] = '?';
}
}
......@@ -330,12 +330,12 @@ class ClassMetadataFactory
// Add discriminator column to the INSERT SQL if necessary
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined() && $class->name == $class->rootEntityName) {
$columns[] = $class->discriminatorColumn['name'];
$columns[] = $class->getQuotedDiscriminatorColumnName($this->_targetPlatform);
$values[] = '?';
}
$class->insertSql = 'INSERT INTO ' .
$this->_targetPlatform->quoteIdentifier($class->primaryTable['name'])
$class->getQuotedTableName($this->_targetPlatform)
. ' (' . implode(', ', $columns) . ') '
. 'VALUES (' . implode(', ', $values) . ')';
}
......
......@@ -60,7 +60,7 @@ class ManyToManyMapping extends AssociationMapping
public $targetToRelationKeyColumns = array();
/**
* The columns on the join table.
* List of aggregated column names on the join table.
*/
public $joinTableColumns = array();
......@@ -91,22 +91,30 @@ class ManyToManyMapping extends AssociationMapping
if ( ! isset($mapping['joinTable'])) {
throw MappingException::joinTableRequired($mapping['fieldName']);
}
// owning side MUST specify joinColumns
if ( ! isset($mapping['joinTable']['joinColumns'])) {
throw MappingException::invalidMapping($this->_sourceFieldName);
}
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
// owning side MUST specify inverseJoinColumns
if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
throw MappingException::invalidMapping($this->_sourceFieldName);
}
foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
if ($joinColumn['name'][0] == '`') {
$joinColumn['name'] = trim($joinColumn['name'], '`');
$joinColumn['quoted'] = true;
}
$this->sourceToRelationKeyColumns[$joinColumn['referencedColumnName']] = $joinColumn['name'];
$this->joinTableColumns[] = $joinColumn['name'];
}
$this->sourceKeyColumns = array_keys($this->sourceToRelationKeyColumns);
// owning side MUST specify inverseJoinColumns
if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
throw MappingException::invalidMapping($this->_sourceFieldName);
foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
if ($inverseJoinColumn['name'][0] == '`') {
$inverseJoinColumn['name'] = trim($inverseJoinColumn['name'], '`');
$inverseJoinColumn['quoted'] = true;
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
$this->targetToRelationKeyColumns[$inverseJoinColumn['referencedColumnName']] = $inverseJoinColumn['name'];
$this->joinTableColumns[] = $inverseJoinColumn['name'];
}
......@@ -114,7 +122,7 @@ class ManyToManyMapping extends AssociationMapping
}
}
public function getJoinTableColumns()
public function getJoinTableColumnNames()
{
return $this->joinTableColumns;
}
......@@ -152,38 +160,30 @@ class ManyToManyMapping extends AssociationMapping
{
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
$joinTableConditions = array();
if ($this->isOwningSide()) {
$joinTable = $this->joinTable;
$joinClauses = $this->targetToRelationKeyColumns;
if ($this->isOwningSide) {
foreach ($this->sourceToRelationKeyColumns as $sourceKeyColumn => $relationKeyColumn) {
// getting id
if (isset($sourceClass->reflFields[$sourceKeyColumn])) {
$joinTableConditions[$relationKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $sourceKeyColumn);
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$joinTableConditions[$relationKeyColumn] = $joinColumnValues[$sourceKeyColumn];
}
}
} else {
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->associationMappings[$this->mappedByFieldName];
$joinTable = $owningAssoc->joinTable;
// TRICKY: since the association is inverted source and target are flipped
$joinClauses = $owningAssoc->sourceToRelationKeyColumns;
foreach ($owningAssoc->targetToRelationKeyColumns as $sourceKeyColumn => $relationKeyColumn) {
// getting id
if (isset($sourceClass->reflFields[$sourceKeyColumn])) {
$joinTableConditions[$relationKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $sourceKeyColumn);
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$joinTableConditions[$relationKeyColumn] = $joinColumnValues[$sourceKeyColumn];
}
}
}
$joinTableCriteria = array(
'table' => $joinTable['name'],
'join' => $joinClauses,
'criteria' => $joinTableConditions
);
$persister = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName);
$persister->loadManyToManyCollection(array($joinTableCriteria), $targetCollection);
$persister->loadManyToManyCollection($this, $joinTableConditions, $targetCollection);
}
/**
......@@ -193,4 +193,19 @@ class ManyToManyMapping extends AssociationMapping
{
return true;
}
/**
* Gets the (possibly quoted) column name of a join column that is safe to use
* in an SQL statement.
*
* @param string $joinColumn
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedJoinColumnName($joinColumn, $platform)
{
return isset($this->joinTable['joinColumns'][$joinColumn]['quoted']) ?
$platform->quoteIdentifier($joinColumn) :
$joinColumn;
}
}
......@@ -124,7 +124,7 @@ class OneToManyMapping extends AssociationMapping
foreach ($owningAssoc->getTargetToSourceKeyColumns() as $sourceKeyColumn => $targetKeyColumn) {
// getting id
if (isset($sourceClass->reflFields[$sourceKeyColumn])) {
$conditions[$targetKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $sourceKeyColumn);
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
}
......
......@@ -67,6 +67,12 @@ class OneToOneMapping extends AssociationMapping
*/
public $joinColumns = array();
/**
* A map of join column names to field names that are used in cases
* when the join columns are fetched as part of the query result.
*
* @var array
*/
public $joinColumnFieldNames = array();
/**
......@@ -98,12 +104,16 @@ class OneToOneMapping extends AssociationMapping
if ( ! isset($mapping['joinColumns'])) {
throw MappingException::invalidMapping($this->sourceFieldName);
}
$this->joinColumns = $mapping['joinColumns'];
foreach ($mapping['joinColumns'] as $joinColumn) {
foreach ($mapping['joinColumns'] as &$joinColumn) {
if ($joinColumn['name'][0] == '`') {
$joinColumn['name'] = trim($joinColumn['name'], '`');
$joinColumn['quoted'] = true;
}
$this->sourceToTargetKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName'];
$this->joinColumnFieldNames[$joinColumn['name']] = isset($joinColumn['fieldName'])
? $joinColumn['fieldName'] : $joinColumn['name'];
}
$this->joinColumns = $mapping['joinColumns'];
$this->targetToSourceKeyColumns = array_flip($this->sourceToTargetKeyColumns);
}
......@@ -154,6 +164,21 @@ class OneToOneMapping extends AssociationMapping
return true;
}
/**
* Gets the (possibly quoted) column name of a join column that is safe to use
* in an SQL statement.
*
* @param string $joinColumn
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedJoinColumnName($joinColumn, $platform)
{
return isset($this->joinColumns[$joinColumn]['quoted']) ?
$platform->quoteIdentifier($joinColumn) :
$joinColumn;
}
/**
* {@inheritdoc}
*
......@@ -174,7 +199,7 @@ class OneToOneMapping extends AssociationMapping
foreach ($this->sourceToTargetKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
// getting customer_id
if (isset($sourceClass->reflFields[$sourceKeyColumn])) {
$conditions[$targetKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $sourceKeyColumn);
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
}
......@@ -182,18 +207,18 @@ class OneToOneMapping extends AssociationMapping
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
if ($targetEntity !== null && $targetClass->hasInverseAssociationMapping($this->sourceFieldName)) {
if ($targetEntity !== null && $targetClass->hasInverseAssociationMapping($this->sourceEntityName, $this->sourceFieldName)) {
$targetClass->setFieldValue($targetEntity,
$targetClass->inverseMappings[$this->sourceFieldName]->sourceFieldName,
$targetClass->inverseMappings[$this->sourceEntityName][$this->sourceFieldName]->sourceFieldName,
$sourceEntity);
}
} else {
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->getAssociationMapping($this->mappedByFieldName);
// TRICKY: since the association is specular source and target are flipped
foreach ($owningAssoc->getTargetToSourceKeyColumns() as $sourceKeyColumn => $targetKeyColumn) {
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
// getting id
if (isset($sourceClass->reflFields[$sourceKeyColumn])) {
$conditions[$targetKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $sourceKeyColumn);
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
}
......
......@@ -138,9 +138,9 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
// For sure bi-directional
$this->_backRefFieldName = $assoc->mappedByFieldName;
} else {
if (isset($this->_typeClass->inverseMappings[$assoc->sourceFieldName])) {
if (isset($this->_typeClass->inverseMappings[$assoc->sourceEntityName][$assoc->sourceFieldName])) {
// Bi-directional
$this->_backRefFieldName = $this->_typeClass->inverseMappings[$assoc->sourceFieldName]->sourceFieldName;
$this->_backRefFieldName = $this->_typeClass->inverseMappings[$assoc->sourceEntityName][$assoc->sourceFieldName]->sourceFieldName;
}
}
}
......
......@@ -32,7 +32,6 @@ use Doctrine\Common\DoctrineException;
* @version $Revision$
* @link www.doctrine-project.org
* @since 2.0
* @todo Reimplement.
*/
class JoinedSubclassPersister extends StandardEntityPersister
{
......@@ -145,12 +144,12 @@ class JoinedSubclassPersister extends StandardEntityPersister
$params = array();
foreach ($insertData[$rootTableName] as $columnName => $value) {
$params[$paramIndex] = $value;
$stmt->bindValue($paramIndex++, $value/*, TODO: TYPE*/);
$stmt->bindValue($paramIndex++, $value);
}
$sqlLogger->logSql($sql[$rootTableName], $params);
} else {
foreach ($insertData[$rootTableName] as $columnName => $value) {
$stmt->bindValue($paramIndex++, $value/*, TODO: TYPE*/);
$stmt->bindValue($paramIndex++, $value);
}
}
$stmt->execute();
......@@ -168,31 +167,31 @@ class JoinedSubclassPersister extends StandardEntityPersister
$stmt = $stmts[$tableName];
$paramIndex = 1;
if ($sqlLogger) {
//TODO: Log type
$params = array();
foreach ((array)$id as $idVal) {
foreach ((array) $id as $idVal) {
$params[$paramIndex] = $idVal;
$stmt->bindValue($paramIndex++, $idVal/*, TODO: TYPE*/);
$stmt->bindValue($paramIndex++, $idVal);
}
foreach ($data as $columnName => $value) {
$params[$paramIndex] = $value;
$stmt->bindValue($paramIndex++, $value/*, TODO: TYPE*/);
$stmt->bindValue($paramIndex++, $value);
}
$sqlLogger->logSql($sql[$tableName], $params);
} else {
foreach ((array)$id as $idVal) {
$stmt->bindValue($paramIndex++, $idVal/*, TODO: TYPE*/);
foreach ((array) $id as $idVal) {
$stmt->bindValue($paramIndex++, $idVal);
}
foreach ($data as $columnName => $value) {
$stmt->bindValue($paramIndex++, $value/*, TODO: TYPE*/);
$stmt->bindValue($paramIndex++, $value);
}
}
$stmt->execute();
}
}
foreach ($stmts as $stmt)
foreach ($stmts as $stmt) {
$stmt->closeCursor();
}
if ($isVersioned) {
$this->_assignDefaultVersionValue($versionedClass, $entity, $id);
......@@ -247,7 +246,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
public function delete($entity)
{
$id = array_combine(
$this->_class->getIdentifierFieldNames(),
$this->_class->identifier,
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
......@@ -257,7 +256,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
$this->_conn->delete($this->_em->getClassMetadata($this->_class->rootEntityName)
->primaryTable['name'], $id);
} else {
// Delete the parent tables, starting from this class' table up to the root table
// Delete from all tables individually, starting from this class' table up to the root table.
$this->_conn->delete($this->_class->primaryTable['name'], $id);
foreach ($this->_class->parentClasses as $parentClass) {
$this->_conn->delete($this->_em->getClassMetadata($parentClass)->primaryTable['name'], $id);
......@@ -266,7 +265,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
}
/**
* Gets the SELECT SQL to select a single entity by a set of field criteria.
* Gets the SELECT SQL to select one or more entities by a set of field criteria.
*
* @param array $criteria
* @return string The SQL.
......
......@@ -40,7 +40,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
{
$mapping = $coll->getMapping();
$joinTable = $mapping->getJoinTable();
$columns = $mapping->getJoinTableColumns();
$columns = $mapping->getJoinTableColumnNames();
return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
}
......@@ -76,7 +76,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
{
$mapping = $coll->getMapping();
$joinTable = $mapping->getJoinTable();
$columns = $mapping->getJoinTableColumns();
$columns = $mapping->getJoinTableColumnNames();
return 'INSERT INTO ' . $joinTable['name'] . ' (' . implode(', ', $columns) . ')'
. ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
}
......
......@@ -21,15 +21,15 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\Common\DoctrineException;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Events;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Collections\ArrayCollection,
Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager,
Doctrine\ORM\UnitOfWork,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Events;
/**
* Base class for all EntityPersisters. An EntityPersister is a class that knows
......@@ -65,6 +65,13 @@ class StandardEntityPersister
*/
protected $_conn;
/**
* The database platform.
*
* @var AbstractPlatform
*/
protected $_platform;
/**
* The EntityManager instance.
*
......@@ -90,16 +97,16 @@ class StandardEntityPersister
public function __construct(EntityManager $em, ClassMetadata $class)
{
$this->_em = $em;
$this->_platform = $em->getConnection()->getDatabasePlatform();
$this->_entityName = $class->name;
$this->_conn = $em->getConnection();
$this->_platform = $this->_conn->getDatabasePlatform();
$this->_entityName = $class->name;
$this->_class = $class;
}
/**
* Adds an entity to the queued inserts.
* Adds an entity to the queued insertions.
*
* @param object $entity
* @param object $entity The entitiy to queue for insertion.
*/
public function addInsert($entity)
{
......@@ -179,7 +186,7 @@ class StandardEntityPersister
$identifier = $this->_class->getIdentifierColumnNames();
$versionFieldColumnName = $this->_class->getColumnName($versionField);
$sql = "SELECT " . $versionFieldColumnName . " FROM " . $class->primaryTable['name'] .
$sql = "SELECT " . $versionFieldColumnName . " FROM " . $class->getQuotedTableName($this->_platform) .
" WHERE " . implode(' = ? AND ', $identifier) . " = ?";
$value = $this->_conn->fetchColumn($sql, (array) $id);
$this->_class->setFieldValue($entity, $versionField, $value[0]);
......@@ -195,7 +202,7 @@ class StandardEntityPersister
$updateData = array();
$this->_prepareData($entity, $updateData);
$id = array_combine(
$this->_class->getIdentifierFieldNames(),
$this->_class->identifier,
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$tableName = $this->_class->primaryTable['name'];
......@@ -217,23 +224,23 @@ class StandardEntityPersister
*/
protected function _doUpdate($entity, $tableName, $data, $where)
{
// Note: $tableName and column names in $data are already quoted for SQL.
$set = array();
foreach ($data as $columnName => $value) {
$set[] = $this->_conn->quoteIdentifier($columnName) . ' = ?';
$set[] = $columnName . ' = ?';
}
if ($isVersioned = $this->_class->isVersioned) {
$versionField = $this->_class->versionField;
$identifier = $this->_class->getIdentifier();
$versionFieldColumnName = $this->_class->getColumnName($versionField);
$where[$versionFieldColumnName] = $entity->version;
$set[] = $this->_conn->quoteIdentifier($versionFieldColumnName) . ' = ' .
$this->_conn->quoteIdentifier($versionFieldColumnName) . ' + 1';
$where[$this->_class->fieldNames[$versionField]] = $entity->version;
$versionFieldColumnName = $this->_class->getQuotedColumnName($versionField, $this->_platform);
$set[] = $versionFieldColumnName . ' = ' . $versionFieldColumnName . ' + 1';
}
$params = array_merge(array_values($data), array_values($where));
$sql = 'UPDATE ' . $this->_conn->quoteIdentifier($tableName)
$sql = 'UPDATE ' . $tableName
. ' SET ' . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', array_keys($where))
. ' = ?';
......@@ -263,6 +270,7 @@ class StandardEntityPersister
* Adds an entity to delete.
*
* @param object $entity
* @todo Impl.
*/
public function addDelete($entity)
{
......@@ -273,6 +281,7 @@ class StandardEntityPersister
* Executes all pending entity deletions.
*
* @see addDelete()
* @todo Impl.
*/
public function executeDeletions()
{
......@@ -306,13 +315,12 @@ class StandardEntityPersister
*
* Notes to inheritors: Be sure to call <code>parent::_prepareData($entity, $result, $isInsert);</code>
*
* @param object $entity
* @param object $entity The entity for which to prepare the data.
* @param array $result The reference to the data array.
* @param boolean $isInsert Whether the preparation is for an INSERT (or UPDATE, if FALSE).
*/
protected function _prepareData($entity, array &$result, $isInsert = false)
{
$platform = $this->_conn->getDatabasePlatform();
$uow = $this->_em->getUnitOfWork();
if ($versioned = $this->_class->isVersioned) {
......@@ -323,11 +331,10 @@ class StandardEntityPersister
if ($versioned && $versionField == $field) {
continue;
}
$oldVal = $change[0];
$newVal = $change[1];
$columnName = $this->_class->getColumnName($field);
if (isset($this->_class->associationMappings[$field])) {
$assocMapping = $this->_class->associationMappings[$field];
// Only owning side of x-1 associations can have a FK column.
......@@ -357,20 +364,24 @@ class StandardEntityPersister
}
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
$quotedSourceColumn = $assocMapping->getQuotedJoinColumnName($sourceColumn, $this->_platform);
if ($newVal === null) {
$result[$this->getOwningTable($field)][$sourceColumn] = null;
$result[$this->getOwningTable($field)][$quotedSourceColumn] = null;
} else {
$otherClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
$result[$this->getOwningTable($field)][$sourceColumn] =
$result[$this->getOwningTable($field)][$quotedSourceColumn] =
$otherClass->reflFields[$otherClass->fieldNames[$targetColumn]]
->getValue($newVal);
}
}
} else if ($newVal === null) {
$columnName = $this->_class->getQuotedColumnName($field, $this->_platform);
$result[$this->getOwningTable($field)][$columnName] = null;
} else {
$columnName = $this->_class->getQuotedColumnName($field, $this->_platform);
$result[$this->getOwningTable($field)][$columnName] = Type::getType(
$this->_class->fieldMappings[$field]['type'])->convertToDatabaseValue($newVal, $platform);
$this->_class->fieldMappings[$field]['type'])
->convertToDatabaseValue($newVal, $this->_platform);
}
}
}
......@@ -383,7 +394,7 @@ class StandardEntityPersister
*/
public function getOwningTable($fieldName)
{
return $this->_class->primaryTable['name'];
return $this->_class->getQuotedTableName($this->_platform);
}
/**
......@@ -400,17 +411,19 @@ class StandardEntityPersister
$stmt->execute(array_values($criteria));
$result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt->closeCursor();
return $this->_createEntity($result, $entity);
}
/**
* Loads a collection of entities into a one-to-many association.
*
*
* @param array $criteria The criteria by which to select the entities.
* @param PersistentCollection The collection to fill.
*/
public function loadOneToManyCollection(array $criteria, PersistentCollection $collection)
{
$sql = $this->_getSelectEntitiesSql($criteria);
$stmt = $this->_conn->prepare($sql);
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria));
$stmt->execute(array_values($criteria));
while ($result = $stmt->fetch(Connection::FETCH_ASSOC)) {
$collection->hydrateAdd($this->_createEntity($result));
......@@ -419,39 +432,40 @@ class StandardEntityPersister
}
/**
* Loads a collection of entities of a many-to-many association.
*
*
* @param array $criteria
* @param PersistentCollection $coll The collection to fill.
*/
public function loadManyToManyCollection(array $criteria, PersistentCollection $collection)
public function loadManyToManyCollection($assoc, array $criteria, PersistentCollection $coll)
{
$sql = $this->_getSelectManyToManyEntityCollectionSql($criteria);
$stmt = $this->_conn->prepare($sql);
$stmt = $this->_conn->prepare($this->_getSelectManyToManyEntityCollectionSql($assoc, $criteria));
$stmt->execute(array_values($criteria));
while ($result = $stmt->fetch(Connection::FETCH_ASSOC)) {
$collection->add($this->_createEntity($result));
$coll->add($this->_createEntity($result));
}
$stmt->closeCursor();
}
/**
* Creates or fills a single entity object from an SQL result.
*
* @param $result
* @param $entity
* @return object
* @param $result The SQL result.
* @param $entity The entity object to fill.
* @return object The filled and managed entity object.
*/
private function _createEntity($result, $entity = null)
{
$data = array();
$joinColumnValues = array();
if ($result === false) {
return null;
}
$data = $joinColumnValues = array();
foreach ($result as $column => $value) {
if (isset($this->_class->fieldNames[$column])) {
$fieldName = $this->_class->fieldNames[$column];
$data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName))
$data[$fieldName] = Type::getType($this->_class->fieldMappings[$fieldName]['type'])
->convertToPHPValue($value, $this->_platform);
} else {
$joinColumnValues[$column] = $value;
......@@ -470,7 +484,7 @@ class StandardEntityPersister
$id[] = $data[$fieldName];
}
} else {
$id = array($data[$this->_class->getSingleIdentifierFieldName()]);
$id = array($data[$this->_class->identifier[0]]);
}
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
}
......@@ -491,7 +505,9 @@ class StandardEntityPersister
}
} else {
// Inject collection
$coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc->targetEntityName),
$coll = new PersistentCollection(
$this->_em,
$this->_em->getClassMetadata($assoc->targetEntityName),
new ArrayCollection);
$coll->setOwner($entity, $assoc);
$this->_class->reflFields[$field]->setValue($entity, $coll);
......@@ -509,20 +525,17 @@ class StandardEntityPersister
}
/**
* Gets the SELECT SQL to select a single entity by a set of field criteria.
* No joins are used but the query can return multiple rows.
* Gets the SELECT SQL to select one or more entities by a set of field criteria.
*
* @param array $criteria every element can be a value or an joinClause
* if it is a joinClause, it will be removed and correspondent nested values will be added to $criteria.
* JoinClauses are used to restrict the result returned but only columns of this entity are selected (@see _getJoinSql()).
* @param array $criteria
* @return string The SQL.
*/
protected function _getSelectEntitiesSql(array &$criteria)
{
$columnList = '';
foreach ($this->_class->columnNames as $column) {
foreach ($this->_class->fieldNames as $field) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->_conn->quoteIdentifier($column);
$columnList .= $this->_class->getQuotedColumnName($field, $this->_platform);
}
$joinColumnNames = array();
......@@ -531,7 +544,7 @@ class StandardEntityPersister
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$joinColumnNames[] = $srcColumn;
$columnList .= ', ' . $this->_conn->quoteIdentifier($srcColumn);
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
}
}
......@@ -544,29 +557,18 @@ class StandardEntityPersister
$conditionSql .= ' AND ';
}
if (is_array($value)) {
$joinSql .= $this->_getJoinSql($value);
foreach ($value['criteria'] as $nestedField => $nestedValue) {
$columnName = "{$value['table']}.{$nestedField}";
$conditionSql .= $this->_conn->quoteIdentifier($columnName) . ' = ?';
$criteria[$columnName] = $nestedValue;
}
unset($criteria[$field]);
continue;
}
if (isset($this->_class->columnNames[$field])) {
$columnName = $this->_class->columnNames[$field];
$columnName = $this->_class->getQuotedColumnName($field, $this->_platform);
} else if (in_array($field, $joinColumnNames)) {
$columnName = $field;
} else {
throw DoctrineException::unrecognizedField($field);
}
$conditionSql .= $this->_conn->quoteIdentifier($columnName) . ' = ?';
$conditionSql .= $columnName . ' = ?';
}
return 'SELECT ' . $columnList
. ' FROM ' . $this->_class->getTableName()
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform)
. $joinSql
. ' WHERE ' . $conditionSql;
}
......@@ -574,63 +576,59 @@ class StandardEntityPersister
/**
* Gets the SQL to select a collection of entities in a many-many association.
*
* @param array $criteria
* @return string
*/
protected function _getSelectManyToManyEntityCollectionSql(array &$criteria)
protected function _getSelectManyToManyEntityCollectionSql($manyToMany, array &$criteria)
{
$columnList = '';
foreach ($this->_class->columnNames as $column) {
foreach ($this->_class->fieldNames as $field) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->_conn->quoteIdentifier($column);
$columnList .= $this->_class->getQuotedColumnName($field, $this->_platform);
}
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) {
foreach ($this->_class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $this->_conn->quoteIdentifier($srcColumn);
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
}
}
}
$joinSql = '';
$conditionSql = '';
foreach ($criteria as $field => $value) {
if ($conditionSql != '') {
$conditionSql .= ' AND ';
if ($manyToMany->isOwningSide) {
$owningAssoc = $manyToMany;
$joinClauses = $manyToMany->targetToRelationKeyColumns;
} else {
$owningAssoc = $this->_em->getClassMetadata($manyToMany->targetEntityName)->associationMappings[$manyToMany->mappedByFieldName];
$joinClauses = $owningAssoc->sourceToRelationKeyColumns;
}
$joinSql .= $this->_getJoinSql($value);
foreach ($value['criteria'] as $nestedField => $nestedValue) {
$columnName = "{$value['table']}.{$nestedField}";
$conditionSql .= $this->_conn->quoteIdentifier($columnName) . ' = ?';
$criteria[$columnName] = $nestedValue;
$joinTableName = $owningAssoc->getQuotedJoinTableName($this->_platform);
$joinSql = '';
foreach ($joinClauses as $sourceField => $joinTableField) {
if ($joinSql != '') $joinSql .= ' AND ';
$joinSql .= $this->_class->getQuotedTableName($this->_platform) .
'.' . $this->_class->getQuotedColumnName($sourceField, $this->_platform) . ' = '
. $joinTableName
. '.' . $owningAssoc->getQuotedJoinColumnName($joinTableField, $this->_platform);
}
unset($criteria[$field]);
$joinSql = ' INNER JOIN ' . $joinTableName . ' ON ' . $joinSql;
$conditionSql = '';
foreach ($criteria as $joinColumn => $value) {
if ($conditionSql != '') $conditionSql .= ' AND ';
$columnName = $joinTableName . '.' . $owningAssoc->getQuotedJoinColumnName($joinColumn, $this->_platform);
$conditionSql .= $columnName . ' = ?';
}
return 'SELECT ' . $columnList
. ' FROM ' . $this->_class->primaryTable['name']
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform)
. $joinSql
. ' WHERE ' . $conditionSql;
}
/**
* Builds an INNER JOIN sql query part using $joinClause.
*
* @param array $joinClause keys are:
* 'table' => table to join
* 'join' => array of [sourceField => joinTableField]
* 'criteria' => array of [joinTableField => value]
* @return string
*/
protected function _getJoinSql(array $joinClause)
{
$clauses = array();
foreach ($joinClause['join'] as $sourceField => $joinTableField) {
$clauses[] = $this->_class->getTableName() . ".{$sourceField} = "
. "{$joinClause['table']}.{$joinTableField}";
}
return ' INNER JOIN ' . $joinClause['table'] . ' ON ' . implode(' AND ', $clauses);
}
}
......@@ -45,8 +45,8 @@ class AggregateExpression extends Node
$this->isDistinct = $isDistinct;
}
public function dispatch($sqlWalker)
public function dispatch($walker)
{
return $sqlWalker->walkAggregateExpression($this);
return $walker->walkAggregateExpression($this);
}
}
\ No newline at end of file
......@@ -47,8 +47,8 @@ class ArithmeticExpression extends Node
return (bool) $this->subselect;
}
public function dispatch($sqlWalker)
public function dispatch($walker)
{
return $sqlWalker->walkArithmeticExpression($this);
return $walker->walkArithmeticExpression($this);
}
}
\ No newline at end of file
......@@ -48,8 +48,8 @@ class InputParameter extends Node
$this->name = $param;
}
public function dispatch($sqlWalker)
public function dispatch($walker)
{
return $sqlWalker->walkInputParameter($this);
return $walker->walkInputParameter($this);
}
}
\ No newline at end of file
......@@ -51,6 +51,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
{
$em = $sqlWalker->getEntityManager();
$conn = $em->getConnection();
$platform = $conn->getDatabasePlatform();
$primaryClass = $sqlWalker->getEntityManager()->getClassMetadata(
$AST->deleteClause->abstractSchemaName
......@@ -81,8 +82,8 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
// 3. Create and store DELETE statements
$classNames = array_merge($primaryClass->parentClasses, array($primaryClass->name), $primaryClass->subClasses);
foreach (array_reverse($classNames) as $className) {
$tableName = $em->getClassMetadata($className)->primaryTable['name'];
$this->_sqlStatements[] = 'DELETE FROM ' . $conn->quoteIdentifier($tableName)
$tableName = $em->getClassMetadata($className)->getQuotedTableName($platform);
$this->_sqlStatements[] = 'DELETE FROM ' . $tableName
. ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')';
}
......
......@@ -53,6 +53,8 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
{
$em = $sqlWalker->getEntityManager();
$conn = $em->getConnection();
$platform = $conn->getDatabasePlatform();
$updateClause = $AST->updateClause;
$primaryClass = $sqlWalker->getEntityManager()->getClassMetadata($updateClause->abstractSchemaName);
......@@ -82,8 +84,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
foreach (array_reverse($classNames) as $className) {
$affected = false;
$class = $em->getClassMetadata($className);
$tableName = $class->primaryTable['name'];
$updateSql = 'UPDATE ' . $conn->quoteIdentifier($tableName) . ' SET ';
$updateSql = 'UPDATE ' . $class->getQuotedTableName($platform) . ' SET ';
foreach ($updateItems as $updateItem) {
$field = $updateItem->field;
......
......@@ -22,9 +22,7 @@
namespace Doctrine\ORM\Query;
use Doctrine\Common\DoctrineException,
Doctrine\ORM\Query,
Doctrine\ORM\Query\AST,
Doctrine\ORM\Query\Exec;
Doctrine\ORM\Query;
/**
* An LL(*) parser for the context-free grammar of the Doctrine Query Language.
......@@ -269,6 +267,18 @@ class Parser
$treeWalker = new $this->_treeWalker(
$this->_query, $this->_parserResult, $this->_queryComponents
);
/*if ($this->_treeWalkers) {
// We got additional walkers, so build a chain.
$treeWalker = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents);
foreach ($this->_treeWalkers as $walker) {
$treeWalker->addTreeWalker(new $walker($this->_query, $this->_parserResult, $this->_queryComponents));
}
$treeWalker->setLastTreeWalker('Doctrine\ORM\Query\SqlWalker');
} else {
$treeWalker = new SqlWalker(
$this->_query, $this->_parserResult, $this->_queryComponents
);
}*/
// Assign an SQL executor to the parser result
$this->_parserResult->setSqlExecutor($treeWalker->getExecutor($AST));
......@@ -594,14 +604,14 @@ class Parser
echo '[Query Components: ' . var_export($this->_queryComponents, true) . ']';
$this->semanticalError(
"Could not find '$identVariable' in query components", $token
"'$idVariable' is not defined", $token
);
}
// Validate if identification variable nesting level is lower or equal than the current one
if ($this->_queryComponents[$identVariable]['nestingLevel'] > $nestingLevel) {
$this->semanticalError(
"Query component '$identVariable' is not in the same nesting level of its declaration",
"'$idVariable' is used outside the scope of its declaration",
$token
);
}
......@@ -1259,7 +1269,7 @@ class Parser
// ResultVariable exists in queryComponents, check nesting level
if ($queryComponent['nestingLevel'] != $this->_nestingLevel) {
$this->semanticalError(
"Query component '$expr' is not in the same nesting level of its declaration"
"'$expr' is used outside the scope of its declaration"
);
}
} else {
......
......@@ -33,8 +33,6 @@ namespace Doctrine\ORM\Query;
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @todo Do not store AssociationMappings in $relationMap. These bloat serialized instances
* and in turn unserialize performance suffers which is important for most effective caching.
*/
class ResultSetMapping
{
......@@ -58,8 +56,6 @@ class ResultSetMapping
public $discriminatorColumns = array();
/** Maps alias names to field names that should be used for indexing. */
public $indexByMap = array();
/** A list of columns that should be ignored/skipped during hydration. */
//public $ignoredColumns = array();
/**
* Adds an entity result to this ResultSetMapping.
......@@ -321,25 +317,5 @@ class ResultSetMapping
$this->metaMappings[$columnName] = $fieldName;
$this->columnOwnerMap[$columnName] = $alias;
}
/**
* Adds a column name that will be ignored during hydration.
*
* @param string $columnName
*/
/*public function addIgnoredColumn($columnName)
{
$this->ignoredColumns[$columnName] = true;
}*/
/**
*
* @param string $columnName
* @return boolean
*/
/*public function isIgnoredColumn($columnName)
{
return isset($this->ignoredColumns[$columnName]);
}*/
}
......@@ -79,6 +79,13 @@ class SqlWalker implements TreeWalker
*/
private $_useSqlTableAliases = true;
/**
* The database platform abstraction.
*
* @var AbstractPlatform
*/
private $_platform;
/**
* @inheritdoc
*/
......@@ -88,6 +95,7 @@ class SqlWalker implements TreeWalker
$this->_query = $query;
$this->_em = $query->getEntityManager();
$this->_conn = $this->_em->getConnection();
$this->_platform = $this->_conn->getDatabasePlatform();
$this->_parserResult = $parserResult;
$this->_queryComponents = $queryComponents;
}
......@@ -109,7 +117,7 @@ class SqlWalker implements TreeWalker
*/
public function getConnection()
{
return $this->_em->getConnection();
return $this->_conn;
}
/**
......@@ -123,9 +131,9 @@ class SqlWalker implements TreeWalker
}
/**
* Gets the Query Component related to the given DQL alias.
* Gets the information about a single query component.
*
* @param string $dqlAlias DQL alias
* @param string $dqlAlias The DQL alias.
* @return array
*/
public function getQueryComponent($dqlAlias)
......@@ -205,7 +213,7 @@ class SqlWalker implements TreeWalker
*/
public function getSqlColumnAlias($columnName)
{
return trim($columnName, '`') . $this->_aliasCounter++;
return $columnName . $this->_aliasCounter++;
}
/**
......@@ -221,22 +229,21 @@ class SqlWalker implements TreeWalker
$sql = '';
$baseTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$idColumns = $class->getIdentifierColumnNames();
// INNER JOIN parent class tables
foreach ($class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$tableAlias = $this->getSqlTableAlias($parentClass->primaryTable['name'], $dqlAlias);
$sql .= ' INNER JOIN ' . $this->_conn->quoteIdentifier($parentClass->primaryTable['name'])
$sql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform)
. ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
foreach ($class->identifier as $idField) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $baseTableAlias . '.' . $this->_conn->quoteIdentifier($idColumn)
$columnName = $class->getQuotedColumnName($idField, $this->_platform);
$sql .= $baseTableAlias . '.' . $columnName
. ' = '
. $tableAlias . '.' . $this->_conn->quoteIdentifier($idColumn);
. $tableAlias . '.' . $columnName;
}
}
......@@ -247,12 +254,12 @@ class SqlWalker implements TreeWalker
$sql .= ' LEFT JOIN ' . $subClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
foreach ($class->identifier as $idField) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $baseTableAlias . '.' . $this->_conn->quoteIdentifier($idColumn)
$columnName = $class->getQuotedColumnName($idField, $this->_platform);
$sql .= $baseTableAlias . '.' . $columnName
. ' = '
. $tableAlias . '.' . $this->_conn->quoteIdentifier($idColumn);
. $tableAlias . '.' . $columnName;
}
}
......@@ -351,6 +358,7 @@ class SqlWalker implements TreeWalker
/**
* Walks down a SelectClause AST node, thereby generating the appropriate SQL.
*
* @param $selectClause
* @return string The SQL.
*/
public function walkSelectClause($selectClause)
......@@ -359,27 +367,69 @@ class SqlWalker implements TreeWalker
', ', array_map(array($this, 'walkSelectExpression'), $selectClause->selectExpressions)
);
$addMetaColumns = ! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
$this->_query->getHydrationMode() == Query::HYDRATE_OBJECT
||
$this->_query->getHydrationMode() != Query::HYDRATE_OBJECT &&
$this->_query->getHint(Query::HINT_INCLUDE_META_COLUMNS);
foreach ($this->_selectedClasses as $dqlAlias => $class) {
// Register as entity or joined entity result
if ($this->_queryComponents[$dqlAlias]['relation'] === null) {
$this->_rsm->addEntityResult($class->name, $dqlAlias);
} else {
$this->_rsm->addJoinedEntityResult(
$class->name, $dqlAlias,
$this->_queryComponents[$dqlAlias]['parent'],
$this->_queryComponents[$dqlAlias]['relation']
$this->_queryComponents[$dqlAlias]['relation']->sourceFieldName
);
}
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
// Add discriminator columns to SQL
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
$tblAlias = $this->getSqlTableAlias($rootClass->getTableName(), $dqlAlias);
$tblAlias = $this->getSqlTableAlias($rootClass->primaryTable['name'], $dqlAlias);
$discrColumn = $rootClass->discriminatorColumn;
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
$sql .= ", $tblAlias." . $this->_conn->quoteIdentifier($discrColumn['name'])
$sql .= ", $tblAlias." . $rootClass->getQuotedDiscriminatorColumnName($this->_platform)
. ' AS ' . $columnAlias;
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
// Add foreign key columns to SQL, if necessary
if ($addMetaColumns) {
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
if (isset($class->inheritedAssociationFields[$assoc->sourceFieldName])) {
$owningClass = $this->_em->getClassMetadata($class->inheritedAssociationFields[$assoc->sourceFieldName]);
$sqlTableAlias = $this->getSqlTableAlias($owningClass->primaryTable['name'], $dqlAlias);
} else {
$sqlTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
}
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= ', ' . $sqlTableAlias . '.' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform) . ' AS ' . $columnAlias;
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
}
}
}
}
} else {
// Add foreign key columns to SQL, if necessary
if ($addMetaColumns) {
$sqlTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= ', ' . $sqlTableAlias . '.' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform) . ' AS ' . $columnAlias;
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
}
}
}
}
}
}
......@@ -402,7 +452,7 @@ class SqlWalker implements TreeWalker
$this->_currentRootAlias = $dqlAlias;
$class = $rangeDecl->classMetadata;
$sql .= $this->_conn->quoteIdentifier($class->getTableName()) . ' '
$sql .= $class->getQuotedTableName($this->_platform) . ' '
. $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
if ($class->isInheritanceTypeJoined()) {
......@@ -451,11 +501,11 @@ class SqlWalker implements TreeWalker
$expr = $orderByItem->expression;
$parts = $expr->parts;
$dqlAlias = $expr->identificationVariable;
$qComp = $this->_queryComponents[$dqlAlias];
$columnName = $qComp['metadata']->getColumnName($parts[0]);
$class = $this->_queryComponents[$dqlAlias]['metadata'];
$columnName = $class->getQuotedColumnName($parts[0], $this->_platform);
return $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.'
. $this->_conn->quoteIdentifier($columnName) . ' ' . strtoupper($orderByItem->type);
return $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.'
. $columnName . ' ' . strtoupper($orderByItem->type);
}
/**
......@@ -492,88 +542,84 @@ class SqlWalker implements TreeWalker
$joinAssocPathExpr = $join->joinAssociationPathExpression;
$joinedDqlAlias = $join->aliasIdentificationVariable;
$sourceQComp = $this->_queryComponents[$joinAssocPathExpr->identificationVariable];
$targetQComp = $this->_queryComponents[$joinedDqlAlias];
$targetClass = $targetQComp['metadata'];
$relation = $targetQComp['relation'];
$sourceClass = $this->_queryComponents[$joinAssocPathExpr->identificationVariable]['metadata'];
$targetTableName = $targetQComp['metadata']->getTableName();
$targetTableAlias = $this->getSqlTableAlias($targetTableName, $joinedDqlAlias);
$targetTableName = $targetClass->getQuotedTableName($this->_platform);
$targetTableAlias = $this->getSqlTableAlias($targetClass->getTableName(), $joinedDqlAlias);
$sourceTableAlias = $this->getSqlTableAlias(
$sourceQComp['metadata']->getTableName(), $joinAssocPathExpr->identificationVariable
$sourceClass->getTableName(), $joinAssocPathExpr->identificationVariable
);
// Ensure we got the owning side, since it has all mapping info
if ( ! $targetQComp['relation']->isOwningSide()) {
$assoc = $targetQComp['metadata']->getAssociationMapping($targetQComp['relation']->getMappedByFieldName());
if ( ! $relation->isOwningSide) {
$assoc = $targetClass->associationMappings[$relation->mappedByFieldName];
} else {
$assoc = $targetQComp['relation'];
$assoc = $relation;
}
if ($assoc->isOneToOne()) {
$sql .= $this->_conn->quoteIdentifier($targetTableName) . ' ' . $targetTableAlias . ' ON ';
$joinColumns = $assoc->getSourceToTargetKeyColumns();
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$first = true;
foreach ($joinColumns as $sourceColumn => $targetColumn) {
foreach ($assoc->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
if ( ! $first) {
$sql .= ' AND ';
} else {
$first = false;
}
if ($targetQComp['relation']->isOwningSide()) {
$sql .= $sourceTableAlias . '.' . $this->_conn->quoteIdentifier($sourceColumn)
$quotedSourceColumn = $assoc->getQuotedJoinColumnName($sourceColumn, $this->_platform);
$quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
if ($relation->isOwningSide) {
$sql .= $sourceTableAlias . '.' . $quotedSourceColumn
. ' = '
. $targetTableAlias . '.' . $this->_conn->quoteIdentifier($targetColumn);
. $targetTableAlias . '.' . $quotedTargetColumn;
} else {
$sql .= $sourceTableAlias . '.' . $this->_conn->quoteIdentifier($targetColumn)
$sql .= $sourceTableAlias . '.' . $quotedTargetColumn
. ' = '
. $targetTableAlias . '.' . $this->_conn->quoteIdentifier($sourceColumn);
. $targetTableAlias . '.' . $quotedSourceColumn;
}
}
} else if ($assoc->isManyToMany()) {
// Join relation table
$joinTable = $assoc->getJoinTable();
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
$sql .= $this->_conn->quoteIdentifier($joinTable['name']) . ' ' . $joinTableAlias . ' ON ';
$sql .= $assoc->getQuotedJoinTableName($this->_platform) . ' ' . $joinTableAlias . ' ON ';
if ($targetQComp['relation']->isOwningSide) {
$sourceToRelationJoinColumns = $assoc->getSourceToRelationKeyColumns();
foreach ($sourceToRelationJoinColumns as $sourceColumn => $relationColumn) {
$sql .= $sourceTableAlias . '.' . $this->_conn->quoteIdentifier($sourceColumn)
if ($relation->isOwningSide) {
foreach ($assoc->sourceToRelationKeyColumns as $sourceColumn => $relationColumn) {
$sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceColumn, $this->_platform)
. ' = '
. $joinTableAlias . '.' . $this->_conn->quoteIdentifier($relationColumn);
. $joinTableAlias . '.' . $assoc->getQuotedJoinColumnName($relationColumn, $this->_platform);
}
} else {
$targetToRelationJoinColumns = $assoc->getTargetToRelationKeyColumns();
foreach ($targetToRelationJoinColumns as $targetColumn => $relationColumn) {
$sql .= $sourceTableAlias . '.' . $this->_conn->quoteIdentifier($targetColumn)
foreach ($assoc->targetToRelationKeyColumns as $targetColumn => $relationColumn) {
$sql .= $sourceTableAlias . '.' . $targetClass->getQuotedColumnName($targetColumn, $this->_platform)
. ' = '
. $joinTableAlias . '.' . $this->_conn->quoteIdentifier($relationColumn);
. $joinTableAlias . '.' . $assoc->getQuotedJoinColumnName($relationColumn, $this->_platform);
}
}
// Join target table
$sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
? ' LEFT JOIN ' : ' INNER JOIN ';
$sql .= $this->_conn->quoteIdentifier($targetTableName) . ' ' . $targetTableAlias . ' ON ';
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
if ($targetQComp['relation']->isOwningSide) {
$targetToRelationJoinColumns = $assoc->getTargetToRelationKeyColumns();
foreach ($targetToRelationJoinColumns as $targetColumn => $relationColumn) {
$sql .= $targetTableAlias . '.' . $this->_conn->quoteIdentifier($targetColumn)
if ($relation->isOwningSide) {
foreach ($assoc->targetToRelationKeyColumns as $targetColumn => $relationColumn) {
$sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetColumn, $this->_platform)
. ' = '
. $joinTableAlias . '.' . $this->_conn->quoteIdentifier($relationColumn);
. $joinTableAlias . '.' . $assoc->getQuotedJoinColumnName($relationColumn, $this->_platform);
}
} else {
$sourceToRelationJoinColumns = $assoc->getSourceToRelationKeyColumns();
foreach ($sourceToRelationJoinColumns as $sourceColumn => $relationColumn) {
$sql .= $targetTableAlias . '.' . $this->_conn->quoteIdentifier($sourceColumn)
foreach ($assoc->sourceToRelationKeyColumns as $sourceColumn => $relationColumn) {
$sql .= $targetTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceColumn, $this->_platform)
. ' = '
. $joinTableAlias . '.' . $this->_conn->quoteIdentifier($relationColumn);
. $joinTableAlias . '.' . $assoc->getQuotedJoinColumnName($relationColumn, $this->_platform);
}
}
}
......@@ -584,8 +630,8 @@ class SqlWalker implements TreeWalker
$sql .= ' AND ' . $discrSql;
}
if ($targetQComp['metadata']->isInheritanceTypeJoined()) {
$sql .= $this->_generateClassTableInheritanceJoins($targetQComp['metadata'], $joinedDqlAlias);
if ($targetClass->isInheritanceTypeJoined()) {
$sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias);
}
return $sql;
......@@ -616,10 +662,9 @@ class SqlWalker implements TreeWalker
}
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
$columnName = $class->getColumnName($fieldName);
$columnAlias = $this->getSqlColumnAlias($columnName);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($columnName)
. ' AS ' . $columnAlias;
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
$columnAlias = $this->getSqlColumnAlias($class->columnNames[$fieldName]);
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
} else {
......@@ -662,7 +707,6 @@ class SqlWalker implements TreeWalker
}
$beginning = true;
if ($class->isInheritanceTypeJoined()) {
// Select all fields from the queried class
foreach ($class->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited'])) {
......@@ -675,7 +719,7 @@ class SqlWalker implements TreeWalker
$sqlTableAlias = $this->getSqlTableAlias($tableName, $dqlAlias);
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName'])
$sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
......@@ -694,57 +738,12 @@ class SqlWalker implements TreeWalker
$sqlTableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName'])
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
}
}
} else {
$fieldMappings = $class->fieldMappings;
foreach ($class->subClasses as $subclassName) {
$fieldMappings = array_merge(
$fieldMappings,
$this->_em->getClassMetadata($subclassName)->fieldMappings
);
}
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
foreach ($fieldMappings as $fieldName => $mapping) {
if ($beginning) $beginning = false; else $sql .= ', ';
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName'])
. ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
}
// Append foreign keys if necessary.
//FIXME: Evaluate HINT_INCLUDE_META_COLUMNS
//FIXME: Needs to be done in the case of Class Table Inheritance, too
// (see upper block of the if/else)
if (
! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)
) {
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= ', ' . $sqlTableAlias . '.'
. $this->_conn->quoteIdentifier($srcColumn)
. ' AS ' . $columnAlias;
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
}
}
}
}
}
}
return $sql;
......@@ -798,7 +797,7 @@ class SqlWalker implements TreeWalker
$rangeDecl = $firstIdentificationVarDecl->rangeVariableDeclaration;
$tblName = $rangeDecl->classMetadata->getTableName();
$sql = ' FROM ' . $this->_conn->quoteIdentifier($tblName) . ' '
$sql = ' FROM ' . $rangeDecl->classMetadata->getQuotedTableName($this->_platform) . ' '
. $this->getSqlTableAlias($tblName, $rangeDecl->aliasIdentificationVariable);
foreach ($firstIdentificationVarDecl->joinVariableDeclarations as $joinVarDecl) {
......@@ -848,7 +847,7 @@ class SqlWalker implements TreeWalker
// in a subquery?
$class = $this->_queryComponents[$expr]['metadata'];
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName(), $expr) . '.'
. $this->_conn->quoteIdentifier($class->getColumnName($class->identifier[0]));
. $class->getQuotedColumnName($class->identifier[0], $this->_platform);
}
return $sql;
......@@ -868,11 +867,11 @@ class SqlWalker implements TreeWalker
$fieldName = $parts[0];
$qComp = $this->_queryComponents[$dqlAlias];
$columnName = $qComp['metadata']->getColumnName($fieldName);
$columnName = $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform);
return $aggExpression->functionName . '(' . ($aggExpression->isDistinct ? 'DISTINCT ' : '')
. $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.'
. $this->_conn->quoteIdentifier($columnName) . ')';
. $columnName . ')';
}
/**
......@@ -899,10 +898,9 @@ class SqlWalker implements TreeWalker
$parts = $pathExpr->parts;
$dqlAlias = $pathExpr->identificationVariable;
$qComp = $this->_queryComponents[$dqlAlias];
$columnName = $qComp['metadata']->getColumnName($parts[0]);
$columnName = $qComp['metadata']->getQuotedColumnName($parts[0], $this->_platform);
return $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.'
. $this->_conn->quoteIdentifier($columnName);
return $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
}
/**
......@@ -915,7 +913,7 @@ class SqlWalker implements TreeWalker
{
$sql = 'DELETE FROM ';
$class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
$sql .= $this->_conn->quoteIdentifier($class->getTableName());
$sql .= $class->getQuotedTableName($this->_platform);
if ($this->_useSqlTableAliases) {
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName());
......@@ -936,7 +934,7 @@ class SqlWalker implements TreeWalker
{
$sql = 'UPDATE ';
$class = $this->_em->getClassMetadata($updateClause->abstractSchemaName);
$sql .= $this->_conn->quoteIdentifier($class->getTableName());
$sql .= $class->getQuotedTableName($this->_platform);
if ($this->_useSqlTableAliases) {
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName());
......@@ -970,7 +968,7 @@ class SqlWalker implements TreeWalker
$sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName()) . '.';
}
$sql .= $this->_conn->quoteIdentifier($qComp['metadata']->getColumnName($updateItem->field)) . ' = ';
$sql .= $qComp['metadata']->getQuotedColumnName($updateItem->field, $this->_platform) . ' = ';
$newValue = $updateItem->newValue;
......@@ -1041,7 +1039,8 @@ class SqlWalker implements TreeWalker
$sql .= $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.';
}
$sql .= $this->_conn->quoteIdentifier($discrColumn['name']) . ' IN (' . implode(', ', $values) . ')';
$sql .= $class->getQuotedDiscriminatorColumnName($this->_platform) .
' IN (' . implode(', ', $values) . ')';
}
}
......@@ -1133,7 +1132,7 @@ class SqlWalker implements TreeWalker
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$sql .= $this->_conn->quoteIdentifier($targetClass->primaryTable['name'])
$sql .= $targetClass->getQuotedTableName($this->_platform)
. ' ' . $targetTableAlias . ' WHERE ';
$owningAssoc = $targetClass->associationMappings[$assoc->mappedByFieldName];
......@@ -1143,9 +1142,9 @@ class SqlWalker implements TreeWalker
foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $sourceTableAlias . '.' . $this->_conn->quoteIdentifier($targetColumn)
$sql .= $sourceTableAlias . '.' . $class->getQuotedColumnName($targetColumn, $this->_platform)
. ' = '
. $targetTableAlias . '.' . $this->_conn->quoteIdentifier($sourceColumn);
. $targetTableAlias . '.' . $owningAssoc->getQuotedJoinColumnName($sourceColumn, $this->_platform);
}
$sql .= ' AND ';
......@@ -1156,35 +1155,38 @@ class SqlWalker implements TreeWalker
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= $targetTableAlias . '.'
. $this->_conn->quoteIdentifier($targetClass->columnNames[$idField]) . ' = ?';
. $targetClass->getQuotedColumnName($idField, $this->_platform) . ' = ?';
}
} else { // many-to-many
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$joinTable = $assoc->isOwningSide
? $assoc->joinTable
: $targetClass->associationMappings[$assoc->mappedByFieldName]->joinTable;
$owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedByFieldName];
$joinTable = $assoc->isOwningSide ? $assoc->joinTable : $owningAssoc->joinTable;
// SQL table aliases
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
// join to target table
$sql .= $this->_conn->quoteIdentifier($joinTable['name'])
$sql .= $assoc->getQuotedJoinTableName($this->_platform)
. ' ' . $joinTableAlias . ' INNER JOIN '
. $this->_conn->quoteIdentifier($targetClass->primaryTable['name'])
. $targetClass->getQuotedTableName($this->_platform)
. ' ' . $targetTableAlias . ' ON ';
// join conditions
$joinColumns = $assoc->isOwningSide
? $joinTable['joinColumns']
: $joinTable['inverseJoinColumns'];
$first = true;
$referencedColumnClass = $assoc->isOwningSide ? $class : $targetClass;
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $joinTableAlias . '.' . $this->_conn->quoteIdentifier($joinColumn['name'])
$sql .= $joinTableAlias . '.' . $owningAssoc->getQuotedJoinColumnName($joinColumn['name'], $this->_platform)
. ' = '
. $sourceTableAlias . '.' . $this->_conn->quoteIdentifier($joinColumn['referencedColumnName']);
. $sourceTableAlias . '.' . $referencedColumnClass->getQuotedColumnName($joinColumn['referencedColumnName'], $this->_platform);
}
$sql .= ' WHERE ';
......@@ -1192,14 +1194,14 @@ class SqlWalker implements TreeWalker
$joinColumns = $assoc->isOwningSide
? $joinTable['inverseJoinColumns']
: $joinTable['joinColumns'];
$first = true;
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $joinTableAlias . '.' . $this->_conn->quoteIdentifier($joinColumn['name'])
$sql .= $joinTableAlias . '.' . $owningAssoc->getQuotedJoinColumnName($joinColumn['name'], $this->_platform)
. ' = '
. $targetTableAlias . '.' . $this->_conn->quoteIdentifier($joinColumn['referencedColumnName']);
. $targetTableAlias . '.' . $referencedColumnClass->getQuotedColumnName($joinColumn['referencedColumnName'], $this->_platform);
}
$sql .= ' AND ';
......@@ -1210,7 +1212,7 @@ class SqlWalker implements TreeWalker
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= $targetTableAlias . '.'
. $this->_conn->quoteIdentifier($targetClass->columnNames[$idField]) . ' = ?';
. $targetClass->getQuotedColumnName($idField, $this->_platform) . ' = ?';
}
}
......@@ -1503,11 +1505,10 @@ class SqlWalker implements TreeWalker
if (isset($class->associationMappings[$fieldName])) {
//FIXME: Inverse side support
//FIXME: Throw exception on composite key
$sql .= $this->_conn->quoteIdentifier(
$class->associationMappings[$fieldName]->joinColumns[0]['name']
);
$assoc = $class->associationMappings[$fieldName];
$sql .= $assoc->getQuotedJoinColumnName($assoc->joinColumns[0]['name'], $this->_platform);
} else {
$sql .= $this->_conn->quoteIdentifier($class->getColumnName($fieldName));
$sql .= $class->getQuotedColumnName($fieldName, $this->_platform);
}
} else if ($pathExprType == AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) {
throw DoctrineException::updateMe("Not yet implemented.");
......
......@@ -113,7 +113,8 @@ class SchemaTool
// Add all non-inherited fields as columns
foreach ($class->fieldMappings as $fieldName => $mapping) {
if ( ! isset($mapping['inherited'])) {
$columns[$mapping['columnName']] = $this->_gatherColumn($class, $mapping, $options);
$columnName = $class->getQuotedColumnName($mapping['columnName'], $this->_platform);
$columns[$columnName] = $this->_gatherColumn($class, $mapping, $options);
}
}
......@@ -128,17 +129,16 @@ class SchemaTool
$idMapping = $class->fieldMappings[$class->identifier[0]];
$idColumn = $this->_gatherColumn($class, $idMapping, $options);
unset($idColumn['autoincrement']);
$columns[$idMapping['columnName']] = $idColumn;
$columns[$idColumn['name']] = $idColumn;
// Add a FK constraint on the ID column
$constraint = array();
$constraint['tableName'] = $class->getTableName();
$constraint['foreignTable'] = $this->_em->getClassMetadata($class->rootEntityName)->getTableName();
$constraint['local'] = array($idMapping['columnName']);
$constraint['foreign'] = array($idMapping['columnName']);
$constraint['tableName'] = $class->getQuotedTableName($this->_platform);
$constraint['foreignTable'] = $this->_em->getClassMetadata($class->rootEntityName)->getQuotedTableName($this->_platform);
$constraint['local'] = array($idColumn['name']);
$constraint['foreign'] = array($idColumn['name']);
$constraint['onDelete'] = 'CASCADE';
$foreignKeyConstraints[] = $constraint;
}
} else if ($class->isInheritanceTypeTablePerClass()) {
//TODO
} else {
......@@ -146,7 +146,8 @@ class SchemaTool
$this->_gatherRelationsSql($class, $sql, $columns, $foreignKeyConstraints);
}
$sql = array_merge($sql, $this->_platform->getCreateTableSql($class->getTableName(), $columns, $options));
$sql = array_merge($sql, $this->_platform->getCreateTableSql(
$class->getQuotedTableName($this->_platform), $columns, $options));
$processedClasses[$class->name] = true;
if ($class->isIdGeneratorSequence() && $class->name == $class->rootEntityName) {
......@@ -162,7 +163,7 @@ class SchemaTool
// Append the foreign key constraints SQL
if ($this->_platform->supportsForeignKeyConstraints()) {
foreach ($foreignKeyConstraints as $fkConstraint) {
$sql = array_merge($sql, (array)$this->_platform->getCreateForeignKeySql($fkConstraint['tableName'], $fkConstraint));
$sql = array_merge($sql, (array) $this->_platform->getCreateForeignKeySql($fkConstraint['tableName'], $fkConstraint));
}
}
......@@ -176,7 +177,7 @@ class SchemaTool
{
$discrColumn = $class->discriminatorColumn;
return array(
'name' => $discrColumn['name'],
'name' => $class->getQuotedDiscriminatorColumnName($this->_platform),
'type' => Type::getType($discrColumn['type']),
'length' => $discrColumn['length'],
'notnull' => true
......@@ -194,7 +195,8 @@ class SchemaTool
{
$columns = array();
foreach ($class->fieldMappings as $fieldName => $mapping) {
$columns[$mapping['columnName']] = $this->_gatherColumn($class, $mapping, $options);
$column = $this->_gatherColumn($class, $mapping, $options);
$columns[$column['name']] = $column;
}
return $columns;
......@@ -203,7 +205,7 @@ class SchemaTool
private function _gatherColumn($class, array $mapping, array &$options)
{
$column = array();
$column['name'] = $mapping['columnName'];
$column['name'] = $class->getQuotedColumnName($mapping['columnName'], $this->_platform);
$column['type'] = Type::getType($mapping['type']);
$column['length'] = $mapping['length'];
$column['notnull'] = ! $mapping['nullable'];
......@@ -231,16 +233,16 @@ class SchemaTool
$foreignClass = $this->_em->getClassMetadata($mapping->targetEntityName);
if ($mapping->isOneToOne() && $mapping->isOwningSide) {
$constraint = array();
$constraint['tableName'] = $class->getTableName();
$constraint['foreignTable'] = $foreignClass->getTableName();
$constraint['tableName'] = $class->getQuotedTableName($this->_platform);
$constraint['foreignTable'] = $foreignClass->getQuotedTableName($this->_platform);
$constraint['local'] = array();
$constraint['foreign'] = array();
foreach ($mapping->getJoinColumns() as $joinColumn) {
$column = array();
$column['name'] = $joinColumn['name'];
$column['name'] = $mapping->getQuotedJoinColumnName($joinColumn['name'], $this->_platform);
$column['type'] = Type::getType($foreignClass->getTypeOfColumn($joinColumn['referencedColumnName']));
$columns[$joinColumn['name']] = $column;
$constraint['local'][] = $joinColumn['name'];
$columns[$column['name']] = $column;
$constraint['local'][] = $column['name'];
$constraint['foreign'][] = $joinColumn['referencedColumnName'];
}
$constraints[] = $constraint;
......@@ -253,8 +255,8 @@ class SchemaTool
$joinTableOptions = array();
$joinTable = $mapping->getJoinTable();
$constraint1 = array(
'tableName' => $joinTable['name'],
'foreignTable' => $class->getTableName(),
'tableName' => $mapping->getQuotedJoinTableName($this->_platform),
'foreignTable' => $class->getQuotedTableName($this->_platform),
'local' => array(),
'foreign' => array()
);
......@@ -262,17 +264,17 @@ class SchemaTool
$column = array();
$column['primary'] = true;
$joinTableOptions['primary'][] = $joinColumn['name'];
$column['name'] = $joinColumn['name'];
$column['name'] = $mapping->getQuotedJoinColumnName($joinColumn['name'], $this->_platform);
$column['type'] = Type::getType($class->getTypeOfColumn($joinColumn['referencedColumnName']));
$joinTableColumns[$joinColumn['name']] = $column;
$constraint1['local'][] = $joinColumn['name'];
$joinTableColumns[$column['name']] = $column;
$constraint1['local'][] = $column['name'];
$constraint1['foreign'][] = $joinColumn['referencedColumnName'];
}
$constraints[] = $constraint1;
$constraint2 = array();
$constraint2['tableName'] = $joinTable['name'];
$constraint2['foreignTable'] = $foreignClass->getTableName();
$constraint2['tableName'] = $mapping->getQuotedJoinTableName($this->_platform);
$constraint2['foreignTable'] = $foreignClass->getQuotedTableName($this->_platform);
$constraint2['local'] = array();
$constraint2['foreign'] = array();
foreach ($joinTable['inverseJoinColumns'] as $inverseJoinColumn) {
......@@ -289,7 +291,8 @@ class SchemaTool
$constraints[] = $constraint2;
$sql = array_merge($sql, $this->_platform->getCreateTableSql(
$joinTable['name'], $joinTableColumns, $joinTableOptions));
$mapping->getQuotedJoinTableName($this->_platform), $joinTableColumns, $joinTableOptions)
);
}
}
}
......
......@@ -1924,4 +1924,23 @@ class UnitOfWork implements PropertyChangedListener
$this->_entityUpdates[$oid] = $entity;
}
}
public function dump()
{
var_dump($this->_identityMap);
var_dump($this->_entityIdentifiers);
var_dump($this->_originalEntityData);
var_dump($this->_entityChangeSets);
var_dump($this->_entityStates);
var_dump($this->_scheduledForDirtyCheck);
var_dump($this->_entityInsertions);
var_dump($this->_entityUpdates);
var_dump($this->_entityDeletions);
var_dump($this->_collectionDeletions);
//$this->_collectionCreations =
var_dump($this->_collectionUpdates);
var_dump($this->_orphanRemovals);
//var_dump($this->_commitOrderCalculator->clear();
}
}
......@@ -60,7 +60,7 @@ class MsSqlPlatformTest extends \Doctrine\Tests\DbalTestCase
public function testGeneratesSqlSnippets()
{
$this->assertEquals('RLIKE', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct');
$this->assertEquals('`', $this->_platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct');
$this->assertEquals('"', $this->_platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct');
$this->assertEquals('RAND()', $this->_platform->getRandomExpression(), 'Random function is not correct');
$this->assertEquals('(column1 + column2 + column3)', $this->_platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct');
$this->assertEquals('CHARACTER SET utf8', $this->_platform->getCharsetFieldDeclaration('utf8'), 'Charset declaration is not correct');
......
......@@ -40,30 +40,4 @@ class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase
$persister->load(array('customer_id' => $customer->getId()), $newCart);
$this->assertEquals('Credit card', $newCart->getPayment());
}
public function testAcceptsJoinTableAsCriteria()
{
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$cart = new ECommerceCart();
$product = new ECommerceProduct();
$product->setName('Star Wars: A New Hope');
$cart->addProduct($product);
$this->_em->persist($cart);
$this->_em->flush();
$this->_em->clear();
unset($product);
$persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$newProduct = new ECommerceProduct();
$criteria = array(
array(
'table' => 'ecommerce_carts_products',
'join' => array('id' => 'product_id'),
'criteria' => array('cart_id' => $cart->getId())
)
);
$persister->load($criteria, $newProduct);
$this->assertEquals('Star Wars: A New Hope', $newProduct->getName());
}
}
......@@ -104,11 +104,8 @@ class ArrayHydratorTest extends HydrationTestCase
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
);
'Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p',
'u', 'phonenumbers');
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('sclr0', 'nameUpper');
......@@ -219,7 +216,7 @@ class ArrayHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -294,13 +291,13 @@ class ArrayHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle',
'a',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles')
'articles'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -414,19 +411,19 @@ class ArrayHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle',
'a',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles')
'articles'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsComment',
'c',
'a',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle')->getAssociationMapping('comments')
'comments'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -571,7 +568,7 @@ class ArrayHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\Forum\ForumBoard',
'b',
'c',
$this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory')->getAssociationMapping('boards')
'boards'
);
$rsm->addFieldResult('c', 'c__id', 'id');
$rsm->addFieldResult('c', 'c__position', 'position');
......
......@@ -159,7 +159,7 @@ class ObjectHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -280,7 +280,7 @@ class ObjectHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -359,13 +359,13 @@ class ObjectHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle',
'a',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles')
'articles'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -474,19 +474,19 @@ class ObjectHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle',
'a',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('articles')
'articles'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsComment',
'c',
'a',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle')->getAssociationMapping('comments')
'comments'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -625,7 +625,7 @@ class ObjectHydratorTest extends HydrationTestCase
'Doctrine\Tests\Models\Forum\ForumBoard',
'b',
'c',
$this->_em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumCategory')->getAssociationMapping('boards')
'boards'
);
$rsm->addFieldResult('c', 'c__id', 'id');
$rsm->addFieldResult('c', 'c__position', 'position');
......
......@@ -90,7 +90,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......@@ -218,7 +218,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
......
......@@ -29,8 +29,8 @@ class InsertPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$this->setMaxRunningTime(10);
//$mem = memory_get_usage();
//echo "Memory usage before: " . ($mem / 1024) . " KB" . PHP_EOL;
//echo "Memory usage before: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;
$batchSize = 20;
for ($i=1; $i<=10000; ++$i) {
$user = new CmsUser;
......@@ -43,8 +43,9 @@ class InsertPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$this->_em->clear();
}
}
//$memAfter = memory_get_usage();
//echo "Memory usage after: " . ($memAfter / 1024) . " KB" . PHP_EOL;
//gc_collect_cycles();
//echo "Memory usage after: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL;
$e = microtime(true);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment