named native query metadata
This commit is contained in:
parent
530e4840dd
commit
91e4702772
@ -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
|
||||
* <tt>Class Table Inheritance</tt>.
|
||||
*/
|
||||
const INHERITANCE_TYPE_JOINED = 2;
|
||||
|
||||
/**
|
||||
* SINGLE_TABLE means the class will be persisted according to the rules of
|
||||
* <tt>Single Table Inheritance</tt>.
|
||||
*/
|
||||
const INHERITANCE_TYPE_SINGLE_TABLE = 3;
|
||||
|
||||
/**
|
||||
* TABLE_PER_CLASS means the class will be persisted according to the rules
|
||||
* of <tt>Concrete Table Inheritance</tt>.
|
||||
@ -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 <tt>NotifyPropertyChanged</tt> 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,21 @@ 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:
|
||||
* <pre>
|
||||
* array(
|
||||
* 'name' => <query name>,
|
||||
* 'query' => <sql query>,
|
||||
* 'resultClass' => <class of the result>,
|
||||
* 'resultSetMapping' => <name of a SqlResultSetMapping>
|
||||
* )
|
||||
* </pre>
|
||||
*/
|
||||
public $namedNativeQueries = array();
|
||||
|
||||
/**
|
||||
* READ-ONLY: The field names of all fields that are part of the identifier/primary key
|
||||
* of the mapped entity class.
|
||||
@ -1051,6 +1085,33 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates & completes the given field mapping.
|
||||
*
|
||||
@ -1826,10 +1887,18 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function addNamedQuery(array $queryMapping)
|
||||
{
|
||||
if (!isset($queryMapping['name'])) {
|
||||
throw MappingException::nameIsMandatoryQueryMapping($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 +1909,38 @@ 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::nameIsMandatoryQueryMapping($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']);
|
||||
}
|
||||
|
||||
if (isset($queryMapping['resultClass']) && $queryMapping['resultClass'] === '__CLASS__') {
|
||||
$queryMapping['resultClass'] = $this->name;
|
||||
}
|
||||
|
||||
$this->namedNativeQueries[$queryMapping['name']] = $queryMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a one-to-one mapping.
|
||||
*
|
||||
@ -2061,6 +2162,17 @@ 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 $fieldName
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasNamedNativeQuery($queryName)
|
||||
{
|
||||
return isset($this->namedNativeQueries[$queryName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the class has a mapped association with the given field name.
|
||||
*
|
||||
|
@ -93,6 +93,21 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
return new self("No query found named '$queryName' on class '$className'.");
|
||||
}
|
||||
|
||||
public static function emptyQueryMapping($entity, $queryName)
|
||||
{
|
||||
return new self('Query named "'.$queryName.'" in "'.$entity.'" could not be empty.');
|
||||
}
|
||||
|
||||
public static function nameIsMandatoryQueryMapping($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 oneToManyRequiresMappedBy($fieldName)
|
||||
{
|
||||
return new self("OneToMany mapping on field '$fieldName' requires the 'mappedBy' attribute.");
|
||||
@ -178,27 +193,31 @@ 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 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 +243,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."
|
||||
|
@ -525,6 +525,59 @@ 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 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,6 +592,26 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', $cm->getNamedQuery('userById'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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()));
|
||||
|
||||
$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()));
|
||||
}
|
||||
|
||||
public function testNamingCollisionNamedQueryShouldThrowException()
|
||||
{
|
||||
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
@ -558,6 +631,32 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1663
|
||||
*/
|
||||
public function testNamingCollisionNamedNativeQueryShouldThrowException()
|
||||
{
|
||||
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
|
||||
$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'
|
||||
));
|
||||
|
||||
$cm->addNamedNativeQuery(array(
|
||||
'name' => 'find-all',
|
||||
'query' => 'SELECT * FROM cms_users',
|
||||
'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser',
|
||||
'resultSetMapping' => 'result-mapping-name'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1068
|
||||
*/
|
||||
@ -596,6 +695,38 @@ 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'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Doctrine\ORM\Mapping\MappingException
|
||||
* @expectedExceptionMessage Discriminator column name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined.
|
||||
|
Loading…
x
Reference in New Issue
Block a user