1
0
mirror of synced 2024-12-12 22:36:02 +03:00

Intermediate checkin.

This commit is contained in:
romanb 2008-08-02 17:41:37 +00:00
parent e704cd0fd2
commit 3cd4fc5542
22 changed files with 793 additions and 883 deletions

View File

@ -0,0 +1,455 @@
<?php
#namespace Doctrine::ORM;
/**
* The ActiveEntity class adds an ActiveRecord-like interface to Entity classes
* that allows the Entities to directly interact with the persistence layer.
* This is mostly just a convenient wrapper for people who want it that forwards
* most method calls to the EntityManager.
*
* @since 2.0
*/
class Doctrine_ActiveEntity extends Doctrine_Entity
{
/**
* Saves the current state of the entity into the database.
*
* @param Doctrine_Connection $conn optional connection parameter
* @return void
* @todo ActiveEntity method.
*/
public function save()
{
// TODO: Forward to EntityManager. There: registerNew() OR registerDirty() on UnitOfWork.
$this->_em->save($this);
}
/**
* Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
* query, except that if there is already a row in the table with the same
* key field values, the REPLACE query just updates its values instead of
* inserting a new row.
*
* The REPLACE type of query does not make part of the SQL standards. Since
* practically only MySQL and SQLIte implement it natively, this type of
* query isemulated through this method for other DBMS using standard types
* of queries inside a transaction to assure the atomicity of the operation.
*
* @param Doctrine_Connection $conn optional connection parameter
* @throws Doctrine_Connection_Exception if some of the key values was null
* @throws Doctrine_Connection_Exception if there were no key fields
* @throws Doctrine_Connection_Exception if something fails at database level
* @return integer number of rows affected
* @todo ActiveEntity method.
*/
public function replace()
{
return $this->_em->replace(
$this->_class,
$this->getPrepared(),
$this->_id);
}
/**
* Creates an array representation of the object's data.
*
* @param boolean $deep - Return also the relations
* @return array
* @todo ActiveEntity method.
* @todo Move implementation to EntityManager.
*/
public function toArray($deep = true, $prefixKey = false)
{
$a = array();
foreach ($this as $column => $value) {
if ($value === Doctrine_Null::$INSTANCE || is_object($value)) {
$value = null;
}
$a[$column] = $value;
}
if ($this->_class->getIdentifierType() == Doctrine::IDENTIFIER_AUTOINC) {
$idFieldNames = $this->_class->getIdentifier();
$idFieldName = $idFieldNames[0];
$ids = $this->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
$a[$idFieldName] = $id;
}
if ($deep) {
foreach ($this->_references as $key => $relation) {
if ( ! $relation instanceof Doctrine_Null) {
$a[$key] = $relation->toArray($deep, $prefixKey);
}
}
}
// [FIX] Prevent mapped Doctrine_Entitys from being displayed fully
foreach ($this->_values as $key => $value) {
if ($value instanceof Doctrine_Entity) {
$a[$key] = $value->toArray($deep, $prefixKey);
} else {
$a[$key] = $value;
}
}
return $a;
}
/**
* Merges this Entity with an array of values
* or with another existing instance of.
*
* @param mixed $data Data to merge. Either another instance of this model or an array
* @param bool $deep Bool value for whether or not to merge the data deep
* @return void
* @todo ActiveEntity method.
* @todo Move implementation to EntityManager.
*/
public function merge($data, $deep = true)
{
if ($data instanceof $this) {
$array = $data->toArray($deep);
} else if (is_array($data)) {
$array = $data;
} else {
$array = array();
}
return $this->fromArray($array, $deep);
}
/**
* fromArray
*
* @param string $array
* @param bool $deep Bool value for whether or not to merge the data deep
* @return void
* @todo ActiveEntity method.
* @todo Move implementation to EntityManager.
*/
public function fromArray($array, $deep = true)
{
if (is_array($array)) {
foreach ($array as $key => $value) {
if ($deep && $this->getTable()->hasRelation($key)) {
$this->$key->fromArray($value, $deep);
} else if ($this->getTable()->hasField($key)) {
$this->set($key, $value);
}
}
}
}
/**
* Synchronizes a Doctrine_Entity and its relations with data from an array
*
* It expects an array representation of a Doctrine_Entity similar to the return
* value of the toArray() method. If the array contains relations it will create
* those that don't exist, update the ones that do, and delete the ones missing
* on the array but available on the Doctrine_Entity
*
* @param array $array representation of a Doctrine_Entity
* @todo ActiveEntity method.
* @todo Move implementation to EntityManager.
*/
public function synchronizeFromArray(array $array)
{
foreach ($array as $key => $value) {
if ($this->getTable()->hasRelation($key)) {
$this->get($key)->synchronizeFromArray($value);
} else if ($this->getTable()->hasColumn($key)) {
$this->set($key, $value);
}
}
// eliminate relationships missing in the $array
foreach ($this->_references as $name => $obj) {
if ( ! isset($array[$name])) {
unset($this->$name);
}
}
}
/**
* exportTo
*
* @param string $type
* @param string $deep
* @return void
* @todo ActiveEntity method.
*/
public function exportTo($type, $deep = true)
{
if ($type == 'array') {
return $this->toArray($deep);
} else {
return Doctrine_Parser::dump($this->toArray($deep, true), $type);
}
}
/**
* importFrom
*
* @param string $type
* @param string $data
* @return void
* @author Jonathan H. Wage
* @todo ActiveEntity method.
*/
public function importFrom($type, $data)
{
if ($type == 'array') {
return $this->fromArray($data);
} else {
return $this->fromArray(Doctrine_Parser::load($data, $type));
}
}
/**
* Deletes the persistent state of the entity.
*
* @return boolean TRUE on success, FALSE on failure.
* @todo ActiveRecord method.
*/
public function delete()
{
// TODO: Forward to EntityManager. There: registerRemoved() on UnitOfWork
return $this->_em->remove($this);
}
/**
* Creates a copy of the entity.
*
* @return Doctrine_Entity
* @todo ActiveEntity method. Implementation to EntityManager.
*/
public function copy($deep = true)
{
$data = $this->_data;
if ($this->_class->getIdentifierType() === Doctrine::IDENTIFIER_AUTOINC) {
$idFieldNames = (array)$this->_class->getIdentifier();
$id = $idFieldNames[0];
unset($data[$id]);
}
$ret = $this->_em->createEntity($this->_entityName, $data);
$modified = array();
foreach ($data as $key => $val) {
if ( ! ($val instanceof Doctrine_Null)) {
$ret->_modified[] = $key;
}
}
if ($deep) {
foreach ($this->_references as $key => $value) {
if ($value instanceof Doctrine_Collection) {
foreach ($value as $record) {
$ret->{$key}[] = $record->copy($deep);
}
} else {
$ret->set($key, $value->copy($deep));
}
}
}
return $ret;
}
/**
* Removes links from this record to given records
* if no ids are given, it removes all links
*
* @param string $alias related component alias
* @param array $ids the identifiers of the related records
* @return Doctrine_Entity this object
* @todo ActiveEntity method.
*/
public function unlink($alias, $ids = array())
{
$ids = (array) $ids;
$q = new Doctrine_Query();
$rel = $this->getTable()->getRelation($alias);
if ($rel instanceof Doctrine_Relation_Association) {
$q->delete()
->from($rel->getAssociationTable()->getComponentName())
->where($rel->getLocal() . ' = ?', array_values($this->identifier()));
if (count($ids) > 0) {
$q->whereIn($rel->getForeign(), $ids);
}
$q->execute();
} else if ($rel instanceof Doctrine_Relation_ForeignKey) {
$q->update($rel->getTable()->getComponentName())
->set($rel->getForeign(), '?', array(null))
->addWhere($rel->getForeign() . ' = ?', array_values($this->identifier()));
if (count($ids) > 0) {
$relTableIdFieldNames = (array)$rel->getTable()->getIdentifier();
$q->whereIn($relTableIdFieldNames[0], $ids);
}
$q->execute();
}
if (isset($this->_references[$alias])) {
foreach ($this->_references[$alias] as $k => $record) {
if (in_array(current($record->identifier()), $ids)) {
$this->_references[$alias]->remove($k);
}
}
$this->_references[$alias]->takeSnapshot();
}
return $this;
}
/**
* Creates links from this record to given records.
*
* @param string $alias related component alias
* @param array $ids the identifiers of the related records
* @return Doctrine_Entity this object
* @todo ActiveEntity method.
*/
public function link($alias, array $ids)
{
if ( ! count($ids)) {
return $this;
}
$identifier = array_values($this->identifier());
$identifier = array_shift($identifier);
$rel = $this->getTable()->getRelation($alias);
if ($rel instanceof Doctrine_Relation_Association) {
$modelClassName = $rel->getAssociationTable()->getComponentName();
$localFieldName = $rel->getLocalFieldName();
$localFieldDef = $rel->getAssociationTable()->getColumnDefinition($localFieldName);
if ($localFieldDef['type'] == 'integer') {
$identifier = (integer) $identifier;
}
$foreignFieldName = $rel->getForeignFieldName();
$foreignFieldDef = $rel->getAssociationTable()->getColumnDefinition($foreignFieldName);
if ($foreignFieldDef['type'] == 'integer') {
for ($i = 0; $i < count($ids); $i++) {
$ids[$i] = (integer) $ids[$i];
}
}
foreach ($ids as $id) {
$record = new $modelClassName;
$record[$localFieldName] = $identifier;
$record[$foreignFieldName] = $id;
$record->save();
}
} else if ($rel instanceof Doctrine_Relation_ForeignKey) {
$q = new Doctrine_Query();
$q->update($rel->getTable()->getComponentName())
->set($rel->getForeign(), '?', array_values($this->identifier()));
if (count($ids) > 0) {
$relTableIdFieldNames = (array)$rel->getTable()->getIdentifier();
$q->whereIn($relTableIdFieldNames[0], $ids);
}
$q->execute();
} else if ($rel instanceof Doctrine_Relation_LocalKey) {
$q = new Doctrine_Query();
$q->update($this->getTable()->getComponentName())
->set($rel->getLocalFieldName(), '?', $ids);
if (count($ids) > 0) {
$relTableIdFieldNames = (array)$rel->getTable()->getIdentifier();
$q->whereIn($relTableIdFieldNames[0], array_values($this->identifier()));
}
$q->execute();
}
return $this;
}
/**
* Refresh internal data from the database
*
* @param bool $deep If true, fetch also current relations. Caution: this deletes
* any aggregated values you may have queried beforee
*
* @throws Doctrine_Record_Exception When the refresh operation fails (when the database row
* this record represents does not exist anymore)
* @return boolean
* @todo Implementation to EntityManager.
* @todo Move to ActiveEntity (extends Entity). Implementation to EntityManager.
*/
public function refresh($deep = false)
{
$id = $this->identifier();
if ( ! is_array($id)) {
$id = array($id);
}
if (empty($id)) {
return false;
}
$id = array_values($id);
if ($deep) {
$query = $this->_em->createQuery()->from($this->_entityName);
foreach (array_keys($this->_references) as $name) {
$query->leftJoin(get_class($this) . '.' . $name);
}
$query->where(implode(' = ? AND ', $this->_class->getIdentifierColumnNames()) . ' = ?');
$this->clearRelated();
$record = $query->fetchOne($id);
} else {
// Use FETCH_ARRAY to avoid clearing object relations
$record = $this->getRepository()->find($this->identifier(), Doctrine::HYDRATE_ARRAY);
if ($record) {
$this->hydrate($record);
}
}
if ($record === false) {
throw new Doctrine_Record_Exception('Failed to refresh. Record does not exist.');
}
$this->_modified = array();
$this->_extractIdentifier();
$this->_state = Doctrine_Entity::STATE_CLEAN;
return $this;
}
/**
* Hydrates this object from given array
*
* @param array $data
* @return boolean
*/
final public function hydrate(array $data)
{
$this->_data = array_merge($this->_data, $data);
$this->_extractIdentifier();
}
}
?>

View File

@ -63,13 +63,13 @@ class Doctrine_Configuration
/**
* Initializes the attributes.
* Changes null default values to references to the Null object to allow
* fast isset() checks instead of array_key_exists().
*
* @return void
*/
private function _initAttributes()
{
// Change null default values to references to the Null object to allow
// fast isset() checks instead of array_key_exists().
foreach ($this->_attributes as $key => $value) {
if ($value === null) {
$this->_attributes[$key] = $this->_nullObject;

View File

@ -26,7 +26,7 @@
#use Doctrine::DBAL::Exceptions::ConnectionException;
/**
* A thin connection wrapper on top of PDO.
* A thin wrapper on top of the PDO class.
*
* 1. Event listeners
* An easy to use, pluggable eventlistener architecture. Aspects such as
@ -117,9 +117,9 @@ abstract class Doctrine_Connection
protected $_quoteIdentifiers;
/**
* @var array $serverInfo
* @var array
*/
protected $serverInfo = array();
protected $_serverInfo = array();
/**
* The parameters used during creation of the Connection.
@ -154,11 +154,18 @@ abstract class Doctrine_Connection
protected $_platform;
/**
* Enter description here...
* The transaction object.
*
* @var Doctrine::DBAL::Transactions::Transaction
*/
protected $_transaction;
/**
* The sequence manager.
*
* @var Doctrine::DBAL::Sequencing::SequenceManager
*/
protected $_sequenceManager;
/**
* Constructor.
@ -339,20 +346,13 @@ abstract class Doctrine_Connection
*
* @return string
* @todo make abstract, implement in subclasses.
* @todo throw different exception?
*/
protected function _constructPdoDsn()
{
throw Doctrine_Exception::notImplemented('_constructPdoDsn', get_class($this));
}
/**
* @todo Remove. Breaks encapsulation.
*/
public function incrementQueryCount()
{
$this->_queryCount++;
}
/**
* Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
* query, except that if there is already a row in the table with the same
@ -360,8 +360,8 @@ abstract class Doctrine_Connection
* inserting a new row.
*
* The REPLACE type of query does not make part of the SQL standards. Since
* practically only MySQL and SQLIte implement it natively, this type of
* query isemulated through this method for other DBMS using standard types
* practically only MySQL and SQLite implement it natively, this type of
* query is emulated through this method for other DBMS using standard types
* of queries inside a transaction to assure the atomicity of the operation.
*
* @param string name of the table on which the REPLACE query will
@ -490,7 +490,7 @@ abstract class Doctrine_Connection
// column names are specified as array keys
$cols = array();
// the query VALUES will contain either expresions (eg 'NOW()') or ?
// the query VALUES will contain either expressions (eg 'NOW()') or ?
$a = array();
foreach ($data as $columnName => $value) {
$cols[] = $this->quoteIdentifier($columnName);
@ -502,13 +502,10 @@ abstract class Doctrine_Connection
}
}
// build the statement
$query = 'INSERT INTO ' . $this->quoteIdentifier($tableName)
. ' (' . implode(', ', $cols) . ') '
. 'VALUES (';
$query .= implode(', ', $a) . ')';
// prepare and execute the statement
return $this->exec($query, array_values($data));
}
@ -567,14 +564,15 @@ abstract class Doctrine_Connection
// quick fix for the identifiers that contain a dot
if (strpos($str, '.')) {
$e = explode('.', $str);
return $this->quoteIdentifier($e[0]) . '.'
return $this->quoteIdentifier($e[0])
. '.'
. $this->quoteIdentifier($e[1]);
}
$q = $this->properties['identifier_quoting'];
$str = str_replace($q['end'], $q['escape'] . $q['end'], $str);
return $q['start'] . $str . $q['end'];
$c = $this->_platform->getIdentifierQuoteCharacter();
$str = str_replace($c, $c . $c, $str);
return $c . $str . $c;
}
/**
@ -603,55 +601,16 @@ abstract class Doctrine_Connection
}
/**
* Quotes given input parameter
* Quotes given input parameter.
*
* @param mixed $input parameter to be quoted
* @param string $type
* @return mixed
* @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)
{
return $this->_pdo->quote($input, $type);
}
/**
* quote
* quotes given input parameter
*
* @param mixed $input parameter to be quoted
* @param string $type
* @return mixed
*/
/*public function quote($input, $type = null)
{
if ($type == null) {
$type = gettype($input);
}
switch ($type) {
case 'integer':
case 'enum':
case 'boolean':
case 'double':
case 'float':
case 'bool':
case 'decimal':
case 'int':
return $input;
case 'array':
case 'object':
$input = serialize($input);
case 'date':
case 'time':
case 'timestamp':
case 'string':
case 'char':
case 'varchar':
case 'text':
case 'gzip':
case 'blob':
case 'clob':
return $this->conn->quote($input);
}
}*/
/**
* Set the date/time format for the current connection
@ -882,21 +841,14 @@ abstract class Doctrine_Connection
* @throws Doctrine_Connection_Exception
*/
public function rethrowException(Exception $e, $invoker)
{
//$event = new Doctrine_Event($this, Doctrine_Event::CONN_ERROR);
//$this->getListener()->preError($event);
{
$name = 'Doctrine_Connection_' . $this->_driverName . '_Exception';
$exc = new $name($e->getMessage(), (int) $e->getCode());
if ( ! is_array($e->errorInfo)) {
$e->errorInfo = array(null, null, null, null);
}
$exc->processErrorInfo($e->errorInfo);
throw $exc;
//$this->getListener()->postError($event);
}
/**
@ -1007,7 +959,7 @@ abstract class Doctrine_Connection
*/
public function commit($savepoint = null)
{
return $this->transaction->commit($savepoint);
return $this->_transaction->commit($savepoint);
}
/**
@ -1025,7 +977,7 @@ abstract class Doctrine_Connection
*/
public function rollback($savepoint = null)
{
$this->transaction->rollback($savepoint);
$this->_transaction->rollback($savepoint);
}
/**
@ -1202,31 +1154,18 @@ abstract class Doctrine_Connection
return Doctrine_Lib::getConnectionAsString($this);
}
/*
* ----------- Mixed methods (need to figure out where they go) ---------------
*/
/**
* retrieves a database connection attribute
* Gets the SequenceManager that can be used to retrieve sequence values
* through this connection.
*
* @param integer $attribute
* @return mixed
* @todo Implementation or remove if not needed. Configuration is the main
* container for all the attributes now.
* @return Doctrine::DBAL::Sequencing::SequenceManager
*/
public function getAttribute($attribute)
{
if ($attribute == Doctrine::ATTR_QUOTE_IDENTIFIER) {
return false;
}
}
public function getSequenceManager()
{
if ( ! $this->modules['sequence']) {
if ( ! $this->_sequenceManager) {
$class = "Doctrine_Sequence_" . $this->_driverName;
$this->modules['sequence'] = new $class;
$this->_sequenceManager = new $class;
}
return $this->modules['sequence'];
return $this->_sequenceManager;
}
}

View File

@ -58,7 +58,10 @@ class Doctrine_Connection_Mock extends Doctrine_Connection_Common
}
public function quote($input, $type = null)
{
{
if ($type === 'string') {
return "'" . $input . "'";
}
return $input;
}
}

View File

@ -18,12 +18,10 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Adapter_Statement_Interface');
/**
* Doctrine_Connection_Statement
* A thin wrapper around PDOStatement.
*
* @package Doctrine
* @subpackage Connection
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
@ -31,7 +29,7 @@ Doctrine::autoload('Doctrine_Adapter_Statement_Interface');
* @version $Revision: 1532 $
* @todo Do we seriously need this wrapper?
*/
class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interface
class Doctrine_Connection_Statement
{
/**
* @var Doctrine_Connection $conn Doctrine_Connection object, every connection
@ -40,7 +38,7 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
protected $_conn;
/**
* @var mixed $_stmt PDOStatement object, boolean false or Doctrine_Adapter_Statement object
* @var PDOStatement $_stmt PDOStatement object, boolean false or Doctrine_Adapter_Statement object
*/
protected $_stmt;
@ -81,7 +79,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* bindColumn
* 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.
@ -125,7 +122,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* bindParam
* Binds a PHP variable to a corresponding named or question mark placeholder in the
* SQL statement that was use to prepare the statement. Unlike Doctrine_Adapter_Statement_Interface->bindValue(),
* the variable is bound as a reference and will only be evaluated at the time
@ -161,7 +157,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* closeCursor
* Closes the cursor, enabling the statement to be executed again.
*
* @return boolean Returns TRUE on success or FALSE on failure.
@ -172,7 +167,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* columnCount
* Returns the number of columns in the result set
*
* @return integer Returns the number of columns in the result set represented
@ -185,7 +179,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* errorCode
* Fetch the SQLSTATE associated with the last operation on the statement handle
*
* @see Doctrine_Adapter_Interface::errorCode()
@ -197,7 +190,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* errorInfo
* Fetch extended error information associated with the last operation on the statement handle
*
* @see Doctrine_Adapter_Interface::errorInfo()
@ -209,7 +201,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* execute
* Executes a prepared statement
*
* If the prepared statement included parameter markers, you must either:
@ -226,24 +217,22 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
public function execute($params = null)
{
try {
$event = new Doctrine_Event($this, Doctrine_Event::STMT_EXECUTE, $this->getQuery(), $params);
$this->_conn->getListener()->preStmtExecute($event);
//$event = new Doctrine_Event($this, Doctrine_Event::STMT_EXECUTE, $this->getQuery(), $params);
//$this->_conn->getListener()->preStmtExecute($event);
$result = true;
if ( ! $event->skipOperation) {
//if ( ! $event->skipOperation) {
$result = $this->_stmt->execute($params);
$this->_conn->incrementQueryCount();
}
//$this->_conn->incrementQueryCount();
//}
$this->_conn->getListener()->postStmtExecute($event);
//$this->_conn->getListener()->postStmtExecute($event);
return $result;
} catch (PDOException $e) {
} catch (Doctrine_Adapter_Exception $e) {
} catch (PDOException $e) {
$this->_conn->rethrowException($e, $this);
}
$this->_conn->rethrowException($e, $this);
return false;
}
@ -278,25 +267,23 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
$cursorOrientation = Doctrine::FETCH_ORI_NEXT,
$cursorOffset = null)
{
$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCH, $this->getQuery());
//$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCH, $this->getQuery());
//$event->fetchMode = $fetchMode;
//$event->cursorOrientation = $cursorOrientation;
//$event->cursorOffset = $cursorOffset;
$event->fetchMode = $fetchMode;
$event->cursorOrientation = $cursorOrientation;
$event->cursorOffset = $cursorOffset;
//$data = $this->_conn->getListener()->preFetch($event);
$data = $this->_conn->getListener()->preFetch($event);
if ( ! $event->skipOperation) {
//if ( ! $event->skipOperation) {
$data = $this->_stmt->fetch($fetchMode, $cursorOrientation, $cursorOffset);
}
//}
$this->_conn->getListener()->postFetch($event);
//$this->_conn->getListener()->postFetch($event);
return $data;
}
/**
* fetchAll
* Returns an array containing all of the result set rows
*
* @param integer $fetchMode Controls how the next row will be returned to the caller.
@ -308,32 +295,28 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
*
* @return array
*/
public function fetchAll($fetchMode = Doctrine::FETCH_BOTH,
$columnIndex = null)
public function fetchAll($fetchMode = Doctrine::FETCH_BOTH, $columnIndex = null)
{
$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCHALL, $this->getQuery());
$event->fetchMode = $fetchMode;
$event->columnIndex = $columnIndex;
//$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCHALL, $this->getQuery());
//$event->fetchMode = $fetchMode;
//$event->columnIndex = $columnIndex;
//$this->_conn->getListener()->preFetchAll($event);
$this->_conn->getListener()->preFetchAll($event);
if ( ! $event->skipOperation) {
//if ( ! $event->skipOperation) {
if ($columnIndex !== null) {
$data = $this->_stmt->fetchAll($fetchMode, $columnIndex);
} else {
$data = $this->_stmt->fetchAll($fetchMode);
}
//$event->data = $data;
//}
$event->data = $data;
}
$this->_conn->getListener()->postFetchAll($event);
//$this->_conn->getListener()->postFetchAll($event);
return $data;
}
/**
* fetchColumn
* Returns a single column from the next row of a
* result set or FALSE if there are no more rows.
*
@ -349,7 +332,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* fetchObject
* Fetches the next row and returns it as an object.
*
* Fetches the next row and returns it as an object. This function is an alternative to
@ -367,7 +349,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* getAttribute
* Retrieve a statement attribute
*
* @param integer $attribute
@ -380,7 +361,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* getColumnMeta
* Returns metadata for a column in a result set
*
* @param integer $column The 0-indexed column in the result set.
@ -401,7 +381,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* nextRowset
* Advances to the next rowset in a multi-rowset statement handle
*
* Some database servers support stored procedures that return more than one rowset
@ -417,7 +396,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* rowCount
* rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
* executed by the corresponding object.
*
@ -434,7 +412,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* setAttribute
* Set a statement attribute
*
* @param integer $attribute
@ -447,7 +424,6 @@ class Doctrine_Connection_Statement implements Doctrine_Adapter_Statement_Interf
}
/**
* setFetchMode
* Set the default fetch mode for this statement
*
* @param integer $mode The fetch mode must be one of the Doctrine::FETCH_* constants.

View File

@ -10,66 +10,64 @@
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class Doctrine_DatabasePlatform
{
{
/**
* An array containing all features this platform supports, keys representing feature
* names and values as one of the following (true, false, 'emulated').
*
* @var array
* Constructor.
*/
protected $_supported = array();
/**
* Platform specific properties. Subclasses can override these in the
* constructor.
*
* @var array $properties
*/
protected $_properties = array(
'sql_comments' => array(
array(
'start' => '--',
'end' => "\n",
'escape' => false
),
array(
'start' => '/*',
'end' => '*/',
'escape' => false
)
),
'identifier_quoting' => array(
'start' => '"',
'end' => '"',
'escape' => '"'
),
'string_quoting' => array(
'start' => "'",
'end' => "'",
'escape' => false,
'escape_pattern' => false
),
'wildcards' => array('%', '_'),
'varchar_max_length' => 255,
);
public function __construct() {}
/**
* Checks whether a certain feature is supported.
* Gets the character used for identifier quoting.
*
* @param string $feature the name of the feature
* @return boolean whether or not this drivers supports given feature
* @return string
*/
public function supports($feature)
public function getIdentifierQuoteCharacter()
{
return (isset($this->_supported[$feature]) &&
($this->_supported[$feature] === 'emulated' || $this->_supported[$feature]));
return '"';
}
/**
* regexp
* returns the regular expression operator
* Gets the string portion that starts an SQL comment.
*
* @return string
*/
public function getSqlCommentStartString()
{
return "--";
}
/**
* Gets the string portion that starts an SQL comment.
*
* @return string
*/
public function getSqlCommentEndString()
{
return "\n";
}
/**
* Gets the maximum length of a varchar field.
*
* @return integer
*/
public function getVarcharMaxLength()
{
return 255;
}
/**
* Gets all SQL wildcard characters of the platform.
*
* @return array
*/
public function getWildcards()
{
return array('%', '_');
}
/**
* Returns the regular expression operator.
*
* @return string
*/
@ -889,9 +887,10 @@ abstract class Doctrine_DatabasePlatform
*
* @param string $query The SQL string to write to / append to.
* @return string
* @todo Remove the ORM dependency
*/
public function writeLimitClauseInSubquery(Doctrine_ClassMetadata $rootClass, $query,
$limit = false, $offset = false)
public function writeLimitClauseInSubquery(Doctrine_ClassMetadata $rootClass,
$query, $limit = false, $offset = false)
{
return $this->modifyLimitQuery($query, $limit, $offset);
}
@ -910,6 +909,46 @@ abstract class Doctrine_DatabasePlatform
}
return $this->_properties[$name];
}
public function supportsSequences()
{
return false;
}
public function supportsIdentityColumns()
{
return false;
}
public function supportsIndexes()
{
return true;
}
public function supportsTransactions()
{
return true;
}
public function supportsSavepoints()
{
return true;
}
public function supportsPrimaryConstraints()
{
return true;
}
public function supportsForeignKeyConstraints()
{
return true;
}
public function supportsGettingAffectedRows()
{
return true;
}
}

View File

@ -16,26 +16,6 @@ class Doctrine_DatabasePlatform_FirebirdPlatform extends Doctrine_DatabasePlatfo
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => true,
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'transactions' => true,
'savepoints' => true,
'current_id' => true,
'limit_queries' => 'emulated',
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => false,
'pattern_escaping' => true
);
}
/**

View File

@ -8,24 +8,6 @@ class Doctrine_DatabasePlatform_MsSqlPlatform extends Doctrine_DatabasePlatform
public function __construct()
{
parent::__construct();
// initialize all driver options
$this->_supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => 'emulated',
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
);
}
/**

View File

@ -15,7 +15,7 @@ class Doctrine_DatabasePlatform_MySqlPlatform extends Doctrine_DatabasePlatform
* @var array
* @todo Needed? What about lazy initialization?
*/
protected static $_reservedKeywords = array(
/*protected static $_reservedKeywords = array(
'ADD', 'ALL', 'ALTER',
'ANALYZE', 'AND', 'AS',
'ASC', 'ASENSITIVE', 'BEFORE',
@ -90,56 +90,30 @@ class Doctrine_DatabasePlatform_MySqlPlatform extends Doctrine_DatabasePlatform
'WHEN', 'WHERE', 'WHILE',
'WITH', 'WRITE', 'X509',
'XOR', 'YEAR_MONTH', 'ZEROFILL'
);
);*/
/**
* Constructor.
* Creates a new MySqlPlatform.
* Creates a new MySqlPlatform instance.
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => false,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => true
);
$this->_properties['string_quoting'] = array(
'start' => "'",
'end' => "'",
'escape' => '\\',
'escape_pattern' => '\\');
$this->_properties['identifier_quoting'] = array(
'start' => '`',
'end' => '`',
'escape' => '`');
$this->_properties['sql_comments'] = array(
array('start' => '-- ', 'end' => "\n", 'escape' => false),
array('start' => '#', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false),
);
$this->properties['varchar_max_length'] = 255;
parent::__construct();
}
/**
* returns the regular expression operator
* Gets the character used for identifier quoting.
*
* @return string
* @override
*/
public function getIdentifierQuoteCharacter()
{
return '`';
}
/**
* Returns the regular expression operator.
*
* @return string
* @override
@ -204,6 +178,7 @@ class Doctrine_DatabasePlatform_MySqlPlatform extends Doctrine_DatabasePlatform
}
$match.= "'";
$match.= $this->patternEscapeString();
return $match;
}
@ -555,6 +530,29 @@ class Doctrine_DatabasePlatform_MySqlPlatform extends Doctrine_DatabasePlatform
{
return true;
}
/**
* Whether the platform supports identity columns.
* MySql supports this through AUTO_INCREMENT columns.
*
* @return boolean
* @override
*/
public function supportsIdentityColumns()
{
return true;
}
/**
* Whether the platform supports savepoints. MySql does not.
*
* @return boolean
* @override
*/
public function supportsSavepoints()
{
return false;
}
}
?>

