Commit 4adc2895 authored by romanb's avatar romanb

[2.0][DDC-284] Fixed. API polish and some convention over configuration...

[2.0][DDC-284] Fixed. API polish and some convention over configuration simplifications for join columns and join tables.
parent da2c329e
......@@ -113,11 +113,11 @@
<xs:enumeration value="EAGER"/>
<xs:enumeration value="LAZY"/>
</xs:restriction>
</xs:simpleType>
</xs:simpleType>
<xs:complexType name="field">
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
<xs:attribute name="column" type="xs:NMTOKEN" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
......@@ -167,7 +167,7 @@
</xs:complexType>
<xs:complexType name="generator">
<xs:attribute name="strategy" type="orm:generator-strategy" use="required" />
<xs:attribute name="strategy" type="orm:generator-strategy" use="optional" default="AUTO" />
</xs:complexType>
<xs:complexType name="id">
......@@ -187,7 +187,7 @@
<xs:complexType name="join-column">
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="referenced-column-name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="referenced-column-name" type="xs:NMTOKEN" use="optional" default="id" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
<xs:attribute name="nullable" type="xs:boolean" default="true" />
<xs:attribute name="on-delete" type="orm:fk-action" />
......@@ -213,7 +213,7 @@
<xs:complexType name="many-to-many">
<xs:sequence>
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
<xs:element name="join-table" type="orm:join-table" />
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
</xs:sequence>
<xs:attribute name="target-entity" type="xs:NMTOKEN" use="required" />
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
......@@ -235,7 +235,7 @@
<xs:complexType name="many-to-one">
<xs:sequence>
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
<xs:choice minOccurs="1" maxOccurs="1">
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="join-column" type="orm:join-column"/>
<xs:element name="join-columns" type="orm:join-columns"/>
</xs:choice>
......
......@@ -52,4 +52,14 @@ class Annotation
$this->$key = $value;
}
}
public function __get($name)
{
throw new \BadMethodCallException("Unknown annotation property '$name' on annotation '".get_class($this)."'.");
}
public function __set($name, $value)
{
throw new \BadMethodCallException("Unknown annotation property '$name' on annotation '".get_class($this)."'.");
}
}
\ No newline at end of file
......@@ -82,7 +82,6 @@ class Configuration
*
* @param array $types Key-value map of types to include
* @param boolean $override Optional flag to support only inclusion or also override
* @throws DoctrineException
*/
public function setCustomTypes(array $types, $override = false)
{
......@@ -97,7 +96,6 @@ class Configuration
* Overrides existent types in Doctrine
*
* @param array $types Key-value map of types to override
* @throws DoctrineException
*/
public function setTypeOverrides(array $overrides)
{
......
......@@ -22,7 +22,6 @@
namespace Doctrine\DBAL;
use Doctrine\Common\EventManager,
Doctrine\Common\DoctrineException,
Doctrine\DBAL\DBALException;
/**
......
......@@ -21,8 +21,6 @@
namespace Doctrine\DBAL;
use Doctrine\Common\DoctrineException;
/**
* Doctrine\DBAL\ConnectionException
*
......@@ -32,20 +30,15 @@ use Doctrine\Common\DoctrineException;
* @version $Revision: 4628 $
* @author Jonathan H. Wage <jonwage@gmail.com
*/
class ConnectionException extends DoctrineException
class ConnectionException extends DBALException
{
public static function invalidPDOInstance()
{
return new self("Invalid PDO instance provided on connection creation.");
}
public static function driverRequired()
public static function commitFailedRollbackOnly()
{
return new self("Please provide a driver or a driverClass to be able to start a Connection.");
return new self("Transaction commit failed because the transaction has been marked for rollback only.");
}
public static function unknownDriver($driver)
public static function noActiveTransaction()
{
return new self("Unknown Connection driver '$driver'.");
return new self("There is no active transaction.");
}
}
\ No newline at end of file
......@@ -21,7 +21,6 @@
namespace Doctrine\DBAL;
use Doctrine\Common\DoctrineException;
use Doctrine\Common\EventManager;
/**
......
......@@ -147,7 +147,7 @@ abstract class AbstractQuery
}
/**
* Get all defined parameters
* Get all defined parameters.
*
* @return array Defined parameters
*/
......
......@@ -22,7 +22,6 @@
namespace Doctrine\ORM;
use Doctrine\Common\EventManager,
Doctrine\Common\DoctrineException,
Doctrine\DBAL\Connection,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\ClassMetadataFactory,
......@@ -96,6 +95,11 @@ class EntityManager
* @var Doctrine\ORM\Proxy\ProxyFactory
*/
private $_proxyFactory;
/**
* @var ExpressionBuilder The expression builder instance used to generate query expressions.
*/
private $_expressionBuilder;
/**
* Whether the EntityManager is closed or not.
......@@ -144,6 +148,27 @@ class EntityManager
return $this->_metadataFactory;
}
/**
* Gets an ExpressionBuilder used for object-oriented construction of query expressions.
*
* Example:
*
* [php]
* $qb = $em->createQueryBuilder();
* $expr = $em->getExpressionBuilder();
* $qb->select('u')->from('User', 'u')
* ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2)));
*
* @return ExpressionBuilder
*/
public function getExpressionBuilder()
{
if ($this->_expressionBuilder === null) {
$this->_expressionBuilder = new Query\Expr;
}
return $this->_expressionBuilder;
}
/**
* Starts a transaction on the underlying database connection.
*/
......
......@@ -2,7 +2,7 @@
namespace Doctrine\ORM\Internal\Hydration;
class HydrationException extends \Doctrine\Common\DoctrineException
class HydrationException extends \Doctrine\ORM\ORMException
{
public static function nonUniqueResult()
{
......
......@@ -129,6 +129,7 @@ abstract class AssociationMapping
* Validates & completes the mapping. Mapping defaults are applied here.
*
* @param array $mapping
* @throws MappingException If something is wrong with the mapping.
*/
protected function _validateAndCompleteMapping(array $mapping)
{
......@@ -151,7 +152,7 @@ abstract class AssociationMapping
// Mandatory and optional attributes for either side
if ( ! isset($mapping['mappedBy'])) {
// Optional
if (isset($mapping['joinTable'])) {
if (isset($mapping['joinTable']) && $mapping['joinTable']) {
if ($mapping['joinTable']['name'][0] == '`') {
$mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
$mapping['joinTable']['quoted'] = true;
......@@ -164,8 +165,7 @@ abstract class AssociationMapping
}
// Optional attributes for both sides
$this->fetchMode = isset($mapping['fetch']) ?
$mapping['fetch'] : self::FETCH_LAZY;
$this->fetchMode = isset($mapping['fetch']) ? $mapping['fetch'] : self::FETCH_LAZY;
$cascades = isset($mapping['cascade']) ? $mapping['cascade'] : array();
if (in_array('all', $cascades)) {
......@@ -178,11 +178,11 @@ abstract class AssociationMapping
);
}
$this->isCascadeRemove = in_array('remove', $cascades);
$this->isCascadeRemove = in_array('remove', $cascades);
$this->isCascadePersist = in_array('persist', $cascades);
$this->isCascadeRefresh = in_array('refresh', $cascades);
$this->isCascadeMerge = in_array('merge', $cascades);
$this->isCascadeDetach = in_array('detach', $cascades);
$this->isCascadeMerge = in_array('merge', $cascades);
$this->isCascadeDetach = in_array('detach', $cascades);
}
/**
......
......@@ -254,15 +254,6 @@ class ClassMetadataInfo
*/
public $columnNames = array();
/**
* Whether to automatically OUTER JOIN subtypes when a basetype is queried.
*
* <b>This does only apply to the JOINED inheritance mapping strategy.</b>
*
* @var boolean
*/
//public $joinSubclasses = true;
/**
* The discriminator value of this class.
*
......@@ -270,7 +261,7 @@ class ClassMetadataInfo
* where a discriminator column is used.</b>
*
* @var mixed
* @see _discriminatorColumn
* @see discriminatorColumn
*/
public $discriminatorValue;
......@@ -281,7 +272,7 @@ class ClassMetadataInfo
* where a discriminator column is used.</b>
*
* @var mixed
* @see _discriminatorColumn
* @see discriminatorColumn
*/
public $discriminatorMap = array();
......@@ -670,7 +661,8 @@ class ClassMetadataInfo
throw MappingException::missingFieldName($this->name, $mapping);
}
if ( ! isset($mapping['type'])) {
throw MappingException::missingType($this->name, $mapping);
// Default to string
$mapping['type'] = 'string';
}
// Complete fieldName and columnName mapping
......@@ -734,6 +726,7 @@ class ClassMetadataInfo
* entity classes that have a single-field pk.
*
* @return string
* @throws MappingException If the class has a composite primary key.
*/
public function getSingleIdentifierFieldName()
{
......@@ -748,6 +741,7 @@ class ClassMetadataInfo
* entity classes that have a single-field pk.
*
* @return string
* @throws MappingException If the class has a composite primary key.
*/
public function getSingleIdentifierColumnName()
{
......@@ -776,16 +770,6 @@ class ClassMetadataInfo
return isset($this->fieldMappings[$fieldName]);
}
public function hasInheritedMapping($fieldName)
{
if (isset($this->fieldMappings[$fieldName]) || isset($this->associationMappings[$fieldName]))
{
} else {
return false;
}
}
/**
* Gets all field mappings.
*
......@@ -1008,7 +992,7 @@ class ClassMetadataInfo
/**
* Sets the mapped subclasses of this class.
*
* @param array $subclasses The names of all mapped subclasses.
* @param array $subclasses The names of all mapped subclasses.
*/
public function setSubclasses(array $subclasses)
{
......@@ -1337,33 +1321,6 @@ class ClassMetadataInfo
{
return $this->customRepositoryClassName;
}
/**
* Sets whether sub classes should be automatically OUTER JOINed when a base
* class is queried in a class hierarchy that uses the JOINED inheritance mapping
* strategy.
*
* <b>This options does only apply to the JOINED inheritance mapping strategy.</b>
*
* @param boolean $bool
* @see getJoinSubClasses()
*/
/*public function setJoinSubClasses($bool)
{
$this->joinSubclasses = (bool)$bool;
}*/
/**
* Gets whether the class mapped by this instance should OUTER JOIN sub classes
* when a base class is queried.
*
* @return <type>
* @see setJoinSubClasses()
*/
/*public function getJoinSubClasses()
{
return $this->joinSubclasses;
}*/
/**
* Dispatches the lifecycle event of the given entity to the registered
......@@ -1608,7 +1565,6 @@ class ClassMetadataInfo
* value to use depending on the column type
*
* @param array $mapping The version field mapping array
* @return void
*/
public function setVersionMapping(array &$mapping)
{
......
......@@ -40,13 +40,13 @@ final class DiscriminatorMap extends Annotation {}
/*final class SubClasses extends Annotation {}*/
final class Id extends Annotation {}
final class GeneratedValue extends Annotation {
public $strategy;
public $strategy = 'AUTO';
}
final class Version extends Annotation {}
final class JoinColumn extends Annotation {
public $name;
public $fieldName; // field name used in non-object hydration (array/scalar)
public $referencedColumnName;
public $referencedColumnName = 'id';
public $unique = false;
public $nullable = true;
public $onDelete;
......@@ -55,10 +55,12 @@ final class JoinColumn extends Annotation {
}
final class JoinColumns extends Annotation {}
final class Column extends Annotation {
public $type;
public $type = 'string';
public $length;
public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column)
public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column)
// The precision for a decimal (exact numeric) column (Applies only for decimal column)
public $precision = 0;
// The scale for a decimal (exact numeric) column (Applies only for decimal column)
public $scale = 0;
public $unique = false;
public $nullable = false;
public $name;
......@@ -132,5 +134,3 @@ final class PreRemove extends Annotation {}
final class PostRemove extends Annotation {}
final class PostLoad extends Annotation {}
/* Generic annotation for Doctrine extensions */
final class DoctrineX extends Annotation {}
......@@ -187,8 +187,10 @@ class XmlDriver extends AbstractFileDriver
$metadata->mapField($mapping);
if (isset($idElement->generator)) {
$strategy = isset($idElement->generator['strategy']) ?
(string)$idElement->generator['strategy'] : 'AUTO';
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
. strtoupper((string)$idElement->generator['strategy'])));
. $strategy));
}
// Check for SequenceGenerator/TableGenerator definition
......@@ -227,8 +229,6 @@ class XmlDriver extends AbstractFileDriver
foreach ($oneToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
} else {
throw MappingException::invalidMapping($mapping['fieldName']);
}
$mapping['joinColumns'] = $joinColumns;
......@@ -295,8 +295,6 @@ class XmlDriver extends AbstractFileDriver
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
} else {
throw MappingException::invalidMapping($mapping['fieldName']);
}
$mapping['joinColumns'] = $joinColumns;
......@@ -346,8 +344,6 @@ class XmlDriver extends AbstractFileDriver
}
$mapping['joinTable'] = $joinTable;
} else {
throw MappingException::invalidMapping($mapping['fieldName']);
}
if (isset($manyToManyElement->cascade)) {
......
......@@ -249,8 +249,6 @@ class YamlDriver extends AbstractFileDriver
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
} else {
throw MappingException::invalidMapping($mapping['fieldName']);
}
$mapping['joinColumns'] = $joinColumns;
......@@ -309,8 +307,6 @@ class YamlDriver extends AbstractFileDriver
$joinColumns[] = $this->_getJoinColumnMapping($joinColumnElement);
}
} else {
throw MappingException::invalidMapping($mapping['fieldName']);
}
$mapping['joinColumns'] = $joinColumns;
......@@ -364,8 +360,6 @@ class YamlDriver extends AbstractFileDriver
}
$mapping['joinTable'] = $joinTable;
} else {
throw MappingException::invalidMapping($mapping['fieldName']);
}
if (isset($manyToManyElement['cascade'])) {
......
......@@ -32,6 +32,9 @@ namespace Doctrine\ORM\Mapping;
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* Instances of this class are stored serialized in the metadata cache together with the
* owning <tt>ClassMetadata</tt> instance.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
......@@ -78,18 +81,36 @@ class ManyToManyMapping extends AssociationMapping
parent::_validateAndCompleteMapping($mapping);
if ($this->isOwningSide) {
// owning side MUST have a join table
if ( ! isset($mapping['joinTable'])) {
throw MappingException::joinTableRequired($mapping['fieldName']);
if ( ! isset($mapping['joinTable']) || ! $mapping['joinTable']) {
// Apply default join table
$sourceShortName = substr($this->sourceEntityName, strrpos($this->sourceEntityName, '\\') + 1);
$targetShortName = substr($this->targetEntityName, strrpos($this->targetEntityName, '\\') + 1);
$mapping['joinTable'] = array(
'name' => $sourceShortName .'_' . $targetShortName,
'joinColumns' => array(
array(
'name' => $sourceShortName . '_id',
'referencedColumnName' => 'id'
)
),
'inverseJoinColumns' => array(
array(
'name' => $targetShortName . '_id',
'referencedColumnName' => 'id'
)
)
);
$this->joinTable = $mapping['joinTable'];
}
// owning side MUST specify joinColumns
if ( ! isset($mapping['joinTable']['joinColumns'])) {
else if ( ! isset($mapping['joinTable']['joinColumns'])) {
throw MappingException::missingRequiredOption(
$this->sourceFieldName, 'joinColumns',
'Did you think of case sensitivity / plural s?'
);
}
// owning side MUST specify inverseJoinColumns
if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
else if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
throw MappingException::missingRequiredOption(
$this->sourceFieldName, 'inverseJoinColumns',
'Did you think of case sensitivity / plural s?'
......@@ -151,7 +172,9 @@ class ManyToManyMapping extends AssociationMapping
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$joinTableConditions[$relationKeyColumn] = $joinColumnValues[$sourceKeyColumn];
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
);
}
}
} else {
......@@ -162,7 +185,9 @@ class ManyToManyMapping extends AssociationMapping
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$joinTableConditions[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
$joinTableConditions[$relationKeyColumn] = $joinColumnValues[$sourceKeyColumn];
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
);
}
}
}
......
......@@ -36,6 +36,9 @@ namespace Doctrine\ORM\Mapping;
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* Instances of this class are stored serialized in the metadata cache together with the
* owning <tt>ClassMetadata</tt> instance.
*
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
......@@ -47,13 +50,6 @@ class OneToManyMapping extends AssociationMapping
public $orphanRemoval = false;
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/**
* TODO: Allow any combination of source/target columns in lazy loading.
* What is supported now is primary key (that can spread on multiple fields)
* pointed to foreign keys on the target
public $targetColumns;
*/
/**
* Initializes a new OneToManyMapping.
......
......@@ -32,6 +32,9 @@ namespace Doctrine\ORM\Mapping;
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* Instances of this class are stored serialized in the metadata cache together with the
* owning <tt>ClassMetadata</tt> instance.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
......@@ -109,8 +112,12 @@ class OneToOneMapping extends AssociationMapping
}
if ($this->isOwningSide) {
if ( ! isset($mapping['joinColumns'])) {
throw MappingException::invalidMapping($this->sourceFieldName);
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
// Apply default join column
$mapping['joinColumns'] = array(array(
'name' => $this->sourceFieldName . '_id',
'referencedColumnName' => 'id'
));
}
foreach ($mapping['joinColumns'] as &$joinColumn) {
if ($joinColumn['name'][0] == '`') {
......@@ -126,7 +133,7 @@ class OneToOneMapping extends AssociationMapping
}
$this->isOptional = isset($mapping['optional']) ?
(bool)$mapping['optional'] : true;
(bool) $mapping['optional'] : true;
$this->orphanRemoval = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
......@@ -141,7 +148,6 @@ class OneToOneMapping extends AssociationMapping
* Whether the association is optional (0..1), or not (1..1).
*
* @return boolean TRUE if the association is optional, FALSE otherwise.
* @todo Only applicable to OneToOne. Move there.
*/
public function isOptional()
{
......
......@@ -21,8 +21,7 @@
namespace Doctrine\ORM;
use Doctrine\Common\DoctrineException,
Doctrine\ORM\Mapping\AssociationMapping,
use Doctrine\ORM\Mapping\AssociationMapping,
\Closure;
/**
......
......@@ -184,7 +184,7 @@ class StandardEntityPersister
$this->_assignDefaultVersionValue($this->_class, $entity, $id);
}
}
$stmt->closeCursor();
$this->_queuedInserts = array();
......@@ -462,7 +462,7 @@ class StandardEntityPersister
foreach ($this->_class->associationMappings as $field => $assoc) {
$value = $this->_class->reflFields[$field]->getValue($entity);
if ($assoc->isOneToOne()) {
if ($value instanceof Proxy && ! $value->__isInitialized()) {
if ($value instanceof Proxy && ! $value->__isInitialized__) {
continue; // skip uninitialized proxies
}
......
This diff is collapsed.
......@@ -61,7 +61,7 @@ abstract class Base
$class = get_class($arg);
if ( ! in_array($class, $this->_allowedClasses)) {
throw \Doctrine\Common\DoctrineException::classNotAllowed($class, $this);
throw new \InvalidArgumentException("Expression of type '$class' not allowed in this context.");
}
}
......
......@@ -39,8 +39,8 @@ class Func
public function __construct($name, $arguments)
{
$this->_name = $name;
$this->_arguments = (array) $arguments;
$this->_name = $name;
$this->_arguments = (array) $arguments;
}
public function __toString()
......
<?php
namespace Doctrine\ORM\Query\Expr;
class Literal extends Base
{
protected $_preSeparator = '';
protected $_postSeparator = '';
}
This diff is collapsed.
......@@ -40,7 +40,7 @@ class CmsAddress
/**
* @OneToOne(targetEntity="CmsUser")
* @JoinColumn(name="user_id", referencedColumnName="id")
// * @JoinColumn(name="user_id", referencedColumnName="id")
*/
public $user;
......
......@@ -12,7 +12,7 @@ class CmsUser
{
/**
* @Id @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
* @GeneratedValue
*/
public $id;
/**
......
......@@ -39,8 +39,8 @@ class ManyToManyBasicAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCa
$user->addGroup($group2);
$this->_em->persist($user); // cascades to groups
$this->_em->flush();
$this->_em->flush();
$this->_em->clear();
$uRep = $this->_em->getRepository(get_class($user));
......
......@@ -25,16 +25,15 @@ class AnnotationDriverTest extends \Doctrine\Tests\OrmTestCase
/**
* @group DDC-268
*/
public function testColumnWithMissingTypeThrowsException()
public function testColumnWithMissingTypeDefaultsToString()
{
$cm = new ClassMetadata('Doctrine\Tests\ORM\Mapping\InvalidColumn');
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache());
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
$annotationDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException',
"The attribute 'type' is required for the column description of property Doctrine\\Tests\\ORM\\Mapping\\InvalidColumn::\$id");
$annotationDriver->loadMetadataForClass('Doctrine\Tests\ORM\Mapping\InvalidColumn', $cm);
$this->assertEquals('string', $cm->fieldMappings['id']['type']);
}
}
......
......@@ -86,6 +86,24 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals("DoctrineGlobal_User", $cm->associationMappings['author']->targetEntityName);
}
public function testMapManyToManyJoinTableDefaults()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->mapManyToMany(
array(
'fieldName' => 'groups',
'targetEntity' => 'CmsGroup'
));
$assoc = $cm->associationMappings['groups'];
$this->assertTrue($assoc instanceof \Doctrine\ORM\Mapping\ManyToManyMapping);
$this->assertEquals(array(
'name' => 'CmsUser_CmsGroup',
'joinColumns' => array(array('name' => 'CmsUser_id', 'referencedColumnName' => 'id')),
'inverseJoinColumns' => array(array('name' => 'CmsGroup_id', 'referencedColumnName' => 'id'))
), $assoc->joinTable);
}
/**
* @group DDC-115
......@@ -141,8 +159,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateAssociationMappingException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$a1 = new \Doctrine\ORM\Mapping\OneToOneMapping(array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'joinColumns' => array()));
$a2 = new \Doctrine\ORM\Mapping\OneToOneMapping(array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'joinColumns' => array()));
$a1 = new \Doctrine\ORM\Mapping\OneToOneMapping(array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'));
$a2 = new \Doctrine\ORM\Mapping\OneToOneMapping(array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'));
$cm->addAssociationMapping($a1);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
......
......@@ -20,10 +20,8 @@
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
<one-to-one field="address" target-entity="Address">
<cascade><cascade-remove /></cascade>
<join-column name="address_id" referenced-column-name="id"/>
<cascade>
<cascade-remove />
</cascade>
</one-to-one>
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user">
......@@ -33,6 +31,9 @@
</one-to-many>
<many-to-many field="groups" target-entity="Group">
<cascade>
<cascade-all/>
</cascade>
<join-table name="cms_users_groups">
<join-columns>
<join-column name="user_id" referenced-column-name="id" nullable="false" unique="false" />
......@@ -41,9 +42,6 @@
<join-column name="group_id" referenced-column-name="id" column-definition="INT NULL" />
</inverse-join-columns>
</join-table>
<cascade>
<cascade-all/>
</cascade>
</many-to-many>
</entity>
......
......@@ -266,53 +266,29 @@ class ExprTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('(1 = 1) OR (1 < 5)', (string) $orExpr);
}
public function testSelectExpr()
{
$selectExpr = $this->_expr->select();
$selectExpr->add('u.id');
$selectExpr->add('u.username');
$this->assertEquals('u.id, u.username', (string) $selectExpr);
}
public function testFromExpr()
{
$this->assertEquals('User u', (string) $this->_expr->from('User', 'u'));
}
public function testExprBaseCount()
{
$selectExpr = $this->_expr->select();
$selectExpr->add('u.id');
$selectExpr->add('u.username');
$this->assertEquals($selectExpr->count(), 2);
}
public function testOrderByCountExpr()
{
$orderByExpr = $this->_expr->orderBy();
$orderByExpr->add('u.username', 'DESC');
$orderExpr = $this->_expr->desc('u.username');
$this->assertEquals($orderByExpr->count(), 1);
$this->assertEquals('u.username DESC', (string) $orderByExpr);
$this->assertEquals($orderExpr->count(), 1);
$this->assertEquals('u.username DESC', (string) $orderExpr);
}
public function testOrderByOrder()
{
$orderByExpr = $this->_expr->orderBy('u.username', 'DESC');
$this->assertEquals('u.username DESC', (string) $orderByExpr);
$orderExpr = $this->_expr->desc('u.username');
$this->assertEquals('u.username DESC', (string) $orderExpr);
}
public function testOrderByDefaultOrderIsAsc()
public function testOrderByAsc()
{
$orderByExpr = $this->_expr->orderBy('u.username');
$this->assertEquals('u.username ASC', (string) $orderByExpr);
$orderExpr = $this->_expr->asc('u.username');
$this->assertEquals('u.username ASC', (string) $orderExpr);
}
/**
* @expectedException Doctrine\Common\DoctrineException
* @expectedException \InvalidArgumentException
*/
public function testAddThrowsException()
{
......
......@@ -281,6 +281,16 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username ASC');
}
public function testOrderByWithExpression()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->orderBy($qb->expr()->asc('u.username'));
$this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username ASC');
}
public function testAddOrderBy()
{
......@@ -335,7 +345,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
->where('u.id = :id');
$qb->setParameters(array('id' => 1));
$this->assertEquals(array('id' => 1, 'test' => 1), $qb->getParameters(array('test' => 1)));
$this->assertEquals(array('id' => 1), $qb->getParameters());
}
public function testGetParameter()
......@@ -382,7 +392,7 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
public function testComplexWhere()
{
$qb = $this->_em->createQueryBuilder();
$orExpr = $qb->expr()->orx();
$orExpr = $qb->expr()->orX();
$orExpr->add($qb->expr()->eq('u.id', ':uid3'));
$orExpr->add($qb->expr()->in('u.id', array(1)));
......@@ -392,6 +402,90 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid3) OR (u.id IN(1))');
}
public function testWhereInWithStringLiterals()
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($qb->expr()->in('u.name', array('one', 'two', 'three')));
$this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('one', 'two', 'three')");
$qb->where($qb->expr()->in('u.name', array("O'Reilly", "O'Neil", 'Smith')));
$this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('O''Reilly', 'O''Neil', 'Smith')");
}
public function testWhereInWithObjectLiterals()
{
$qb = $this->_em->createQueryBuilder();
$expr = $this->_em->getExpressionBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($expr->in('u.name', array($expr->literal('one'), $expr->literal('two'), $expr->literal('three'))));
$this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('one', 'two', 'three')");
$qb->where($expr->in('u.name', array($expr->literal("O'Reilly"), $expr->literal("O'Neil"), $expr->literal('Smith'))));
$this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('O''Reilly', 'O''Neil', 'Smith')");
}
public function testNegation()
{
$expr = $this->_em->getExpressionBuilder();
$orExpr = $expr->orX();
$orExpr->add($expr->eq('u.id', ':uid3'));
$orExpr->add($expr->not($expr->in('u.id', array(1))));
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($orExpr);
$this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid3) OR (NOT(u.id IN(1)))');
}
public function testSomeAllAny()
{
$qb = $this->_em->createQueryBuilder();
$expr = $this->_em->getExpressionBuilder();
//$subquery = $qb->subquery('Doctrine\Tests\Models\CMS\CmsArticle', 'a')->select('a.id');
$qb->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($expr->gt('u.id', $expr->all('select a.id from Doctrine\Tests\Models\CMS\CmsArticle a')));
$this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > ALL(select a.id from Doctrine\Tests\Models\CMS\CmsArticle a)');
}
public function testMultipleIsolatedQueryConstruction()
{
$qb = $this->_em->createQueryBuilder();
$expr = $this->_em->getExpressionBuilder();
$qb->select('u')->from('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$qb->where($expr->eq('u.name', ':name'));
$qb->setParameter('name', 'romanb');
$q1 = $qb->getQuery();
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = :name', $q1->getDql());
$this->assertEquals(1, count($q1->getParameters()));
// add another condition and construct a second query
$qb->andWhere($expr->eq('u.id', ':id'));
$qb->setParameter('id', 42);
$q2 = $qb->getQuery();
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.name = :name) AND (u.id = :id)', $q2->getDql());
$this->assertTrue($q1 !== $q2); // two different, independent queries
$this->assertEquals(2, count($q2->getParameters()));
$this->assertEquals(1, count($q1->getParameters())); // $q1 unaffected
}
public function testGetEntityManager()
{
......
......@@ -128,7 +128,7 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
if (isset($this->_usedModelSets['generic'])) {
$conn->executeUpdate('DELETE FROM date_time_model');
}
$this->_em->clear();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment