@@ -93,6 +138,7 @@
+
diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php
index 75cbf029e..f2f6a396f 100644
--- a/lib/Doctrine/ORM/EntityRepository.php
+++ b/lib/Doctrine/ORM/EntityRepository.php
@@ -89,6 +89,21 @@ class EntityRepository implements ObjectRepository
return $this->_em->createQuery($this->_class->getNamedQuery($queryName));
}
+ /**
+ * Creates a native SQL query.
+ *
+ * @param string $queryName
+ * @return NativeQuery
+ */
+ public function createNativeNamedQuery($queryName)
+ {
+ $queryMapping = $this->_class->getNamedNativeQuery($queryName);
+ $rsm = new Query\ResultSetMappingBuilder($this->_em);
+ $rsm->addNamedNativeQueryMapping($this->_class, $queryMapping);
+
+ return $this->_em->createNativeQuery($queryMapping['query'], $rsm);
+ }
+
/**
* Clears the repository, causing all managed entities to become detached.
*/
diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
index 2aaa30a44..63ac01c25 100644
--- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
+++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
@@ -326,6 +326,14 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$this->addInheritedNamedQueries($class, $parent);
}
+ if ($parent && !empty ($parent->namedNativeQueries)) {
+ $this->addInheritedNamedNativeQueries($class, $parent);
+ }
+
+ if ($parent && !empty ($parent->sqlResultSetMappings)) {
+ $this->addInheritedSqlResultSetMappings($class, $parent);
+ }
+
$class->setParentClasses($visited);
if ($this->evm->hasListeners(Events::loadClassMetadata)) {
@@ -466,6 +474,58 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
}
+ /**
+ * Adds inherited named native queries to the subclass mapping.
+ *
+ * @since 2.3
+ * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
+ * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
+ */
+ private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
+ {
+ foreach ($parentClass->namedNativeQueries as $name => $query) {
+ if (!isset ($subClass->namedNativeQueries[$name])) {
+ $subClass->addNamedNativeQuery(array(
+ 'name' => $query['name'],
+ 'query' => $query['query'],
+ 'isSelfClass' => $query['isSelfClass'],
+ 'resultSetMapping' => $query['resultSetMapping'],
+ 'resultClass' => $query['isSelfClass'] ? $subClass->name : $query['resultClass'],
+ ));
+ }
+ }
+ }
+
+ /**
+ * Adds inherited sql result set mappings to the subclass mapping.
+ *
+ * @since 2.3
+ * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
+ * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
+ */
+ private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass)
+ {
+ foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
+ if (!isset ($subClass->sqlResultSetMappings[$name])) {
+ $entities = array();
+ foreach ($mapping['entities'] as $entity) {
+ $entities[] = array(
+ 'fields' => $entity['fields'],
+ 'isSelfClass' => $entity['isSelfClass'],
+ 'discriminatorColumn' => $entity['discriminatorColumn'],
+ 'entityClass' => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'],
+ );
+ }
+
+ $subClass->addSqlResultSetMapping(array(
+ 'name' => $mapping['name'],
+ 'columns' => $mapping['columns'],
+ 'entities' => $entities,
+ ));
+ }
+ }
+ }
+
/**
* Completes the ID generator mapping. If "auto" is specified we choose the generator
* most appropriate for the targeted database platform.
diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
index 80498b737..1f3b00dbf 100644
--- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
+++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
@@ -49,16 +49,19 @@ class ClassMetadataInfo implements ClassMetadata
* and therefore does not need an inheritance mapping type.
*/
const INHERITANCE_TYPE_NONE = 1;
+
/**
* JOINED means the class will be persisted according to the rules of
* Class Table Inheritance.
*/
const INHERITANCE_TYPE_JOINED = 2;
+
/**
* SINGLE_TABLE means the class will be persisted according to the rules of
* Single Table Inheritance.
*/
const INHERITANCE_TYPE_SINGLE_TABLE = 3;
+
/**
* TABLE_PER_CLASS means the class will be persisted according to the rules
* of Concrete Table Inheritance.
@@ -71,17 +74,20 @@ class ClassMetadataInfo implements ClassMetadata
* Offers full portability.
*/
const GENERATOR_TYPE_AUTO = 1;
+
/**
* SEQUENCE means a separate sequence object will be used. Platforms that do
* not have native sequence support may emulate it. Full portability is currently
* not guaranteed.
*/
const GENERATOR_TYPE_SEQUENCE = 2;
+
/**
* TABLE means a separate table is used for id generation.
* Offers full portability.
*/
const GENERATOR_TYPE_TABLE = 3;
+
/**
* IDENTITY means an identity column is used for id generation. The database
* will fill in the id column on insertion. Platforms that do not support
@@ -89,11 +95,13 @@ class ClassMetadataInfo implements ClassMetadata
* not guaranteed.
*/
const GENERATOR_TYPE_IDENTITY = 4;
+
/**
* NONE means the class does not have a generated id. That means the class
* must have a natural, manually assigned id.
*/
const GENERATOR_TYPE_NONE = 5;
+
/**
* UUID means that a UUID/GUID expression is used for id generation. Full
* portability is currently not guaranteed.
@@ -111,53 +119,64 @@ class ClassMetadataInfo implements ClassMetadata
* This is the default change tracking policy.
*/
const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
+
/**
* DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
* by doing a property-by-property comparison with the original data. This will
* be done only for entities that were explicitly saved (through persist() or a cascade).
*/
const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
+
/**
* NOTIFY means that Doctrine relies on the entities sending out notifications
* when their properties change. Such entity classes must implement
* the NotifyPropertyChanged interface.
*/
const CHANGETRACKING_NOTIFY = 3;
+
/**
* Specifies that an association is to be fetched when it is first accessed.
*/
const FETCH_LAZY = 2;
+
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
*/
const FETCH_EAGER = 3;
+
/**
* Specifies that an association is to be fetched lazy (on first access) and that
* commands such as Collection#count, Collection#slice are issued directly against
* the database if the collection is not yet initialized.
*/
const FETCH_EXTRA_LAZY = 4;
+
/**
* Identifies a one-to-one association.
*/
const ONE_TO_ONE = 1;
+
/**
* Identifies a many-to-one association.
*/
const MANY_TO_ONE = 2;
+
/**
* Identifies a one-to-many association.
*/
const ONE_TO_MANY = 4;
+
/**
* Identifies a many-to-many association.
*/
const MANY_TO_MANY = 8;
+
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
+
/**
* Combined bitmask for to-many (collection-valued) associations.
*/
@@ -237,6 +256,35 @@ class ClassMetadataInfo implements ClassMetadata
*/
public $namedQueries = array();
+ /**
+ * READ-ONLY: The named native queries allowed to be called directly from Repository.
+ *
+ * A native SQL named query definition has the following structure:
+ *
+ * array(
+ * 'name' => ,
+ * 'query' => ,
+ * 'resultClass' => ,
+ * 'resultSetMapping' =>
+ * )
+ *
+ */
+ public $namedNativeQueries = array();
+
+ /**
+ * READ-ONLY: The mappings of the results of native SQL queries.
+ *
+ * A native result mapping definition has the following structure:
+ *
+ * array(
+ * 'name' => ,
+ * 'entities' => array(),
+ * 'columns' => array()
+ * )
+ *
+ */
+ public $sqlResultSetMappings = array();
+
/**
* READ-ONLY: The field names of all fields that are part of the identifier/primary key
* of the mapped entity class.
@@ -748,6 +796,14 @@ class ClassMetadataInfo implements ClassMetadata
$serialized[] = 'namedQueries';
}
+ if ($this->namedNativeQueries) {
+ $serialized[] = 'namedNativeQueries';
+ }
+
+ if ($this->sqlResultSetMappings) {
+ $serialized[] = 'sqlResultSetMappings';
+ }
+
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
@@ -1051,6 +1107,60 @@ class ClassMetadataInfo implements ClassMetadata
return $this->namedQueries;
}
+ /**
+ * Gets the named native query.
+ *
+ * @see ClassMetadataInfo::$namedNativeQueries
+ * @throws MappingException
+ * @param string $queryName The query name
+ * @return array
+ */
+ public function getNamedNativeQuery($queryName)
+ {
+ if ( ! isset($this->namedNativeQueries[$queryName])) {
+ throw MappingException::queryNotFound($this->name, $queryName);
+ }
+
+ return $this->namedNativeQueries[$queryName];
+ }
+
+ /**
+ * Gets all named native queries of the class.
+ *
+ * @return array
+ */
+ public function getNamedNativeQueries()
+ {
+ return $this->namedNativeQueries;
+ }
+
+ /**
+ * Gets the result set mapping.
+ *
+ * @see ClassMetadataInfo::$sqlResultSetMappings
+ * @throws MappingException
+ * @param string $name The result set mapping name
+ * @return array
+ */
+ public function getSqlResultSetMapping($name)
+ {
+ if ( ! isset($this->sqlResultSetMappings[$name])) {
+ throw MappingException::resultMappingNotFound($this->name, $name);
+ }
+
+ return $this->sqlResultSetMappings[$name];
+ }
+
+ /**
+ * Gets all sql result set mappings of the class.
+ *
+ * @return array
+ */
+ public function getSqlResultSetMappings()
+ {
+ return $this->sqlResultSetMappings;
+ }
+
/**
* Validates & completes the given field mapping.
*
@@ -1826,10 +1936,18 @@ class ClassMetadataInfo implements ClassMetadata
*/
public function addNamedQuery(array $queryMapping)
{
+ if (!isset($queryMapping['name'])) {
+ throw MappingException::nameIsMandatoryForQueryMapping($this->name);
+ }
+
if (isset($this->namedQueries[$queryMapping['name']])) {
throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
}
+ if (!isset($queryMapping['query'])) {
+ throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
+ }
+
$name = $queryMapping['name'];
$query = $queryMapping['query'];
$dql = str_replace('__CLASS__', $this->name, $query);
@@ -1840,6 +1958,107 @@ class ClassMetadataInfo implements ClassMetadata
);
}
+ /**
+ * INTERNAL:
+ * Adds a named native query to this class.
+ *
+ * @throws MappingException
+ * @param array $queryMapping
+ */
+ public function addNamedNativeQuery(array $queryMapping)
+ {
+ if (!isset($queryMapping['name'])) {
+ throw MappingException::nameIsMandatoryForQueryMapping($this->name);
+ }
+
+ if (isset($this->namedNativeQueries[$queryMapping['name']])) {
+ throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
+ }
+
+ if (!isset($queryMapping['query'])) {
+ throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']);
+ }
+
+ if (!isset($queryMapping['resultClass']) && !isset($queryMapping['resultSetMapping'])) {
+ throw MappingException::missingQueryMapping($this->name, $queryMapping['name']);
+ }
+
+ $queryMapping['isSelfClass'] = false;
+ if (isset($queryMapping['resultClass'])) {
+
+ if($queryMapping['resultClass'] === '__CLASS__') {
+
+ $queryMapping['isSelfClass'] = true;
+ $queryMapping['resultClass'] = $this->name;
+
+ } else if (strlen($this->namespace) > 0 && strpos($queryMapping['resultClass'], '\\') === false) {
+ $queryMapping['resultClass'] = $this->namespace . '\\' . $queryMapping['resultClass'];
+ }
+
+ $queryMapping['resultClass'] = ltrim($queryMapping['resultClass'], '\\');
+ }
+
+ $this->namedNativeQueries[$queryMapping['name']] = $queryMapping;
+ }
+
+ /**
+ * INTERNAL:
+ * Adds a sql result set mapping to this class.
+ *
+ * @throws MappingException
+ * @param array $resultMapping
+ */
+ public function addSqlResultSetMapping(array $resultMapping)
+ {
+ if (!isset($resultMapping['name'])) {
+ throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->name);
+ }
+
+ if (isset($this->sqlResultSetMappings[$resultMapping['name']])) {
+ throw MappingException::duplicateResultSetMapping($this->name, $resultMapping['name']);
+ }
+
+ if (isset($resultMapping['entities'])) {
+ foreach ($resultMapping['entities'] as $key => $entityResult) {
+ if (!isset($entityResult['entityClass'])) {
+ throw MappingException::missingResultSetMappingEntity($this->name, $resultMapping['name']);
+ }
+
+ $entityResult['isSelfClass'] = false;
+ if($entityResult['entityClass'] === '__CLASS__') {
+
+ $entityResult['isSelfClass'] = true;
+ $entityResult['entityClass'] = $this->name;
+
+ } else if (strlen($this->namespace) > 0 && strpos($entityResult['entityClass'], '\\') === false) {
+ $entityResult['entityClass'] = $this->namespace . '\\' . $entityResult['entityClass'];
+ }
+
+ $resultMapping['entities'][$key]['entityClass'] = ltrim($entityResult['entityClass'], '\\');
+ $resultMapping['entities'][$key]['isSelfClass'] = $entityResult['isSelfClass'];
+
+ if (isset($entityResult['fields'])) {
+ foreach ($entityResult['fields'] as $k => $field) {
+ if (!isset($field['name'])) {
+ throw MappingException::missingResultSetMappingFieldName($this->name, $resultMapping['name']);
+ }
+
+ if (!isset($field['column'])) {
+ $fieldName = $field['name'];
+ if(strpos($fieldName, '.')){
+ list(, $fieldName) = explode('.', $fieldName);
+ }
+
+ $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
+ }
+ }
+ }
+ }
+ }
+
+ $this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping;
+ }
+
/**
* Adds a one-to-one mapping.
*
@@ -2053,7 +2272,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Checks whether the class has a named query with the given query name.
*
- * @param string $fieldName
+ * @param string $queryName
* @return boolean
*/
public function hasNamedQuery($queryName)
@@ -2061,6 +2280,28 @@ class ClassMetadataInfo implements ClassMetadata
return isset($this->namedQueries[$queryName]);
}
+ /**
+ * Checks whether the class has a named native query with the given query name.
+ *
+ * @param string $queryName
+ * @return boolean
+ */
+ public function hasNamedNativeQuery($queryName)
+ {
+ return isset($this->namedNativeQueries[$queryName]);
+ }
+
+ /**
+ * Checks whether the class has a named native query with the given query name.
+ *
+ * @param string $name
+ * @return boolean
+ */
+ public function hasSqlResultSetMapping($name)
+ {
+ return isset($this->sqlResultSetMappings[$name]);
+ }
+
/**
* Checks whether the class has a mapped association with the given field name.
*
@@ -2397,4 +2638,19 @@ class ClassMetadataInfo implements ClassMetadata
{
return $this->associationMappings[$fieldName]['mappedBy'];
}
+
+ /**
+ * @param string $targetClass
+ * @return array
+ */
+ public function getAssociationsByTargetClass($targetClass)
+ {
+ $relations = array();
+ foreach ($this->associationMappings as $mapping) {
+ if ($mapping['targetEntity'] == $targetClass) {
+ $relations[$mapping['fieldName']] = $mapping;
+ }
+ }
+ return $relations;
+ }
}
diff --git a/lib/Doctrine/ORM/Mapping/ColumnResult.php b/lib/Doctrine/ORM/Mapping/ColumnResult.php
new file mode 100644
index 000000000..ff5cf272e
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/ColumnResult.php
@@ -0,0 +1,42 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * References name of a column in the SELECT clause of a SQL query.
+ * Scalar result types can be included in the query result by specifying this annotation in the metadata.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("ANNOTATION")
+ */
+final class ColumnResult implements Annotation
+{
+
+ /**
+ * The name of a column in the SELECT clause of a SQL query
+ *
+ * @var string
+ */
+ public $name;
+
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
index 22a1250ba..6a89131fe 100644
--- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
+++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
@@ -204,6 +204,58 @@ class AnnotationDriver implements Driver
$metadata->setPrimaryTable($primaryTable);
}
+ // Evaluate NamedNativeQueries annotation
+ if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'])) {
+ $namedNativeQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'];
+
+ foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) {
+ $metadata->addNamedNativeQuery(array(
+ 'name' => $namedNativeQuery->name,
+ 'query' => $namedNativeQuery->query,
+ 'resultClass' => $namedNativeQuery->resultClass,
+ 'resultSetMapping' => $namedNativeQuery->resultSetMapping,
+ ));
+ }
+ }
+
+ // Evaluate SqlResultSetMappings annotation
+ if (isset($classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'])) {
+ $sqlResultSetMappingsAnnot = $classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'];
+
+ foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) {
+ $entities = array();
+ $columns = array();
+ foreach ($resultSetMapping->entities as $entityResultAnnot) {
+ $entityResult = array(
+ 'fields' => array(),
+ 'entityClass' => $entityResultAnnot->entityClass,
+ 'discriminatorColumn' => $entityResultAnnot->discriminatorColumn,
+ );
+
+ foreach ($entityResultAnnot->fields as $fieldResultAnnot) {
+ $entityResult['fields'][] = array(
+ 'name' => $fieldResultAnnot->name,
+ 'column' => $fieldResultAnnot->column
+ );
+ }
+
+ $entities[] = $entityResult;
+ }
+
+ foreach ($resultSetMapping->columns as $columnResultAnnot) {
+ $columns[] = array(
+ 'name' => $columnResultAnnot->name,
+ );
+ }
+
+ $metadata->addSqlResultSetMapping(array(
+ 'name' => $resultSetMapping->name,
+ 'entities' => $entities,
+ 'columns' => $columns
+ ));
+ }
+ }
+
// Evaluate NamedQueries annotation
if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
$namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];
diff --git a/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php b/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php
index bd1632b2c..46fa1551b 100644
--- a/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php
+++ b/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php
@@ -53,3 +53,10 @@ require_once __DIR__.'/../PreRemove.php';
require_once __DIR__.'/../PostRemove.php';
require_once __DIR__.'/../PostLoad.php';
require_once __DIR__.'/../PreFlush.php';
+require_once __DIR__.'/../FieldResult.php';
+require_once __DIR__.'/../ColumnResult.php';
+require_once __DIR__.'/../EntityResult.php';
+require_once __DIR__.'/../NamedNativeQuery.php';
+require_once __DIR__.'/../NamedNativeQueries.php';
+require_once __DIR__.'/../SqlResultSetMapping.php';
+require_once __DIR__.'/../SqlResultSetMappings.php';
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php
index 3b2e54ac4..005dc44d1 100644
--- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php
+++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php
@@ -85,6 +85,58 @@ class XmlDriver extends AbstractFileDriver
}
}
+ // Evaluate native named queries
+ if (isset($xmlRoot->{'named-native-queries'})) {
+ foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} as $nativeQueryElement) {
+ $metadata->addNamedNativeQuery(array(
+ 'name' => isset($nativeQueryElement['name']) ? (string)$nativeQueryElement['name'] : null,
+ 'query' => isset($nativeQueryElement->query) ? (string)$nativeQueryElement->query : null,
+ 'resultClass' => isset($nativeQueryElement['result-class']) ? (string)$nativeQueryElement['result-class'] : null,
+ 'resultSetMapping' => isset($nativeQueryElement['result-set-mapping']) ? (string)$nativeQueryElement['result-set-mapping'] : null,
+ ));
+ }
+ }
+
+ // Evaluate sql result set mapping
+ if (isset($xmlRoot->{'sql-result-set-mappings'})) {
+ foreach ($xmlRoot->{'sql-result-set-mappings'}->{'sql-result-set-mapping'} as $rsmElement) {
+ $entities = array();
+ $columns = array();
+ foreach ($rsmElement as $entityElement) {
+ //
+ if (isset($entityElement['entity-class'])) {
+ $entityResult = array(
+ 'fields' => array(),
+ 'entityClass' => (string)$entityElement['entity-class'],
+ 'discriminatorColumn' => isset($entityElement['discriminator-column']) ? (string)$entityElement['discriminator-column'] : null,
+ );
+
+ foreach ($entityElement as $fieldElement) {
+ $entityResult['fields'][] = array(
+ 'name' => isset($fieldElement['name']) ? (string)$fieldElement['name'] : null,
+ 'column' => isset($fieldElement['column']) ? (string)$fieldElement['column'] : null,
+ );
+ }
+
+ $entities[] = $entityResult;
+ }
+
+ //
+ if (isset($entityElement['name'])) {
+ $columns[] = array(
+ 'name' => (string)$entityElement['name'],
+ );
+ }
+ }
+
+ $metadata->addSqlResultSetMapping(array(
+ 'name' => (string)$rsmElement['name'],
+ 'entities' => $entities,
+ 'columns' => $columns
+ ));
+ }
+ }
+
/* not implemented specially anyway. use table = schema.table
if (isset($xmlRoot['schema'])) {
$metadata->table['schema'] = (string)$xmlRoot['schema'];
diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php
index 0c4fb43cb..d602ed975 100644
--- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php
+++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php
@@ -83,6 +83,68 @@ class YamlDriver extends AbstractFileDriver
}
}
+ // Evaluate named native queries
+ if (isset($element['namedNativeQueries'])) {
+ foreach ($element['namedNativeQueries'] as $name => $mappingElement) {
+ if (!isset($mappingElement['name'])) {
+ $mappingElement['name'] = $name;
+ }
+ $metadata->addNamedNativeQuery(array(
+ 'name' => $mappingElement['name'],
+ 'query' => isset($mappingElement['query']) ? $mappingElement['query'] : null,
+ 'resultClass' => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null,
+ 'resultSetMapping' => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null,
+ ));
+ }
+ }
+
+ // Evaluate sql result set mappings
+ if (isset($element['sqlResultSetMappings'])) {
+ foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) {
+ if (!isset($resultSetMapping['name'])) {
+ $resultSetMapping['name'] = $name;
+ }
+
+ $entities = array();
+ $columns = array();
+ if (isset($resultSetMapping['entityResult'])) {
+ foreach ($resultSetMapping['entityResult'] as $entityResultElement) {
+ $entityResult = array(
+ 'fields' => array(),
+ 'entityClass' => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null,
+ 'discriminatorColumn' => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null,
+ );
+
+ if (isset($entityResultElement['fieldResult'])) {
+ foreach ($entityResultElement['fieldResult'] as $fieldResultElement) {
+ $entityResult['fields'][] = array(
+ 'name' => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null,
+ 'column' => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null,
+ );
+ }
+ }
+
+ $entities[] = $entityResult;
+ }
+ }
+
+
+ if (isset($resultSetMapping['columnResult'])) {
+ foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) {
+ $columns[] = array(
+ 'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null,
+ );
+ }
+ }
+
+ $metadata->addSqlResultSetMapping(array(
+ 'name' => $resultSetMapping['name'],
+ 'entities' => $entities,
+ 'columns' => $columns
+ ));
+ }
+ }
+
/* not implemented specially anyway. use table = schema.table
if (isset($element['schema'])) {
$metadata->table['schema'] = $element['schema'];
@@ -484,10 +546,14 @@ class YamlDriver extends AbstractFileDriver
*/
private function _getJoinColumnMapping($joinColumnElement)
{
- $joinColumn = array(
- 'name' => $joinColumnElement['name'],
- 'referencedColumnName' => $joinColumnElement['referencedColumnName']
- );
+ $joinColumn = array();
+ if (isset($joinColumnElement['referencedColumnName'])) {
+ $joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
+ }
+
+ if (isset($joinColumnElement['name'])) {
+ $joinColumn['name'] = (string) $joinColumnElement['name'];
+ }
if (isset($joinColumnElement['fieldName'])) {
$joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
diff --git a/lib/Doctrine/ORM/Mapping/EntityResult.php b/lib/Doctrine/ORM/Mapping/EntityResult.php
new file mode 100644
index 000000000..1be9206e7
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/EntityResult.php
@@ -0,0 +1,58 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * References an entity in the SELECT clause of a SQL query.
+ * If this annotation is used, the SQL statement should select all of the columns that are mapped to the entity object.
+ * This should include foreign key columns to related entities.
+ * The results obtained when insufficient data is available are undefined.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("ANNOTATION")
+ */
+final class EntityResult implements Annotation
+{
+
+ /**
+ * The class of the result
+ *
+ * @var string
+ */
+ public $entityClass;
+
+ /**
+ * Maps the columns specified in the SELECT list of the query to the properties or fields of the entity class.
+ *
+ * @var array<\Doctrine\ORM\Mapping\FieldResult>
+ */
+ public $fields = array();
+
+ /**
+ * Specifies the column name of the column in the SELECT list that is used to determine the type of the entity instance.
+ *
+ * @var string
+ */
+ public $discriminatorColumn;
+
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/FieldResult.php b/lib/Doctrine/ORM/Mapping/FieldResult.php
new file mode 100644
index 000000000..c2c49c68d
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/FieldResult.php
@@ -0,0 +1,48 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * Is used to map the columns specified in the SELECT list of the query to the properties or fields of the entity class.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("ANNOTATION")
+ */
+final class FieldResult implements Annotation
+{
+
+ /**
+ * Name of the column in the SELECT clause.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Name of the persistent field or property of the class.
+ *
+ * @var string
+ */
+ public $column;
+
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php
index 3e8022280..5c3ed8ef2 100644
--- a/lib/Doctrine/ORM/Mapping/MappingException.php
+++ b/lib/Doctrine/ORM/Mapping/MappingException.php
@@ -93,6 +93,41 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("No query found named '$queryName' on class '$className'.");
}
+ public static function resultMappingNotFound($className, $resultName)
+ {
+ return new self("No result set mapping found named '$resultName' on class '$className'.");
+ }
+
+ public static function emptyQueryMapping($entity, $queryName)
+ {
+ return new self('Query named "'.$queryName.'" in "'.$entity.'" could not be empty.');
+ }
+
+ public static function nameIsMandatoryForQueryMapping($className)
+ {
+ return new self("Query name on entity class '$className' is not defined.");
+ }
+
+ public static function missingQueryMapping($entity, $queryName)
+ {
+ return new self('Query named "'.$queryName.'" in "'.$entity.' requires a result class or result set mapping.');
+ }
+
+ public static function missingResultSetMappingEntity($entity, $resultName)
+ {
+ return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a entity class name.');
+ }
+
+ public static function missingResultSetMappingFieldName($entity, $resultName)
+ {
+ return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a field name.');
+ }
+
+ public static function nameIsMandatoryForSqlResultSetMapping($className)
+ {
+ return new self("Result set mapping name on entity class '$className' is not defined.");
+ }
+
public static function oneToManyRequiresMappedBy($fieldName)
{
return new self("OneToMany mapping on field '$fieldName' requires the 'mappedBy' attribute.");
@@ -178,27 +213,36 @@ class MappingException extends \Doctrine\ORM\ORMException
}
/**
- *
* @param string $entity The entity's name
* @param string $fieldName The name of the field that was already declared
*/
- public static function duplicateFieldMapping($entity, $fieldName) {
+ public static function duplicateFieldMapping($entity, $fieldName)
+ {
return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
- public static function duplicateAssociationMapping($entity, $fieldName) {
+ public static function duplicateAssociationMapping($entity, $fieldName)
+ {
return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
- public static function duplicateQueryMapping($entity, $queryName) {
+ public static function duplicateQueryMapping($entity, $queryName)
+ {
return new self('Query named "'.$queryName.'" in "'.$entity.'" was already declared, but it must be declared only once');
}
- public static function singleIdNotAllowedOnCompositePrimaryKey($entity) {
+ public static function duplicateResultSetMapping($entity, $resultName)
+ {
+ return new self('Result set mapping named "'.$resultName.'" in "'.$entity.'" was already declared, but it must be declared only once');
+ }
+
+ public static function singleIdNotAllowedOnCompositePrimaryKey($entity)
+ {
return new self('Single id is not allowed on composite primary key in entity '.$entity);
}
- public static function unsupportedOptimisticLockingType($entity, $fieldName, $unsupportedType) {
+ public static function unsupportedOptimisticLockingType($entity, $fieldName, $unsupportedType)
+ {
return new self('Locking type "'.$unsupportedType.'" (specified in "'.$entity.'", field "'.$fieldName.'") '
.'is not supported by Doctrine.'
);
@@ -224,7 +268,8 @@ class MappingException extends \Doctrine\ORM\ORMException
* @param string $owningClass The class that declares the discriminator map.
* @return self
*/
- public static function invalidClassInDiscriminatorMap($className, $owningClass) {
+ public static function invalidClassInDiscriminatorMap($className, $owningClass)
+ {
return new self(
"Entity class '$className' used in the discriminator map of class '$owningClass' ".
"does not exist."
diff --git a/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php b/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php
new file mode 100644
index 000000000..f01090ee6
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php
@@ -0,0 +1,40 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * Is used to specify an array of native SQL named queries.
+ * The NamedNativeQueries annotation can be applied to an entity or mapped superclass.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("CLASS")
+ */
+final class NamedNativeQueries implements Annotation
+{
+ /**
+ * One or more NamedNativeQuery annotations.
+ *
+ * @var array<\Doctrine\ORM\Mapping\NamedNativeQuery>
+ */
+ public $value = array();
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php b/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php
new file mode 100644
index 000000000..052eded64
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php
@@ -0,0 +1,63 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * Is used to specify a native SQL named query.
+ * The NamedNativeQuery annotation can be applied to an entity or mapped superclass.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("ANNOTATION")
+ */
+final class NamedNativeQuery implements Annotation
+{
+
+ /**
+ * The name used to refer to the query with the EntityManager methods that create query objects.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * The SQL query string.
+ *
+ * @var string
+ */
+ public $query;
+
+ /**
+ * The class of the result.
+ *
+ * @var string
+ */
+ public $resultClass;
+
+ /**
+ * The name of a SqlResultSetMapping, as defined in metadata.
+ *
+ * @var string
+ */
+ public $resultSetMapping;
+
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php b/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php
new file mode 100644
index 000000000..e009ceea2
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php
@@ -0,0 +1,56 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * The SqlResultSetMapping annotation is used to specify the mapping of the result of a native SQL query.
+ * The SqlResultSetMapping annotation can be applied to an entity or mapped superclass.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("ANNOTATION")
+ */
+final class SqlResultSetMapping implements Annotation
+{
+
+ /**
+ * The name given to the result set mapping, and used to refer to it in the methods of the Query API.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Specifies the result set mapping to entities.
+ *
+ * @var array<\Doctrine\ORM\Mapping\EntityResult>
+ */
+ public $entities = array();
+
+ /**
+ * Specifies the result set mapping to scalar values.
+ *
+ * @var array<\Doctrine\ORM\Mapping\ColumnResult>
+ */
+ public $columns = array();
+
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php b/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php
new file mode 100644
index 000000000..fa04387a2
--- /dev/null
+++ b/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php
@@ -0,0 +1,40 @@
+.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * Is used to specify an array of mappings.
+ * The SqlResultSetMappings annotation can be applied to an entity or mapped superclass.
+ *
+ * @author Fabio B. Silva
+ * @since 2.3
+ *
+ * @Annotation
+ * @Target("CLASS")
+ */
+final class SqlResultSetMappings implements Annotation
+{
+ /**
+ * One or more SqlResultSetMapping annotations.
+ *
+ * @var array<\Doctrine\ORM\Mapping\SqlResultSetMapping>
+ */
+ public $value = array();
+}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php b/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
index 316a2012c..7c187dd77 100644
--- a/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
+++ b/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
@@ -106,4 +106,159 @@ class ResultSetMappingBuilder extends ResultSetMapping
}
}
}
-}
+
+
+ /**
+ * Adds the mappings of the results of native SQL queries to the result set.
+ *
+ * @param ClassMetadataInfo $class
+ * @param array $queryMapping
+ * @return ResultSetMappingBuilder
+ */
+ public function addNamedNativeQueryMapping(ClassMetadataInfo $class, array $queryMapping)
+ {
+ if (isset($queryMapping['resultClass'])) {
+ return $this->addNamedNativeQueryResultClassMapping($class, $queryMapping['resultClass']);
+ }
+
+ return $this->addNamedNativeQueryResultSetMapping($class, $queryMapping['resultSetMapping']);
+ }
+
+ /**
+ * Adds the class mapping of the results of native SQL queries to the result set.
+ *
+ * @param ClassMetadataInfo $class
+ * @param string $resultClassName
+ * @return ResultSetMappingBuilder
+ */
+ public function addNamedNativeQueryResultClassMapping(ClassMetadataInfo $class, $resultClassName)
+ {
+
+ $classMetadata = $this->em->getClassMetadata($resultClassName);
+ $shortName = $classMetadata->reflClass->getShortName();
+ $alias = strtolower($shortName[0]).'0';
+
+ $this->addEntityResult($class->name, $alias);
+
+ if ($classMetadata->discriminatorColumn) {
+ $discriminatorColumn = $classMetadata->discriminatorColumn;
+ $this->setDiscriminatorColumn($alias, $discriminatorColumn['name']);
+ $this->addMetaResult($alias, $discriminatorColumn['name'], $discriminatorColumn['fieldName']);
+ }
+
+ foreach ($classMetadata->getColumnNames() as $key => $columnName) {
+ $propertyName = $classMetadata->getFieldName($columnName);
+ $this->addFieldResult($alias, $columnName, $propertyName);
+ }
+
+ foreach ($classMetadata->associationMappings as $associationMapping) {
+ if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
+ foreach ($associationMapping['joinColumns'] as $joinColumn) {
+ $columnName = $joinColumn['name'];
+ $this->addMetaResult($alias, $columnName, $columnName, $classMetadata->isIdentifier($columnName));
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds the result set mapping of the results of native SQL queries to the result set.
+ *
+ * @param ClassMetadataInfo $class
+ * @param string $resultSetMappingName
+ * @return ResultSetMappingBuilder
+ */
+ public function addNamedNativeQueryResultSetMapping(ClassMetadataInfo $class, $resultSetMappingName)
+ {
+ $counter = 0;
+ $resultMapping = $class->getSqlResultSetMapping($resultSetMappingName);
+ $rooShortName = $class->reflClass->getShortName();
+ $rootAlias = strtolower($rooShortName[0]) . $counter;
+
+
+ if (isset($resultMapping['entities'])) {
+ foreach ($resultMapping['entities'] as $key => $entityMapping) {
+ $classMetadata = $this->em->getClassMetadata($entityMapping['entityClass']);
+
+ if ($class->reflClass->name == $classMetadata->reflClass->name) {
+ $this->addEntityResult($classMetadata->name, $rootAlias);
+ $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $rootAlias);
+ } else {
+ $shortName = $classMetadata->reflClass->getShortName();
+ $joinAlias = strtolower($shortName[0]) . ++ $counter;
+ $associations = $class->getAssociationsByTargetClass($classMetadata->name);
+
+ foreach ($associations as $relation => $mapping) {
+ $this->addJoinedEntityResult($mapping['targetEntity'], $joinAlias, $rootAlias, $relation);
+ $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $joinAlias);
+ }
+ }
+
+ }
+ }
+
+ if (isset($resultMapping['columns'])) {
+ foreach ($resultMapping['columns'] as $entityMapping) {
+ $this->addScalarResult($entityMapping['name'], $entityMapping['name']);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds the entity result mapping of the results of native SQL queries to the result set.
+ *
+ * @param ClassMetadataInfo $classMetadata
+ * @param array $entityMapping
+ * @param string $alias
+ * @return ResultSetMappingBuilder
+ */
+ public function addNamedNativeQueryEntityResultMapping(ClassMetadataInfo $classMetadata, array $entityMapping, $alias)
+ {
+ if (isset($entityMapping['discriminatorColumn']) && $entityMapping['discriminatorColumn']) {
+ $discriminatorColumn = $entityMapping['discriminatorColumn'];
+ $this->setDiscriminatorColumn($alias, $discriminatorColumn);
+ $this->addMetaResult($alias, $discriminatorColumn, $discriminatorColumn);
+ }
+
+ if (isset($entityMapping['fields']) && !empty($entityMapping['fields'])) {
+ foreach ($entityMapping['fields'] as $field) {
+ $fieldName = $field['name'];
+ $relation = null;
+
+ if(strpos($fieldName, '.')){
+ list($relation, $fieldName) = explode('.', $fieldName);
+ }
+
+ if (isset($classMetadata->associationMappings[$relation])) {
+ if($relation) {
+ $associationMapping = $classMetadata->associationMappings[$relation];
+ $joinAlias = $alias.$relation;
+ $parentAlias = $alias;
+
+ $this->addJoinedEntityResult($associationMapping['targetEntity'], $joinAlias, $parentAlias, $relation);
+ $this->addFieldResult($joinAlias, $field['column'], $fieldName);
+ }else {
+ $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name);
+ }
+ } else {
+ if(!isset($classMetadata->fieldMappings[$fieldName])) {
+ throw new \InvalidArgumentException("Entity '".$classMetadata->name."' has no field '".$fieldName."'. ");
+ }
+ $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name);
+ }
+ }
+
+ } else {
+ foreach ($classMetadata->getColumnNames() as $columnName) {
+ $propertyName = $classMetadata->getFieldName($columnName);
+ $this->addFieldResult($alias, $columnName, $propertyName);
+ }
+ }
+
+ return $this;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php
index d32416a5e..9833f3dfb 100644
--- a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php
+++ b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php
@@ -8,6 +8,57 @@ namespace Doctrine\Tests\Models\CMS;
* @author Roman S. Borschel
* @Entity
* @Table(name="cms_addresses")
+ *
+ * @NamedNativeQueries({
+ * @NamedNativeQuery(
+ * name = "find-all",
+ * resultSetMapping = "mapping-find-all",
+ * query = "SELECT id, country, city FROM cms_addresses"
+ * ),
+ * @NamedNativeQuery(
+ * name = "find-by-id",
+ * resultClass = "CmsAddress",
+ * query = "SELECT * FROM cms_addresses WHERE id = ?"
+ * ),
+ * @NamedNativeQuery(
+ * name = "count",
+ * resultSetMapping= "mapping-count",
+ * query = "SELECT COUNT(*) AS count FROM cms_addresses"
+ * )
+ * })
+ *
+ * @SqlResultSetMappings({
+ * @SqlResultSetMapping(
+ * name = "mapping-find-all",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "CmsAddress",
+ * fields = {
+ * @FieldResult(name = "id", column="id"),
+ * @FieldResult(name = "city", column="city"),
+ * @FieldResult(name = "country", column="country")
+ * }
+ * )
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mapping-without-fields",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__"
+ * )
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mapping-count",
+ * columns = {
+ * @ColumnResult(
+ * name = "count"
+ * )
+ * }
+ * )
+ * })
+ *
*/
class CmsAddress
{
@@ -69,4 +120,72 @@ class CmsAddress
$user->setAddress($this);
}
}
+
+ public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
+ {
+ $metadata->setPrimaryTable(array(
+ 'name' => 'company_person',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'find-all',
+ 'query' => 'SELECT id, country, city FROM cms_addresses',
+ 'resultSetMapping' => 'mapping-find-all',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'find-by-id',
+ 'query' => 'SELECT * FROM cms_addresses WHERE id = ?',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'count',
+ 'query' => 'SELECT COUNT(*) AS count FROM cms_addresses',
+ 'resultSetMapping' => 'mapping-count',
+ ));
+
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mapping-find-all',
+ 'columns' => array(),
+ 'entities' => array ( array (
+ 'fields' => array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'city',
+ 'column' => 'city',
+ ),
+ array (
+ 'name' => 'country',
+ 'column' => 'country',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress',
+ ),
+ ),
+ ));
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mapping-without-fields',
+ 'columns' => array(),
+ 'entities' => array(array (
+ 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress',
+ 'fields' => array()
+ )
+ )
+ ));
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mapping-count',
+ 'columns' =>array (
+ array (
+ 'name' => 'count',
+ ),
+ )
+ ));
+ }
}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/CMS/CmsUser.php b/tests/Doctrine/Tests/Models/CMS/CmsUser.php
index 1e5465784..2bae6ed4f 100644
--- a/tests/Doctrine/Tests/Models/CMS/CmsUser.php
+++ b/tests/Doctrine/Tests/Models/CMS/CmsUser.php
@@ -10,6 +10,113 @@ use Doctrine\Common\Collections\ArrayCollection;
* @NamedQueries({
* @NamedQuery(name="all", query="SELECT u FROM __CLASS__ u")
* })
+ *
+ * @NamedNativeQueries({
+ * @NamedNativeQuery(
+ * name = "fetchIdAndUsernameWithResultClass",
+ * resultClass = "CmsUser",
+ * query = "SELECT id, username FROM cms_users WHERE username = ?"
+ * ),
+ * @NamedNativeQuery(
+ * name = "fetchAllColumns",
+ * resultClass = "CmsUser",
+ * query = "SELECT * FROM cms_users WHERE username = ?"
+ * ),
+ * @NamedNativeQuery(
+ * name = "fetchJoinedAddress",
+ * resultSetMapping= "mappingJoinedAddress",
+ * query = "SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?"
+ * ),
+ * @NamedNativeQuery(
+ * name = "fetchJoinedPhonenumber",
+ * resultSetMapping= "mappingJoinedPhonenumber",
+ * query = "SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?"
+ * ),
+ * @NamedNativeQuery(
+ * name = "fetchUserPhonenumberCount",
+ * resultSetMapping= "mappingUserPhonenumberCount",
+ * query = "SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username"
+ * ),
+ * @NamedNativeQuery(
+ * name = "fetchMultipleJoinsEntityResults",
+ * resultSetMapping= "mappingMultipleJoinsEntityResults",
+ * query = "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username"
+ * ),
+ * })
+ *
+ * @SqlResultSetMappings({
+ * @SqlResultSetMapping(
+ * name = "mappingJoinedAddress",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__",
+ * fields = {
+ * @FieldResult(name = "id"),
+ * @FieldResult(name = "name"),
+ * @FieldResult(name = "status"),
+ * @FieldResult(name = "address.zip"),
+ * @FieldResult(name = "address.city"),
+ * @FieldResult(name = "address.country"),
+ * @FieldResult(name = "address.id", column = "a_id"),
+ * }
+ * )
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mappingJoinedPhonenumber",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "CmsUser",
+ * fields = {
+ * @FieldResult("id"),
+ * @FieldResult("name"),
+ * @FieldResult("status"),
+ * @FieldResult("phonenumbers.phonenumber" , column = "number"),
+ * }
+ * )
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mappingUserPhonenumberCount",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "CmsUser",
+ * fields = {
+ * @FieldResult(name = "id"),
+ * @FieldResult(name = "name"),
+ * @FieldResult(name = "status"),
+ * }
+ * )
+ * },
+ * columns = {
+ * @ColumnResult("numphones")
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mappingMultipleJoinsEntityResults",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__",
+ * fields = {
+ * @FieldResult(name = "id", column="u_id"),
+ * @FieldResult(name = "name", column="u_name"),
+ * @FieldResult(name = "status", column="u_status"),
+ * }
+ * ),
+ * @EntityResult(
+ * entityClass = "CmsAddress",
+ * fields = {
+ * @FieldResult(name = "id", column="a_id"),
+ * @FieldResult(name = "zip", column="a_zip"),
+ * @FieldResult(name = "country", column="a_country"),
+ * }
+ * )
+ * },
+ * columns = {
+ * @ColumnResult("numphones")
+ * }
+ * )
+ * })
*/
class CmsUser
{
@@ -140,4 +247,191 @@ class CmsUser
}
}
}
+
+ public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
+ {
+ $metadata->setPrimaryTable(array(
+ 'name' => 'cms_users',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchIdAndUsernameWithResultClass',
+ 'query' => 'SELECT id, username FROM cms_users WHERE username = ?',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchAllColumns',
+ 'query' => 'SELECT * FROM cms_users WHERE username = ?',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchJoinedAddress',
+ 'query' => 'SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?',
+ 'resultSetMapping' => 'mappingJoinedAddress',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchJoinedPhonenumber',
+ 'query' => 'SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?',
+ 'resultSetMapping' => 'mappingJoinedPhonenumber',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchUserPhonenumberCount',
+ 'query' => 'SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username',
+ 'resultSetMapping' => 'mappingUserPhonenumberCount',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ "name" => "fetchMultipleJoinsEntityResults",
+ "resultSetMapping" => "mappingMultipleJoinsEntityResults",
+ "query" => "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username"
+ ));
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingJoinedAddress',
+ 'columns' => array(),
+ 'entities' => array(array (
+ 'fields'=> array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ array (
+ 'name' => 'status',
+ 'column' => 'status',
+ ),
+ array (
+ 'name' => 'address.zip',
+ 'column' => 'zip',
+ ),
+ array (
+ 'name' => 'address.city',
+ 'column' => 'city',
+ ),
+ array (
+ 'name' => 'address.country',
+ 'column' => 'country',
+ ),
+ array (
+ 'name' => 'address.id',
+ 'column' => 'a_id',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'discriminatorColumn' => null
+ ),
+ ),
+ ));
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingJoinedPhonenumber',
+ 'columns' => array(),
+ 'entities' => array(array(
+ 'fields'=> array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ array (
+ 'name' => 'status',
+ 'column' => 'status',
+ ),
+ array (
+ 'name' => 'phonenumbers.phonenumber',
+ 'column' => 'number',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
+ 'discriminatorColumn' => null
+ ),
+ ),
+ ));
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingUserPhonenumberCount',
+ 'columns' => array(),
+ 'entities' => array (
+ array(
+ 'fields' => array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ array (
+ 'name' => 'status',
+ 'column' => 'status',
+ )
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'discriminatorColumn' => null
+ )
+ ),
+ 'columns' => array (
+ array (
+ 'name' => 'numphones',
+ )
+ )
+ ));
+
+ $metadata->addSqlResultSetMapping(array(
+ 'name' => 'mappingMultipleJoinsEntityResults',
+ 'entities' => array(array(
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column' => 'u_id',
+ ),
+ array(
+ 'name' => 'name',
+ 'column' => 'u_name',
+ ),
+ array(
+ 'name' => 'status',
+ 'column' => 'u_status',
+ )
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'discriminatorColumn' => null,
+ ),
+ array(
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column' => 'a_id',
+ ),
+ array(
+ 'name' => 'zip',
+ 'column' => 'a_zip',
+ ),
+ array(
+ 'name' => 'country',
+ 'column' => 'a_country',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress',
+ 'discriminatorColumn' => null,
+ ),
+ ),
+ 'columns' => array(array(
+ 'name' => 'numphones',
+ )
+ )
+ ));
+
+ }
}
diff --git a/tests/Doctrine/Tests/Models/Company/CompanyContract.php b/tests/Doctrine/Tests/Models/Company/CompanyContract.php
index 7787e96be..bc8503dfe 100644
--- a/tests/Doctrine/Tests/Models/Company/CompanyContract.php
+++ b/tests/Doctrine/Tests/Models/Company/CompanyContract.php
@@ -12,6 +12,48 @@ namespace Doctrine\Tests\Models\Company;
* "flexible" = "CompanyFlexContract",
* "flexultra" = "CompanyFlexUltraContract"
* })
+ *
+ * @NamedNativeQueries({
+ * @NamedNativeQuery(
+ * name = "all-contracts",
+ * resultClass = "__CLASS__",
+ * query = "SELECT id, completed, discr FROM company_contracts"
+ * ),
+ * @NamedNativeQuery(
+ * name = "all",
+ * resultClass = "__CLASS__",
+ * query = "SELECT id, completed, discr FROM company_contracts"
+ * ),
+ * })
+ *
+ * @SqlResultSetMappings({
+ * @SqlResultSetMapping(
+ * name = "mapping-all-contracts",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__",
+ * discriminatorColumn = "discr",
+ * fields = {
+ * @FieldResult("id"),
+ * @FieldResult("completed"),
+ * }
+ * )
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mapping-all",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__",
+ * discriminatorColumn = "discr",
+ * fields = {
+ * @FieldResult("id"),
+ * @FieldResult("completed"),
+ * }
+ * )
+ * }
+ * ),
+ * })
*/
abstract class CompanyContract
{
diff --git a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php
index e32288897..121d8ec8e 100644
--- a/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php
+++ b/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php
@@ -3,6 +3,48 @@ namespace Doctrine\Tests\Models\Company;
/**
* @Entity
+ *
+ * @NamedNativeQueries({
+ * @NamedNativeQuery(
+ * name = "all",
+ * resultClass = "__CLASS__",
+ * query = "SELECT id, hoursWorked, discr FROM company_contracts"
+ * ),
+ * @NamedNativeQuery(
+ * name = "all-flex",
+ * resultClass = "CompanyFlexContract",
+ * query = "SELECT id, hoursWorked, discr FROM company_contracts"
+ * ),
+ * })
+ *
+ * @SqlResultSetMappings({
+ * @SqlResultSetMapping(
+ * name = "mapping-all-flex",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__",
+ * discriminatorColumn = "discr",
+ * fields = {
+ * @FieldResult("id"),
+ * @FieldResult("hoursWorked"),
+ * }
+ * )
+ * }
+ * ),
+ * @SqlResultSetMapping(
+ * name = "mapping-all",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "CompanyFlexContract",
+ * discriminatorColumn = "discr",
+ * fields = {
+ * @FieldResult("id"),
+ * @FieldResult("hoursWorked"),
+ * }
+ * )
+ * }
+ * ),
+ * })
*/
class CompanyFlexContract extends CompanyContract
{
diff --git a/tests/Doctrine/Tests/Models/Company/CompanyPerson.php b/tests/Doctrine/Tests/Models/Company/CompanyPerson.php
index 0dfe9191c..1bc916d81 100644
--- a/tests/Doctrine/Tests/Models/Company/CompanyPerson.php
+++ b/tests/Doctrine/Tests/Models/Company/CompanyPerson.php
@@ -11,9 +11,39 @@ namespace Doctrine\Tests\Models\Company;
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({
- * "person" = "CompanyPerson",
- * "manager" = "CompanyManager",
- * "employee" = "CompanyEmployee"})
+ * "person" = "CompanyPerson",
+ * "manager" = "CompanyManager",
+ * "employee" = "CompanyEmployee"
+ * })
+ *
+ * @NamedNativeQueries({
+ * @NamedNativeQuery(
+ * name = "fetchAllWithResultClass",
+ * resultClass = "__CLASS__",
+ * query = "SELECT id, name, discr FROM company_persons ORDER BY name"
+ * ),
+ * @NamedNativeQuery(
+ * name = "fetchAllWithSqlResultSetMapping",
+ * resultSetMapping= "mappingFetchAll",
+ * query = "SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name"
+ * )
+ * })
+ *
+ * @SqlResultSetMappings({
+ * @SqlResultSetMapping(
+ * name = "mappingFetchAll",
+ * entities= {
+ * @EntityResult(
+ * entityClass = "__CLASS__",
+ * discriminatorColumn = "discriminator",
+ * fields = {
+ * @FieldResult("id"),
+ * @FieldResult("name"),
+ * }
+ * )
+ * }
+ * )
+ * })
*/
class CompanyPerson
{
@@ -78,5 +108,45 @@ class CompanyPerson
$this->spouse->setSpouse($this);
}
}
+
+ public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
+ {
+
+ $metadata->setPrimaryTable(array(
+ 'name' => 'company_person',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchAllWithResultClass',
+ 'query' => 'SELECT id, name, discr FROM company_persons ORDER BY name',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\Company\\CompanyPerson',
+ ));
+
+ $metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchAllWithSqlResultSetMapping',
+ 'query' => 'SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name',
+ 'resultSetMapping' => 'mappingFetchAll',
+ ));
+
+ $metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingFetchAll',
+ 'columns' => array(),
+ 'entities' => array ( array (
+ 'fields' => array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\Company\CompanyPerson',
+ 'discriminatorColumn' => 'discriminator',
+ ),
+ ),
+ ));
+ }
}
diff --git a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php
index eb46329f1..a6a9016a4 100644
--- a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php
+++ b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php
@@ -7,8 +7,11 @@ use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsAddress;
+use Doctrine\Tests\Models\CMS\CmsEmail;
+use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\Company\CompanyFixContract;
use Doctrine\Tests\Models\Company\CompanyEmployee;
+use Doctrine\Tests\Models\Company\CompanyPerson;
require_once __DIR__ . '/../../TestInit.php';
@@ -23,6 +26,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
protected function setUp() {
$this->useModelSet('cms');
+ $this->useModelSet('company');
parent::setUp();
$this->platform = $this->_em->getConnection()->getDatabasePlatform();
}
@@ -329,5 +333,372 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
);
$users = $query->getResult();
}
-}
+
+ /**
+ * @group DDC-1663
+ */
+ public function testBasicNativeNamedQueryWithSqlResultSetMapping()
+ {
+ $user = new CmsUser;
+ $user->name = 'Fabio B. Silva';
+ $user->username = 'FabioBatSilva';
+ $user->status = 'dev';
+
+ $addr = new CmsAddress;
+ $addr->country = 'Brazil';
+ $addr->zip = 10827;
+ $addr->city = 'São Paulo';
+
+ $user->setAddress($addr);
+
+ $this->_em->clear();
+ $this->_em->persist($user);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
+ $query = $repository->createNativeNamedQuery('find-all');
+ $result = $query->getResult();
+
+ $this->assertCount(1, $result);
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0]);
+ $this->assertEquals($addr->id, $result[0]->id);
+ $this->assertEquals($addr->city, $result[0]->city);
+ $this->assertEquals($addr->country, $result[0]->country);
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testBasicNativeNamedQueryWithResultClass()
+ {
+ $user = new CmsUser;
+ $user->name = 'Fabio B. Silva';
+ $user->username = 'FabioBatSilva';
+ $user->status = 'dev';
+
+ $email = new CmsEmail();
+ $email->email = 'fabio.bat.silva@gmail.com';
+
+ $user->setEmail($email);
+
+ $this->_em->clear();
+ $this->_em->persist($user);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
+
+
+ $result = $repository->createNativeNamedQuery('fetchIdAndUsernameWithResultClass')
+ ->setParameter(1, 'FabioBatSilva')->getResult();
+
+ $this->assertEquals(1, count($result));
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]);
+ $this->assertNull($result[0]->name);
+ $this->assertNull($result[0]->email);
+ $this->assertEquals($user->id, $result[0]->id);
+ $this->assertEquals('FabioBatSilva', $result[0]->username);
+
+ $this->_em->clear();
+
+
+ $result = $repository->createNativeNamedQuery('fetchAllColumns')
+ ->setParameter(1, 'FabioBatSilva')->getResult();
+
+ $this->assertEquals(1, count($result));
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]);
+ $this->assertEquals($user->id, $result[0]->id);
+ $this->assertEquals('Fabio B. Silva', $result[0]->name);
+ $this->assertEquals('FabioBatSilva', $result[0]->username);
+ $this->assertEquals('dev', $result[0]->status);
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsEmail', $result[0]->email);
+ }
+
+
+ /**
+ * @group DDC-1663
+ */
+ public function testJoinedOneToOneNativeNamedQueryWithResultSetMapping()
+ {
+ $user = new CmsUser;
+ $user->name = 'Fabio B. Silva';
+ $user->username = 'FabioBatSilva';
+ $user->status = 'dev';
+
+ $addr = new CmsAddress;
+ $addr->country = 'Brazil';
+ $addr->zip = 10827;
+ $addr->city = 'São Paulo';
+
+
+ $user->setAddress($addr);
+
+ $this->_em->persist($user);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
+
+
+ $result = $repository->createNativeNamedQuery('fetchJoinedAddress')
+ ->setParameter(1, 'FabioBatSilva')->getResult();
+
+ $this->assertEquals(1, count($result));
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]);
+ $this->assertEquals('Fabio B. Silva', $result[0]->name);
+ $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0]->getPhonenumbers());
+ $this->assertFalse($result[0]->getPhonenumbers()->isInitialized());
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0]->getAddress());
+ $this->assertTrue($result[0]->getAddress()->getUser() == $result[0]);
+ $this->assertEquals('Brazil', $result[0]->getAddress()->getCountry());
+ $this->assertEquals(10827, $result[0]->getAddress()->getZipCode());
+ $this->assertEquals('São Paulo', $result[0]->getAddress()->getCity());
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testJoinedOneToManyNativeNamedQueryWithResultSetMapping()
+ {
+ $user = new CmsUser;
+ $user->name = 'Fabio B. Silva';
+ $user->username = 'FabioBatSilva';
+ $user->status = 'dev';
+
+ $phone = new CmsPhonenumber;
+ $phone->phonenumber = 424242;
+
+ $user->addPhonenumber($phone);
+
+ $this->_em->persist($user);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
+
+ $result = $repository->createNativeNamedQuery('fetchJoinedPhonenumber')
+ ->setParameter(1, 'FabioBatSilva')->getResult();
+
+ $this->assertEquals(1, count($result));
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]);
+ $this->assertEquals('Fabio B. Silva', $result[0]->name);
+ $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0]->getPhonenumbers());
+ $this->assertTrue($result[0]->getPhonenumbers()->isInitialized());
+ $this->assertEquals(1, count($result[0]->getPhonenumbers()));
+ $phones = $result[0]->getPhonenumbers();
+ $this->assertEquals(424242, $phones[0]->phonenumber);
+ $this->assertTrue($phones[0]->getUser() === $result[0]);
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testMixedNativeNamedQueryNormalJoin()
+ {
+ $user1 = new CmsUser;
+ $user1->name = 'Fabio B. Silva';
+ $user1->username = 'FabioBatSilva';
+ $user1->status = 'dev';
+
+ $user2 = new CmsUser;
+ $user2->name = 'test tester';
+ $user2->username = 'test';
+ $user2->status = 'tester';
+
+ $phone1 = new CmsPhonenumber;
+ $phone2 = new CmsPhonenumber;
+ $phone3 = new CmsPhonenumber;
+ $phone1->phonenumber = 11111111;
+ $phone2->phonenumber = 22222222;
+ $phone3->phonenumber = 33333333;
+
+ $user1->addPhonenumber($phone1);
+ $user1->addPhonenumber($phone2);
+ $user2->addPhonenumber($phone3);
+
+ $this->_em->persist($user1);
+ $this->_em->persist($user2);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
+
+ $result = $repository->createNativeNamedQuery('fetchUserPhonenumberCount')
+ ->setParameter(1, array('test','FabioBatSilva'))->getResult();
+
+ $this->assertEquals(2, count($result));
+ $this->assertTrue(is_array($result[0]));
+ $this->assertTrue(is_array($result[1]));
+
+ // first user => 2 phonenumbers
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]);
+ $this->assertEquals('Fabio B. Silva', $result[0][0]->name);
+ $this->assertEquals(2, $result[0]['numphones']);
+
+ // second user => 1 phonenumbers
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][0]);
+ $this->assertEquals('test tester', $result[1][0]->name);
+ $this->assertEquals(1, $result[1]['numphones']);
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testNativeNamedQueryInheritance()
+ {
+ $person = new CompanyPerson;
+ $person->setName('Fabio B. Silva');
+
+ $employee = new CompanyEmployee;
+ $employee->setName('Fabio Silva');
+ $employee->setSalary(100000);
+ $employee->setDepartment('IT');
+
+ $this->_em->persist($person);
+ $this->_em->persist($employee);
+
+ $this->_em->flush();
+ $this->_em->clear();
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson');
+
+ $result = $repository->createNativeNamedQuery('fetchAllWithSqlResultSetMapping')
+ ->getResult();
+
+ $this->assertEquals(2, count($result));
+ $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result[0]);
+ $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[1]);
+ $this->assertTrue(is_numeric($result[0]->getId()));
+ $this->assertTrue(is_numeric($result[1]->getId()));
+ $this->assertEquals('Fabio B. Silva', $result[0]->getName());
+ $this->assertEquals('Fabio Silva', $result[1]->getName());
+
+
+ $this->_em->clear();
+
+
+ $result = $repository->createNativeNamedQuery('fetchAllWithResultClass')
+ ->getResult();
+
+ $this->assertEquals(2, count($result));
+ $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result[0]);
+ $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[1]);
+ $this->assertTrue(is_numeric($result[0]->getId()));
+ $this->assertTrue(is_numeric($result[1]->getId()));
+ $this->assertEquals('Fabio B. Silva', $result[0]->getName());
+ $this->assertEquals('Fabio Silva', $result[1]->getName());
+ }
+
+ /**
+ * @group DDC-1663
+ * DQL : SELECT u, a, COUNT(p) AS numphones FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.address a JOIN u.phonenumbers p
+ */
+ public function testMultipleEntityResults()
+ {
+
+ $user = new CmsUser;
+ $user->name = 'Fabio B. Silva';
+ $user->username = 'FabioBatSilva';
+ $user->status = 'dev';
+
+ $addr = new CmsAddress;
+ $addr->country = 'Brazil';
+ $addr->zip = 10827;
+ $addr->city = 'São Paulo';
+
+ $phone = new CmsPhonenumber;
+ $phone->phonenumber = 424242;
+
+
+ $user->setAddress($addr);
+ $user->addPhonenumber($phone);
+
+
+ $this->_em->clear();
+ $this->_em->persist($user);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+
+ $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
+ $query = $repository->createNativeNamedQuery('fetchMultipleJoinsEntityResults');
+ $result = $query->getResult();
+
+
+ $this->assertEquals(1, count($result));
+ $this->assertTrue(is_array($result[0]));
+
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]);
+ $this->assertEquals('Fabio B. Silva', $result[0][0]->name);
+ $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0][0]->getAddress());
+ $this->assertTrue($result[0][0]->getAddress()->getUser() == $result[0][0]);
+ $this->assertEquals('Brazil', $result[0][0]->getAddress()->getCountry());
+ $this->assertEquals(10827, $result[0][0]->getAddress()->getZipCode());
+
+ $this->assertEquals(1, $result[0]['numphones']);
+
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testNamedNativeQueryInheritance()
+ {
+ $contractMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyContract');
+ $flexMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyFlexContract');
+
+ $contractQueries = $contractMetadata->getNamedNativeQueries();
+ $flexQueries = $flexMetadata->getNamedNativeQueries();
+
+ $contractMappings = $contractMetadata->getSqlResultSetMappings();
+ $flexMappings = $flexMetadata->getSqlResultSetMappings();
+
+
+ // contract queries
+ $this->assertEquals('all-contracts', $contractQueries['all-contracts']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractQueries['all-contracts']['resultClass']);
+
+ $this->assertEquals('all', $contractQueries['all']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractQueries['all']['resultClass']);
+
+
+ // flex contract queries
+ $this->assertEquals('all-contracts', $flexQueries['all-contracts']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexQueries['all-contracts']['resultClass']);
+
+ $this->assertEquals('all-flex', $flexQueries['all-flex']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexQueries['all-flex']['resultClass']);
+
+ $this->assertEquals('all', $flexQueries['all']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexQueries['all']['resultClass']);
+
+
+ // contract result mapping
+ $this->assertEquals('mapping-all-contracts', $contractMappings['mapping-all-contracts']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractMappings['mapping-all-contracts']['entities'][0]['entityClass']);
+
+ $this->assertEquals('mapping-all', $contractMappings['mapping-all']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractMappings['mapping-all-contracts']['entities'][0]['entityClass']);
+
+ // flex contract result mapping
+ $this->assertEquals('mapping-all-contracts', $flexMappings['mapping-all-contracts']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexMappings['mapping-all-contracts']['entities'][0]['entityClass']);
+
+ $this->assertEquals('mapping-all', $flexMappings['mapping-all']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexMappings['mapping-all']['entities'][0]['entityClass']);
+
+ $this->assertEquals('mapping-all-flex', $flexMappings['mapping-all-flex']['name']);
+ $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexMappings['mapping-all-flex']['entities'][0]['entityClass']);
+
+ }
+
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php
index 785c19b74..801937f2d 100644
--- a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php
+++ b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php
@@ -93,5 +93,167 @@ class ResultSetMappingTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($rms->hasParentAlias('p'));
$this->assertTrue($rms->isMixedResult());
}
+
+ /**
+ * @group DDC-1663
+ */
+ public function testAddNamedNativeQueryResultSetMapping()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->mapOneToOne(array(
+ 'fieldName' => 'email',
+ 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsEmail',
+ 'cascade' => array('persist'),
+ 'inversedBy' => 'user',
+ 'orphanRemoval' => false,
+ 'joinColumns' => array(array(
+ 'nullable' => true,
+ 'referencedColumnName' => 'id',
+ )
+ )
+ ));
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT u.id AS user_id, e.id AS email_id, u.name, e.email, u.id + e.id AS scalarColumn FROM cms_users u INNER JOIN cms_emails e ON e.id = u.email_id',
+ 'resultSetMapping' => 'find-all',
+ ));
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => '__CLASS__',
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column'=> 'user_id'
+ ),
+ array(
+ 'name' => 'name',
+ 'column'=> 'name'
+ )
+ )
+ ),
+ array(
+ 'entityClass' => 'CmsEmail',
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column'=> 'email_id'
+ ),
+ array(
+ 'name' => 'email',
+ 'column'=> 'email'
+ )
+ )
+ )
+ ),
+ 'columns' => array(
+ array(
+ 'name' => 'scalarColumn'
+ )
+ )
+ ));
+
+
+ $queryMapping = $cm->getNamedNativeQuery('find-all');
+
+ $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em);
+ $rsm->addNamedNativeQueryMapping($cm, $queryMapping);
+
+ $this->assertEquals('scalarColumn', $rsm->getScalarAlias('scalarColumn'));
+
+ $this->assertEquals('c0', $rsm->getEntityAlias('user_id'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('name'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getClassName('c0'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('name'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('user_id'));
+
+
+ $this->assertEquals('c1', $rsm->getEntityAlias('email_id'));
+ $this->assertEquals('c1', $rsm->getEntityAlias('email'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $rsm->getClassName('c1'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $rsm->getDeclaringClass('email'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $rsm->getDeclaringClass('email_id'));
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testAddNamedNativeQueryResultSetMappingWithoutFields()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT u.id AS user_id, e.id AS email_id, u.name, e.email, u.id + e.id AS scalarColumn FROM cms_users u INNER JOIN cms_emails e ON e.id = u.email_id',
+ 'resultSetMapping' => 'find-all',
+ ));
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => '__CLASS__',
+ )
+ ),
+ 'columns' => array(
+ array(
+ 'name' => 'scalarColumn'
+ )
+ )
+ ));
+
+
+ $queryMapping = $cm->getNamedNativeQuery('find-all');
+
+ $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em);
+ $rsm->addNamedNativeQueryMapping($cm, $queryMapping);
+
+ $this->assertEquals('scalarColumn', $rsm->getScalarAlias('scalarColumn'));
+
+ $this->assertEquals('c0', $rsm->getEntityAlias('id'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('name'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('status'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('username'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getClassName('c0'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('id'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('name'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('status'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('username'));
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testAddNamedNativeQueryResultClass()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'resultClass' => '__CLASS__',
+ 'query' => 'SELECT * FROM cms_users',
+ ));
+
+ $queryMapping = $cm->getNamedNativeQuery('find-all');
+
+ $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em);
+ $rsm->addNamedNativeQueryMapping($cm, $queryMapping);
+
+
+ $this->assertEquals('c0', $rsm->getEntityAlias('id'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('name'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('status'));
+ $this->assertEquals('c0', $rsm->getEntityAlias('username'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getClassName('c0'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('id'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('name'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('status'));
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('username'));
+ }
}
diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
index 3233c3104..0efb3aca2 100644
--- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
+++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
@@ -467,6 +467,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
}
/**
+<<<<<<< HEAD
* @group DDC-889
* @expectedException Doctrine\ORM\Mapping\MappingException
* @expectedExceptionMessage Class "Doctrine\Tests\Models\DDC889\DDC889Class" sub class of "Doctrine\Tests\Models\DDC889\DDC889SuperClass" is not a valid entity or mapped super class.
@@ -488,6 +489,130 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$factory->getMetadataFor('Doctrine\Tests\Models\DDC889\DDC889Entity');
}
+
+ /**
+ * @group DDC-1663
+ */
+ public function testNamedNativeQuery()
+ {
+
+ $class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
+
+ //named native query
+ $this->assertCount(3, $class->namedNativeQueries);
+ $this->assertArrayHasKey('find-all', $class->namedNativeQueries);
+ $this->assertArrayHasKey('find-by-id', $class->namedNativeQueries);
+
+
+ $findAllQuery = $class->getNamedNativeQuery('find-all');
+ $this->assertEquals('find-all', $findAllQuery['name']);
+ $this->assertEquals('mapping-find-all', $findAllQuery['resultSetMapping']);
+ $this->assertEquals('SELECT id, country, city FROM cms_addresses', $findAllQuery['query']);
+
+ $findByIdQuery = $class->getNamedNativeQuery('find-by-id');
+ $this->assertEquals('find-by-id', $findByIdQuery['name']);
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress',$findByIdQuery['resultClass']);
+ $this->assertEquals('SELECT * FROM cms_addresses WHERE id = ?', $findByIdQuery['query']);
+
+ $countQuery = $class->getNamedNativeQuery('count');
+ $this->assertEquals('count', $countQuery['name']);
+ $this->assertEquals('mapping-count', $countQuery['resultSetMapping']);
+ $this->assertEquals('SELECT COUNT(*) AS count FROM cms_addresses', $countQuery['query']);
+
+ // result set mapping
+ $this->assertCount(3, $class->sqlResultSetMappings);
+ $this->assertArrayHasKey('mapping-count', $class->sqlResultSetMappings);
+ $this->assertArrayHasKey('mapping-find-all', $class->sqlResultSetMappings);
+ $this->assertArrayHasKey('mapping-without-fields', $class->sqlResultSetMappings);
+
+ $findAllMapping = $class->getSqlResultSetMapping('mapping-find-all');
+ $this->assertEquals('mapping-find-all', $findAllMapping['name']);
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $findAllMapping['entities'][0]['entityClass']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $findAllMapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'city','column'=>'city'), $findAllMapping['entities'][0]['fields'][1]);
+ $this->assertEquals(array('name'=>'country','column'=>'country'), $findAllMapping['entities'][0]['fields'][2]);
+
+ $withoutFieldsMapping = $class->getSqlResultSetMapping('mapping-without-fields');
+ $this->assertEquals('mapping-without-fields', $withoutFieldsMapping['name']);
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $withoutFieldsMapping['entities'][0]['entityClass']);
+ $this->assertEquals(array(), $withoutFieldsMapping['entities'][0]['fields']);
+
+ $countMapping = $class->getSqlResultSetMapping('mapping-count');
+ $this->assertEquals('mapping-count', $countMapping['name']);
+ $this->assertEquals(array('name'=>'count'), $countMapping['columns'][0]);
+
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testSqlResultSetMapping()
+ {
+
+ $userMetadata = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $personMetadata = $this->createClassMetadata('Doctrine\Tests\Models\Company\CompanyPerson');
+
+ // user asserts
+ $this->assertCount(4, $userMetadata->getSqlResultSetMappings());
+
+ $mapping = $userMetadata->getSqlResultSetMapping('mappingJoinedAddress');
+ $this->assertEquals(array(),$mapping['columns']);
+ $this->assertEquals('mappingJoinedAddress', $mapping['name']);
+ $this->assertNull($mapping['entities'][0]['discriminatorColumn']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]);
+ $this->assertEquals(array('name'=>'status','column'=>'status'), $mapping['entities'][0]['fields'][2]);
+ $this->assertEquals(array('name'=>'address.zip','column'=>'zip'), $mapping['entities'][0]['fields'][3]);
+ $this->assertEquals(array('name'=>'address.city','column'=>'city'), $mapping['entities'][0]['fields'][4]);
+ $this->assertEquals(array('name'=>'address.country','column'=>'country'), $mapping['entities'][0]['fields'][5]);
+ $this->assertEquals(array('name'=>'address.id','column'=>'a_id'), $mapping['entities'][0]['fields'][6]);
+ $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']);
+
+
+ $mapping = $userMetadata->getSqlResultSetMapping('mappingJoinedPhonenumber');
+ $this->assertEquals(array(),$mapping['columns']);
+ $this->assertEquals('mappingJoinedPhonenumber', $mapping['name']);
+ $this->assertNull($mapping['entities'][0]['discriminatorColumn']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]);
+ $this->assertEquals(array('name'=>'status','column'=>'status'), $mapping['entities'][0]['fields'][2]);
+ $this->assertEquals(array('name'=>'phonenumbers.phonenumber','column'=>'number'), $mapping['entities'][0]['fields'][3]);
+ $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']);
+
+ $mapping = $userMetadata->getSqlResultSetMapping('mappingUserPhonenumberCount');
+ $this->assertEquals(array('name'=>'numphones'),$mapping['columns'][0]);
+ $this->assertEquals('mappingUserPhonenumberCount', $mapping['name']);
+ $this->assertNull($mapping['entities'][0]['discriminatorColumn']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]);
+ $this->assertEquals(array('name'=>'status','column'=>'status'), $mapping['entities'][0]['fields'][2]);
+ $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']);
+
+ $mapping = $userMetadata->getSqlResultSetMapping('mappingMultipleJoinsEntityResults');
+ $this->assertEquals(array('name'=>'numphones'),$mapping['columns'][0]);
+ $this->assertEquals('mappingMultipleJoinsEntityResults', $mapping['name']);
+ $this->assertNull($mapping['entities'][0]['discriminatorColumn']);
+ $this->assertEquals(array('name'=>'id','column'=>'u_id'), $mapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'name','column'=>'u_name'), $mapping['entities'][0]['fields'][1]);
+ $this->assertEquals(array('name'=>'status','column'=>'u_status'), $mapping['entities'][0]['fields'][2]);
+ $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']);
+ $this->assertNull($mapping['entities'][1]['discriminatorColumn']);
+ $this->assertEquals(array('name'=>'id','column'=>'a_id'), $mapping['entities'][1]['fields'][0]);
+ $this->assertEquals(array('name'=>'zip','column'=>'a_zip'), $mapping['entities'][1]['fields'][1]);
+ $this->assertEquals(array('name'=>'country','column'=>'a_country'), $mapping['entities'][1]['fields'][2]);
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $mapping['entities'][1]['entityClass']);
+
+ //person asserts
+ $this->assertCount(1, $personMetadata->getSqlResultSetMappings());
+
+ $mapping = $personMetadata->getSqlResultSetMapping('mappingFetchAll');
+ $this->assertEquals(array(),$mapping['columns']);
+ $this->assertEquals('mappingFetchAll', $mapping['name']);
+ $this->assertEquals('discriminator', $mapping['entities'][0]['discriminatorColumn']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]);
+ $this->assertEquals($personMetadata->name, $mapping['entities'][0]['entityClass']);
+ }
}
/**
diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
index 4d7ec352f..fd6afe960 100644
--- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
+++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
@@ -510,6 +510,29 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(1, count($cm->getNamedQueries()));
}
+ /**
+ * @group DDC-1663
+ */
+ public function testRetrievalOfResultSetMappings()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+
+ $this->assertEquals(0, count($cm->getSqlResultSetMappings()));
+
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ ),
+ ),
+ ));
+
+ $this->assertEquals(1, count($cm->getSqlResultSetMappings()));
+ }
+
public function testExistanceOfNamedQuery()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
@@ -525,6 +548,138 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertFalse($cm->hasNamedQuery('userById'));
}
+ /**
+ * @group DDC-1663
+ */
+ public function testRetrieveOfNamedNativeQuery()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT * FROM cms_users',
+ 'resultSetMapping' => 'result-mapping-name',
+ 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ ));
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-by-id',
+ 'query' => 'SELECT * FROM cms_users WHERE id = ?',
+ 'resultClass' => '__CLASS__',
+ 'resultSetMapping' => 'result-mapping-name',
+ ));
+
+ $mapping = $cm->getNamedNativeQuery('find-all');
+ $this->assertEquals('SELECT * FROM cms_users', $mapping['query']);
+ $this->assertEquals('result-mapping-name', $mapping['resultSetMapping']);
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $mapping['resultClass']);
+
+ $mapping = $cm->getNamedNativeQuery('find-by-id');
+ $this->assertEquals('SELECT * FROM cms_users WHERE id = ?', $mapping['query']);
+ $this->assertEquals('result-mapping-name', $mapping['resultSetMapping']);
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $mapping['resultClass']);
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testRetrieveOfSqlResultSetMapping()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => '__CLASS__',
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column'=> 'id'
+ ),
+ array(
+ 'name' => 'name',
+ 'column'=> 'name'
+ )
+ )
+ ),
+ array(
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsEmail',
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column'=> 'id'
+ ),
+ array(
+ 'name' => 'email',
+ 'column'=> 'email'
+ )
+ )
+ )
+ ),
+ 'columns' => array(
+ array(
+ 'name' => 'scalarColumn'
+ )
+ )
+ ));
+
+ $mapping = $cm->getSqlResultSetMapping('find-all');
+
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $mapping['entities'][0]['entityClass']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]);
+ $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]);
+
+ $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $mapping['entities'][1]['entityClass']);
+ $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][1]['fields'][0]);
+ $this->assertEquals(array('name'=>'email','column'=>'email'), $mapping['entities'][1]['fields'][1]);
+
+ $this->assertEquals('scalarColumn', $mapping['columns'][0]['name']);
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testExistanceOfSqlResultSetMapping()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ ),
+ ),
+ ));
+
+ $this->assertTrue($cm->hasSqlResultSetMapping('find-all'));
+ $this->assertFalse($cm->hasSqlResultSetMapping('find-by-id'));
+ }
+
+ /**
+ * @group DDC-1663
+ */
+ public function testExistanceOfNamedNativeQuery()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT * FROM cms_users',
+ 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'resultSetMapping' => 'result-mapping-name'
+ ));
+
+ $this->assertTrue($cm->hasNamedNativeQuery('find-all'));
+ $this->assertFalse($cm->hasNamedNativeQuery('find-by-id'));
+ }
+
public function testRetrieveOfNamedQuery()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
@@ -539,13 +694,34 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', $cm->getNamedQuery('userById'));
}
- public function testNamingCollisionNamedQueryShouldThrowException()
+ /**
+ * @group DDC-1663
+ */
+ public function testRetrievalOfNamedNativeQueries()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+ $this->assertEquals(0, count($cm->getNamedNativeQueries()));
- $this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT * FROM cms_users',
+ 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'resultSetMapping' => 'result-mapping-name'
+ ));
+
+ $this->assertEquals(1, count($cm->getNamedNativeQueries()));
+ }
+
+ /**
+ * @expectedException \Doctrine\ORM\Mapping\MappingException
+ * @expectedExceptionMessage Query named "userById" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once
+ */
+ public function testNamingCollisionNamedQueryShouldThrowException()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->addNamedQuery(array(
'name' => 'userById',
@@ -558,6 +734,62 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
));
}
+ /**
+ * @group DDC-1663
+ *
+ * @expectedException \Doctrine\ORM\Mapping\MappingException
+ * @expectedExceptionMessage Query named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once
+ */
+ public function testNamingCollisionNamedNativeQueryShouldThrowException()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT * FROM cms_users',
+ 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'resultSetMapping' => 'result-mapping-name'
+ ));
+
+ $cm->addNamedNativeQuery(array(
+ 'name' => 'find-all',
+ 'query' => 'SELECT * FROM cms_users',
+ 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'resultSetMapping' => 'result-mapping-name'
+ ));
+ }
+
+ /**
+ * @group DDC-1663
+ *
+ * @expectedException \Doctrine\ORM\Mapping\MappingException
+ * @expectedExceptionMessage Result set mapping named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once
+ */
+ public function testNamingCollisionSqlResultSetMappingShouldThrowException()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ ),
+ ),
+ ));
+
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ ),
+ ),
+ ));
+ }
+
/**
* @group DDC-1068
*/
@@ -596,6 +828,58 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$cm->validateAssocations();
}
+ /**
+ * @group DDC-1663
+ *
+ * @expectedException \Doctrine\ORM\Mapping\MappingException
+ * @expectedExceptionMessage Query name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined.
+ */
+ public function testNameIsMandatoryForNamedQueryMappingException()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+ $cm->addNamedQuery(array(
+ 'query' => 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u',
+ ));
+ }
+
+ /**
+ * @group DDC-1663
+ *
+ * @expectedException \Doctrine\ORM\Mapping\MappingException
+ * @expectedExceptionMessage Query name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined.
+ */
+ public function testNameIsMandatoryForNameNativeQueryMappingException()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+ $cm->addNamedQuery(array(
+ 'query' => 'SELECT * FROM cms_users',
+ 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'resultSetMapping' => 'result-mapping-name'
+ ));
+ }
+
+ /**
+ * @group DDC-1663
+ *
+ * @expectedException \Doctrine\ORM\Mapping\MappingException
+ * @expectedExceptionMessage Result set mapping named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser requires a entity class name.
+ */
+ public function testNameIsMandatoryForEntityNameSqlResultSetMappingException()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+ $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
+ $cm->addSqlResultSetMapping(array(
+ 'name' => 'find-all',
+ 'entities' => array(
+ array(
+ 'fields' => array()
+ )
+ ),
+ ));
+ }
+
/**
* @expectedException \Doctrine\ORM\Mapping\MappingException
* @expectedExceptionMessage Discriminator column name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined.
diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php
new file mode 100644
index 000000000..964065cbd
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php
@@ -0,0 +1,69 @@
+setPrimaryTable(array(
+ 'name' => 'company_person',
+));
+
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'find-all',
+ 'query' => 'SELECT id, country, city FROM cms_addresses',
+ 'resultSetMapping' => 'mapping-find-all',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'find-by-id',
+ 'query' => 'SELECT * FROM cms_addresses WHERE id = ?',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'count',
+ 'query' => 'SELECT COUNT(*) AS count FROM cms_addresses',
+ 'resultSetMapping' => 'mapping-count',
+));
+
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mapping-find-all',
+ 'columns' => array(),
+ 'entities' => array ( array (
+ 'fields' => array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'city',
+ 'column' => 'city',
+ ),
+ array (
+ 'name' => 'country',
+ 'column' => 'country',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress',
+ ),
+ ),
+));
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mapping-without-fields',
+ 'columns' => array(),
+ 'entities' => array(array (
+ 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress',
+ 'fields' => array()
+ )
+ )
+));
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mapping-count',
+ 'columns' =>array (
+ array (
+ 'name' => 'count',
+ ),
+ )
+));
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php
new file mode 100644
index 000000000..9484bf750
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php
@@ -0,0 +1,186 @@
+setPrimaryTable(array(
+ 'name' => 'cms_users',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchIdAndUsernameWithResultClass',
+ 'query' => 'SELECT id, username FROM cms_users WHERE username = ?',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchAllColumns',
+ 'query' => 'SELECT * FROM cms_users WHERE username = ?',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchJoinedAddress',
+ 'query' => 'SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?',
+ 'resultSetMapping' => 'mappingJoinedAddress',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchJoinedPhonenumber',
+ 'query' => 'SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?',
+ 'resultSetMapping' => 'mappingJoinedPhonenumber',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchUserPhonenumberCount',
+ 'query' => 'SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username',
+ 'resultSetMapping' => 'mappingUserPhonenumberCount',
+));
+
+$metadata->addNamedNativeQuery(array (
+ "name" => "fetchMultipleJoinsEntityResults",
+ "resultSetMapping" => "mappingMultipleJoinsEntityResults",
+ "query" => "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username"
+));
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingJoinedAddress',
+ 'columns' => array(),
+ 'entities' => array(array (
+ 'fields'=> array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ array (
+ 'name' => 'status',
+ 'column' => 'status',
+ ),
+ array (
+ 'name' => 'address.zip',
+ 'column' => 'zip',
+ ),
+ array (
+ 'name' => 'address.city',
+ 'column' => 'city',
+ ),
+ array (
+ 'name' => 'address.country',
+ 'column' => 'country',
+ ),
+ array (
+ 'name' => 'address.id',
+ 'column' => 'a_id',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'discriminatorColumn' => null
+ ),
+ ),
+));
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingJoinedPhonenumber',
+ 'columns' => array(),
+ 'entities' => array(array(
+ 'fields'=> array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ array (
+ 'name' => 'status',
+ 'column' => 'status',
+ ),
+ array (
+ 'name' => 'phonenumbers.phonenumber',
+ 'column' => 'number',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser',
+ 'discriminatorColumn' => null
+ ),
+ ),
+));
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingUserPhonenumberCount',
+ 'columns' => array(),
+ 'entities' => array (
+ array(
+ 'fields' => array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ array (
+ 'name' => 'status',
+ 'column' => 'status',
+ )
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'discriminatorColumn' => null
+ )
+ ),
+ 'columns' => array (
+ array (
+ 'name' => 'numphones',
+ )
+ )
+));
+
+$metadata->addSqlResultSetMapping(array(
+ 'name' => 'mappingMultipleJoinsEntityResults',
+ 'entities' => array(array(
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column' => 'u_id',
+ ),
+ array(
+ 'name' => 'name',
+ 'column' => 'u_name',
+ ),
+ array(
+ 'name' => 'status',
+ 'column' => 'u_status',
+ )
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
+ 'discriminatorColumn' => null,
+ ),
+ array(
+ 'fields' => array(
+ array(
+ 'name' => 'id',
+ 'column' => 'a_id',
+ ),
+ array(
+ 'name' => 'zip',
+ 'column' => 'a_zip',
+ ),
+ array(
+ 'name' => 'country',
+ 'column' => 'a_country',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress',
+ 'discriminatorColumn' => null,
+ ),
+ ),
+ 'columns' => array(array(
+ 'name' => 'numphones',
+ )
+ )
+));
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php
new file mode 100644
index 000000000..68703f40a
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php
@@ -0,0 +1,39 @@
+setPrimaryTable(array(
+ 'name' => 'company_person',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchAllWithResultClass',
+ 'query' => 'SELECT id, name, discr FROM company_persons ORDER BY name',
+ 'resultClass' => 'Doctrine\\Tests\\Models\\Company\\CompanyPerson',
+));
+
+$metadata->addNamedNativeQuery(array (
+ 'name' => 'fetchAllWithSqlResultSetMapping',
+ 'query' => 'SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name',
+ 'resultSetMapping' => 'mappingFetchAll',
+));
+
+$metadata->addSqlResultSetMapping(array (
+ 'name' => 'mappingFetchAll',
+ 'columns' => array(),
+ 'entities' => array ( array (
+ 'fields' => array (
+ array (
+ 'name' => 'id',
+ 'column' => 'id',
+ ),
+ array (
+ 'name' => 'name',
+ 'column' => 'name',
+ ),
+ ),
+ 'entityClass' => 'Doctrine\Tests\Models\Company\CompanyPerson',
+ 'discriminatorColumn' => 'discriminator',
+ ),
+ ),
+));
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml
new file mode 100644
index 000000000..0af5facda
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+ SELECT id, country, city FROM cms_addresses
+
+
+
+ SELECT * FROM cms_addresses WHERE id = ?
+
+
+
+ SELECT COUNT(*) AS count FROM cms_addresses
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml
new file mode 100644
index 000000000..64a545df6
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, username FROM cms_users WHERE username = ?
+
+
+
+ SELECT * FROM cms_users WHERE username = ?
+
+
+
+ SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?
+
+
+
+ SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?
+
+
+
+ SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username
+
+
+
+ SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml
new file mode 100644
index 000000000..c573504e0
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+ SELECT id, name, discr FROM company_persons ORDER BY name
+
+
+
+ SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml
new file mode 100644
index 000000000..604acb293
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml
@@ -0,0 +1,62 @@
+Doctrine\Tests\Models\CMS\CmsAddress:
+ type: entity
+ table: cms_address
+ namedNativeQueries:
+ find-all:
+ resultSetMapping: mapping-find-all
+ query: SELECT id, country, city FROM cms_addresses
+ find-by-id:
+ name: find-by-id
+ resultClass: CmsAddress
+ query: SELECT * FROM cms_addresses WHERE id = ?
+ count:
+ name: count
+ resultSetMapping: mapping-count
+ query: SELECT COUNT(*) AS count FROM cms_addresses
+
+ sqlResultSetMappings:
+ mapping-find-all:
+ entityResult:
+ address:
+ entityClass: CmsAddress
+ fieldResult:
+ 0:
+ name: id
+ column: id
+ 1:
+ name: city
+ column: city
+ 2:
+ name: country
+ column: country
+ mapping-without-fields:
+ name: mapping-without-fields
+ entityResult:
+ address:
+ entityClass: CmsAddress
+ mapping-count:
+ name: mapping-count
+ columnResult:
+ count:
+ name: count
+ id:
+ id:
+ type: integer
+ generator:
+ strategy: AUTO
+ fields:
+ country:
+ type: string
+ length: 50
+ city:
+ type: string
+ length: 50
+ zip:
+ type: string
+ length: 50
+ oneToOne:
+ address:
+ targetEntity: CmsUser
+ inversedBy: address
+ joinColumn:
+ referencedColumnName: id
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml
new file mode 100644
index 000000000..3a03dd6c3
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml
@@ -0,0 +1,158 @@
+Doctrine\Tests\Models\CMS\CmsUser:
+ type: entity
+ table: cms_users
+ namedQueries:
+ all: SELECT u FROM __CLASS__ u
+ namedNativeQueries:
+ fetchIdAndUsernameWithResultClass:
+ resultClass: CmsUser
+ query: SELECT id, username FROM cms_users WHERE username = ?
+ fetchAllColumns:
+ name: fetchAllColumns
+ resultClass: CmsUser
+ query: SELECT * FROM cms_users WHERE username = ?
+ fetchJoinedAddress:
+ name: fetchJoinedAddress
+ resultSetMapping: mappingJoinedAddress
+ query: SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?
+ fetchJoinedPhonenumber:
+ name: fetchJoinedPhonenumber
+ resultSetMapping: mappingJoinedPhonenumber
+ query: SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?
+ fetchUserPhonenumberCount:
+ name: fetchUserPhonenumberCount
+ resultSetMapping: mappingUserPhonenumberCount
+ query: SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username
+ fetchMultipleJoinsEntityResults:
+ name: fetchMultipleJoinsEntityResults
+ resultSetMapping: mappingMultipleJoinsEntityResults
+ query: SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username
+
+ sqlResultSetMappings:
+ mappingJoinedAddress:
+ entityResult:
+ 0:
+ entityClass: __CLASS__
+ fieldResult:
+ 0:
+ name: id
+ 1:
+ name: name
+ 2:
+ name: status
+ 3:
+ name: address.zip
+ 4:
+ name: address.city
+ 5:
+ name: address.country
+ 6:
+ name: address.id
+ column: a_id
+ mappingJoinedPhonenumber:
+ name: mappingJoinedPhonenumber
+ entityResult:
+ user:
+ entityClass: CmsUser
+ fieldResult:
+ 0:
+ name: id
+ 1:
+ name: name
+ 2:
+ name: status
+ 3:
+ name: phonenumbers.phonenumber
+ column: number
+ mappingUserPhonenumberCount:
+ name: mappingUserPhonenumberCount
+ columnResult:
+ 0:
+ name: numphones
+ entityResult:
+ user_0:
+ entityClass: CmsUser
+ fieldResult:
+ 0:
+ name: id
+ 1:
+ name: name
+ 2:
+ name: status
+ mappingMultipleJoinsEntityResults:
+ name: mappingMultipleJoinsEntityResults
+ columnResult:
+ 0:
+ name: numphones
+ entityResult:
+ 0:
+ entityClass: __CLASS__
+ fieldResult:
+ 0:
+ name: id
+ column: u_id
+ 1:
+ name: name
+ column: u_name
+ 2:
+ name: status
+ column: u_status
+ 1:
+ entityClass: CmsAddress
+ fieldResult:
+ 0:
+ name: id
+ column: a_id
+ 1:
+ name: zip
+ column: a_zip
+ 2:
+ name: country
+ column: a_country
+ id:
+ id:
+ type: integer
+ generator:
+ strategy: AUTO
+ fields:
+ name:
+ type: string
+ length: 255
+ username:
+ type: string
+ length: 255
+ unique: true
+ status:
+ type: string
+ length: 50
+ unique: true
+ oneToOne:
+ address:
+ targetEntity: CmsAddress
+ orphanRemoval: true
+ inversedBy: user
+ joinColumn:
+ name: address_id
+ referencedColumnName: id
+ cascade: [ persist ]
+ oneToOne:
+ email:
+ targetEntity: CmsEmail
+ orphanRemoval: true
+ inversedBy: user
+ joinColumn:
+ nullable: true
+ referencedColumnName: id
+ cascade: [ persist ]
+ manyToMany:
+ groups:
+ targetEntity: CmsGroup
+ joinTable:
+ name: cms_users_groups
+ joinColumns:
+ user_id:
+ referencedColumnName: id
+ inverseJoinColumns:
+ group_id:
+ referencedColumnName: id
+ cascade: [ persist , detach, merge]
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml
new file mode 100644
index 000000000..26846c5de
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml
@@ -0,0 +1,75 @@
+Doctrine\Tests\Models\Company\CompanyPerson:
+ type: entity
+ table: company_persons
+ inheritanceType: JOINED
+ discriminatorMap:
+ person: CompanyPerson
+ manager: CompanyManager
+ employee: CompanyEmployee
+ namedNativeQueries:
+ fetchAllWithResultClass:
+ resultClass: __CLASS__
+ query: SELECT id, name, discr FROM company_persons ORDER BY name
+ fetchAllWithSqlResultSetMapping:
+ name: fetchAllWithSqlResultSetMapping
+ resultSetMapping: mappingFetchAll
+ query: SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name
+
+ sqlResultSetMappings:
+ mappingFetchAll:
+ entityResult:
+ 0:
+ entityClass: __CLASS__
+ discriminatorColumn: discriminator
+ fieldResult:
+ 0:
+ name: id
+ 1:
+ name: name
+ id:
+ id:
+ type: integer
+ generator:
+ strategy: AUTO
+ fields:
+ name:
+ type: string
+ length: 255
+ username:
+ type: string
+ length: 255
+ unique: true
+ status:
+ type: string
+ length: 50
+ unique: true
+ oneToOne:
+ address:
+ targetEntity: CmsAddress
+ orphanRemoval: true
+ inversedBy: user
+ joinColumn:
+ name: address_id
+ referencedColumnName: id
+ cascade: [ persist ]
+ oneToOne:
+ email:
+ targetEntity: CmsEmail
+ orphanRemoval: true
+ inversedBy: user
+ joinColumn:
+ nullable: true
+ referencedColumnName: id
+ cascade: [ persist ]
+ manyToMany:
+ groups:
+ targetEntity: CmsGroup
+ joinTable:
+ name: cms_users_groups
+ joinColumns:
+ user_id:
+ referencedColumnName: id
+ inverseJoinColumns:
+ group_id:
+ referencedColumnName: id
+ cascade: [ persist , detach, merge]
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php
index 4b92ed5d3..9d9776ba9 100644
--- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php
+++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php
@@ -147,6 +147,7 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
$conn->executeUpdate('DELETE FROM cms_comments');
$conn->executeUpdate('DELETE FROM cms_articles');
$conn->executeUpdate('DELETE FROM cms_users');
+ $conn->executeUpdate('DELETE FROM cms_emails');
}
if (isset($this->_usedModelSets['ecommerce'])) {