View File

@ -8,26 +8,6 @@ class Doctrine_DatabasePlatform_OraclePlatform extends Doctrine_DatabasePlatform
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => true,
'indexes' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => true,
'limit_queries' => true,
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => false, // implementation is broken
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => true,
'pattern_escaping' => true,
);
}
/**
@ -44,6 +24,9 @@ class Doctrine_DatabasePlatform_OraclePlatform extends Doctrine_DatabasePlatform
return $this->_createLimitSubquery($query, $limit, $offset);
}
/**
* @todo Doc
*/
private function _createLimitSubquery($query, $limit, $offset, $column = null)
{
$limit = (int) $limit;

View File

@ -9,7 +9,7 @@ class Doctrine_DatabasePlatform_PostgreSqlPlatform extends Doctrine_DatabasePlat
* @param array
* @todo Nedded? What about lazy initialization?
*/
protected static $_reservedKeywords = array(
/*protected static $_reservedKeywords = array(
'abort', 'absolute', 'access', 'action', 'add', 'after', 'aggregate',
'all', 'alter', 'analyse', 'analyze', 'and', 'any', 'as', 'asc',
'assertion', 'assignment', 'at', 'authorization', 'backward', 'before',
@ -54,7 +54,7 @@ class Doctrine_DatabasePlatform_PostgreSqlPlatform extends Doctrine_DatabasePlat
'unknown', 'unlisten', 'until', 'update', 'usage', 'user', 'using',
'vacuum', 'valid', 'validator', 'values', 'varchar', 'varying',
'verbose', 'version', 'view', 'volatile', 'when', 'where', 'with',
'without', 'work', 'write', 'year','zone');
'without', 'work', 'write', 'year','zone');*/
/**
@ -63,28 +63,7 @@ class Doctrine_DatabasePlatform_PostgreSqlPlatform extends Doctrine_DatabasePlat
*/
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => true,
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'transactions' => true,
'savepoints' => true,
'current_id' => true,
'limit_queries' => true,
'LOBs' => true,
'replace' => 'emulated',
'sub_selects' => true,
'auto_increment' => 'emulated',
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => true,
'identifier_quoting' => true,
'pattern_escaping' => true,
);
parent::__construct();
$this->_properties['string_quoting'] = array('start' => "'",
'end' => "'",
'escape' => "'",
@ -94,7 +73,6 @@ class Doctrine_DatabasePlatform_PostgreSqlPlatform extends Doctrine_DatabasePlat
'escape' => '"');
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.
@ -509,7 +487,39 @@ class Doctrine_DatabasePlatform_PostgreSqlPlatform extends Doctrine_DatabasePlat
public function parseBoolean($value)
{
return $value;
}
}
/**
* Whether the platform supports sequences.
* Postgres has native support for sequences.
*
* @return boolean
*/
public function supportsSequences()
{
return true;
}
/**
* Whether the platform supports identity columns.
* Postgres supports these through the SERIAL keyword.
*
* @return boolean
*/
public function supportsIdentityColumns()
{
return true;
}
/**
* Whether the platform prefers sequences for ID generation.
*
* @return boolean
*/
public function prefersSequences()
{
return true;
}
}
?>

