Commit 354ede1e authored by romanb's avatar romanb

[2.0][DDC-354][DDC-425] Fixed. Encapsulated SQL logging better in the DBAL....

[2.0][DDC-354][DDC-425] Fixed. Encapsulated SQL logging better in the DBAL. Added binding types to DBAL mapping types as well as using these binding types in the persisters. Query and NativeQuery now support PDO binding types as well as DBAL mapping types when binding parameters.
parent 70141886
# Upgrade from 2.0-ALPHA4 to 2.0-BETA1
## New inversedBy attribute
It is now *mandatory* that the owning side of a bidirectional association specifies the
'inversedBy' attribute that points to the name of the field on the inverse side that completes
the association. Example:
[php]
// BEFORE (ALPHA4 AND EARLIER)
class User
{
//...
/** @OneToOne(targetEntity="Address", mappedBy="user") */
private $address;
//...
}
class Address
{
//...
/** @OneToOne(targetEntity="User") */
private $address;
//...
}
// SINCE BETA1
// User class DOES NOT CHANGE
class Address
{
//...
/** @OneToOne(targetEntity="User", inversedBy="address") */
private $user;
//...
}
Thus, the inversedBy attribute is the counterpart to the mappedBy attribute. This change
was necessary to enable some simplifications and further performance improvements. We
apologize for the inconvenience.
## Default Property for Field Mappings
The "default" option for database column defaults has been removed. If desired, database column defaults can
......
......@@ -43,10 +43,18 @@ class EventArgs
* @static
*/
private static $_emptyEventArgsInstance;
/**
* Gets the single, empty EventArgs instance.
*
* Gets the single, empty and immutable EventArgs instance.
*
* This instance will be used when events are dispatched without any parameter,
* like this: EventManager::dispatchEvent('eventname');
*
* The benefit from this is that only one empty instance is instantiated and shared
* (otherwise there would be instances for every dispatched in the abovementioned form)
*
* @see EventManager::dispatchEvent
* @link http://msdn.microsoft.com/en-us/library/system.eventargs.aspx
* @static
* @return EventArgs
*/
......@@ -55,7 +63,7 @@ class EventArgs
if ( ! self::$_emptyEventArgsInstance) {
self::$_emptyEventArgsInstance = new EventArgs;
}
return self::$_emptyEventArgsInstance;
}
}
}
......@@ -33,7 +33,6 @@ use Doctrine\DBAL\Types\Type;
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*
* @internal When adding a new configuration option just write a getter/setter
* pair and add the option to the _attributes array with a proper default value.
*/
......@@ -61,6 +60,7 @@ class Configuration
* Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled.
*
* @param SqlLogger $logger
* @todo Rename to setSQLLogger()
*/
public function setSqlLogger($logger)
{
......@@ -71,6 +71,7 @@ class Configuration
* Gets the SQL logger that is used.
*
* @return SqlLogger
* @todo Rename to getSQLLogger()
*/
public function getSqlLogger()
{
......
......@@ -21,7 +21,11 @@
namespace Doctrine\DBAL;
use Doctrine\Common\EventManager,
use PDO, Closure,
Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Driver\Statement as DriverStatement,
Doctrine\DBAL\Driver\Connection as DriverConnection,
Doctrine\Common\EventManager,
Doctrine\DBAL\DBALException;
/**
......@@ -39,7 +43,7 @@ use Doctrine\Common\EventManager,
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (MDB2 library)
*/
class Connection
class Connection implements DriverConnection
{
/**
* Constant for transaction isolation level READ UNCOMMITTED.
......@@ -61,15 +65,6 @@ class Connection
*/
const TRANSACTION_SERIALIZABLE = 4;
/**
* Derived PDO constants
*/
const FETCH_ASSOC = 2;
const FETCH_BOTH = 4;
//const FETCH_COLUMN = 7; Apparently not used.
const FETCH_NUM = 3;
const ATTR_AUTOCOMMIT = 0;
/**
* The wrapped driver connection.
*
......@@ -78,15 +73,11 @@ class Connection
protected $_conn;
/**
* The Configuration.
*
* @var Doctrine\DBAL\Configuration
*/
protected $_config;
/**
* The EventManager.
*
* @var Doctrine\Common\EventManager
*/
protected $_eventManager;
......@@ -308,7 +299,7 @@ class Connection
$this->_isConnected = true;
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new \Doctrine\DBAL\Event\ConnectionEventArgs($this);
$eventArgs = new Event\ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
......@@ -326,7 +317,7 @@ class Connection
*/
public function fetchRow($statement, array $params = array())
{
return $this->execute($statement, $params)->fetch(Connection::FETCH_ASSOC);
return $this->execute($statement, $params)->fetch(PDO::FETCH_ASSOC);
}
/**
......@@ -339,7 +330,7 @@ class Connection
*/
public function fetchArray($statement, array $params = array())
{
return $this->execute($statement, $params)->fetch(Connection::FETCH_NUM);
return $this->execute($statement, $params)->fetch(PDO::FETCH_NUM);
}
/**
......@@ -367,20 +358,30 @@ class Connection
}
/**
* Deletes table row(s) matching the specified identifier.
* Checks whether a transaction is currently active.
*
* @return boolean TRUE if a transaction is currently active, FALSE otherwise.
*/
public function isTransactionActive()
{
return $this->_transactionNestingLevel > 0;
}
/**
* Executes an SQL DELETE statement on a table.
*
* @param string $table The table to delete data from.
* @param array $identifier An associateve array containing identifier fieldname-value pairs.
* @return integer The number of affected rows
* @param string $table The name of the table on which to delete.
* @param array $identifier The deletion criteria. An associateve array containing column-value pairs.
* @return integer The number of affected rows.
*/
public function delete($tableName, array $identifier)
{
$this->connect();
$criteria = array();
foreach (array_keys($identifier) as $id) {
$criteria[] = $id . ' = ?';
foreach (array_keys($identifier) as $columnName) {
$criteria[] = $columnName . ' = ?';
}
$query = 'DELETE FROM ' . $tableName . ' WHERE ' . implode(' AND ', $criteria);
......@@ -423,24 +424,16 @@ class Connection
}
/**
* Updates table row(s) with specified data
* Executes an SQL UPDATE statement on a table.
*
* @throws Doctrine\DBAL\ConnectionException if something went wrong at the database level
* @param string $table The table to insert data into
* @param array $values An associateve array containing column-value pairs.
* @return mixed boolean false if empty value array was given,
* otherwise returns the number of affected rows
* @param string $table The name of the table to update.
* @param array $identifier The update criteria. An associative array containing column-value pairs.
* @return integer The number of affected rows.
*/
public function update($tableName, array $data, array $identifier)
{
$this->connect();
if (empty($data)) {
return false;
}
$set = array();
foreach ($data as $columnName => $value) {
$set[] = $columnName . ' = ?';
}
......@@ -457,39 +450,34 @@ class Connection
/**
* Inserts a table row with specified data.
*
* @param string $table The table to insert data into.
* @param array $fields An associateve array containing fieldname-value pairs.
* @return mixed boolean false if empty value array was given,
* otherwise returns the number of affected rows
* @param string $table The name of the table to insert data into.
* @param array $data An associative array containing column-value pairs.
* @return integer The number of affected rows.
*/
public function insert($tableName, array $data)
{
$this->connect();
if (empty($data)) {
return false;
}
// column names are specified as array keys
$cols = array();
$a = array();
$placeholders = array();
foreach ($data as $columnName => $value) {
$cols[] = $columnName;
$a[] = '?';
$placeholders[] = '?';
}
$query = 'INSERT INTO ' . $tableName
. ' (' . implode(', ', $cols) . ')'
. ' VALUES (' . implode(', ', $a) . ')';
. ' VALUES (' . implode(', ', $placeholders) . ')';
return $this->executeUpdate($query, array_values($data));
}
/**
* Set the charset on the current connection
* Sets the given charset on the current connection.
*
* @param string charset
* @param string $charset The charset to set.
*/
public function setCharset($charset)
{
......@@ -502,12 +490,12 @@ class Connection
*
* Delimiting style depends on the underlying database platform that is being used.
*
* NOTE: Just because you CAN use delimited identifiers doesn't mean
* you SHOULD use them. In general, they end up causing way more
* NOTE: Just because you CAN use quoted identifiers does not mean
* you SHOULD use them. In general, they end up causing way more
* problems than they solve.
*
* @param string $str identifier name to be quoted
* @return string quoted identifier string
* @param string $str The name to be quoted.
* @return string The quoted name.
*/
public function quoteIdentifier($str)
{
......@@ -517,9 +505,9 @@ class Connection
/**
* Quotes a given input parameter.
*
* @param mixed $input Parameter to be quoted.
* @param string $type Type of the parameter.
* @return string The quoted parameter.
* @param mixed $input Parameter to be quoted.
* @param string $type Type of the parameter.
* @return string The quoted parameter.
*/
public function quote($input, $type = null)
{
......@@ -537,106 +525,146 @@ class Connection
*/
public function fetchAll($sql, array $params = array())
{
return $this->execute($sql, $params)->fetchAll(Connection::FETCH_ASSOC);
return $this->execute($sql, $params)->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Prepares an SQL statement.
*
* @param string $statement The SQL statement to prepare.
* @return Statement The prepared statement.
* @return Doctrine\DBAL\Driver\Statement The prepared statement.
*/
public function prepare($statement)
{
$this->connect();
return $this->_conn->prepare($statement);
return new Statement($statement, $this);
}
/**
* Prepares and executes an SQL query.
* Executes an, optionally parameterized, SQL query.
*
* @param string $query The SQL query to prepare and execute.
* @param array $params The parameters, if any.
* @return Statement The prepared and executed statement.
* If the query is parameterized, a prepared statement is used.
* If an SQLLogger is configured, the execution is logged.
*
* @param string $query The SQL query to execute.
* @param array $params The parameters to bind to the query, if any.
* @return Doctrine\DBAL\Driver\Statement The executed statement.
* @todo Rename to executeQuery ?
* @internal PERF: Directly prepares a driver statement, not a wrapper.
*/
public function execute($query, array $params = array())
public function execute($query, array $params = array(), $types = array())
{
$this->connect();
if ($this->_config->getSqlLogger()) {
$this->_config->getSqlLogger()->logSql($query, $params);
if ($this->_config->getSQLLogger() !== null) {
$this->_config->getSQLLogger()->logSQL($query, $params);
}
if ( ! empty($params)) {
if ($params) {
$stmt = $this->_conn->prepare($query);
$stmt->execute($params);
if ($types) {
$this->_bindTypedValues($stmt, $params, $types);
$stmt->execute();
} else {
$stmt->execute($params);
}
} else {
$stmt = $this->_conn->query($query);
}
return $stmt;
}
/**
* Prepares and executes an SQL query and returns the result, optionally applying a
* transformation on the rows of the result.
* Executes an, optionally parameterized, SQL query and returns the result,
* applying a given projection/transformation function on each row of the result.
*
* @param string $query The SQL query to execute.
* @param array $params The parameters, if any.
* @param Closure $mapper The transformation function that is applied on each row.
* The function receives a single paramater, an array, that
* represents a row of the result set.
* @return mixed The (possibly transformed) result of the query.
* @return mixed The projected result of the query.
*/
public function query($query, array $params = array(), \Closure $mapper = null)
public function project($query, array $params = array(), Closure $function)
{
$result = array();
$stmt = $this->execute($query, $params);
while ($row = $stmt->fetch()) {
if ($mapper === null) {
$result[] = $row;
} else {
$result[] = $mapper($row);
}
$result[] = $function($row);
}
$stmt->closeCursor();
return $result;
}
/**
* Executes an SQL INSERT/UPDATE/DELETE query with the given parameters.
* Executes an SQL statement, returning a result set as a Statement object.
*
* @param string $statement
* @param integer $fetchType
* @return Doctrine\DBAL\Driver\Statement
*/
public function query()
{
return call_user_func_array(array($this->_conn, 'query'), func_get_args());
}
/**
* Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
* and returns the number of affected rows.
*
* This method supports PDO binding types as well as DBAL mapping types.
*
* @param string $query sql query
* @param array $params query parameters
* @return integer
* @param string $query The SQL query.
* @param array $params The query parameters.
* @param array $types The parameter types.
* @return integer The number of affected rows.
* @internal PERF: Directly prepares a driver statement, not a wrapper.
*/
public function executeUpdate($query, array $params = array())
public function executeUpdate($query, array $params = array(), array $types = array())
{
$this->connect();
if ($this->_config->getSqlLogger()) {
$this->_config->getSqlLogger()->logSql($query, $params);
if ($this->_config->getSQLLogger() !== null) {
$this->_config->getSQLLogger()->logSQL($query, $params);
}
if ( ! empty($params)) {
if ($params) {
$stmt = $this->_conn->prepare($query);
$stmt->execute($params);
if ($types) {
$this->_bindTypedValues($stmt, $params, $types);
$stmt->execute();
} else {
$stmt->execute($params);
}
$result = $stmt->rowCount();
} else {
$result = $this->_conn->exec($query);
}
return $result;
}
/**
* Execute an SQL statement and return the number of affected rows.
*
* @param string $statement
* @return integer The number of affected rows.
*/
public function exec($statement)
{
$this->connect();
return $this->_conn->exec($statement);
}
/**
* Returns the current transaction nesting level.
*
* @return integer The nesting level. A value of 0 means theres no active transaction.
* @return integer The nesting level. A value of 0 means there's no active transaction.
*/
public function getTransactionNestingLevel()
{
......@@ -644,26 +672,24 @@ class Connection
}
/**
* Fetch the SQLSTATE associated with the last operation on the database handle
* Fetch the SQLSTATE associated with the last database operation.
*
* @return integer
* @return integer The last error code.
*/
public function errorCode()
{
$this->connect();
return $this->_conn->errorCode();
}
/**
* Fetch extended error information associated with the last operation on the database handle
* Fetch extended error information associated with the last database operation.
*
* @return array
* @return array The last error information.
*/
public function errorInfo()
{
$this->connect();
return $this->_conn->errorInfo();
}
......@@ -672,31 +698,31 @@ class Connection
* depending on the underlying driver.
*
* Note: This method may not return a meaningful or consistent result across different drivers,
* because the underlying database may not even support the notion of auto-increment fields or sequences.
* because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
* columns or sequences.
*
* @param string $table Name of the table into which a new row was inserted.
* @param string $field Name of the field into which a new row was inserted.
* @param string $seqName Name of the sequence object from which the ID should be returned.
* @return string A string representation of the last inserted ID.
*/
public function lastInsertId($seqName = null)
{
$this->connect();
return $this->_conn->lastInsertId($seqName);
}
/**
* Start a transaction by suspending auto-commit mode.
* Starts a transaction by suspending auto-commit mode.
*
* @return void
*/
public function beginTransaction()
{
$this->connect();
if ($this->_transactionNestingLevel == 0) {
$this->_conn->beginTransaction();
}
++$this->_transactionNestingLevel;
}
......@@ -721,15 +747,12 @@ class Connection
if ($this->_transactionNestingLevel == 1) {
$this->_conn->commit();
}
--$this->_transactionNestingLevel;
}
/**
* Cancel any database changes done during a transaction or since a specific
* savepoint that is in progress. This function may only be called when
* auto-committing is disabled, otherwise it will fail. Therefore, a new
* transaction is implicitly started after canceling the pending changes.
* Cancel any database changes done during the current transaction.
*
* this method can be listened with onPreTransactionRollback and onTransactionRollback
* eventlistener methods
......@@ -762,7 +785,7 @@ class Connection
public function getWrappedConnection()
{
$this->connect();
return $this->_conn;
}
......@@ -777,15 +800,15 @@ class Connection
if ( ! $this->_schemaManager) {
$this->_schemaManager = $this->_driver->getSchemaManager($this);
}
return $this->_schemaManager;
}
/**
* Marks the current transaction so that the only possible
* outcome for the transaction to be rolled back.
*
* @throws BadMethodCallException If no transaction is active.
* @throws ConnectionException If no transaction is active.
*/
public function setRollbackOnly()
{
......@@ -794,12 +817,12 @@ class Connection
}
$this->_isRollbackOnly = true;
}
/**
* Check whether the current transaction is marked for rollback only.
*
* @return boolean
* @throws BadMethodCallException If no transaction is active.
* @throws ConnectionException If no transaction is active.
*/
public function getRollbackOnly()
{
......@@ -808,4 +831,86 @@ class Connection
}
return $this->_isRollbackOnly;
}
/**
* Converts a given value to its database representation according to the conversion
* rules of a specific DBAL mapping type.
*
* @param mixed $value The value to convert.
* @param string $type The name of the DBAL mapping type.
* @return mixed The converted value.
*/
public function convertToDatabaseValue($value, $type)
{
return Type::getType($type)->convertToDatabaseValue($value, $this->_platform);
}
/**
* Converts a given value to its PHP representation according to the conversion
* rules of a specific DBAL mapping type.
*
* @param mixed $value The value to convert.
* @param string $type The name of the DBAL mapping type.
* @return mixed The converted type.
*/
public function convertToPHPValue($value, $type)
{
return Type::getType($type)->convertToPHPValue($value, $this->_platform);
}
/**
* Binds a set of parameters, some or all of which are typed with a PDO binding type
* or DBAL mapping type, to a given statement.
*
* @param DriverStatement $stmt The statement to bind the values to.
* @param array $params The map/list of named/positional parameters.
* @param array $types The parameter types (PDO binding types or DBAL mapping types).
*/
private function _bindTypedValues(DriverStatement $stmt, array $params, array $types)
{
// Check whether parameters are positional or named. Mixing is not allowed, just like in PDO.
if (is_int(key($params))) {
// Positional parameters
$typeOffset = isset($types[0]) ? -1 : 0;
$bindIndex = 1;
foreach ($params as $position => $value) {
$typeIndex = $bindIndex + $typeOffset;
if (isset($types[$typeIndex])) {
$type = $types[$typeIndex];
if (is_string($type)) {
$type = Type::getType($type);
}
if ($type instanceof Type) {
$value = $type->convertToDatabaseValue($value, $this->_platform);
$bindingType = $type->getBindingType();
} else {
$bindingType = $type; // PDO::PARAM_* constants
}
$stmt->bindValue($bindIndex, $value, $bindingType);
} else {
$stmt->bindValue($bindIndex, $value);
}
++$bindIndex;
}
} else {
// Named parameters
foreach ($params as $name => $value) {
if (isset($types[$name])) {
$type = $types[$name];
if (is_string($type)) {
$type = Type::getType($type);
}
if ($type instanceof Type) {
$value = $type->convertToDatabaseValue($value, $this->_platform);
$bindingType = $type->getBindingType();
} else {
$bindingType = $type; // PDO::PARAM_* constants
}
$stmt->bindValue($name, $value, $bindingType);
} else {
$stmt->bindValue($name, $value);
}
}
}
}
}
......@@ -46,7 +46,7 @@ interface Driver
public function getName();
/**
* Get the name of the database connected to for this driver instance
* Get the name of the database connected to for this driver.
*
* @param Doctrine\DBAL\Connection $conn
* @return string $database
......
......@@ -25,7 +25,7 @@ namespace Doctrine\DBAL\Driver;
* Connection interface.
* Driver connections must implement this interface.
*
* This resembles the PDO interface.
* This resembles (a subset of) the PDO interface.
*
* @since 2.0
*/
......@@ -33,7 +33,7 @@ interface Connection
{
function prepare($prepareString);
function query();
function quote($input);
function quote($input, $type=\PDO::PARAM_STR);
function exec($statement);
function lastInsertId($name = null);
function beginTransaction();
......
......@@ -21,7 +21,7 @@
namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Connection;
use \PDO;
/**
* The OCI8 implementation of the Statement interface.
......@@ -36,17 +36,31 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
private $_paramCounter = 0;
private static $_PARAM = ':param';
private static $fetchStyleMap = array(
Connection::FETCH_BOTH => OCI_BOTH,
Connection::FETCH_ASSOC => OCI_ASSOC,
Connection::FETCH_NUM => OCI_NUM
PDO::FETCH_BOTH => OCI_BOTH,
PDO::FETCH_ASSOC => OCI_ASSOC,
PDO::FETCH_NUM => OCI_NUM
);
private $_paramMap = array();
/**
* Creates a new OCI8Statement that uses the given connection handle and SQL statement.
*
* @param resource $dbh The connection handle.
* @param string $statement The SQL statement.
*/
public function __construct($dbh, $statement)
{
$this->_sth = oci_parse($dbh, $this->_convertPositionalToNamedPlaceholders($statement));
}
/**
* Oracle does not support positional parameters, hence this method converts all
* positional parameters into artificially named parameters. Note that this conversion
* is not perfect. All question marks (?) in the original statement are treated as
* placeholders and converted to a named parameter.
*
* @param string $statement The SQL statement to convert.
*/
private function _convertPositionalToNamedPlaceholders($statement)
{
$count = 1;
......@@ -55,17 +69,9 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
$statement = substr_replace($statement, ":param$count", $pos, 1);
++$count;
}
return $statement;
}
/**
* {@inheritdoc}
*/
public function bindColumn($column, &$param, $type = null)
{
return oci_define_by_name($this->_sth, strtoupper($column), $param, $type);
}
/**
* {@inheritdoc}
......@@ -78,7 +84,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
/**
* {@inheritdoc}
*/
public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array())
public function bindParam($column, &$variable, $type = null)
{
$column = isset($this->_paramMap[$column]) ? $this->_paramMap[$column] : $column;
......@@ -136,9 +142,9 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
$this->bindValue($key, $val);
}
}
$ret = @oci_execute($this->_sth, OCI_DEFAULT);
if (!$ret) {
if ( ! $ret) {
throw OCI8Exception::fromErrorInfo($this->errorInfo());
}
return $ret;
......@@ -147,7 +153,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
/**
* {@inheritdoc}
*/
public function fetch($fetchStyle = Connection::FETCH_BOTH)
public function fetch($fetchStyle = PDO::FETCH_BOTH)
{
if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
......@@ -159,7 +165,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
/**
* {@inheritdoc}
*/
public function fetchAll($fetchStyle = Connection::FETCH_BOTH)
public function fetchAll($fetchStyle = PDO::FETCH_BOTH)
{
if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
......
......@@ -21,7 +21,7 @@
namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\Connection as DBALConnection;
use \PDO;
/**
* Statement interface.
......@@ -38,18 +38,6 @@ use Doctrine\DBAL\Connection as DBALConnection;
*/
interface Statement
{
/**
* Bind a column to a PHP variable
*
* @param mixed $column Number of the column (1-indexed) or name of the column in the result set.
* If using the column name, be aware that the name should match
* the case of the column, as returned by the driver.
* @param string $param Name of the PHP variable to which the column will be bound.
* @param integer $type Data type of the parameter, specified by the PDO::PARAM_* constants.
* @return boolean Returns TRUE on success or FALSE on failure
*/
function bindColumn($column, &$param, $type = null);
/**
* Binds a value to a corresponding named or positional
* placeholder in the SQL statement that was used to prepare the statement.
......@@ -85,13 +73,9 @@ interface Statement
* @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return
* an INOUT parameter from a stored procedure, use the bitwise OR operator to set the
* PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter.
*
* @param integer $length Length of the data type. To indicate that a parameter is an OUT parameter
* from a stored procedure, you must explicitly set the length.
* @param mixed $driverOptions
* @return boolean Returns TRUE on success or FALSE on failure.
*/
function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array());
function bindParam($column, &$variable, $type = null);
/**
* Closes the cursor, enabling the statement to be executed again.
......@@ -142,7 +126,7 @@ interface Statement
* bound parameters in the SQL statement being executed.
* @return boolean Returns TRUE on success or FALSE on failure.
*/
function execute($params = array());
function execute($params = null);
/**
* fetch
......@@ -171,7 +155,7 @@ interface Statement
*
* @return mixed
*/
function fetch($fetchStyle = DBALConnection::FETCH_BOTH);
function fetch($fetchStyle = PDO::FETCH_BOTH);
/**
* Returns an array containing all of the result set rows
......@@ -185,7 +169,7 @@ interface Statement
*
* @return array
*/
function fetchAll($fetchStyle = DBALConnection::FETCH_BOTH);
function fetchAll($fetchStyle = PDO::FETCH_BOTH);
/**
* fetchColumn
......
......@@ -80,6 +80,7 @@ abstract class AbstractAsset
return substr($columnName, -floor(($maxSize-$postfixLen)/$columnCount - 1));
}, $columnNames);
$parts[] = $postfix;
return trim(implode("_", $parts), '_');
}
}
\ No newline at end of file
......@@ -81,7 +81,7 @@ class SqliteSchemaManager extends AbstractSchemaManager
// fetch primary
$stmt = $this->_conn->execute( "PRAGMA TABLE_INFO ('$tableName')" );
$indexArray = $stmt->fetchAll(\Doctrine\DBAL\Connection::FETCH_ASSOC);
$indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach($indexArray AS $indexColumnRow) {
if($indexColumnRow['pk'] == "1") {
$indexBuffer[] = array(
......@@ -102,7 +102,7 @@ class SqliteSchemaManager extends AbstractSchemaManager
$idx['non_unique'] = $tableIndex['unique']?false:true;
$stmt = $this->_conn->execute( "PRAGMA INDEX_INFO ( '{$keyName}' )" );
$indexArray = $stmt->fetchAll(\Doctrine\DBAL\Connection::FETCH_ASSOC);
$indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach ( $indexArray as $indexColumnRow ) {
$idx['column_name'] = $indexColumnRow['name'];
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL;
use PDO,
Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Driver\Statement as DriverStatement;
/**
* A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support
* for logging, DBAL mapping types, etc.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
class Statement implements DriverStatement
{
/**
* @var string The SQL statement.
*/
private $_sql;
/**
* @var array The bound parameters.
*/
private $_params = array();
/**
* @var Doctrine\DBAL\Driver\Statement The underlying driver statement.
*/
private $_stmt;
/**
* @var Doctrine\DBAL\Platforms\AbstractPlatform The underlying database platform.
*/
private $_platform;
/**
* @var Doctrine\DBAL\Connection The connection this statement is bound to and executed on.
*/
private $_conn;
/**
* Creates a new <tt>Statement</tt> for the given SQL and <tt>Connection</tt>.
*
* @param string $sql The SQL of the statement.
* @param Doctrine\DBAL\Connection The connection on which the statement should be executed.
*/
public function __construct($sql, Connection $conn)
{
$this->_sql = $sql;
$this->_stmt = $conn->getWrappedConnection()->prepare($sql);
$this->_conn = $conn;
$this->_platform = $conn->getDatabasePlatform();
}
/**
* Binds a parameter value to the statement.
*
* The value can optionally be bound with a PDO binding type or a DBAL mapping type.
* If bound with a DBAL mapping type, the binding type is derived from the mapping
* type and the value undergoes the conversion routines of the mapping type before
* being bound.
*
* @param $name The name or position of the parameter.
* @param $value The value of the parameter.
* @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance.
* @return boolean TRUE on success, FALSE on failure.
*/
public function bindValue($name, $value, $type = null)
{
$this->_params[$name] = $value;
if ($type !== null) {
if (is_string($type)) {
$type = Type::getType($type);
}
if ($type instanceof Type) {
$value = $type->convertToDatabaseValue($value, $this->_platform);
$bindingType = $type->getBindingType();
} else {
$bindingType = $type; // PDO::PARAM_* constants
}
return $this->_stmt->bindValue($name, $value, $bindingType);
} else {
return $this->_stmt->bindValue($name, $value);
}
}
/**
* Binds a parameter to a value by reference.
*
* Binding a parameter by reference does not support DBAL mapping types.
*
* @param string $name The name or position of the parameter.
* @param mixed $value The reference to the variable to bind
* @param integer $type The PDO binding type.
* @return boolean TRUE on success, FALSE on failure.
*/
public function bindParam($name, &$var, $type = PDO::PARAM_STR)
{
return $this->_stmt->bindParam($name, $var, $type);
}
/**
* Executes the statement with the currently bound parameters.
*
* @return boolean TRUE on success, FALSE on failure.
*/
public function execute($params = null)
{
if ($this->_conn->getConfiguration()->getSQLLogger()) {
$this->_conn->getConfiguration()->getSQLLogger()->logSQL($this->_sql, $this->_params);
}
$this->_params = array();
return $this->_stmt->execute($params);
}
/**
* Closes the cursor, freeing the database resources used by this statement.
*
* @return boolean TRUE on success, FALSE on failure.
*/
public function closeCursor()
{
return $this->_stmt->closeCursor();
}
/**
* Returns the number of columns in the result set.
*
* @return integer
*/
public function columnCount()
{
return $this->_stmt->columnCount();
}
/**
* Fetches the SQLSTATE associated with the last operation on the statement.
*
* @return string
*/
public function errorCode()
{
return $this->_stmt->errorCode();
}
/**
* Fetches extended error information associated with the last operation on the statement.
*
* @return array
*/
public function errorInfo()
{
return $this->_stmt->errorInfo();
}
/**
* Fetches the next row from a result set.
*
* @param integer $fetchStyle
* @return mixed The return value of this function on success depends on the fetch type.
* In all cases, FALSE is returned on failure.
*/
public function fetch($fetchStyle = PDO::FETCH_BOTH)
{
return $this->_stmt->fetch($fetchStyle);
}
/**
* Returns an array containing all of the result set rows.
*
* @param integer $fetchStyle
* @param integer $columnIndex
* @return array An array containing all of the remaining rows in the result set.
*/
public function fetchAll($fetchStyle = PDO::FETCH_BOTH, $columnIndex = 0)
{
if ($columnIndex != 0) {
return $this->_stmt->fetchAll($fetchStyle, $columnIndex);
}
return $this->_stmt->fetchAll($fetchStyle);
}
/**
* Returns a single column from the next row of a result set.
*
* @param integer $columnIndex
* @return mixed A single column from the next row of a result set or FALSE if there are no more rows.
*/
public function fetchColumn($columnIndex = 0)
{
return $this->_stmt->fetchColumn($columnIndex);
}
/**
* Returns the number of rows affected by the last execution of this statement.
*
* @return integer The number of affected rows.
*/
public function rowCount()
{
return $this->_stmt->rowCount();
}
/**
* Gets the wrapped driver statement.
*
* @return Doctrine\DBAL\Driver\Statement
*/
public function getWrappedStatement()
{
return $this->_stmt;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
......@@ -26,6 +45,6 @@ class ArrayType extends Type
public function getName()
{
return 'Array';
return Type::TARRAY;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Type that maps a database BIGINT to a PHP string.
*
......@@ -12,16 +33,16 @@ class BigIntType extends Type
{
public function getName()
{
return 'BigInteger';
return Type::BIGINT;
}
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getBigIntTypeDeclarationSQL($fieldDeclaration);
}
public function getTypeCode()
public function getBindingType()
{
return self::CODE_INT;
return \PDO::PARAM_INT;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
......@@ -28,6 +47,11 @@ class BooleanType extends Type
public function getName()
{
return 'boolean';
return Type::BOOLEAN;
}
public function getBindingType()
{
return \PDO::PARAM_BOOL;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
......@@ -13,7 +32,7 @@ class DateTimeType extends Type
{
public function getName()
{
return 'DateTime';
return Type::DATETIME;
}
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
......@@ -13,7 +32,7 @@ class DateType extends Type
{
public function getName()
{
return 'Date';
return Type::DATE;
}
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Type that maps an SQL DECIMAL to a PHP double.
*
......@@ -11,15 +32,15 @@ class DecimalType extends Type
{
public function getName()
{
return 'Decimal';
return Type::DECIMAL;
}
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration);
}
public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return (double) $value;
}
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Type that maps an SQL INT to a PHP integer.
*
......@@ -12,21 +33,21 @@ class IntegerType extends Type
{
public function getName()
{
return 'Integer';
return Type::INTEGER;
}
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration);
}
public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return (int) $value;
}
public function getTypeCode()
public function getBindingType()
{
return self::CODE_INT;
return \PDO::PARAM_INT;
}
}
\ No newline at end of file
......@@ -26,6 +26,6 @@ class ObjectType extends Type
public function getName()
{
return 'Object';
return Type::OBJECT;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Type that maps a database SMALLINT to a PHP integer.
*
......@@ -11,21 +32,21 @@ class SmallIntType extends Type
{
public function getName()
{
return "SmallInteger";
return Type::SMALLINT;
}
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration);
}
public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return (int) $value;
}
public function getTypeCode()
public function getBindingType()
{
return self::CODE_INT;
return \PDO::PARAM_INT;
}
}
\ No newline at end of file
......@@ -21,6 +21,8 @@
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Type that maps an SQL VARCHAR to a PHP string.
*
......@@ -29,13 +31,13 @@ namespace Doctrine\DBAL\Types;
class StringType extends Type
{
/** @override */
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
}
/** @override */
public function getDefaultLength(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getDefaultLength(AbstractPlatform $platform)
{
return $platform->getVarcharDefaultLength();
}
......@@ -43,6 +45,6 @@ class StringType extends Type
/** @override */
public function getName()
{
return 'string';
return Type::STRING;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Type that maps an SQL CLOB to a PHP string.
*
......@@ -10,13 +31,13 @@ namespace Doctrine\DBAL\Types;
class TextType extends Type
{
/** @override */
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getClobTypeDeclarationSQL($fieldDeclaration);
}
public function getName()
{
return 'text';
return Type::TEXT;
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Types;
......@@ -13,7 +32,7 @@ class TimeType extends Type
{
public function getName()
{
return 'Time';
return Type::TIME;
}
/**
......@@ -26,19 +45,15 @@ class TimeType extends Type
/**
* {@inheritdoc}
*
* @override
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return ($value !== null)
? $value->format($platform->getTimeFormatString()) : null;
}
/**
* {@inheritdoc}
*
* @override
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
......
......@@ -34,32 +34,36 @@ use Doctrine\DBAL\Platforms\AbstractPlatform,
*/
abstract class Type
{
/* The following constants represent type codes and mirror the PDO::PARAM_X constants
* to decouple ourself from PDO.
*/
const CODE_BOOL = 5;
const CODE_NULL = 0;
const CODE_INT = 1;
const CODE_STR = 2;
const CODE_LOB = 3;
const TARRAY = 'array';
const BIGINT = 'bigint';
const BOOLEAN = 'boolean';
const DATETIME = 'datetime';
const DATE = 'date';
const TIME = 'time';
const DECIMAL = 'decimal';
const INTEGER = 'integer';
const OBJECT = 'object';
const SMALLINT = 'smallint';
const STRING = 'string';
const TEXT = 'text';
/** Map of already instantiated type objects. One instance per type (flyweight). */
private static $_typeObjects = array();
/** The map of supported doctrine mapping types. */
private static $_typesMap = array(
'array' => 'Doctrine\DBAL\Types\ArrayType',
'object' => 'Doctrine\DBAL\Types\ObjectType',
'boolean' => 'Doctrine\DBAL\Types\BooleanType',
'integer' => 'Doctrine\DBAL\Types\IntegerType',
'smallint' => 'Doctrine\DBAL\Types\SmallIntType',
'bigint' => 'Doctrine\DBAL\Types\BigIntType',
'string' => 'Doctrine\DBAL\Types\StringType',
'text' => 'Doctrine\DBAL\Types\TextType',
'datetime' => 'Doctrine\DBAL\Types\DateTimeType',
'date' => 'Doctrine\DBAL\Types\DateType',
'time' => 'Doctrine\DBAL\Types\TimeType',
'decimal' => 'Doctrine\DBAL\Types\DecimalType'
self::TARRAY => 'Doctrine\DBAL\Types\ArrayType',
self::OBJECT => 'Doctrine\DBAL\Types\ObjectType',
self::BOOLEAN => 'Doctrine\DBAL\Types\BooleanType',
self::INTEGER => 'Doctrine\DBAL\Types\IntegerType',
self::SMALLINT => 'Doctrine\DBAL\Types\SmallIntType',
self::BIGINT => 'Doctrine\DBAL\Types\BigIntType',
self::STRING => 'Doctrine\DBAL\Types\StringType',
self::TEXT => 'Doctrine\DBAL\Types\TextType',
self::DATETIME => 'Doctrine\DBAL\Types\DateTimeType',
self::DATE => 'Doctrine\DBAL\Types\DateType',
self::TIME => 'Doctrine\DBAL\Types\TimeType',
self::DECIMAL => 'Doctrine\DBAL\Types\DecimalType'
);
/* Prevent instantiation and force use of the factory method. */
......@@ -117,16 +121,6 @@ abstract class Type
*/
abstract public function getName();
/**
* Gets the type code of this type.
*
* @return integer
*/
public function getTypeCode()
{
return self::CODE_STR;
}
/**
* Factory method to create type instances.
* Type instances are implemented as flyweights.
......@@ -194,6 +188,25 @@ abstract class Type
self::$_typesMap[$name] = $className;
}
/**
* Gets the (preferred) binding type for values of this type that
* can be used when binding parameters to prepared statements.
*
* This method should return one of the PDO::PARAM_* constants, that is, one of:
*
* PDO::PARAM_BOOL
* PDO::PARAM_NULL
* PDO::PARAM_INT
* PDO::PARAM_STR
* PDO::PARAM_LOB
*
* @return integer
*/
public function getBindingType()
{
return \PDO::PARAM_STR;
}
/**
* Get the types array map which holds all registered types and the corresponding
* type class
......
......@@ -19,12 +19,13 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query;
namespace Doctrine\ORM;
use Doctrine\ORM\Query\QueryException;
use Doctrine\DBAL\Types\Type,
Doctrine\ORM\Query\QueryException;
/**
* Base class for Query and NativeQuery.
* Base contract for ORM queries. Base class for Query and NativeQuery.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
......@@ -53,20 +54,19 @@ abstract class AbstractQuery
* Hydrates a single scalar value.
*/
const HYDRATE_SINGLE_SCALAR = 4;
/**
* Hydrates nothing.
* @var array The parameter map of this query.
*/
//const HYDRATE_NONE = 5;
protected $_params = array();
/**
* @var array $params Parameters of this query.
* @var array The parameter type map of this query.
*/
protected $_params = array();
protected $_paramTypes = array();
/**
* The user-specified ResultSetMapping to use.
*
* @var ResultSetMapping
* @var ResultSetMapping The user-specified ResultSetMapping to use.
*/
protected $_resultSetMapping;
......@@ -76,9 +76,7 @@ abstract class AbstractQuery
protected $_em;
/**
* A set of query hints.
*
* @var array
* @var array The map of query hints.
*/
protected $_hints = array();
......@@ -95,16 +93,14 @@ abstract class AbstractQuery
protected $_resultCacheDriver;
/**
* Boolean flag for whether or not to cache the result sets of this query.
* Boolean flag for whether or not to cache the results of this query.
*
* @var boolean
*/
protected $_useResultCache;
/**
* The id to store the result cache entry under.
*
* @var string
* @var string The id to store the result cache entry under.
*/
protected $_resultCacheId;
......@@ -123,9 +119,9 @@ abstract class AbstractQuery
*
* @param Doctrine\ORM\EntityManager $entityManager
*/
public function __construct(\Doctrine\ORM\EntityManager $entityManager)
public function __construct(EntityManager $em)
{
$this->_em = $entityManager;
$this->_em = $em;
}
/**
......@@ -149,13 +145,10 @@ abstract class AbstractQuery
/**
* Get all defined parameters.
*
* @return array Defined parameters
* @return array The defined query parameters.
*/
public function getParameters($params = array())
public function getParameters()
{
if ($params) {
return ($this->_params + $params);
}
return $this->_params;
}
......@@ -177,17 +170,23 @@ abstract class AbstractQuery
*
* @return string SQL query
*/
abstract public function getSql();
abstract public function getSQL();
/**
* Sets a query parameter.
*
* @param string|integer $key The parameter position or name.
* @param mixed $value The parameter value.
* @return Doctrine\ORM\AbstractQuery
* @param string $type The parameter type. If specified, the given value will be run through
* the type conversion of this type. This is usually not needed for
* strings and numeric types.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setParameter($key, $value)
public function setParameter($key, $value, $type = null)
{
if ($type !== null) {
$this->_paramTypes[$key] = $type;
}
$this->_params[$key] = $value;
return $this;
}
......@@ -196,12 +195,17 @@ abstract class AbstractQuery
* Sets a collection of query parameters.
*
* @param array $params
* @return Doctrine\ORM\AbstractQuery
* @param array $types
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setParameters(array $params)
public function setParameters(array $params, array $types = array())
{
foreach ($params as $key => $value) {
$this->setParameter($key, $value);
if (isset($types[$key])) {
$this->setParameter($key, $value, $types[$key]);
} else {
$this->setParameter($key, $value);
}
}
return $this;
}
......@@ -212,7 +216,7 @@ abstract class AbstractQuery
* @param ResultSetMapping $rsm
* @return Doctrine\ORM\AbstractQuery
*/
public function setResultSetMapping($rsm)
public function setResultSetMapping(Query\ResultSetMapping $rsm)
{
$this->_resultSetMapping = $rsm;
return $this;
......@@ -222,12 +226,12 @@ abstract class AbstractQuery
* Defines a cache driver to be used for caching result sets.
*
* @param Doctrine\Common\Cache\Cache $driver Cache driver
* @return Doctrine\ORM\Query\AbstractQuery
* @return Doctrine\ORM\AbstractQuery
*/
public function setResultCacheDriver($resultCacheDriver = null)
{
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
throw \Doctrine\ORM\ORMException::invalidResultCacheDriver();
throw ORMException::invalidResultCacheDriver();
}
$this->_resultCacheDriver = $resultCacheDriver;
if ($resultCacheDriver) {
......@@ -251,9 +255,13 @@ abstract class AbstractQuery
}
/**
* Set whether or not to cache the result sets for this query
* Set whether or not to cache the results of this query and if so, for
* how long and which ID to use for the cache entry.
*
* @param boolean $bool
* @param integer $timeToLive
* @param string $resultCacheId
* @return This query instance.
*/
public function useResultCache($bool, $timeToLive = null, $resultCacheId = null)
{
......@@ -264,13 +272,14 @@ abstract class AbstractQuery
if ($resultCacheId) {
$this->_resultCacheId = $resultCacheId;
}
return $this;
}
/**
* Defines how long the result cache will be active before expire.
*
* @param integer $timeToLive How long the cache entry is valid
* @return Doctrine\ORM\Query\AbstractQuery
* @param integer $timeToLive How long the cache entry is valid.
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheLifetime($timeToLive)
{
......@@ -285,7 +294,7 @@ abstract class AbstractQuery
/**
* Retrieves the lifetime of resultset cache.
*
* @return int
* @return integer
*/
public function getResultCacheLifetime()
{
......@@ -296,7 +305,7 @@ abstract class AbstractQuery
* Defines if the result cache is active or not.
*
* @param boolean $expire Whether or not to force resultset cache expiration.
* @return Doctrine\ORM\Query\AbstractQuery
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function expireResultCache($expire = true)
{
......@@ -307,7 +316,7 @@ abstract class AbstractQuery
/**
* Retrieves if the resultset cache is active or not.
*
* @return bool
* @return boolean
*/
public function getExpireResultCache()
{
......@@ -315,11 +324,11 @@ abstract class AbstractQuery
}
/**
* Defines the processing mode to be used during hydration.
* Defines the processing mode to be used during hydration / result set transformation.
*
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return Doctrine\ORM\Query\AbstractQuery
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setHydrationMode($hydrationMode)
{
......@@ -383,25 +392,25 @@ abstract class AbstractQuery
*
* @param integer $hydrationMode
* @return mixed
* @throws Doctrine\ORM\NonUniqueResultException If the query result is not unique.
* @throws Doctrine\ORM\NoResultException If the query returned no result.
* @throws NonUniqueResultException If the query result is not unique.
* @throws NoResultException If the query returned no result.
*/
public function getSingleResult($hydrationMode = null)
{
$result = $this->execute(array(), $hydrationMode);
if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) {
throw new \Doctrine\ORM\NoResultException;
throw new NoResultException;
}
if (is_array($result)) {
if (count($result) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
throw new NonUniqueResultException;
}
return array_shift($result);
} else if (is_object($result)) {
if (count($result) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
throw new NonUniqueResultException;
}
return $result->first();
}
......@@ -415,8 +424,7 @@ abstract class AbstractQuery
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
*
* @return mixed
* @throws Doctrine\ORM\NonUniqueResultException If the query result is not unique.
* @throws Doctrine\ORM\NoResultException If the query returned no result.
* @throws QueryException If the query result is not unique.
*/
public function getSingleScalarResult()
{
......@@ -428,7 +436,7 @@ abstract class AbstractQuery
*
* @param string $name The name of the hint.
* @param mixed $value The value of the hint.
* @return Doctrine\ORM\Query\AbstractQuery
* @return Doctrine\ORM\AbstractQuery
*/
public function setHint($name, $value)
{
......@@ -484,20 +492,22 @@ abstract class AbstractQuery
$this->setHydrationMode($hydrationMode);
}
$params = $this->getParameters($params);
if ($params) {
$this->setParameters($params);
}
if (isset($params[0])) {
if (isset($this->_params[0])) {
throw QueryException::invalidParameterPosition(0);
}
// Check result cache
if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) {
$id = $this->_getResultCacheId($params);
$id = $this->_getResultCacheId();
$cached = $this->_expireResultCache ? false : $cacheDriver->fetch($id);
if ($cached === false) {
// Cache miss.
$stmt = $this->_doExecute($params);
$stmt = $this->_doExecute();
$result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
$stmt, $this->_resultSetMapping, $this->_hints
......@@ -512,7 +522,7 @@ abstract class AbstractQuery
}
}
$stmt = $this->_doExecute($params);
$stmt = $this->_doExecute();
if (is_numeric($stmt)) {
return $stmt;
......@@ -529,7 +539,7 @@ abstract class AbstractQuery
* generated for you.
*
* @param string $id
* @return Doctrine\ORM\Query\AbstractQuery
* @return Doctrine\ORM\AbstractQuery This query instance.
*/
public function setResultCacheId($id)
{
......@@ -542,36 +552,24 @@ abstract class AbstractQuery
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @param array $params
* @return string $id
*/
protected function _getResultCacheId(array $params)
protected function _getResultCacheId()
{
if ($this->_resultCacheId) {
return $this->_resultCacheId;
} else {
$sql = $this->getSql();
ksort($this->_hints);
return md5(implode(";", (array)$sql) . var_export($params, true) .
return md5(implode(";", (array)$sql) . var_export($this->_params, true) .
var_export($this->_hints, true)."&hydrationMode=".$this->_hydrationMode);
}
}
/**
* Prepares the given parameters for execution in an SQL statement.
* Executes the query and returns a the resulting Statement object.
*
* Note to inheritors: This method must return a numerically, continuously indexed array,
* starting with index 0 where the values (the parameter values) are in the order
* in which the parameters appear in the SQL query.
*
* @return array The SQL parameter array.
*/
abstract protected function _prepareParams(array $params);
/**
* Executes the query and returns a reference to the resulting Statement object.
*
* @param array $params
* @return Doctrine\DBAL\Driver\Statement The executed database statement that holds the results.
*/
abstract protected function _doExecute(array $params);
abstract protected function _doExecute();
}
......@@ -21,8 +21,10 @@
namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type;
use PDO,
Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager;
/**
* Base class for all hydrators. A hydrator is a class that provides some form
......@@ -54,7 +56,7 @@ abstract class AbstractHydrator
/** @var Statement The statement that provides the data to hydrate. */
protected $_stmt;
/** @var array The query hints. */
protected $_hints;
......@@ -63,7 +65,7 @@ abstract class AbstractHydrator
*
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
*/
public function __construct(\Doctrine\ORM\EntityManager $em)
public function __construct(EntityManager $em)
{
$this->_em = $em;
$this->_platform = $em->getConnection()->getDatabasePlatform();
......@@ -112,18 +114,18 @@ abstract class AbstractHydrator
*/
public function hydrateRow()
{
$row = $this->_stmt->fetch(Connection::FETCH_ASSOC);
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
if ( ! $row) {
$this->_cleanup();
return false;
}
$result = $this->_getRowContainer();
$result = array();
$this->_hydrateRow($row, $this->_cache, $result);
return $result;
}
/**
* Excutes one-time preparation tasks once each time hydration is started
* Excutes one-time preparation tasks, once each time hydration is started
* through {@link hydrateAll} or {@link iterate()}.
*/
protected function _prepare()
......@@ -149,7 +151,7 @@ abstract class AbstractHydrator
* @param array $cache The cache to use.
* @param mixed $result The result to fill.
*/
protected function _hydrateRow(array &$data, array &$cache, array &$result)
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
throw new HydrationException("_hydrateRow() not implemented by this hydrator.");
}
......@@ -159,14 +161,6 @@ abstract class AbstractHydrator
*/
abstract protected function _hydrateAll();
/**
* Gets the row container used during row-by-row hydration through {@link iterate()}.
*/
protected function _getRowContainer()
{
return array();
}
/**
* Processes a row of the result set.
* Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY).
......@@ -178,7 +172,7 @@ abstract class AbstractHydrator
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component alias.
*/
protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents)
protected function _gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
{
$rowData = array();
......
......@@ -21,7 +21,7 @@
namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Connection;
use PDO, Doctrine\DBAL\Connection;
/**
* The ArrayHydrator produces a nested array "graph" that is often (not always)
......@@ -60,7 +60,7 @@ class ArrayHydrator extends AbstractHydrator
{
$result = array();
$cache = array();
while ($data = $this->_stmt->fetch(Connection::FETCH_ASSOC)) {
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($data, $cache, $result);
}
......@@ -68,7 +68,7 @@ class ArrayHydrator extends AbstractHydrator
}
/** @override */
protected function _hydrateRow(array &$data, array &$cache, array &$result)
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
// 1) Initialize
$id = $this->_idTemplate; // initialize the id-memory
......
......@@ -31,18 +31,17 @@ namespace Doctrine\ORM\Internal\Hydration;
class IterableResult implements \Iterator
{
/**
*
* @var \Doctrine\ORM\Internal\Hydration\AbstractHydrator
* @var Doctrine\ORM\Internal\Hydration\AbstractHydrator
*/
private $_hydrator;
/**
* @var bool
* @var boolean
*/
private $_rewinded = false;
/**
* @var int
* @var integer
*/
private $_key = -1;
......@@ -52,8 +51,7 @@ class IterableResult implements \Iterator
private $_current = null;
/**
*
* @param \Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
* @param Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator
*/
public function __construct($hydrator)
{
......@@ -62,7 +60,7 @@ class IterableResult implements \Iterator
public function rewind()
{
if($this->_rewinded == true) {
if ($this->_rewinded == true) {
throw new HydrationException("Can only iterate a Result once.");
} else {
$this->_current = $this->next();
......
......@@ -21,7 +21,8 @@
namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\ORM\PersistentCollection,
use PDO,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Query,
Doctrine\Common\Collections\ArrayCollection,
Doctrine\Common\Collections\Collection;
......@@ -102,7 +103,7 @@ class ObjectHydrator extends AbstractHydrator
}
}
}
/**
* {@inheritdoc}
*/
......@@ -122,8 +123,9 @@ class ObjectHydrator extends AbstractHydrator
{
$result = array();
$cache = array();
while ($data = $this->_stmt->fetch(\Doctrine\DBAL\Connection::FETCH_ASSOC)) {
$this->_hydrateRow($data, $cache, $result);
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($row, $cache, $result);
}
// Take snapshots from all newly initialized collections
......@@ -189,7 +191,6 @@ class ObjectHydrator extends AbstractHydrator
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
unset($data[$discrColumn]);
}
return $this->_uow->createEntity($className, $data, $this->_hints);
}
......@@ -244,7 +245,7 @@ class ObjectHydrator extends AbstractHydrator
* @param array $cache
* @param array $result
*/
protected function _hydrateRow(array &$data, array &$cache, array &$result)
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
// Initialize
$id = $this->_idTemplate; // initialize the id-memory
......@@ -263,12 +264,11 @@ class ObjectHydrator extends AbstractHydrator
// Hydrate the data chunks
foreach ($rowData as $dqlAlias => $data) {
$index = false;
$entityName = $this->_rsm->aliasMap[$dqlAlias];
if (isset($this->_rsm->parentAliasMap[$dqlAlias])) {
// It's a joined result
$parentAlias = $this->_rsm->parentAliasMap[$dqlAlias];
// Get a reference to the parent object to which the joined element belongs.
......
......@@ -38,14 +38,14 @@ class ScalarHydrator extends AbstractHydrator
{
$result = array();
$cache = array();
while ($data = $this->_stmt->fetch(Connection::FETCH_ASSOC)) {
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $this->_gatherScalarRowData($data, $cache);
}
return $result;
}
/** @override */
protected function _hydrateRow(array &$data, array &$cache, array &$result)
protected function _hydrateRow(array $data, array &$cache, array &$result)
{
$result[] = $this->_gatherScalarRowData($data, $cache);
}
......
......@@ -35,7 +35,7 @@ class SingleScalarHydrator extends AbstractHydrator
protected function _hydrateAll()
{
$cache = array();
$result = $this->_stmt->fetchAll(Connection::FETCH_ASSOC);
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
if (count($result) > 1 || count($result[key($result)]) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
}
......
......@@ -249,16 +249,6 @@ abstract class AssociationMapping
return $this->fetchMode == self::FETCH_LAZY;
}
/**
* Whether the source entity of this association represents the inverse side.
*
* @return boolean
*/
public function isInverseSide()
{
return ! $this->isOwningSide;
}
/**
* Whether the association is a one-to-one association.
*
......@@ -298,7 +288,12 @@ abstract class AssociationMapping
{
return (bool) $this->joinTable;
}
/**
* Checks whether the association has any cascades configured.
*
* @return boolean
*/
public function hasCascades()
{
return $this->isCascadePersist ||
......
......@@ -21,6 +21,8 @@
namespace Doctrine\ORM\Mapping;
use ReflectionClass, ReflectionProperty;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
* of an entity and it's associations.
......@@ -73,7 +75,7 @@ class ClassMetadata extends ClassMetadataInfo
$this->name = $entityName;
$this->reflClass = new \ReflectionClass($entityName);
$this->namespace = $this->reflClass->getNamespaceName();
$this->primaryTable['name'] = $this->reflClass->getShortName();
$this->table['name'] = $this->reflClass->getShortName();
$this->rootEntityName = $entityName;
}
......@@ -271,9 +273,9 @@ class ClassMetadata extends ClassMetadataInfo
*/
public function getQuotedTableName($platform)
{
return isset($this->primaryTable['quoted']) ?
$platform->quoteIdentifier($this->primaryTable['name']) :
$this->primaryTable['name'];
return isset($this->table['quoted']) ?
$platform->quoteIdentifier($this->table['name']) :
$this->table['name'];
}
/**
......@@ -306,8 +308,8 @@ class ClassMetadata extends ClassMetadataInfo
'discriminatorColumn',
'discriminatorValue',
'discriminatorMap',
'fieldMappings',
'fieldNames', //TODO: Not all of this stuff needs to be serialized. Only type, columnName and fieldName.
'fieldMappings',//TODO: Not all of this stuff needs to be serialized. Only type, columnName and fieldName.
'fieldNames',
'generatorType',
'identifier',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
......@@ -320,13 +322,13 @@ class ClassMetadata extends ClassMetadataInfo
'lifecycleCallbacks',
'name',
'parentClasses',
'primaryTable',
'table',
'rootEntityName',
'subClasses',
'versionField'
);
}
/**
* Restores some state that can not be serialized/unserialized.
*
......@@ -335,22 +337,21 @@ class ClassMetadata extends ClassMetadataInfo
public function __wakeup()
{
// Restore ReflectionClass and properties
$this->reflClass = new \ReflectionClass($this->name);
$this->reflClass = new ReflectionClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
if (isset($mapping['inherited'])) {
$reflField = new \ReflectionProperty($mapping['inherited'], $field);
$reflField = new ReflectionProperty($mapping['inherited'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
foreach ($this->associationMappings as $field => $mapping) {
if (isset($this->inheritedAssociationFields[$field])) {
$reflField = new \ReflectionProperty($this->inheritedAssociationFields[$field], $field);
$reflField = new ReflectionProperty($this->inheritedAssociationFields[$field], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}
......
......@@ -294,8 +294,9 @@ class ClassMetadataInfo
* uniqueConstraints => array
*
* @var array
* @todo Rename to just $table
*/
public $primaryTable;
public $table;
/**
* READ-ONLY: The registered lifecycle callbacks for entities of this class.
......@@ -862,7 +863,7 @@ class ClassMetadataInfo
*/
public function getTableName()
{
return $this->primaryTable['name'];
return $this->table['name'];
}
/**
......@@ -872,7 +873,7 @@ class ClassMetadataInfo
*/
public function getTemporaryIdTableName()
{
return $this->primaryTable['name'] . '_id_tmp';
return $this->table['name'] . '_id_tmp';
}
/**
......@@ -966,7 +967,7 @@ class ClassMetadataInfo
*/
public function setTableName($tableName)
{
$this->primaryTable['name'] = $tableName;
$this->table['name'] = $tableName;
}
/**
......@@ -981,7 +982,7 @@ class ClassMetadataInfo
*/
public function setPrimaryTable(array $primaryTableDefinition)
{
$this->primaryTable = $primaryTableDefinition;
$this->table = $primaryTableDefinition;
}
/**
......@@ -1101,7 +1102,7 @@ class ClassMetadataInfo
*/
private function _registerMappingIfInverse(AssociationMapping $assoc)
{
if ($assoc->isInverseSide()) {
if ( ! $assoc->isOwningSide) {
$this->inverseMappings[$assoc->targetEntityName][$assoc->mappedBy] = $assoc;
}
}
......
......@@ -63,7 +63,7 @@ class DatabaseDriver implements Driver
$className = Inflector::classify($tableName);
$metadata->name = $className;
$metadata->primaryTable['name'] = $tableName;
$metadata->table['name'] = $tableName;
$columns = $this->_sm->listTableColumns($tableName);
......
......@@ -31,6 +31,7 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
* @since 2.0
* @version $Revision: 1393 $
* @author Jonathan H. Wage <jonwage@gmail.com>
* @todo Rename: MetadataDriver
*/
interface Driver
{
......
......@@ -41,6 +41,7 @@ use Doctrine\Common\Cache\ArrayCache,
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @todo Rename: PHPDriver
*/
class PhpDriver extends AbstractFileDriver
{
......
......@@ -62,11 +62,11 @@ class XmlDriver extends AbstractFileDriver
// Evaluate <entity...> attributes
if (isset($xmlRoot['table'])) {
$metadata->primaryTable['name'] = (string)$xmlRoot['table'];
$metadata->table['name'] = (string)$xmlRoot['table'];
}
if (isset($xmlRoot['schema'])) {
$metadata->primaryTable['schema'] = (string)$xmlRoot['schema'];
$metadata->table['schema'] = (string)$xmlRoot['schema'];
}
if (isset($xmlRoot['inheritance-type'])) {
......@@ -108,7 +108,7 @@ class XmlDriver extends AbstractFileDriver
$columns = $index['columns'];
}
$metadata->primaryTable['indexes'][$index['name']] = array(
$metadata->table['indexes'][$index['name']] = array(
'columns' => $columns
);
}
......@@ -123,7 +123,7 @@ class XmlDriver extends AbstractFileDriver
$columns = $unique['columns'];
}
$metadata->primaryTable['uniqueConstraints'][$unique['name']] = array(
$metadata->table['uniqueConstraints'][$unique['name']] = array(
'columns' => $columns
);
}
......
......@@ -62,11 +62,11 @@ class YamlDriver extends AbstractFileDriver
// Evaluate root level properties
if (isset($element['table'])) {
$metadata->primaryTable['name'] = $element['table'];
$metadata->table['name'] = $element['table'];
}
if (isset($element['schema'])) {
$metadata->primaryTable['schema'] = $element['schema'];
$metadata->table['schema'] = $element['schema'];
}
if (isset($element['inheritanceType'])) {
......@@ -107,7 +107,7 @@ class YamlDriver extends AbstractFileDriver
$columns = $index['columns'];
}
$metadata->primaryTable['indexes'][$index['name']] = array(
$metadata->table['indexes'][$index['name']] = array(
'columns' => $columns
);
}
......@@ -126,7 +126,7 @@ class YamlDriver extends AbstractFileDriver
$columns = $unique['columns'];
}
$metadata->primaryTable['uniqueConstraints'][$unique['name']] = array(
$metadata->table['uniqueConstraints'][$unique['name']] = array(
'columns' => $columns
);
}
......
......@@ -21,7 +21,7 @@
namespace Doctrine\ORM;
use Doctrine\ORM\Query\AbstractQuery;
use Doctrine\DBAL\Types\Type;
/**
* Represents a native SQL query.
......@@ -33,24 +33,13 @@ final class NativeQuery extends AbstractQuery
{
private $_sql;
/**
* Initializes a new instance of the <tt>NativeQuery</tt> class that is bound
* to the given EntityManager.
*
* @param EntityManager $em The EntityManager to use.
*/
public function __construct(EntityManager $em)
{
parent::__construct($em);
}
/**
* Sets the SQL of the query.
*
* @param string $sql
* @return Doctrine\ORM\AbstractQuery
* @return NativeQuery This query instance.
*/
public function setSql($sql)
public function setSQL($sql)
{
$this->_sql = $sql;
return $this;
......@@ -62,37 +51,27 @@ final class NativeQuery extends AbstractQuery
* @return mixed The built SQL query or an array of all SQL queries.
* @override
*/
public function getSql()
public function getSQL()
{
return $this->_sql;
}
/**
* Executes the query.
*
* @param array $params
* @return Statement The Statement handle.
* @override
*/
protected function _doExecute(array $params)
{
return $this->_em->getConnection()->execute($this->_sql, $this->_prepareParams($params));
}
/**
* {@inheritdoc}
*
* @override
*/
protected function _prepareParams(array $params)
protected function _doExecute()
{
$sqlParams = array();
$stmt = $this->_em->getConnection()->prepare($this->_sql);
$params = $this->_params;
foreach ($params as $key => $value) {
$sqlParams[$key] = $value;
if (isset($this->_paramTypes[$key])) {
$stmt->bindValue($key, $value, $this->_paramTypes[$key]);
} else {
$stmt->bindValue($key, $value);
}
}
ksort($sqlParams);
return array_values($sqlParams);
$stmt->execute();
return $stmt;
}
}
\ No newline at end of file
......@@ -290,7 +290,12 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
*/
private function _changed()
{
$this->_isDirty = true;
if ( ! $this->_isDirty) {
$this->_isDirty = true;
//if ($this->_isNotifyRequired) {
//$this->_em->getUnitOfWork()->scheduleCollectionUpdate($this);
//}
}
}
/**
......
......@@ -61,14 +61,6 @@ abstract class AbstractCollectionPersister
$this->_conn = $em->getConnection();
}
/*public function recreate(PersistentCollection $coll)
{
if ($coll->getRelation()->isInverseSide()) {
return;
}
//...
}*/
/**
* Deletes the persistent state represented by the given collection.
*
......@@ -76,7 +68,7 @@ abstract class AbstractCollectionPersister
*/
public function delete(PersistentCollection $coll)
{
if ($coll->getMapping()->isInverseSide()) {
if ( ! $coll->getMapping()->isOwningSide) {
return; // ignore inverse side
}
$sql = $this->_getDeleteSql($coll);
......@@ -106,7 +98,7 @@ abstract class AbstractCollectionPersister
*/
public function update(PersistentCollection $coll)
{
if ($coll->getMapping()->isInverseSide()) {
if ( ! $coll->getMapping()->isOwningSide) {
return; // ignore inverse side
}
$this->deleteRows($coll);
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\DBAL\Types\Type;
/**
* Base class for entity persisters that implement a certain inheritance mapping strategy.
* All these persisters are assumed to use a discriminator column to discriminate entity
* types in the hierarchy.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
abstract class AbstractEntityInheritancePersister extends StandardEntityPersister
{
/**
* Map from column names to class names that declare the field the column is mapped to.
*
* @var array
*/
private $_declaringClassMap = array();
/**
* {@inheritdoc}
*/
protected function _prepareInsertData($entity)
{
$data = parent::_prepareInsertData($entity);
// Populate the discriminator column
$discColumn = $this->_class->discriminatorColumn;
$this->_columnTypes[$discColumn['name']] = $discColumn['type'];
$data[$this->_getDiscriminatorColumnTableName()][$discColumn['name']] = $this->_class->discriminatorValue;
return $data;
}
/**
* Gets the name of the table that contains the discriminator column.
*
* @return string The table name.
*/
abstract protected function _getDiscriminatorColumnTableName();
/**
* {@inheritdoc}
*/
protected function _processSQLResult(array $sqlResult)
{
$data = array();
$discrColumnName = $this->_platform->getSQLResultCasing($this->_class->discriminatorColumn['name']);
$entityName = $this->_class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
foreach ($sqlResult as $column => $value) {
$realColumnName = $this->_resultColumnNames[$column];
if (isset($this->_declaringClassMap[$column])) {
$class = $this->_declaringClassMap[$column];
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) {
$field = $class->fieldNames[$realColumnName];
$data[$field] = Type::getType($class->fieldMappings[$field]['type'])
->convertToPHPValue($value, $this->_platform);
}
} else {
$data[$realColumnName] = $value;
}
}
return array($entityName, $data);
}
/**
* {@inheritdoc}
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class)
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
$this->_resultColumnNames[$columnAlias] = $columnName;
$this->_declaringClassMap[$columnAlias] = $class;
}
return "$sql AS $columnAlias";
}
}
\ No newline at end of file
......@@ -25,60 +25,51 @@ use Doctrine\ORM\ORMException;
/**
* The joined subclass persister maps a single entity instance to several tables in the
* database as it is defined by <tt>Class Table Inheritance</tt>.
* database as it is defined by the <tt>Class Table Inheritance</tt> strategy.
*
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @link www.doctrine-project.org
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
*/
class JoinedSubclassPersister extends StandardEntityPersister
class JoinedSubclassPersister extends AbstractEntityInheritancePersister
{
/** Map that maps column names to the table names that own them.
* This is mainly a temporary cache, used during a single request.
/**
* Map that maps column names to the table names that own them.
* This is mainly a temporary cache, used during a single request.
*/
private $_owningTableMap = array();
/**
* {@inheritdoc}
*
* @override
*/
protected function _prepareData($entity, array &$result, $isInsert = false)
protected function _getDiscriminatorColumnTableName()
{
parent::_prepareData($entity, $result, $isInsert);
// Populate the discriminator column
if ($isInsert) {
$discColumn = $this->_class->discriminatorColumn;
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
$result[$rootClass->primaryTable['name']][$discColumn['name']] = $this->_class->discriminatorValue;
if ($this->_class->name == $this->_class->rootEntityName) {
return $this->_class->table['name'];
} else {
return $this->_em->getClassMetadata($this->_class->rootEntityName)->table['name'];
}
}
/**
* This function finds the ClassMetadata instance in a inheritance hierarchy
* This function finds the ClassMetadata instance in an inheritance hierarchy
* that is responsible for enabling versioning.
*
* @return mixed ClassMetadata instance or false if versioning is not enabled.
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
private function _getVersionedClassMetadata()
{
if ($this->_class->isVersioned) {
if (isset($this->_class->fieldMappings[$this->_class->versionField]['inherited'])) {
$definingClassName = $this->_class->fieldMappings[$this->_class->versionField]['inherited'];
$versionedClass = $this->_em->getClassMetadata($definingClassName);
} else {
$versionedClass = $this->_class;
}
return $versionedClass;
if (isset($this->_class->fieldMappings[$this->_class->versionField]['inherited'])) {
$definingClassName = $this->_class->fieldMappings[$this->_class->versionField]['inherited'];
return $this->_em->getClassMetadata($definingClassName);
}
return false;
return $this->_class;
}
/**
* Gets the name of the table that owns the column the given field is mapped to.
* Does only look upwards in the hierarchy, not downwards.
*
* @param string $fieldName
* @return string
......@@ -91,16 +82,16 @@ class JoinedSubclassPersister extends StandardEntityPersister
if (isset($this->_class->inheritedAssociationFields[$fieldName])) {
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
$this->_class->inheritedAssociationFields[$fieldName]
)->primaryTable['name'];
)->table['name'];
} else {
$this->_owningTableMap[$fieldName] = $this->_class->primaryTable['name'];
$this->_owningTableMap[$fieldName] = $this->_class->table['name'];
}
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
$this->_class->fieldMappings[$fieldName]['inherited']
)->primaryTable['name'];
)->table['name'];
} else {
$this->_owningTableMap[$fieldName] = $this->_class->primaryTable['name'];
$this->_owningTableMap[$fieldName] = $this->_class->table['name'];
}
}
......@@ -109,8 +100,6 @@ class JoinedSubclassPersister extends StandardEntityPersister
/**
* {@inheritdoc}
*
* @override
*/
public function executeInserts()
{
......@@ -118,7 +107,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
return;
}
if ($isVersioned = $this->_class->isVersioned) {
if ($this->_class->isVersioned) {
$versionedClass = $this->_getVersionedClassMetadata();
}
......@@ -130,53 +119,33 @@ class JoinedSubclassPersister extends StandardEntityPersister
$rootClass = $this->_class->name == $this->_class->rootEntityName ?
$this->_class : $this->_em->getClassMetadata($this->_class->rootEntityName);
$rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name);
$rootTableName = $rootClass->primaryTable['name'];
$rootTableName = $rootClass->table['name'];
$rootTableStmt = $this->_conn->prepare($rootPersister->getInsertSQL());
if ($this->_sqlLogger !== null) {
$sql = array();
$sql[$rootTableName] = $rootPersister->getInsertSQL();
}
// Prepare statements for sub tables.
$subTableStmts = array();
if ($rootClass !== $this->_class) {
$subTableStmts[$this->_class->primaryTable['name']] = $this->_conn->prepare($this->getInsertSQL());
if ($this->_sqlLogger !== null) {
$sql[$this->_class->primaryTable['name']] = $this->getInsertSQL();
}
$subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->getInsertSQL());
}
foreach ($this->_class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$parentTableName = $parentClass->primaryTable['name'];
$parentTableName = $parentClass->table['name'];
if ($parentClass !== $rootClass) {
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->getInsertSQL());
if ($this->_sqlLogger !== null) {
$sql[$parentTableName] = $parentPersister->getInsertSQL();
}
}
}
// Execute all inserts. For each entity:
// 1) Insert on root table
// 2) Insert on sub tables
foreach ($this->_queuedInserts as $entity) {
$insertData = array();
$this->_prepareData($entity, $insertData, true);
$insertData = $this->_prepareInsertData($entity);
// Execute insert on root table
$paramIndex = 1;
if ($this->_sqlLogger !== null) {
$params = array();
foreach ($insertData[$rootTableName] as $columnName => $value) {
$params[$paramIndex] = $value;
$rootTableStmt->bindValue($paramIndex++, $value);
}
$this->_sqlLogger->logSql($sql[$rootTableName], $params);
} else {
foreach ($insertData[$rootTableName] as $columnName => $value) {
$rootTableStmt->bindValue($paramIndex++, $value);
}
foreach ($insertData[$rootTableName] as $columnName => $value) {
$rootTableStmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
}
$rootTableStmt->execute();
......@@ -192,24 +161,11 @@ class JoinedSubclassPersister extends StandardEntityPersister
foreach ($subTableStmts as $tableName => $stmt) {
$data = isset($insertData[$tableName]) ? $insertData[$tableName] : array();
$paramIndex = 1;
if ($this->_sqlLogger !== null) {
$params = array();
foreach ((array) $id as $idVal) {
$params[$paramIndex] = $idVal;
$stmt->bindValue($paramIndex++, $idVal);
}
foreach ($data as $columnName => $value) {
$params[$paramIndex] = $value;
$stmt->bindValue($paramIndex++, $value);
}
$this->_sqlLogger->logSql($sql[$tableName], $params);
} else {
foreach ((array) $id as $idVal) {
$stmt->bindValue($paramIndex++, $idVal);
}
foreach ($data as $columnName => $value) {
$stmt->bindValue($paramIndex++, $value);
}
foreach ((array) $id as $idVal) {
$stmt->bindValue($paramIndex++, $idVal);
}
foreach ($data as $columnName => $value) {
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
}
$stmt->execute();
}
......@@ -220,7 +176,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
$stmt->closeCursor();
}
if ($isVersioned) {
if (isset($versionedClass)) {
$this->_assignDefaultVersionValue($versionedClass, $entity, $id);
}
......@@ -230,45 +186,30 @@ class JoinedSubclassPersister extends StandardEntityPersister
}
/**
* Updates an entity.
*
* @param object $entity The entity to update.
* @override
* {@inheritdoc}
*/
public function update($entity)
{
$updateData = array();
$this->_prepareData($entity, $updateData);
$id = array_combine(
$this->_class->getIdentifierColumnNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$updateData = $this->_prepareUpdateData($entity);
if ($isVersioned = $this->_class->isVersioned) {
$versionedClass = $this->_getVersionedClassMetadata();
$versionedTable = $versionedClass->primaryTable['name'];
$versionedTable = $this->_getVersionedClassMetadata()->table['name'];
}
if ($updateData) {
foreach ($updateData as $tableName => $data) {
if ($isVersioned && $versionedTable == $tableName) {
$this->_doUpdate($entity, $tableName, $data, $id);
} else {
$this->_conn->update($tableName, $data, $id);
}
$this->_updateTable($entity, $tableName, $data, $isVersioned && $versionedTable == $tableName);
}
// Make sure the table with the version column is updated even if no columns on that
// table were affected.
if ($isVersioned && ! isset($updateData[$versionedTable])) {
$this->_doUpdate($entity, $versionedTable, array(), $id);
$this->_updateTable($entity, $versionedTable, array(), true);
}
}
}
/**
* Deletes an entity.
*
* @param object $entity The entity to delete.
* @override
* {@inheritdoc}
*/
public function delete($entity)
{
......@@ -279,26 +220,20 @@ class JoinedSubclassPersister extends StandardEntityPersister
// If the database platform supports FKs, just
// delete the row from the root table. Cascades do the rest.
if ($this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) {
if ($this->_platform->supportsForeignKeyConstraints()) {
$this->_conn->delete($this->_em->getClassMetadata($this->_class->rootEntityName)
->primaryTable['name'], $id);
->getQuotedTableName($this->_platform), $id);
} else {
// Delete from all tables individually, starting from this class' table up to the root table.
$this->_conn->delete($this->_class->primaryTable['name'], $id);
$this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id);
foreach ($this->_class->parentClasses as $parentClass) {
$this->_conn->delete($this->_em->getClassMetadata($parentClass)->primaryTable['name'], $id);
$this->_conn->delete($this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id);
}
}
}
/**
* Gets the SELECT SQL to select one or more entities by a set of field criteria.
*
* @param array $criteria
* @param AssociationMapping $assoc
* @param string $orderBy
* @return string
* @override
* {@inheritdoc}
*/
protected function _getSelectEntitiesSQL(array &$criteria, $assoc = null, $orderBy = null)
{
......@@ -331,7 +266,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
}
}
// Add discriminator column (DO NOT ALIAS THIS COLUMN).
// Add discriminator column (DO NOT ALIAS THIS COLUMN, see StandardEntityPersister#_processSQLResultInheritanceAware).
$discrColumn = $this->_class->discriminatorColumn['name'];
if ($this->_class->rootEntityName == $this->_class->name) {
$columnList .= ", $baseTableAlias.$discrColumn";
......@@ -428,19 +363,13 @@ class JoinedSubclassPersister extends StandardEntityPersister
. ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
}
/** Ensure this is never called. This persister overrides _getSelectEntitiesSQL directly. */
/** Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
protected function _getSelectColumnListSQL()
{
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__." on JoinedSubclassPersister.");
}
/** @override */
protected function _processSQLResult(array $sqlResult)
{
return $this->_processSQLResultInheritanceAware($sqlResult);
}
/** @override */
/** {@inheritdoc} */
protected function _getInsertColumnList()
{
// Identifier columns must always come first in the column list of subclasses.
......
......@@ -27,27 +27,20 @@ use Doctrine\ORM\Mapping\ClassMetadata;
* Persister for entities that participate in a hierarchy mapped with the
* SINGLE_TABLE strategy.
*
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision: 3406 $
* @link www.doctrine-project.org
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @since 2.0
* @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
*/
class SingleTablePersister extends StandardEntityPersister
class SingleTablePersister extends AbstractEntityInheritancePersister
{
/** @override */
protected function _prepareData($entity, array &$result, $isInsert = false)
/** {@inheritdoc} */
protected function _getDiscriminatorColumnTableName()
{
parent::_prepareData($entity, $result, $isInsert);
// Populate the discriminator column
if ($isInsert) {
$discColumn = $this->_class->discriminatorColumn['name'];
$result[$this->_class->getQuotedTableName($this->_platform)][$discColumn] =
$this->_class->discriminatorValue;
}
return $this->_class->table['name'];
}
/** @override */
/** {@inheritdoc} */
protected function _getSelectColumnListSQL()
{
$columnList = parent::_getSelectColumnListSQL();
......@@ -86,7 +79,7 @@ class SingleTablePersister extends StandardEntityPersister
return $columnList;
}
/** @override */
/** {@inheritdoc} */
protected function _getInsertColumnList()
{
$columns = parent::_getInsertColumnList();
......@@ -96,19 +89,13 @@ class SingleTablePersister extends StandardEntityPersister
return $columns;
}
/** @override */
protected function _processSQLResult(array $sqlResult)
{
return $this->_processSQLResultInheritanceAware($sqlResult);
}
/** @override */
/** {@inheritdoc} */
protected function _getSQLTableAlias(ClassMetadata $class)
{
if (isset($this->_sqlTableAliases[$class->rootEntityName])) {
return $this->_sqlTableAliases[$class->rootEntityName];
}
$tableAlias = $this->_em->getClassMetadata($class->rootEntityName)->primaryTable['name'][0] . $this->_sqlAliasCounter++;
$tableAlias = $this->_em->getClassMetadata($class->rootEntityName)->table['name'][0] . $this->_sqlAliasCounter++;
$this->_sqlTableAliases[$class->rootEntityName] = $tableAlias;
return $tableAlias;
......
......@@ -21,25 +21,22 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\ORMException,
Doctrine\Common\Collections\ArrayCollection,
Doctrine\DBAL\Connection,
use PDO,
Doctrine\ORM\ORMException,
Doctrine\ORM\OptimisticLockException,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager,
Doctrine\ORM\Query,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Events;
Doctrine\ORM\Mapping\ClassMetadata;
/**
* Base class for all EntityPersisters. An EntityPersister is a class that knows
* how to persist and load entities of a specific type.
* A basic entity persister that maps an entity with no (mapped) inheritance to a single table
* in the relational database.
*
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision: 3406 $
* @link www.doctrine-project.org
* @since 2.0
* @todo Rename: BasicEntityPersister
*/
......@@ -72,13 +69,6 @@ class StandardEntityPersister
* @var Doctrine\ORM\EntityManager
*/
protected $_em;
/**
* The SqlLogger to use, if any.
*
* @var Doctrine\DBAL\Logging\SqlLogger
*/
protected $_sqlLogger;
/**
* Queued inserts.
......@@ -88,15 +78,27 @@ class StandardEntityPersister
protected $_queuedInserts = array();
/**
* Mappings of column names as they appear in an SQL result set to
* column names as they are defined in the mapping.
* Case-sensitive mappings of column names as they appear in an SQL result set
* to column names as they are defined in the mapping. This is necessary because different
* RDBMS vendors return column names in result sets in different casings.
*
* @var array
*/
protected $_resultColumnNames = array();
/**
* The map of column names to DBAL mapping types of all prepared columns used when INSERTing
* or UPDATEing an entity.
*
* @var array
* @see _prepareInsertData($entity)
* @see _prepareUpdateData($entity)
*/
protected $_columnTypes = array();
/**
* The INSERT SQL statement used for entities handled by this persister.
* This SQL is only generated once per request, if at all.
*
* @var string
*/
......@@ -104,18 +106,12 @@ class StandardEntityPersister
/**
* The SELECT column list SQL fragment used for querying entities by this persister.
* This SQL fragment is only generated once per request, if at all.
*
* @var string
*/
protected $_selectColumnListSql;
/**
* Map from column names to class names that declare the field the column is mapped to.
*
* @var array
*/
protected $_declaringClassMap = array();
/**
* Counter for creating unique SQL table and column aliases.
*
......@@ -124,7 +120,7 @@ class StandardEntityPersister
protected $_sqlAliasCounter = 0;
/**
* Map from class names to the corresponding generated SQL table aliases.
* Map from class names (FQCN) to the corresponding generated SQL table aliases.
*
* @var array
*/
......@@ -132,17 +128,16 @@ class StandardEntityPersister
/**
* Initializes a new <tt>StandardEntityPersister</tt> that uses the given EntityManager
* and persists instances of the class described by the given class metadata descriptor.
* and persists instances of the class described by the given ClassMetadata descriptor.
*
* @param EntityManager $em
* @param ClassMetadata $class
* @param Doctrine\ORM\EntityManager $em
* @param Doctrine\ORM\Mapping\ClassMetadata $class
*/
public function __construct(EntityManager $em, ClassMetadata $class)
{
$this->_em = $em;
$this->_class = $class;
$this->_conn = $em->getConnection();
$this->_sqlLogger = $this->_conn->getConfiguration()->getSqlLogger();
$this->_platform = $this->_conn->getDatabasePlatform();
}
......@@ -158,9 +153,13 @@ class StandardEntityPersister
}
/**
* Executes all queued inserts.
* Executes all queued entity insertions and returns any generated post-insert
* identifiers that were created as a result of the insertions.
*
* If no inserts are queued, invoking this method is a NOOP.
*
* @return array An array of any generated post-insert IDs.
* @return array An array of any generated post-insert IDs. This will be an empty array
* if the entity class does not use the IDENTITY generation strategy.
*/
public function executeInserts()
{
......@@ -168,37 +167,23 @@ class StandardEntityPersister
return;
}
$isVersioned = $this->_class->isVersioned;
$postInsertIds = array();
$idGen = $this->_class->idGenerator;
$isPostInsertId = $idGen->isPostInsertGenerator();
$stmt = $this->_conn->prepare($this->getInsertSQL());
$primaryTableName = $this->_class->primaryTable['name'];
$tableName = $this->_class->table['name'];
foreach ($this->_queuedInserts as $entity) {
$insertData = array();
$this->_prepareData($entity, $insertData, true);
$insertData = $this->_prepareInsertData($entity);
if (isset($insertData[$primaryTableName])) {
if (isset($insertData[$tableName])) {
$paramIndex = 1;
if ($this->_sqlLogger !== null) {
$params = array();
foreach ($insertData[$primaryTableName] as $value) {
$params[$paramIndex] = $value;
$stmt->bindValue($paramIndex++, $value);
}
$this->_sqlLogger->logSql($this->getInsertSQL(), $params);
} else {
foreach ($insertData[$primaryTableName] as $value) {
$stmt->bindValue($paramIndex++, $value);
}
foreach ($insertData[$tableName] as $column => $value) {
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$column]);
}
} else if ($this->_sqlLogger !== null) {
$this->_sqlLogger->logSql($this->getInsertSQL());
}
$stmt->execute();
if ($isPostInsertId) {
......@@ -208,11 +193,11 @@ class StandardEntityPersister
$id = $this->_class->getIdentifierValues($entity);
}
if ($isVersioned) {
if ($this->_class->isVersioned) {
$this->_assignDefaultVersionValue($this->_class, $entity, $id);
}
}
$stmt->closeCursor();
$this->_queuedInserts = array();
......@@ -220,11 +205,13 @@ class StandardEntityPersister
}
/**
* This function retrieves the default version value which was created
* by the DBMS INSERT statement. The value is assigned back in to the
* $entity versionField property.
* Retrieves the default version value which was created
* by the preceding INSERT statement and assigns it back in to the
* entities version field.
*
* @return void
* @param $class
* @param $entity
* @param $id
*/
protected function _assignDefaultVersionValue($class, $entity, $id)
{
......@@ -245,60 +232,65 @@ class StandardEntityPersister
*/
public function update($entity)
{
$updateData = array();
$this->_prepareData($entity, $updateData);
$id = array_combine(
$this->_class->getIdentifierColumnNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$tableName = $this->_class->primaryTable['name'];
$updateData = $this->_prepareUpdateData($entity);
$tableName = $this->_class->table['name'];
if (isset($updateData[$tableName]) && $updateData[$tableName]) {
$this->_doUpdate($entity, $tableName, $updateData[$tableName], $id);
$this->_updateTable($entity, $tableName, $updateData[$tableName], $this->_class->isVersioned);
}
}
/**
* Perform UPDATE statement for an entity. This function has support for
* optimistic locking if the entities ClassMetadata has versioning enabled.
* Performs an UPDATE statement for an entity on a specific table.
* The UPDATE can be optionally versioned, which requires the entity to have a version field.
*
* @param object $entity The entity object being updated
* @param string $tableName The name of the table being updated
* @param array $data The array of data to set
* @param array $where The condition used to update
* @return void
* @param object $entity The entity object being updated.
* @param string $tableName The name of the table to apply the UPDATE on.
* @param array $updateData The map of columns to update (column => value).
* @param boolean $versioned Whether the UPDATE should be versioned.
*/
protected function _doUpdate($entity, $tableName, $data, $where)
protected function _updateTable($entity, $tableName, $updateData, $versioned = false)
{
// Note: $tableName and column names in $data are already quoted for SQL.
$set = array();
foreach ($data as $columnName => $value) {
$set[] = $columnName . ' = ?';
$set = $params = $types = array();
foreach ($updateData as $columnName => $value) {
if (isset($this->_class->fieldNames[$columnName])) {
$set[] = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?';
} else {
$set[] = $columnName . ' = ?';
}
$params[] = $value;
$types[] = $this->_columnTypes[$columnName];
}
$where = array();
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
foreach ($this->_class->identifier as $idField) {
$where[] = $this->_class->getQuotedColumnName($idField, $this->_platform);
$params[] = $id[$idField];
$types[] = $this->_class->fieldMappings[$idField]['type'];
}
if ($isVersioned = $this->_class->isVersioned) {
if ($versioned) {
$versionField = $this->_class->versionField;
$versionFieldType = $this->_class->getTypeOfField($versionField);
$where[$versionField] = Type::getType($versionFieldType)
->convertToDatabaseValue($this->_class->reflFields[$versionField]->getValue($entity), $this->_platform);
$versionFieldColumnName = $this->_class->getQuotedColumnName($versionField, $this->_platform);
if ($versionFieldType == 'integer') {
$set[] = $versionFieldColumnName . ' = ' . $versionFieldColumnName . ' + 1';
} else if ($versionFieldType == 'datetime') {
$set[] = $versionFieldColumnName . ' = CURRENT_TIMESTAMP';
$versionColumn = $this->_class->getQuotedColumnName($versionField, $this->_platform);
if ($versionFieldType == Type::INTEGER) {
$set[] = $versionColumn . ' = ' . $versionColumn . ' + 1';
} else if ($versionFieldType == Type::DATETIME) {
$set[] = $versionColumn . ' = CURRENT_TIMESTAMP';
}
$where[] = $versionColumn;
$params[] = $this->_class->reflFields[$versionField]->getValue($entity);
$types[] = $this->_class->fieldMappings[$versionField]['type'];
}
$params = array_merge(array_values($data), array_values($where));
$sql = 'UPDATE ' . $tableName
. ' SET ' . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', array_keys($where)) . ' = ?';
$sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
. ' WHERE ' . implode(' = ? AND ', $where) . ' = ?';
$result = $this->_conn->executeUpdate($sql, $params);
$result = $this->_conn->executeUpdate($sql, $params, $types);
if ($isVersioned && ! $result) {
throw \Doctrine\ORM\OptimisticLockException::lockFailed();
if ($this->_class->isVersioned && ! $result) {
throw OptimisticLockException::lockFailed();
}
}
......@@ -313,7 +305,7 @@ class StandardEntityPersister
$this->_class->getIdentifierColumnNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$this->_conn->delete($this->_class->primaryTable['name'], $id);
$this->_conn->delete($this->_class->table['name'], $id);
}
/**
......@@ -327,7 +319,7 @@ class StandardEntityPersister
}
/**
* Prepares the data changeset of an entity for database insertion (INSERT/UPDATE).
* Prepares the data changeset of an entity for database insertion.
*
* During this preparation the array that is passed as the second parameter is filled with
* <columnName> => <value> pairs, grouped by table name.
......@@ -344,11 +336,11 @@ class StandardEntityPersister
* Notes to inheritors: Be sure to call <code>parent::_prepareData($entity, $result, $isInsert);</code>
*
* @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).
* @return array The prepared data.
*/
protected function _prepareData($entity, array &$result, $isInsert = false)
protected function _prepareUpdateData($entity)
{
$result = array();
$uow = $this->_em->getUnitOfWork();
if ($versioned = $this->_class->isVersioned) {
......@@ -359,7 +351,7 @@ class StandardEntityPersister
if ($versioned && $versionField == $field) {
continue;
}
$oldVal = $change[0];
$newVal = $change[1];
......@@ -382,31 +374,34 @@ class StandardEntityPersister
$newVal = null;
}
}
if ($newVal !== null) {
$newValId = $uow->getEntityIdentifier($newVal);
}
$targetClass = $this->_em->getClassMetadata($assocMapping->targetEntityName);
$owningTable = $this->getOwningTable($field);
foreach ($assocMapping->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
if ($newVal === null) {
$result[$owningTable][$sourceColumn] = null;
} else {
$result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
}
$this->_columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn);
}
} 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, $this->_platform);
$columnName = $this->_class->columnNames[$field];
$this->_columnTypes[$columnName] = $this->_class->fieldMappings[$field]['type'];
$result[$this->getOwningTable($field)][$columnName] = $newVal;
}
}
return $result;
}
protected function _prepareInsertData($entity)
{
return $this->_prepareUpdateData($entity);
}
/**
......@@ -417,7 +412,7 @@ class StandardEntityPersister
*/
public function getOwningTable($fieldName)
{
return $this->_class->getQuotedTableName($this->_platform);
return $this->_class->table['name'];
}
/**
......@@ -434,16 +429,10 @@ class StandardEntityPersister
{
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
$params = array_values($criteria);
if ($this->_sqlLogger !== null) {
$this->_sqlLogger->logSql($sql, $params);
}
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt = $this->_conn->execute($sql, $params);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
return $this->_createEntity($result, $entity, $hints);
}
......@@ -453,37 +442,31 @@ class StandardEntityPersister
* @param array $id The identifier of the entity as an associative array from column names to values.
* @param object $entity The entity to refresh.
*/
final public function refresh(array $id, $entity)
public function refresh(array $id, $entity)
{
$sql = $this->_getSelectEntitiesSQL($id);
$params = array_values($id);
if ($this->_sqlLogger !== null) {
$this->_sqlLogger->logSql($sql, $params);
}
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt = $this->_conn->execute($sql, $params);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
$metaColumns = array();
$newData = array();
// Refresh simple state
foreach ($result as $column => $value) {
$column = $this->_resultColumnNames[$column];
if (isset($this->_class->fieldNames[$column])) {
$fieldName = $this->_class->fieldNames[$column];
$type = Type::getType($this->_class->fieldMappings[$fieldName]['type']);
$newValue = $type->convertToPHPValue($value, $this->_platform);
$newValue = $this->_conn->convertToPHPValue($value, $this->_class->fieldMappings[$fieldName]['type']);
$this->_class->reflFields[$fieldName]->setValue($entity, $newValue);
$newData[$fieldName] = $newValue;
} else {
$metaColumns[$column] = $value;
}
}
// Refresh associations
foreach ($this->_class->associationMappings as $field => $assoc) {
$value = $this->_class->reflFields[$field]->getValue($entity);
......@@ -531,12 +514,12 @@ class StandardEntityPersister
$newData[$field] = $value;
}
}
$this->_em->getUnitOfWork()->setOriginalEntityData($entity, $newData);
}
/**
* Loads all entities by a list of field criteria.
* Loads a list of entities by a list of field criteria.
*
* @param array $criteria
* @return array
......@@ -547,23 +530,17 @@ class StandardEntityPersister
$sql = $this->_getSelectEntitiesSQL($criteria);
$params = array_values($criteria);
if ($this->_sqlLogger !== null) {
$this->_sqlLogger->logSql($sql, $params);
}
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll(Connection::FETCH_ASSOC);
$stmt = $this->_conn->execute($sql, $params);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach ($result as $row) {
$entities[] = $this->_createEntity($row);
}
return $entities;
}
/**
* Loads a collection of entities in a one-to-many association.
*
......@@ -574,23 +551,15 @@ class StandardEntityPersister
public function loadOneToManyCollection($assoc, array $criteria, PersistentCollection $coll)
{
$owningAssoc = $this->_class->associationMappings[$coll->getMapping()->mappedBy];
$sql = $this->_getSelectEntitiesSQL($criteria, $owningAssoc, $assoc->orderBy);
$params = array_values($criteria);
if ($this->_sqlLogger !== null) {
$this->_sqlLogger->logSql($sql, $params);
}
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
while ($result = $stmt->fetch(Connection::FETCH_ASSOC)) {
$stmt = $this->_conn->execute($sql, $params);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result));
}
$stmt->closeCursor();
}
/**
* Loads a collection of entities of a many-to-many association.
*
......@@ -602,19 +571,13 @@ class StandardEntityPersister
{
$sql = $this->_getSelectManyToManyEntityCollectionSQL($assoc, $criteria);
$params = array_values($criteria);
if ($this->_sqlLogger !== null) {
$this->_sqlLogger->logSql($sql, $params);
}
$stmt = $this->_conn->prepare($sql);
$stmt->execute($params);
while ($result = $stmt->fetch(Connection::FETCH_ASSOC)) {
$stmt = $this->_conn->execute($sql, $params);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result));
}
$stmt->closeCursor();
}
/**
* Creates or fills a single entity object from an SQL result.
*
......@@ -629,8 +592,8 @@ class StandardEntityPersister
return null;
}
list($entityName, $data) = $this->_processSqlResult($result);
list($entityName, $data) = $this->_processSQLResult($result);
if ($entity !== null) {
$hints[Query::HINT_REFRESH] = true;
$id = array();
......@@ -643,17 +606,17 @@ class StandardEntityPersister
}
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
}
return $this->_em->getUnitOfWork()->createEntity($entityName, $data, $hints);
}
/**
* Processes an SQL result set row that contains data for an entity of the type
* this persister is responsible for.
*
* @param array $sqlResult The SQL result set row to process.
* @return array A tuple where the first value is the actual type of the entity and
* the second value the data of the entity.
* the second value the prepared data of the entity.
*/
protected function _processSQLResult(array $sqlResult)
{
......@@ -715,9 +678,10 @@ class StandardEntityPersister
}
/**
* Generate ORDER BY Sql Snippet for ordered collections
* Generate ORDER BY SQL snippet for ordered collections.
*
* @param array $orderBy
* @param string $baseTableAlias
* @return string
*/
protected function _getCollectionOrderBySQL(array $orderBy, $baseTableAlias)
......@@ -819,30 +783,8 @@ class StandardEntityPersister
. ' WHERE ' . $conditionSql . $orderBySql;
}
final protected function _processSQLResultInheritanceAware(array $sqlResult)
{
$data = array();
$entityName = $this->_class->discriminatorMap[$sqlResult[$this->_class->discriminatorColumn['name']]];
unset($sqlResult[$this->_class->discriminatorColumn['name']]);
foreach ($sqlResult as $column => $value) {
$realColumnName = $this->_resultColumnNames[$column];
if (isset($this->_declaringClassMap[$column])) {
$class = $this->_declaringClassMap[$column];
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) {
$field = $class->fieldNames[$realColumnName];
$data[$field] = Type::getType($class->fieldMappings[$field]['type'])
->convertToPHPValue($value, $this->_platform);
}
} else {
$data[$realColumnName] = $value;
}
}
return array($entityName, $data);
}
/**
* Gets the INSERT SQL used by the persister to persist entities.
* Gets the INSERT SQL used by the persister to persist a new entity.
*
* @return string
*/
......@@ -851,10 +793,9 @@ class StandardEntityPersister
if ($this->_insertSql === null) {
$this->_insertSql = $this->_generateInsertSQL();
}
return $this->_insertSql;
}
/**
* Gets the list of columns to put in the INSERT SQL statement.
*
......@@ -880,10 +821,10 @@ class StandardEntityPersister
$columns[] = $this->_class->getQuotedColumnName($name, $this->_platform);
}
}
return $columns;
}
/**
* Generates the INSERT SQL used by the persister to persist entities.
*
......@@ -907,7 +848,7 @@ class StandardEntityPersister
. ' (' . implode(', ', $columns) . ') '
. 'VALUES (' . implode(', ', $values) . ')';
}
return $insertSql;
}
......@@ -915,7 +856,7 @@ class StandardEntityPersister
* Gets the SQL snippet of a qualified column name for the given field name.
*
* @param string $field The field name.
* @param ClassMetadata $class The class that declares this field. The table this class if
* @param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class)
......@@ -925,7 +866,6 @@ class StandardEntityPersister
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
if ( ! isset($this->_resultColumnNames[$columnAlias])) {
$this->_resultColumnNames[$columnAlias] = $columnName;
$this->_declaringClassMap[$columnAlias] = $class;
}
return "$sql AS $columnAlias";
......@@ -967,7 +907,7 @@ class StandardEntityPersister
if (isset($this->_sqlTableAliases[$class->name])) {
return $this->_sqlTableAliases[$class->name];
}
$tableAlias = $class->primaryTable['name'][0] . $this->_sqlAliasCounter++;
$tableAlias = $class->table['name'][0] . $this->_sqlAliasCounter++;
$this->_sqlTableAliases[$class->name] = $tableAlias;
return $tableAlias;
......
......@@ -114,7 +114,7 @@ class ProxyFactory
}
/**
* Generates a (reference or association) proxy class.
* Generates a proxy class file.
*
* @param $class
* @param $originalClassName
......
......@@ -21,8 +21,7 @@
namespace Doctrine\ORM;
use Doctrine\ORM\Query\AbstractQuery,
Doctrine\ORM\Query\Parser,
use Doctrine\ORM\Query\Parser,
Doctrine\ORM\Query\QueryException;
/**
......@@ -124,7 +123,7 @@ final class Query extends AbstractQuery
private $_maxResults = null;
/**
* @var CacheDriver The cache driver used for caching queries.
* @var CacheDriver The cache driver used for caching queries.
*/
private $_queryCache;
......@@ -161,17 +160,17 @@ final class Query extends AbstractQuery
* @return mixed The built sql query or an array of all sql queries.
* @override
*/
public function getSql()
public function getSQL()
{
return $this->_parse()->getSqlExecutor()->getSqlStatements();
}
/**
* Returns the correspondent AST for this Query.
* Returns the corresponding AST for this DQL query.
*
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
* @return Doctrine\ORM\Query\AST\SelectStatement |
* Doctrine\ORM\Query\AST\UpdateStatement |
* Doctrine\ORM\Query\AST\DeleteStatement
*/
public function getAST()
{
......@@ -216,62 +215,51 @@ final class Query extends AbstractQuery
/**
* {@inheritdoc}
*
* @param array $params
* @return Statement The resulting Statement.
* @override
*/
protected function _doExecute(array $params)
protected function _doExecute()
{
$executor = $this->_parse()->getSqlExecutor();
$params = $this->_prepareParams($params);
if ( ! $this->_resultSetMapping) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
}
return $executor->execute($this->_em->getConnection(), $params);
}
/**
* {@inheritdoc}
*
* @override
*/
protected function _prepareParams(array $params)
{
$sqlParams = array();
// Prepare parameters
$paramMappings = $this->_parserResult->getParameterMappings();
if (count($paramMappings) != count($params)) {
if (count($paramMappings) != count($this->_params)) {
throw QueryException::invalidParameterNumber();
}
foreach ($params as $key => $value) {
$sqlParams = $types = array();
foreach ($this->_params as $key => $value) {
if ( ! isset($paramMappings[$key])) {
throw QueryException::unknownParameter($key);
}
if (isset($this->_paramTypes[$key])) {
foreach ($paramMappings[$key] as $position) {
$types[$position] = $this->_paramTypes[$key];
}
}
if (is_object($value)) {
//$values = $this->_em->getClassMetadata(get_class($value))->getIdentifierValues($value);
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
$values = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
//var_dump($this->_em->getUnitOfWork()->getEntityIdentifier($value));
$sqlPositions = $paramMappings[$key];
$sqlParams = array_merge($sqlParams, array_combine((array)$sqlPositions, $values));
} else if (is_bool($value)) {
$boolValue = $this->_em->getConnection()->getDatabasePlatform()->convertBooleans($value);
foreach ($paramMappings[$key] as $position) {
$sqlParams[$position] = $boolValue;
}
} else {
foreach ($paramMappings[$key] as $position) {
$sqlParams[$position] = $value;
}
}
}
ksort($sqlParams);
return array_values($sqlParams);
if ($sqlParams) {
ksort($sqlParams);
$sqlParams = array_values($sqlParams);
}
if ($this->_resultSetMapping === null) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
}
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
}
/**
......
......@@ -57,8 +57,8 @@ class SizeFunction extends FunctionNode
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
$targetAssoc = $targetClass->associationMappings[$assoc->mappedBy];
$targetTableAlias = $sqlWalker->getSqlTableAlias($targetClass->primaryTable['name']);
$sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->primaryTable['name'], $dqlAlias);
$targetTableAlias = $sqlWalker->getSqlTableAlias($targetClass->table['name']);
$sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->table['name'], $dqlAlias);
$whereSql = '';
......@@ -68,10 +68,10 @@ class SizeFunction extends FunctionNode
. $sourceTableAlias . '.' . $targetKeyColumn;
}
$tableName = $targetClass->primaryTable['name'];
$tableName = $targetClass->table['name'];
} else if ($assoc->isManyToMany()) {
$targetTableAlias = $sqlWalker->getSqlTableAlias($assoc->joinTable['name']);
$sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->primaryTable['name'], $dqlAlias);
$sourceTableAlias = $sqlWalker->getSqlTableAlias($qComp['metadata']->table['name'], $dqlAlias);
$whereSql = '';
......
......@@ -21,6 +21,8 @@
namespace Doctrine\ORM\Query\Exec;
use Doctrine\DBAL\Connection;
/**
* Base class for SQL statement executors.
*
......@@ -28,7 +30,7 @@ namespace Doctrine\ORM\Query\Exec;
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @todo Rename: AbstractSQLExecutor
*/
abstract class AbstractSqlExecutor
{
......@@ -47,8 +49,9 @@ abstract class AbstractSqlExecutor
/**
* Executes all sql statements.
*
* @param Doctrine_Connection $conn The database connection that is used to execute the queries.
* @param Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries.
* @param array $params The parameters.
* @return Doctrine\DBAL\Driver\Statement
*/
abstract public function execute(\Doctrine\DBAL\Connection $conn, array $params);
abstract public function execute(Connection $conn, array $params, array $types);
}
\ No newline at end of file
......@@ -21,7 +21,8 @@
namespace Doctrine\ORM\Query\Exec;
use Doctrine\ORM\Query\AST;
use Doctrine\DBAL\Connection,
Doctrine\ORM\Query\AST;
/**
* Executes the SQL statements for bulk DQL DELETE statements on classes in
......@@ -52,11 +53,11 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
$em = $sqlWalker->getEntityManager();
$conn = $em->getConnection();
$platform = $conn->getDatabasePlatform();
$primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName);
$primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable;
$rootClass = $em->getClassMetadata($primaryClass->rootEntityName);
$tempTable = $rootClass->getTemporaryIdTableName();
$idColumnNames = $rootClass->getIdentifierColumnNames();
$idColumnList = implode(', ', $idColumnNames);
......@@ -64,17 +65,17 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
// 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
$this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
. ' SELECT t0.' . implode(', t0.', $idColumnNames);
$sqlWalker->setSqlTableAlias($primaryClass->primaryTable['name'] . $primaryDqlAlias, 't0');
$sqlWalker->setSqlTableAlias($primaryClass->table['name'] . $primaryDqlAlias, 't0');
$rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias);
$fromClause = new AST\FromClause(array(new AST\IdentificationVariableDeclaration($rangeDecl, null, array())));
$this->_insertSql .= $sqlWalker->walkFromClause($fromClause);
// Append WHERE clause, if there is one.
if ($AST->whereClause) {
$this->_insertSql .= $sqlWalker->walkWhereClause($AST->whereClause);
}
// 2. Create ID subselect statement used in DELETE .... WHERE ... IN (subselect)
// 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect)
$idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable;
// 3. Create and store DELETE statements
......@@ -106,24 +107,24 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
* @param array $params The parameters.
* @override
*/
public function execute(\Doctrine\DBAL\Connection $conn, array $params)
public function execute(Connection $conn, array $params, array $types)
{
$numDeleted = 0;
// Create temporary id table
$conn->executeUpdate($this->_createTempTableSql);
// Insert identifiers
$numDeleted = $conn->executeUpdate($this->_insertSql, $params);
$numDeleted = $conn->executeUpdate($this->_insertSql, $params, $types);
// Execute DELETE statements
foreach ($this->_sqlStatements as $sql) {
$conn->executeUpdate($sql);
}
// Drop temporary table
$conn->executeUpdate($this->_dropTempTableSql);
return $numDeleted;
}
}
\ No newline at end of file
......@@ -21,7 +21,9 @@
namespace Doctrine\ORM\Query\Exec;
use Doctrine\ORM\Query\AST;
use Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\Query\AST;
/**
* Executes the SQL statements for bulk DQL UPDATE statements on classes in
......@@ -69,7 +71,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
// 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
$this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
. ' SELECT t0.' . implode(', t0.', $idColumnNames);
$sqlWalker->setSqlTableAlias($primaryClass->primaryTable['name'] . $updateClause->aliasIdentificationVariable, 't0');
$sqlWalker->setSqlTableAlias($primaryClass->table['name'] . $updateClause->aliasIdentificationVariable, 't0');
$rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $updateClause->aliasIdentificationVariable);
$fromClause = new AST\FromClause(array(new AST\IdentificationVariableDeclaration($rangeDecl, null, array())));
$this->_insertSql .= $sqlWalker->walkFromClause($fromClause);
......@@ -101,6 +103,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
$updateSql .= $sqlWalker->walkUpdateItem($updateItem);
//FIXME: parameters can be more deeply nested. traverse the tree.
//FIXME (URGENT): With query cache the parameter is out of date. Move to execute() stage.
if ($newValue instanceof AST\InputParameter) {
$paramKey = $newValue->name;
$this->_sqlParameters[$i][] = $sqlWalker->getQuery()->getParameter($paramKey);
......@@ -124,7 +127,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
foreach ($idColumnNames as $idColumnName) {
$columnDefinitions[$idColumnName] = array(
'notnull' => true,
'type' => \Doctrine\DBAL\Types\Type::getType($rootClass->getTypeOfColumn($idColumnName))
'type' => Type::getType($rootClass->getTypeOfColumn($idColumnName))
);
}
$this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
......@@ -134,13 +137,13 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
}
/**
* Executes all sql statements.
* Executes all SQL statements.
*
* @param Doctrine_Connection $conn The database connection that is used to execute the queries.
* @param array $params The parameters.
* @param Connection $conn The database connection that is used to execute the queries.
* @param array $params The parameters.
* @override
*/
public function execute(\Doctrine\DBAL\Connection $conn, array $params)
public function execute(Connection $conn, array $params, array $types)
{
$numUpdated = 0;
......@@ -148,7 +151,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
$conn->executeUpdate($this->_createTempTableSql);
// Insert identifiers. Parameters from the update clause are cut off.
$numUpdated = $conn->executeUpdate($this->_insertSql, array_slice($params, $this->_numParametersInUpdateClause));
$numUpdated = $conn->executeUpdate($this->_insertSql, array_slice($params, $this->_numParametersInUpdateClause), $types);
// Execute UPDATE statements
for ($i=0, $count=count($this->_sqlStatements); $i<$count; ++$i) {
......
......@@ -21,6 +21,10 @@
namespace Doctrine\ORM\Query\Exec;
use Doctrine\DBAL\Connection,
Doctrine\ORM\Query\AST\SelectStatement,
Doctrine\ORM\Query\SqlWalker;
/**
* Executor that executes the SQL statement for simple DQL SELECT statements.
*
......@@ -31,14 +35,14 @@ namespace Doctrine\ORM\Query\Exec;
* @since 2.0
*/
class SingleSelectExecutor extends AbstractSqlExecutor
{
public function __construct(\Doctrine\ORM\Query\AST\SelectStatement $AST, $sqlWalker)
{
public function __construct(SelectStatement $AST, SqlWalker $sqlWalker)
{
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
}
public function execute(\Doctrine\DBAL\Connection $conn, array $params)
public function execute(Connection $conn, array $params, array $types)
{
return $conn->execute($this->_sqlStatements, $params);
return $conn->execute($this->_sqlStatements, $params, $types);
}
}
......@@ -21,7 +21,8 @@
namespace Doctrine\ORM\Query\Exec;
use Doctrine\ORM\Query\AST;
use Doctrine\DBAL\Connection,
Doctrine\ORM\Query\AST;
/**
* Executor that executes the SQL statements for DQL DELETE/UPDATE statements on classes
......@@ -45,8 +46,8 @@ class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
}
}
public function execute(\Doctrine\DBAL\Connection $conn, array $params)
public function execute(Connection $conn, array $params, array $types)
{
return $conn->executeUpdate($this->_sqlStatements, $params);
return $conn->executeUpdate($this->_sqlStatements, $params, $types);
}
}
\ No newline at end of file
......@@ -38,7 +38,7 @@ use Doctrine\ORM\Query;
*/
class Parser
{
/** Maps BUILT-IN string function names to AST class names. */
/** READ-ONLY: Maps BUILT-IN string function names to AST class names. */
private static $_STRING_FUNCTIONS = array(
'concat' => 'Doctrine\ORM\Query\AST\Functions\ConcatFunction',
'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction',
......@@ -47,7 +47,7 @@ class Parser
'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction'
);
/** Maps BUILT-IN numeric function names to AST class names. */
/** READ-ONLY: Maps BUILT-IN numeric function names to AST class names. */
private static $_NUMERIC_FUNCTIONS = array(
'length' => 'Doctrine\ORM\Query\AST\Functions\LengthFunction',
'locate' => 'Doctrine\ORM\Query\AST\Functions\LocateFunction',
......@@ -57,7 +57,7 @@ class Parser
'size' => 'Doctrine\ORM\Query\AST\Functions\SizeFunction'
);
/** Maps BUILT-IN datetime function names to AST class names. */
/** READ-ONLY: Maps BUILT-IN datetime function names to AST class names. */
private static $_DATETIME_FUNCTIONS = array(
'current_date' => 'Doctrine\ORM\Query\AST\Functions\CurrentDateFunction',
'current_time' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimeFunction',
......@@ -2587,18 +2587,12 @@ class Parser
// Check for custom functions afterwards
$config = $this->_em->getConfiguration();
if (($func = $config->getCustomStringFunction($funcName)) !== null) {
self::$_STRING_FUNCTIONS[$funcName] = $func;
return $this->FunctionsReturningStrings();
} else if (($func = $config->getCustomNumericFunction($funcName)) !== null) {
self::$_NUMERIC_FUNCTIONS[$funcName] = $func;
return $this->FunctionsReturningNumerics();
} else if (($func = $config->getCustomDatetimeFunction($funcName)) !== null) {
self::$_DATETIME_FUNCTIONS[$funcName] = $func;
return $this->FunctionsReturningDatetime();
if ($config->getCustomStringFunction($funcName) !== null) {
return $this->CustomFunctionsReturningStrings();
} else if ($config->getCustomNumericFunction($funcName) !== null) {
return $this->CustomFunctionsReturningNumerics();
} else if ($config->getCustomDatetimeFunction($funcName) !== null) {
return $this->CustomFunctionsReturningDatetime();
}
$this->syntaxError('known function', $token);
......@@ -2623,6 +2617,16 @@ class Parser
return $function;
}
public function CustomFunctionsReturningNumerics()
{
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
$funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcNameLower);
$function = new $funcClass($funcNameLower);
$function->parse($this);
return $function;
}
/**
* FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
*/
......@@ -2636,6 +2640,16 @@ class Parser
return $function;
}
public function CustomFunctionsReturningDatetime()
{
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
$funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcNameLower);
$function = new $funcClass($funcNameLower);
$function->parse($this);
return $function;
}
/**
* FunctionsReturningStrings ::=
* "CONCAT" "(" StringPrimary "," StringPrimary ")" |
......@@ -2648,7 +2662,16 @@ class Parser
{
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
$funcClass = self::$_STRING_FUNCTIONS[$funcNameLower];
//$funcClass = $this->_em->getConfiguration()->getDQLStringFunctionClassName($funcNameLower);
$function = new $funcClass($funcNameLower);
$function->parse($this);
return $function;
}
public function CustomFunctionsReturningStrings()
{
$funcNameLower = strtolower($this->_lexer->lookahead['value']);
$funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcNameLower);
$function = new $funcClass($funcNameLower);
$function->parse($this);
......
......@@ -240,12 +240,12 @@ class SqlWalker implements TreeWalker
{
$sql = '';
$baseTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$baseTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
// INNER JOIN parent class tables
foreach ($class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$tableAlias = $this->getSqlTableAlias($parentClass->primaryTable['name'], $dqlAlias);
$tableAlias = $this->getSqlTableAlias($parentClass->table['name'], $dqlAlias);
$sql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform)
. ' ' . $tableAlias . ' ON ';
$first = true;
......@@ -264,7 +264,7 @@ class SqlWalker implements TreeWalker
if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$tableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
$tableAlias = $this->getSqlTableAlias($subClass->table['name'], $dqlAlias);
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform)
. ' ' . $tableAlias . ' ON ';
......@@ -295,7 +295,7 @@ class SqlWalker implements TreeWalker
if ($qComp['metadata']->isInheritanceTypeJoined()) {
$tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName);
} else {
$tableName = $qComp['metadata']->primaryTable['name'];
$tableName = $qComp['metadata']->table['name'];
}
if ($sql != '') {
......@@ -331,7 +331,7 @@ class SqlWalker implements TreeWalker
}
$sql .= (($this->_useSqlTableAliases)
? $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias) . '.' : ''
? $this->getSqlTableAlias($class->table['name'], $dqlAlias) . '.' : ''
) . $class->discriminatorColumn['name']
. ' IN (' . implode(', ', $values) . ')';
}
......@@ -432,7 +432,7 @@ class SqlWalker implements TreeWalker
$class = $this->_em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']);
}
return $this->getSqlTableAlias($class->primaryTable['name'], $identificationVariable);
return $this->getSqlTableAlias($class->table['name'], $identificationVariable);
}
/**
......@@ -519,7 +519,7 @@ class SqlWalker implements TreeWalker
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
// Add discriminator columns to SQL
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
$tblAlias = $this->getSqlTableAlias($rootClass->primaryTable['name'], $dqlAlias);
$tblAlias = $this->getSqlTableAlias($rootClass->table['name'], $dqlAlias);
$discrColumn = $rootClass->discriminatorColumn;
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias;
......@@ -535,9 +535,9 @@ class SqlWalker implements TreeWalker
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);
$sqlTableAlias = $this->getSqlTableAlias($owningClass->table['name'], $dqlAlias);
} else {
$sqlTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$sqlTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
}
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
......@@ -552,7 +552,7 @@ class SqlWalker implements TreeWalker
} else {
// Add foreign key columns to SQL, if necessary
if ($addMetaColumns) {
$sqlTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$sqlTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
......@@ -587,7 +587,7 @@ class SqlWalker implements TreeWalker
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
$sql .= $class->getQuotedTableName($this->_platform) . ' '
. $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
. $this->getSqlTableAlias($class->table['name'], $dqlAlias);
if ($class->isInheritanceTypeJoined()) {
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
......@@ -908,9 +908,9 @@ class SqlWalker implements TreeWalker
}
if (isset($mapping['inherited'])) {
$tableName = $this->_em->getClassMetadata($mapping['inherited'])->primaryTable['name'];
$tableName = $this->_em->getClassMetadata($mapping['inherited'])->table['name'];
} else {
$tableName = $class->primaryTable['name'];
$tableName = $class->table['name'];
}
if ($beginning) $beginning = false; else $sql .= ', ';
......@@ -931,7 +931,7 @@ class SqlWalker implements TreeWalker
if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$sqlTableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
$sqlTableAlias = $this->getSqlTableAlias($subClass->table['name'], $dqlAlias);
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
continue;
......@@ -1016,7 +1016,7 @@ class SqlWalker implements TreeWalker
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
$sql = ' FROM ' . $class->getQuotedTableName($this->_platform) . ' '
. $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
. $this->getSqlTableAlias($class->table['name'], $dqlAlias);
if ($class->isInheritanceTypeJoined()) {
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
......@@ -1302,8 +1302,8 @@ class SqlWalker implements TreeWalker
if ($assoc->isOneToMany()) {
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$targetTableAlias = $this->getSqlTableAlias($targetClass->table['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
$sql .= $targetClass->getQuotedTableName($this->_platform)
. ' ' . $targetTableAlias . ' WHERE ';
......@@ -1338,8 +1338,8 @@ class SqlWalker implements TreeWalker
// SQL table aliases
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
$targetTableAlias = $this->getSqlTableAlias($targetClass->table['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
// join to target table
$sql .= $assoc->getQuotedJoinTableName($this->_platform)
......@@ -1351,8 +1351,7 @@ class SqlWalker implements TreeWalker
$joinColumns = $assoc->isOwningSide
? $joinTable['inverseJoinColumns']
: $joinTable['joinColumns'];
//$referencedColumnClass = $assoc->isOwningSide ? $targetClass : $class;
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
......@@ -1362,13 +1361,13 @@ class SqlWalker implements TreeWalker
$targetClass->fieldNames[$joinColumn['referencedColumnName']],
$this->_platform);
}
$sql .= ' WHERE ';
$joinColumns = $assoc->isOwningSide
? $joinTable['joinColumns']
: $joinTable['inverseJoinColumns'];
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
......
......@@ -35,7 +35,7 @@ abstract class TreeWalkerAdapter implements TreeWalker
private $_queryComponents;
/**
* @inheritdoc
* {@inheritdoc}
*/
public function __construct($query, $parserResult, array $queryComponents)
{
......
......@@ -101,10 +101,10 @@ class ConvertDoctrine1Schema
if (isset($model['tableName']) && $model['tableName']) {
$e = explode('.', $model['tableName']);
if (count($e) > 1) {
$metadata->primaryTable['schema'] = $e[0];
$metadata->primaryTable['name'] = $e[1];
$metadata->table['schema'] = $e[0];
$metadata->table['name'] = $e[1];
} else {
$metadata->primaryTable['name'] = $e[0];
$metadata->table['name'] = $e[0];
}
}
}
......@@ -208,7 +208,7 @@ class ConvertDoctrine1Schema
$type = (isset($index['type']) && $index['type'] == 'unique')
? 'uniqueConstraints' : 'indexes';
$metadata->primaryTable[$type][$name] = array(
$metadata->table[$type][$name] = array(
'columns' => $index['fields']
);
}
......
......@@ -443,12 +443,12 @@ public function <methodName>()
private function _generateTableAnnotation($metadata)
{
$table = array();
if ($metadata->primaryTable['name']) {
$table[] = 'name="' . $metadata->primaryTable['name'] . '"';
if ($metadata->table['name']) {
$table[] = 'name="' . $metadata->table['name'] . '"';
}
if (isset($metadata->primaryTable['schema'])) {
$table[] = 'schema="' . $metadata->primaryTable['schema'] . '"';
if (isset($metadata->table['schema'])) {
$table[] = 'schema="' . $metadata->table['schema'] . '"';
}
return '@Table(' . implode(', ', $table) . ')';
......@@ -570,7 +570,7 @@ public function <methodName>()
. ($associationMapping->isManyToMany() ? ' = array()' : null) . ";\n";
}
return implode("\n", $lines)
return implode("\n", $lines);
}
private function _generateEntityFieldMappingProperties(ClassMetadataInfo $metadata)
......
......@@ -64,8 +64,8 @@ class PhpExporter extends AbstractExporter
$lines[] = "\$metadata->customRepositoryClassName = '" . $metadata->customRepositoryClassName . "';";
}
if ($metadata->primaryTable) {
$lines[] = '$metadata->setPrimaryTable(' . $this->_varExport($metadata->primaryTable) . ');';
if ($metadata->table) {
$lines[] = '$metadata->setPrimaryTable(' . $this->_varExport($metadata->table) . ');';
}
if ($metadata->discriminatorColumn) {
......
......@@ -67,16 +67,16 @@ class XmlExporter extends AbstractExporter
$root->addAttribute('name', $metadata->name);
if (isset($metadata->primaryTable['name'])) {
$root->addAttribute('table', $metadata->primaryTable['name']);
if (isset($metadata->table['name'])) {
$root->addAttribute('table', $metadata->table['name']);
}
if (isset($metadata->primaryTable['schema'])) {
$root->addAttribute('schema', $metadata->primaryTable['schema']);
if (isset($metadata->table['schema'])) {
$root->addAttribute('schema', $metadata->table['schema']);
}
if (isset($metadata->primaryTable['inheritance-type'])) {
$root->addAttribute('inheritance-type', $metadata->primaryTable['inheritance-type']);
if (isset($metadata->table['inheritance-type'])) {
$root->addAttribute('inheritance-type', $metadata->table['inheritance-type']);
}
if ($metadata->discriminatorColumn) {
......@@ -97,20 +97,20 @@ class XmlExporter extends AbstractExporter
$root->addChild('change-tracking-policy', $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy));
if (isset($metadata->primaryTable['indexes'])) {
if (isset($metadata->table['indexes'])) {
$indexesXml = $root->addChild('indexes');
foreach ($metadata->primaryTable['indexes'] as $name => $index) {
foreach ($metadata->table['indexes'] as $name => $index) {
$indexXml = $indexesXml->addChild('index');
$indexXml->addAttribute('name', $name);
$indexXml->addAttribute('columns', implode(',', $index['columns']));
}
}
if (isset($metadata->primaryTable['uniqueConstraints'])) {
if (isset($metadata->table['uniqueConstraints'])) {
$uniqueConstraintsXml = $root->addChild('unique-constraints');
foreach ($metadata->primaryTable['uniqueConstraints'] as $unique) {
foreach ($metadata->table['uniqueConstraints'] as $unique) {
$uniqueConstraintXml = $uniqueConstraintsXml->addChild('unique-constraint');
$uniqueConstraintXml->addAttribute('name', $name);
$uniqueConstraintXml->addAttribute('columns', implode(',', $unique['columns']));
......
......@@ -57,10 +57,10 @@ class YamlExporter extends AbstractExporter
} else {
$array['type'] = 'entity';
}
$array['table'] = $metadata->primaryTable['name'];
$array['table'] = $metadata->table['name'];
if (isset($metadata->primaryTable['schema'])) {
$array['schema'] = $metadata->primaryTable['schema'];
if (isset($metadata->table['schema'])) {
$array['schema'] = $metadata->table['schema'];
}
$inheritanceType = $metadata->inheritanceType;
......@@ -80,12 +80,12 @@ class YamlExporter extends AbstractExporter
$array['changeTrackingPolicy'] = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy);
}
if (isset($metadata->primaryTable['indexes'])) {
$array['indexes'] = $metadata->primaryTable['indexes'];
if (isset($metadata->table['indexes'])) {
$array['indexes'] = $metadata->table['indexes'];
}
if (isset($metadata->primaryTable['uniqueConstraints'])) {
$array['uniqueConstraints'] = $metadata->primaryTable['uniqueConstraints'];
if (isset($metadata->table['uniqueConstraints'])) {
$array['uniqueConstraints'] = $metadata->table['uniqueConstraints'];
}
$fieldMappings = $metadata->fieldMappings;
......
......@@ -112,11 +112,9 @@ class SchemaTool
{
$processedClasses = array(); // Reminder for processed classes, used for hierarchies
$metadataSchemaConfig = new \Doctrine\DBAL\Schema\SchemaConfig();
$metadataSchemaConfig->setExplicitForeignKeyIndexes(false);
$metadataSchemaConfig->setMaxIdentifierLength(63);
$sm = $this->_em->getConnection()->getSchemaManager();
$metadataSchemaConfig = $sm->createSchemaConfig();
$metadataSchemaConfig->setExplicitForeignKeyIndexes(false);
$schema = new \Doctrine\DBAL\Schema\Schema(array(), array(), $metadataSchemaConfig);
$evm = $this->_em->getEventManager();
......@@ -202,14 +200,14 @@ class SchemaTool
$this->_gatherRelationsSql($class, $table, $schema);
}
if (isset($class->primaryTable['indexes'])) {
foreach ($class->primaryTable['indexes'] AS $indexName => $indexData) {
if (isset($class->table['indexes'])) {
foreach ($class->table['indexes'] AS $indexName => $indexData) {
$table->addIndex($indexData['columns'], $indexName);
}
}
if (isset($class->primaryTable['uniqueConstraints'])) {
foreach ($class->primaryTable['uniqueConstraints'] AS $indexName => $indexData) {
if (isset($class->table['uniqueConstraints'])) {
foreach ($class->table['uniqueConstraints'] AS $indexName => $indexData) {
$table->addUniqueIndex($indexData['columns'], $indexName);
}
}
......
......@@ -280,7 +280,7 @@ class UnitOfWork implements PropertyChangedListener
$commitOrder = $this->_getCommitOrder();
$conn = $this->_em->getConnection();
$conn->beginTransaction();
try {
if ($this->_entityInsertions) {
......@@ -645,7 +645,7 @@ class UnitOfWork implements PropertyChangedListener
$actualData[$name] = $refProp->getValue($entity);
}
}
$originalData = $this->_originalEntityData[$oid];
$changeSet = array();
......@@ -693,7 +693,7 @@ class UnitOfWork implements PropertyChangedListener
}
$postInsertIds = $persister->executeInserts();
if ($postInsertIds) {
// Persister returned post-insert IDs
foreach ($postInsertIds as $id => $entity) {
......
......@@ -147,13 +147,13 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->assertType('array', $columns['baz1']->getPlatformOptions());
$this->assertEquals('baz2', strtolower($columns['baz2']->getname()));
$this->assertContains($columns['baz2']->gettype()->getName(), array('Time', 'Date', 'DateTime'));
$this->assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime'));
$this->assertEquals(true, $columns['baz2']->getnotnull());
$this->assertEquals(null, $columns['baz2']->getdefault());
$this->assertType('array', $columns['baz2']->getPlatformOptions());
$this->assertEquals('baz3', strtolower($columns['baz3']->getname()));
$this->assertContains($columns['baz2']->gettype()->getName(), array('Time', 'Date', 'DateTime'));
$this->assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime'));
$this->assertEquals(true, $columns['baz3']->getnotnull());
$this->assertEquals(null, $columns['baz3']->getdefault());
$this->assertType('array', $columns['baz3']->getPlatformOptions());
......
......@@ -6,7 +6,7 @@ class DriverConnectionMock implements \Doctrine\DBAL\Driver\Connection
{
public function prepare($prepareString) {}
public function query() {}
public function quote($input) {}
public function quote($input, $type=\PDO::PARAM_STR) {}
public function exec($statement) {}
public function lastInsertId($name = null) {}
public function beginTransaction() {}
......
......@@ -35,6 +35,6 @@ class OneToOneMappingTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('address', $oneToOneMapping->mappedBy);
$this->assertEquals('Address', $oneToOneMapping->sourceEntityName);
$this->assertEquals('Person', $oneToOneMapping->targetEntityName);
$this->assertTrue($oneToOneMapping->isInverseSide());
$this->assertTrue( ! $oneToOneMapping->isOwningSide);
}
}
\ No newline at end of file
......@@ -123,6 +123,16 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$userId = $this->_em->getConnection()->execute("SELECT user_id FROM cms_addresses WHERE id=?",
array($address->id))->fetchColumn();
$this->assertTrue(is_numeric($userId));
$this->_em->clear();
$user2 = $this->_em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u where u.id=?1')
->setParameter(1, $userId)
->getSingleResult();
// Address has been eager-loaded because it cant be lazy
$this->assertTrue($user2->address instanceof CmsAddress);
$this->assertFalse($user2->address instanceof \Doctrine\ORM\Proxy\Proxy);
}
public function testBasicManyToMany()
......
......@@ -23,10 +23,11 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
protected function setUp() {
$this->useModelSet('company');
parent::setUp();
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSqlLogger);
}
public function testCRUD()
{
{
$person = new CompanyPerson;
$person->setName('Roman S. Borschel');
......@@ -78,7 +79,7 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->clear();
$query = $this->_em->createQuery("update Doctrine\Tests\Models\Company\CompanyEmployee p set p.name = ?1, p.department = ?2 where p.name='Guilherme Blanco' and p.salary = ?3");
$query->setParameter(1, 'NewName');
$query->setParameter(1, 'NewName', 'string');
$query->setParameter(2, 'NewDepartment');
$query->setParameter(3, 100000);
$query->getSql();
......
......@@ -32,14 +32,14 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testGetParameters()
{
$query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1");
$this->assertEquals(array(1 => 42), $query->getParameters(array(1 => 42)));
$this->assertEquals(array(), $query->getParameters());
}
public function testGetParameters_HasSomeAlready()
{
$query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1");
$query->setParameter(2, 84);
$this->assertEquals(array(2 => 84, 1 => 42), $query->getParameters(array(1 => 42)));
$this->assertEquals(array(2 => 84), $query->getParameters());
}
public function testSimpleQueries()
......
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
require_once __DIR__ . '/../../../TestInit.php';
use DateTime, Doctrine\DBAL\Types\Type;
class DDC425Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC425Entity'),
//$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC425Other')
));
}
/**
* @group DDC-425
*/
public function testIssue()
{
//$this->_em->getConnection()->getConfiguration()->setSqlLogger(new \Doctrine\DBAL\Logging\EchoSqlLogger);
$num = $this->_em->createQuery('DELETE '.__NAMESPACE__.'\DDC425Entity e WHERE e.someDatetimeField > ?1')
->setParameter(1, new DateTime, Type::DATETIME)
->getResult();
$this->assertEquals(0, $num);
}
}
/** @Entity */
class DDC425Entity {
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
public $id;
/** @Column(type="datetime") */
public $someDatetimeField;
}
......@@ -9,6 +9,7 @@ class DDC444Test extends \Doctrine\Tests\OrmFunctionalTestCase
public function setUp()
{
parent::setUp();
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSqlLogger);
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC444User'),
));
......
......@@ -106,7 +106,6 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($class->associationMappings['phonenumbers'] instanceof \Doctrine\ORM\Mapping\OneToManyMapping);
$this->assertTrue(isset($class->associationMappings['phonenumbers']));
$this->assertFalse($class->associationMappings['phonenumbers']->isOwningSide);
$this->assertTrue($class->associationMappings['phonenumbers']->isInverseSide());
$this->assertTrue($class->associationMappings['phonenumbers']->isCascadePersist);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRemove);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRefresh);
......
......@@ -65,7 +65,7 @@ class ConvertDoctrine1SchemaTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('Profile', $metadatas['Profile']->associationMappings['User']->sourceEntityName);
$this->assertEquals('User', $metadatas['Profile']->associationMappings['User']->targetEntityName);
$this->assertEquals('username', $metadatas['User']->primaryTable['uniqueConstraints']['username']['columns'][0]);
$this->assertEquals('username', $metadatas['User']->table['uniqueConstraints']['username']['columns'][0]);
unlink(__DIR__ . '/convert/User.dcm.yml');
unlink(__DIR__ . '/convert/Profile.dcm.yml');
......
......@@ -25,7 +25,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
public function testWriteEntityClass()
{
$metadata = new ClassMetadataInfo('EntityGeneratorBook');
$metadata->primaryTable['name'] = 'book';
$metadata->table['name'] = 'book';
$metadata->mapField(array('fieldName' => 'name', 'type' => 'string'));
$metadata->mapField(array('fieldName' => 'status', 'type' => 'string', 'default' => 'published'));
$metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
......
......@@ -124,7 +124,7 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
*/
public function testTableIsExported($metadata)
{
$this->assertEquals('cms_users', $metadata->primaryTable['name']);
$this->assertEquals('cms_users', $metadata->table['name']);
return $metadata;
}
......
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