View File

@ -16,26 +16,6 @@ class Doctrine_DatabasePlatform_SqlitePlatform extends Doctrine_DatabasePlatform
public function __construct()
{
parent::__construct();
$this->_supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'transactions' => true,
'savepoints' => false,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => false, // not implemented
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => false,
);
}
/**

View File

@ -39,7 +39,6 @@
* @link www.phpdoctrine.org
* @since 2.0
* @version $Revision: 4342 $
* @todo Split up into "Entity" and "ActiveEntity" (extends Entity).
*/
abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
{
@ -208,18 +207,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
return $this->_oid;
}
/**
* Hydrates this object from given array
*
* @param array $data
* @return boolean
*/
final public function hydrate(array $data)
{
$this->_data = array_merge($this->_data, $data);
$this->_extractIdentifier();
}
/**
* Copies the identifier names and values from _data into _id.
*/
@ -375,58 +362,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
}
/**
* Refresh internal data from the database
*
* @param bool $deep If true, fetch also current relations. Caution: this deletes
* any aggregated values you may have queried beforee
*
* @throws Doctrine_Record_Exception When the refresh operation fails (when the database row
* this record represents does not exist anymore)
* @return boolean
* @todo Implementation to EntityManager.
* @todo Move to ActiveEntity (extends Entity). Implementation to EntityManager.
*/
public function refresh($deep = false)
{
$id = $this->identifier();
if ( ! is_array($id)) {
$id = array($id);
}
if (empty($id)) {
return false;
}
$id = array_values($id);
if ($deep) {
$query = $this->_em->createQuery()->from($this->_entityName);
foreach (array_keys($this->_references) as $name) {
$query->leftJoin(get_class($this) . '.' . $name);
}
$query->where(implode(' = ? AND ', $this->_class->getIdentifierColumnNames()) . ' = ?');
$this->clearRelated();
$record = $query->fetchOne($id);
} else {
// Use FETCH_ARRAY to avoid clearing object relations
$record = $this->getRepository()->find($this->identifier(), Doctrine::HYDRATE_ARRAY);
if ($record) {
$this->hydrate($record);
}
}
if ($record === false) {
throw new Doctrine_Record_Exception('Failed to refresh. Record does not exist.');
}
$this->_modified = array();
$this->_extractIdentifier();
$this->_state = Doctrine_Entity::STATE_CLEAN;
return $this;
}
/**
* Gets the current field values.
*
@ -438,48 +373,38 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* INTERNAL: (Usage from within extending classes is intended)
*
* Gets the value of a field (regular field or reference).
* If the field is not yet loaded this method does NOT load it.
*
* NOTE: Use of this method from outside the scope of an extending class
* is strongly discouraged.
*
* @param $name name of the property
* @throws Doctrine_Entity_Exception if trying to get an unknown field
* @return mixed
*/
final public function _get($fieldName)
final protected function _get($fieldName)
{
if (isset($this->_data[$fieldName])) {
return $this->_rawGetField($fieldName);
return $this->_internalGetField($fieldName);
} else if (isset($this->_references[$fieldName])) {
return $this->_rawGetReference($fieldName);
return $this->_internalGetReference($fieldName);
} else {
throw Doctrine_Entity_Exception::unknownField($fieldName);
}
}
/**
* INTERNAL: (Usage from within extending classes is intended)
*
* Sets the value of a field (regular field or reference).
* If the field is not yet loaded this method does NOT load it.
*
* NOTE: Use of this method from outside the scope of an extending class
* is strongly discouraged.
*
* @param $name name of the field
* @throws Doctrine_Entity_Exception if trying to get an unknown field
* @return mixed
*/
final public function _set($fieldName, $value)
final protected function _set($fieldName, $value)
{
if (isset($this->_data[$fieldName])) {
return $this->_rawSetField($fieldName, $value);
} else if (isset($this->_references[$fieldName])) {
return $this->_rawSetReference($fieldName, $value);
if ($this->_class->hasField($fieldName)) {
return $this->_internalSetField($fieldName, $value);
} else if ($this->_class->hasRelation($fieldName)) {
return $this->_internalSetReference($fieldName, $value);
} else {
throw Doctrine_Entity_Exception::unknownField($fieldName);
}
@ -489,15 +414,15 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* INTERNAL:
* Gets the value of a field.
*
* NOTE: Use of this method from outside the scope of an extending class
* is strongly discouraged. This method does NOT check whether the field
* exists. _get() in extending classes should be preferred.
* NOTE: Use of this method in userland code is strongly discouraged.
* This method does NOT check whether the field exists.
* _get() in extending classes should be preferred.
*
* @param string $fieldName
* @return mixed
* @todo Rename to _unsafeGetField()
*/
final public function _rawGetField($fieldName)
final public function _internalGetField($fieldName)
{
if ($this->_data[$fieldName] === Doctrine_Null::$INSTANCE) {
return null;
@ -509,15 +434,14 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* INTERNAL:
* Sets the value of a field.
*
* NOTE: Use of this method from outside the scope of an extending class
* is strongly discouraged. This method does NOT check whether the field
* exists. _set() in extending classes should be preferred.
* NOTE: Use of this method in userland code is strongly discouraged.
* This method does NOT check whether the field exists.
* _set() in extending classes should be preferred.
*
* @param string $fieldName
* @param mixed $value
* @todo Rename to _unsafeSetField()
*/
final public function _rawSetField($fieldName, $value)
final public function _internalSetField($fieldName, $value)
{
$this->_data[$fieldName] = $value;
}
@ -525,14 +449,12 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
/**
* Gets a reference to another Entity.
*
* NOTE: Use of this method from outside the scope of an extending class
* is strongly discouraged. This method does NOT check whether the reference
* exists.
* NOTE: Use of this method in userland code is strongly discouraged.
* This method does NOT check whether the reference exists.
*
* @param string $fieldName
* @todo Rename to _unsafeGetReference().
*/
final public function _rawGetReference($fieldName)
final public function _internalGetReference($fieldName)
{
if ($this->_references[$fieldName] === Doctrine_Null::$INSTANCE) {
return null;
@ -544,14 +466,14 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
* INTERNAL:
* Sets a reference to another Entity.
*
* NOTE: Use of this method is strongly discouraged for user-code.
* NOTE: Use of this method in userland code is strongly discouraged.
*
* @param string $fieldName
* @param mixed $value
* @todo Refactor. What about composite keys?
* @todo Rename to _unsafeSetReference()
*/
final public function _rawSetReference($name, $value)
final public function _internalSetReference($name, $value)
{
if ($value === Doctrine_Null::$INSTANCE) {
$this->_references[$name] = $value;
@ -602,11 +524,9 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* Generic getter.
* Generic getter for all persistent fields.
*
* @param mixed $name name of the property or related component
* @param boolean $load whether or not to invoke the loading procedure
* @throws Doctrine_Record_Exception if trying to get a value of unknown property / related component
* @param string $fieldName Name of the field.
* @return mixed
*/
final public function get($fieldName)
@ -710,10 +630,10 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
/**
* Generic setter.
* Generic setter for persistent fields.
*
* @param mixed $name name of the property or reference
* @param mixed $value value of the property or reference
* @param string $name The name of the field to set.
* @param mixed $value The value of the field.
*/
final public function set($fieldName, $value)
{
@ -742,7 +662,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
}
} else if ($this->_class->hasRelation($fieldName)) {
$this->_rawSetReference($fieldName, $value);
$this->_internalSetReference($fieldName, $value);
} else {
throw Doctrine_Entity_Exception::invalidField($fieldName);
}
@ -795,45 +715,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
}
}
}
/**
* Saves the current state of the entity into the database.
*
* @param Doctrine_Connection $conn optional connection parameter
* @return void
* @todo ActiveEntity method.
*/
public function save()
{
// TODO: Forward to EntityManager. There: registerNew() OR registerDirty() on UnitOfWork.
$this->_em->save($this);
}
/**
* Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
* query, except that if there is already a row in the table with the same
* key field values, the REPLACE query just updates its values instead of
* inserting a new row.
*
* The REPLACE type of query does not make part of the SQL standards. Since
* practically only MySQL and SQLIte implement it natively, this type of
* query isemulated through this method for other DBMS using standard types
* of queries inside a transaction to assure the atomicity of the operation.
*
* @param Doctrine_Connection $conn optional connection parameter
* @throws Doctrine_Connection_Exception if some of the key values was null
* @throws Doctrine_Connection_Exception if there were no key fields
* @throws Doctrine_Connection_Exception if something fails at database level
* @return integer number of rows affected
* @todo ActiveEntity method.
*/
public function replace()
{
return $this->_em->replace(
$this->_class,
$this->getPrepared(),
$this->_id);
}
/**
* INTERNAL:
@ -908,160 +789,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
return $dataSet;
}
/**
* Creates an array representation of the object's data.
*
* @param boolean $deep - Return also the relations
* @return array
* @todo ActiveEntity method.
*/
public function toArray($deep = true, $prefixKey = false)
{
$a = array();
foreach ($this as $column => $value) {
if ($value === Doctrine_Null::$INSTANCE || is_object($value)) {
$value = null;
}
$a[$column] = $value;
}
if ($this->_class->getIdentifierType() == Doctrine::IDENTIFIER_AUTOINC) {
$idFieldNames = $this->_class->getIdentifier();
$idFieldName = $idFieldNames[0];
$ids = $this->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
$a[$idFieldName] = $id;
}
if ($deep) {
foreach ($this->_references as $key => $relation) {
if ( ! $relation instanceof Doctrine_Null) {
$a[$key] = $relation->toArray($deep, $prefixKey);
}
}
}
// [FIX] Prevent mapped Doctrine_Entitys from being displayed fully
foreach ($this->_values as $key => $value) {
if ($value instanceof Doctrine_Entity) {
$a[$key] = $value->toArray($deep, $prefixKey);
} else {
$a[$key] = $value;
}
}
return $a;
}
/**
* Merges this Entity with an array of values
* or with another existing instance of.
*
* @param mixed $data Data to merge. Either another instance of this model or an array
* @param bool $deep Bool value for whether or not to merge the data deep
* @return void
* @todo ActiveEntity method.
*/
public function merge($data, $deep = true)
{
if ($data instanceof $this) {
$array = $data->toArray($deep);
} else if (is_array($data)) {
$array = $data;
} else {
$array = array();
}
return $this->fromArray($array, $deep);
}
/**
* fromArray
*
* @param string $array
* @param bool $deep Bool value for whether or not to merge the data deep
* @return void
* @todo ActiveEntity method.
*/
public function fromArray($array, $deep = true)
{
if (is_array($array)) {
foreach ($array as $key => $value) {
if ($deep && $this->getTable()->hasRelation($key)) {
$this->$key->fromArray($value, $deep);
} else if ($this->getTable()->hasField($key)) {
$this->set($key, $value);
}
}
}
}
/**
* Synchronizes a Doctrine_Entity and its relations with data from an array
*
* It expects an array representation of a Doctrine_Entity similar to the return
* value of the toArray() method. If the array contains relations it will create
* those that don't exist, update the ones that do, and delete the ones missing
* on the array but available on the Doctrine_Entity
*
* @param array $array representation of a Doctrine_Entity
* @todo ActiveEntity method.
*/
public function synchronizeFromArray(array $array)
{
foreach ($array as $key => $value) {
if ($this->getTable()->hasRelation($key)) {
$this->get($key)->synchronizeFromArray($value);
} else if ($this->getTable()->hasColumn($key)) {
$this->set($key, $value);
}
}
// eliminate relationships missing in the $array
foreach ($this->_references as $name => $obj) {
if ( ! isset($array[$name])) {
unset($this->$name);
}
}
}
/**
* exportTo
*
* @param string $type
* @param string $deep
* @return void
* @todo ActiveEntity method.
*/
public function exportTo($type, $deep = true)
{
if ($type == 'array') {
return $this->toArray($deep);
} else {
return Doctrine_Parser::dump($this->toArray($deep, true), $type);
}
}
/**
* importFrom
*
* @param string $type
* @param string $data
* @return void
* @author Jonathan H. Wage
* @todo ActiveEntity method.
*/
public function importFrom($type, $data)
{
if ($type == 'array') {
return $this->fromArray($data);
} else {
return $this->fromArray(Doctrine_Parser::load($data, $type));
}
}
/**
* Checks whether the entity already has a persistent state.
@ -1084,58 +811,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
return count($this->_modified) > 0;
}
/**
* Deletes the persistent state of the entity.
*
* @return boolean TRUE on success, FALSE on failure.
* @todo ActiveRecord method.
*/
public function delete()
{
// TODO: Forward to EntityManager. There: registerRemoved() on UnitOfWork
return $this->_em->remove($this);
}
/**
* Creates a copy of the entity.
*
* @return Doctrine_Entity
* @todo ActiveEntity method. Implementation to EntityManager.
*/
public function copy($deep = true)
{
$data = $this->_data;
if ($this->_class->getIdentifierType() === Doctrine::IDENTIFIER_AUTOINC) {
$idFieldNames = (array)$this->_class->getIdentifier();
$id = $idFieldNames[0];
unset($data[$id]);
}
$ret = $this->_em->createEntity($this->_entityName, $data);
$modified = array();
foreach ($data as $key => $val) {
if ( ! ($val instanceof Doctrine_Null)) {
$ret->_modified[] = $key;
}
}
if ($deep) {
foreach ($this->_references as $key => $value) {
if ($value instanceof Doctrine_Collection) {
foreach ($value as $record) {
$ret->{$key}[] = $record->copy($deep);
}
} else {
$ret->set($key, $value->copy($deep));
}
}
}
return $ret;
}
/**
* INTERNAL:
* Assigns an identifier to the entity. This is only intended for use by
@ -1219,132 +894,6 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
$this->_references[$alias] = $coll;
}
/**
* Removes links from this record to given records
* if no ids are given, it removes all links
*
* @param string $alias related component alias
* @param array $ids the identifiers of the related records
* @return Doctrine_Entity this object
* @todo ActiveEntity method.
*/
public function unlink($alias, $ids = array())
{
$ids = (array) $ids;
$q = new Doctrine_Query();
$rel = $this->getTable()->getRelation($alias);
if ($rel instanceof Doctrine_Relation_Association) {
$q->delete()
->from($rel->getAssociationTable()->getComponentName())
->where($rel->getLocal() . ' = ?', array_values($this->identifier()));
if (count($ids) > 0) {
$q->whereIn($rel->getForeign(), $ids);
}
$q->execute();
} else if ($rel instanceof Doctrine_Relation_ForeignKey) {
$q->update($rel->getTable()->getComponentName())
->set($rel->getForeign(), '?', array(null))
->addWhere($rel->getForeign() . ' = ?', array_values($this->identifier()));
if (count($ids) > 0) {
$relTableIdFieldNames = (array)$rel->getTable()->getIdentifier();
$q->whereIn($relTableIdFieldNames[0], $ids);
}
$q->execute();
}
if (isset($this->_references[$alias])) {
foreach ($this->_references[$alias] as $k => $record) {
if (in_array(current($record->identifier()), $ids)) {
$this->_references[$alias]->remove($k);
}
}
$this->_references[$alias]->takeSnapshot();
}
return $this;
}
/**
* Creates links from this record to given records.
*
* @param string $alias related component alias
* @param array $ids the identifiers of the related records
* @return Doctrine_Entity this object
* @todo ActiveEntity method.
*/
public function link($alias, array $ids)
{
if ( ! count($ids)) {
return $this;
}
$identifier = array_values($this->identifier());
$identifier = array_shift($identifier);
$rel = $this->getTable()->getRelation($alias);
if ($rel instanceof Doctrine_Relation_Association) {
$modelClassName = $rel->getAssociationTable()->getComponentName();
$localFieldName = $rel->getLocalFieldName();
$localFieldDef = $rel->getAssociationTable()->getColumnDefinition($localFieldName);
if ($localFieldDef['type'] == 'integer') {
$identifier = (integer) $identifier;
}
$foreignFieldName = $rel->getForeignFieldName();
$foreignFieldDef = $rel->getAssociationTable()->getColumnDefinition($foreignFieldName);
if ($foreignFieldDef['type'] == 'integer') {
for ($i = 0; $i < count($ids); $i++) {
$ids[$i] = (integer) $ids[$i];
}
}
foreach ($ids as $id) {
$record = new $modelClassName;
$record[$localFieldName] = $identifier;
$record[$foreignFieldName] = $id;
$record->save();
}
} else if ($rel instanceof Doctrine_Relation_ForeignKey) {
$q = new Doctrine_Query();
$q->update($rel->getTable()->getComponentName())
->set($rel->getForeign(), '?', array_values($this->identifier()));
if (count($ids) > 0) {
$relTableIdFieldNames = (array)$rel->getTable()->getIdentifier();
$q->whereIn($relTableIdFieldNames[0], $ids);
}
$q->execute();
} else if ($rel instanceof Doctrine_Relation_LocalKey) {
$q = new Doctrine_Query();
$q->update($this->getTable()->getComponentName())
->set($rel->getLocalFieldName(), '?', $ids);
if (count($ids) > 0) {
$relTableIdFieldNames = (array)$rel->getTable()->getIdentifier();
$q->whereIn($relTableIdFieldNames[0], array_values($this->identifier()));
}
$q->execute();
}
return $this;
}
/**
* Gets the ClassMetadata object that describes the entity class.
*
@ -1390,7 +939,7 @@ abstract class Doctrine_Entity extends Doctrine_Access implements Serializable
*/
public function __toString()
{
return (string) $this->_oid;
return (string)$this->_oid;
}
/**

View File

@ -74,7 +74,7 @@ class Doctrine_Hydrator_RecordDriver
$relatedClass = $relation->getTable();
$coll = $this->getElementCollection($relatedClass->getClassName());
$coll->setReference($entity, $relation);
$entity->_rawSetReference($name, $coll);
$entity->_internalSetReference($name, $coll);
$this->_initializedRelations[$entity->getOid()][$name] = true;
}
}
@ -97,23 +97,23 @@ class Doctrine_Hydrator_RecordDriver
public function addRelatedIndexedElement(Doctrine_Entity $entity1, $property,
Doctrine_Entity $entity2, $indexField)
{
$entity1->_rawGetReference($property)->add($entity2, $entity2->_rawGetField($indexField));
$entity1->_internalGetReference($property)->add($entity2, $entity2->_internalGetField($indexField));
}
public function addRelatedElement(Doctrine_Entity $entity1, $property,
Doctrine_Entity $entity2)
{
$entity1->_rawGetReference($property)->add($entity2);
$entity1->_internalGetReference($property)->add($entity2);
}
public function setRelatedElement(Doctrine_Entity $entity1, $property, $entity2)
{
$entity1->_rawSetReference($property, $entity2);
$entity1->_internalSetReference($property, $entity2);
}
public function isIndexKeyInUse(Doctrine_Entity $entity, $assocField, $indexField)
{
return $entity->_rawGetReference($assocField)->contains($indexField);
return $entity->_internalGetReference($assocField)->contains($indexField);
}
public function isFieldSet(Doctrine_Entity $entity, $field)
@ -123,17 +123,17 @@ class Doctrine_Hydrator_RecordDriver
public function getFieldValue(Doctrine_Entity $entity, $field)
{
return $entity->_rawGetField($field);
return $entity->_internalGetField($field);
}
public function getReferenceValue(Doctrine_Entity $entity, $field)
{
return $entity->_rawGetReference($field);
return $entity->_internalGetReference($field);
}
public function addElementToIndexedCollection($coll, $entity, $keyField)
{
$coll->add($entity, $entity->_rawGetField($keyField));
$coll->add($entity, $entity->_internalGetField($keyField));
}
public function addElementToCollection($coll, $entity)

View File

@ -165,7 +165,6 @@ class Doctrine_Query_Parser
if ( ! $isMatch) {
// No definition for value checking.
$this->syntaxError($this->_keywordTable->getLiteral($token));
}
$this->next();

View File

@ -45,26 +45,26 @@ class Doctrine_Query_Production_Atom extends Doctrine_Query_Production
case Doctrine_Query_Token::T_STRING:
$this->_parser->match(Doctrine_Query_Token::T_STRING);
$this->_type = 'string';
break;
break;
case Doctrine_Query_Token::T_INTEGER:
$this->_parser->match(Doctrine_Query_Token::T_INTEGER);
$this->_type = 'integer';
break;
break;
case Doctrine_Query_Token::T_FLOAT:
$this->_parser->match(Doctrine_Query_Token::T_FLOAT);
$this->_type = 'float';
break;
break;
case Doctrine_Query_Token::T_INPUT_PARAMETER:
$this->_parser->match(Doctrine_Query_Token::T_INPUT_PARAMETER);
$this->_type = 'param';
break;
break;
default:
$this->_parser->syntaxError('string, number or parameter (? or :)');
break;
break;
}
$this->_value = $this->_parser->token['value'];
@ -78,19 +78,20 @@ class Doctrine_Query_Production_Atom extends Doctrine_Query_Production
switch ($this->_type) {
case 'param':
return $this->_value;
break;
case 'integer':
case 'float':
case 'string':
//FIXME: Remove the quotes from _value! Should the scanner do that or where?
// 'mystring' => mystring. Otherwise 'mystring' is the content (with quotes)!
// Eg: select ... from ... where f.foo = 'bar'
// => $conn->quote('bar',...), CURRENTLY: $conn->quote("'bar'",...)
// This fix looks a bit ugly or ... ? Should this happen earlier? Syntax?
// Scanner?
if (strpos($this->_value, "'") === 0) {
$this->_value = substr($this->_value, 1, strlen($this->_value) - 2);
}
return $conn->quote($this->_value, $this->_type);
break;
default:
$stringQuoting = $conn->getDatabasePlatform()->getProperty('string_quoting');
return $stringQuoting['start']
. $conn->quote($this->_value, $this->_type)
. $stringQuoting['end'];
break;
return $conn->quote($this->_value, $this->_type);
}
}

View File

@ -33,14 +33,18 @@
class Doctrine_Query_Scanner
{
/**
* Array of scanned tokens
* Array of scanned tokens.
*
* @var array
*/
protected $_tokens = array();
/**
* @todo Doc
*/
protected $_position = 0;
/**
* @todo Doc
*/
protected $_peek = 0;
/**
@ -109,7 +113,9 @@ class Doctrine_Query_Scanner
}
}
/**
* @todo Doc
*/
protected function _getType(&$value)
{
// $value is referenced because it can be changed if it is numeric.
@ -117,30 +123,32 @@ class Doctrine_Query_Scanner
$type = Doctrine_Query_Token::T_NONE;
$newVal = $this->_getNumeric($value);
if($newVal !== false){
if ($newVal !== false){
$value = $newVal;
if (strpos($value, '.') !== false || stripos($value, 'e') !== false) {
$type = Doctrine_Query_Token::T_FLOAT;
} else{
} else {
$type = Doctrine_Query_Token::T_INTEGER;
}
}
if ($value[0] === "'" && $value[strlen($value) - 1] === "'") {
$type = Doctrine_Query_Token::T_STRING;
} elseif (ctype_alpha($value[0]) || $value[0] === '_') {
} else if (ctype_alpha($value[0]) || $value[0] === '_') {
$type = $this->_checkLiteral($value);
} elseif ($value[0] === '?' || $value[0] === ':') {
} else if ($value[0] === '?' || $value[0] === ':') {
$type = Doctrine_Query_Token::T_INPUT_PARAMETER;
}
return $type;
}
/**
* @todo Doc
*/
protected function _getNumeric($value)
{
if (!is_scalar($value)) {
if ( ! is_scalar($value)) {
return false;
}
// Checking for valid numeric numbers: 1.234, -1.234e-2
@ -164,7 +172,9 @@ class Doctrine_Query_Scanner
}
/**
* @todo Doc
*/
public function isA($value, $token)
{
$type = $this->_getType($value);
@ -172,7 +182,9 @@ class Doctrine_Query_Scanner
return $type === $token;
}
/**
* @todo Doc
*/
public function peek()
{
if (isset($this->_tokens[$this->_position + $this->_peek])) {
@ -182,13 +194,14 @@ class Doctrine_Query_Scanner
}
}
/**
* @todo Doc
*/
public function resetPeek()
{
$this->_peek = 0;
}
/**
* Returns the next token in the input string.
*
@ -211,7 +224,9 @@ class Doctrine_Query_Scanner
}
}
/**
* @todo Doc
*/
public function resetPosition($position = 0)
{
$this->_position = $position;

View File

@ -29,7 +29,8 @@
* @version $Revision: 1397 $
* @link www.phpdoctrine.org
* @since 1.0
* @todo Composite key support?
* @todo Composite key support?
* @todo Remove. Association mapping needs a reimplementation.
*/
class Doctrine_Relation_Parser
{

View File

@ -44,9 +44,9 @@ class Doctrine_Sequence_Mysql extends Doctrine_Sequence
*/
public function nextId($seqName, $onDemand = true)
{
$sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($seqName), true);
$seqcolName = $this->conn->quoteIdentifier($this->conn->getAttribute(Doctrine::ATTR_SEQCOL_NAME), true);
$query = 'INSERT INTO ' . $sequenceName . ' (' . $seqcolName . ') VALUES (NULL)';
$sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($seqName), true);
$seqcolName = $this->conn->quoteIdentifier($this->conn->getAttribute(Doctrine::ATTR_SEQCOL_NAME), true);
$query = 'INSERT INTO ' . $sequenceName . ' (' . $seqcolName . ') VALUES (NULL)';
try {
$this->conn->exec($query);
@ -68,7 +68,7 @@ class Doctrine_Sequence_Mysql extends Doctrine_Sequence
$query = 'DELETE FROM ' . $sequenceName . ' WHERE ' . $seqcolName . ' < ' . $value;
try {
$this->conn->exec($query);
} catch(Doctrine_Exception $e) {
} catch (Doctrine_Exception $e) {
throw new Doctrine_Sequence_Exception('could not delete previous sequence table values from ' . $seqName);
}
}

View File

@ -40,7 +40,7 @@ class Doctrine_Sequence_Oracle extends Doctrine_Sequence
*
* @return integer next id in the given sequence
*/
public function nextID($seqName, $onDemand = true)
public function nextId($seqName, $onDemand = true)
{
$sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($seqName), true);
$query = 'SELECT ' . $sequenceName . '.nextval FROM DUAL';
@ -69,10 +69,10 @@ class Doctrine_Sequence_Oracle extends Doctrine_Sequence
* @param string name of the table into which a new row was inserted
* @param string name of the field into which a new row was inserted
*/
public function lastInsertID($table = null, $field = null)
public function lastInsertId($table = null, $field = null)
{
$seqName = $table . (empty($field) ? '' : '_'.$field);
$sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($seqName), true);
$sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($seqName), true);
return $this->conn->fetchOne('SELECT ' . $sequenceName . '.currval');
}
@ -84,7 +84,7 @@ class Doctrine_Sequence_Oracle extends Doctrine_Sequence
*
* @return integer current id in the given sequence
*/
public function currID($seqName)
public function currId($seqName)
{
$sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($seqName), true);
$query = 'SELECT (last_number-1) FROM user_sequences';

View File

@ -13,8 +13,6 @@ class Orm_Entity_AccessorTest extends Doctrine_OrmTestCase
$entity2->username = 'romanb';
$this->assertEquals('romanb?!', $entity1->username);
}
}
@ -41,12 +39,12 @@ class CustomAccessorMutatorTestEntity extends Doctrine_Entity
public function getUsernameCustom()
{
return $this->_rawGetField('username') . "!";
return $this->_get('username') . "!";
}
public function setUsernameCustom($username)
{
$this->_rawSetField('username', $username . "?");
$this->_set('username', $username . "?");
}
}
@ -69,11 +67,11 @@ class MagicAccessorMutatorTestEntity extends Doctrine_Entity
public function getUsername()
{
return $this->_rawGetField('username') . "!";
return $this->_get('username') . "!";
}
public function setUsername($username)
{
$this->_rawSetField('username', $username . "?");
$this->_set('username', $username . "?");
}
}

View File

@ -134,7 +134,9 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
{
$this->assertSqlGeneration(
"SELECT u.name FROM CmsUser u WHERE TRIM(u.name) = 'someone'",
"SELECT cu.name AS cu__name FROM cms_user cu WHERE TRIM(cu.name) = ''someone''" // SQLite double slashes for strings
// String quoting in the SQL usually depends on the database platform.
// This test works with a mock connection which uses ' for string quoting.
"SELECT cu.name AS cu__name FROM cms_user cu WHERE TRIM(cu.name) = 'someone'"
);
}