Commit 0c623fdb authored by piccoloprincipe's avatar piccoloprincipe

[2.0] Accomodate joincolumn names in the metadata, in the selection and the...

[2.0] Accomodate joincolumn names in the metadata, in the selection and the hydration processes. Improved Api of the ProxyFactory. Working implementation of lazy loading for *-to-one associations (affects #2348)
parent 4d146d32
......@@ -777,4 +777,4 @@ class Connection
}
return $this->_schemaManager;
}
}
\ No newline at end of file
}
......@@ -572,7 +572,7 @@ class EntityManager
*
* @return ProxyFactory
*/
public function getProxyGenerator()
public function getProxyFactory()
{
return $this->_proxyFactory;
}
......
......@@ -38,6 +38,8 @@ use Doctrine\Common\DoctrineException;
*/
abstract class AbstractHydrator
{
const TYPES_JOINCOLUMN = 'join_column';
/** The ResultSetMapping. */
protected $_rsm;
......@@ -184,12 +186,16 @@ abstract class AbstractHydrator
} else if (isset($this->_rsm->fieldMappings[$key])) {
$classMetadata = $this->_em->getClassMetadata($this->_rsm->getOwningClass($key));
$fieldName = $this->_rsm->fieldMappings[$key];
if ( ! isset($classMetadata->reflFields[$fieldName])) {
if ( ! isset($classMetadata->reflFields[$fieldName]) && ! in_array($fieldName, $classMetadata->joinColumnNames)) {
$classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName);
}
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['isScalar'] = false;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
if (isset($classMetadata->fieldMappings[$fieldName])) {
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
} else {
$cache[$key]['type'] = self::TYPES_JOINCOLUMN;
}
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
} else {
......@@ -217,7 +223,11 @@ abstract class AbstractHydrator
$id[$dqlAlias] .= '|' . $value;
}
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
if ($cache[$key]['type'] == self::TYPES_JOINCOLUMN) {
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $value;
} else {
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
}
if ( ! isset($nonemptyComponents[$dqlAlias]) && $value !== null) {
$nonemptyComponents[$dqlAlias] = true;
......@@ -302,4 +312,4 @@ abstract class AbstractHydrator
throw DoctrineException::updateMe("No owner found for field '$fieldName' during hydration.");
}
}
\ No newline at end of file
}
......@@ -236,6 +236,13 @@ class ObjectHydrator extends AbstractHydrator
}
$entity = $this->_uow->createEntity($className, $data);
$joinColumnsValues = array();
foreach ($this->_ce[$className]->joinColumnNames as $name) {
if (isset($data[$name])) {
$joinColumnsValues[$name] = $data[$name];
}
}
// Properly initialize any unfetched associations, if partial objects are not allowed.
if ( ! $this->_allowPartialObjects) {
foreach ($this->_ce[$className]->associationMappings as $field => $assoc) {
......@@ -243,7 +250,7 @@ class ObjectHydrator extends AbstractHydrator
if ($assoc->isOneToOne()) {
if ($assoc->isLazilyFetched()) {
// Inject proxy
$proxy = $this->_em->getProxyGenerator()->getAssociationProxy($entity, $assoc);
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnsValues);
$this->_ce[$className]->reflFields[$field]->setValue($entity, $proxy);
} else {
//TODO: Schedule for eager fetching
......@@ -462,4 +469,4 @@ class ObjectHydrator extends AbstractHydrator
{
return new \Doctrine\Common\Collections\Collection;
}
}
\ No newline at end of file
}
......@@ -379,12 +379,13 @@ abstract class AssociationMapping
/**
* Loads data in $targetEntity domain object using this association.
* The data comes from the association navigated from $owningEntity
* The data comes from the association navigated from $sourceEntity
* using $em.
*
* @param object $owningEntity
* @param object $sourceEntity
* @param object $targetEntity
* @param EntityManager $em
* @param array $joinColumnValues
*/
abstract public function load($owningEntity, $targetEntity, $em);
abstract public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues);
}
......@@ -254,6 +254,12 @@ final class ClassMetadata
*/
public $columnNames = array();
/**
* Array of all column names that does not map to a field.
* Foreign keys are here.
*/
public $joinColumnNames = array();
/**
* Whether to automatically OUTER JOIN subtypes when a basetype is queried.
*
......@@ -493,6 +499,11 @@ final class ClassMetadata
$this->reflFields[$propName] = $property;
}
public function addJoinColumn($name)
{
$this->joinColumnNames[] = $name;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
......@@ -1315,7 +1326,7 @@ final class ClassMetadata
/**
* Makes some automatic additions to the association mapping to make the life
* easier for the user.
* easier for the user, and store join columns in the metadata.
*
* @param array $mapping
* @todo Pass param by ref?
......@@ -1326,6 +1337,11 @@ final class ClassMetadata
if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false) {
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
}
if (isset($mapping['joinColumns'])) {
foreach ($mapping['joinColumns'] as $columns) {
$this->addJoinColumn($columns['name']);
}
}
return $mapping;
}
......@@ -1779,4 +1795,4 @@ final class ClassMetadata
{
return __CLASS__ . '@' . spl_object_hash($this);
}
}
\ No newline at end of file
}
......@@ -372,4 +372,4 @@ class ClassMetadataFactory
throw new DoctrineException("Unexhaustive match.");
}
}
}
\ No newline at end of file
}
......@@ -138,7 +138,7 @@ class ManyToManyMapping extends AssociationMapping
return $this->targetKeyColumns;
}
public function load($owningEntity, $targetEntity, $em)
public function load($owningEntity, $targetEntity, $em, array $joinColumnValues)
{
throw new Exception('Not yet implemented.');
}
......
......@@ -97,7 +97,7 @@ class OneToManyMapping extends AssociationMapping
return true;
}
public function load($owningEntity, $targetEntity, $em)
public function load($owningEntity, $targetEntity, $em, array $joinColumnValues)
{
throw new Exception('Not yet implemented.');
}
......
......@@ -35,6 +35,7 @@ namespace Doctrine\ORM\Mapping;
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
*/
class OneToOneMapping extends AssociationMapping
{
......@@ -152,11 +153,13 @@ class OneToOneMapping extends AssociationMapping
/**
* {@inheritdoc}
*
* @param object $owningEntity
* @param object $targetEntity
* @param object $sourceEntity the entity source of this association
* @param object $targetEntity the entity to load data in
* @param EntityManager $em
* @param array $joinColumnValues values of the join columns of $sourceEntity. There are no fields
* to store this data in $sourceEntity
*/
public function load($owningEntity, $targetEntity, $em)
public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues)
{
$sourceClass = $em->getClassMetadata($this->sourceEntityName);
$targetClass = $em->getClassMetadata($this->targetEntityName);
......@@ -165,24 +168,38 @@ class OneToOneMapping extends AssociationMapping
if ($this->isOwningSide) {
foreach ($this->sourceToTargetKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
$conditions[$targetKeyColumn] = $sourceClass->getReflectionProperty(
$sourceClass->getFieldName($sourceKeyColumn))->getValue($owningEntity);
// getting customer_id
if (isset($sourceClass->reflFields[$sourceKeyColumn])) {
$conditions[$targetKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $sourceKeyColumn);
} else {
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
}
}
if ($targetClass->hasInverseAssociation($this->sourceFieldName)) {
if ($targetClass->hasInverseAssociationMapping($this->sourceFieldName)) {
$targetClass->setFieldValue(
$targetEntity,
$targetClass->inverseMappings[$this->_sourceFieldName]->getSourceFieldName(),
$owningEntity);
$targetClass->inverseMappings[$this->sourceFieldName]->getSourceFieldName(),
$sourceEntity);
}
} else {
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->getAssociationMapping($this->mappedByFieldName);
foreach ($owningAssoc->getTargetToSourceKeyColumns() as $targetKeyColumn => $sourceKeyColumn) {
$conditions[$sourceKeyColumn] = $sourceClass->getReflectionProperty(
$sourceClass->getFieldName($targetKeyColumn))->getValue($owningEntity);
// getting id
if (isset($sourceClass->reflFields[$targetKeyColumn])) {
$conditions[$sourceKeyColumn] = $this->_getPrivateValue($sourceClass, $sourceEntity, $targetKeyColumn);
} else {
$conditions[$sourceKeyColumn] = $joinColumnValues[$targetKeyColumn];
}
}
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $owningEntity);
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $sourceEntity);
}
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
}
protected function _getPrivateValue(ClassMetadata $class, $entity, $column)
{
$reflField = $class->getReflectionProperty($class->getFieldName($column));
return $reflField->getValue($entity);
}
}
......@@ -411,10 +411,15 @@ class StandardEntityPersister
$stmt = $this->_conn->prepare($this->_getSelectSingleEntitySql($criteria));
$stmt->execute(array_values($criteria));
$data = array();
$joinColumnValues = array();
foreach ($stmt->fetch(Connection::FETCH_ASSOC) as $column => $value) {
$fieldName = $this->_class->fieldNames[$column];
$data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName))
if (isset($this->_class->fieldNames[$column])) {
$fieldName = $this->_class->fieldNames[$column];
$data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName))
->convertToPHPValue($value, $this->_platform);
} else {
$joinColumnValues[$column] = $value;
}
}
$stmt->closeCursor();
......@@ -440,9 +445,9 @@ class StandardEntityPersister
// empty collections respectively.
foreach ($this->_class->associationMappings as $field => $assoc) {
if ($assoc->isOneToOne()) {
if ($assoc->isLazilyFetched) {
if ($assoc->isLazilyFetched()) {
// Inject proxy
$proxy = $this->_em->getProxyGenerator()->getAssociationProxy($entity, $assoc);
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnValues);
$this->_class->reflFields[$field]->setValue($entity, $proxy);
} else {
//TODO: Eager fetch
......@@ -472,11 +477,23 @@ class StandardEntityPersister
if ($columnList != '') $columnList .= ', ';
$columnList .= $this->_conn->quoteIdentifier($column);
}
if (!$this->_em->getConfiguration()->getAllowPartialObjects()) {
foreach ($this->_class->joinColumnNames as $column) {
$columnList .= ', ' . $this->_conn->quoteIdentifier($column);
}
}
$conditionSql = '';
foreach ($criteria as $field => $value) {
if ($conditionSql != '') $conditionSql .= ' AND ';
$conditionSql .= $this->_conn->quoteIdentifier($this->_class->columnNames[$field]) . ' = ?';
if (isset($this->_class->columnNames[$field])) {
$columnName = $this->_class->columnNames[$field];
} else if (in_array($field, $this->_class->joinColumnNames)) {
$columnName = $field;
} else {
throw new Exception("Unrecognized field: $field");
}
$conditionSql .= $this->_conn->quoteIdentifier($columnName) . ' = ?';
}
return 'SELECT ' . $columnList . ' FROM ' . $this->_class->getTableName()
......
......@@ -88,12 +88,13 @@ class ProxyClassGenerator
$class = $this->_em->getClassMetadata($originalClassName);
$proxyFullyQualifiedClassName = self::$_ns . $proxyClassName;
$class = $this->_em->getClassMetadata($originalClassName);
$this->_em->getMetadataFactory()->setMetadataFor($proxyFullyQualifiedClassName, $class);
if (class_exists($proxyFullyQualifiedClassName, false)) {
return $proxyFullyQualifiedClassName;
}
$class = $this->_em->getClassMetadata($originalClassName);
$this->_em->getMetadataFactory()->setMetadataFor($proxyFullyQualifiedClassName, $class);
$fileName = $this->_cacheDir . $proxyClassName . '.g.php';
if (file_exists($fileName)) {
......@@ -228,18 +229,21 @@ namespace Doctrine\Generated\Proxies {
private $_em;
private $_assoc;
private $_owner;
private $_joinColumnValues;
private $_loaded = false;
public function __construct($em, $assoc, $owner) {
public function __construct($em, $assoc, $owner, array $joinColumnValues) {
$this->_em = $em;
$this->_assoc = $assoc;
$this->_owner = $owner;
$this->_joinColumnValues = $joinColumnValues;
}
private function _load() {
if ( ! $this->_loaded) {
$this->_assoc->load($this->_owner, $this, $this->_em);
$this->_assoc->load($this->_owner, $this, $this->_em, $this->_joinColumnValues);
unset($this->_em);
unset($this->_owner);
unset($this->_assoc);
unset($this->_joinColumnValues);
$this->_loaded = true;
}
}
......
......@@ -66,9 +66,9 @@ class ProxyFactory
/**
* Gets an association proxy instance.
*/
public function getAssociationProxy($owner, \Doctrine\ORM\Mapping\AssociationMapping $assoc)
public function getAssociationProxy($owner, \Doctrine\ORM\Mapping\AssociationMapping $assoc, array $joinColumnValues)
{
$proxyClassName = $this->_generator->generateAssociationProxyClass($assoc->getTargetEntityName());
return new $proxyClassName($this->_em, $assoc, $owner);
return new $proxyClassName($this->_em, $assoc, $owner, $joinColumnValues);
}
}
......@@ -2229,4 +2229,4 @@ class Parser
{
self::$_DATETIME_FUNCTIONS[$name] = $class;
}
}
\ No newline at end of file
}
......@@ -470,6 +470,13 @@ class SqlWalker implements TreeWalker
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
}
if (!$this->_em->getConfiguration()->getAllowPartialObjects()) {
foreach ($class->joinColumnNames as $name) {
$columnAlias = $this->getSqlColumnAlias($name);
$sql .= ', ' . $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($name) . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $name);
}
}
}
}
......@@ -1304,4 +1311,4 @@ class SqlWalker implements TreeWalker
return $sql;
}
}
\ No newline at end of file
}
......@@ -302,4 +302,4 @@ class SchemaTool
{
//TODO
}
}
\ No newline at end of file
}
......@@ -20,6 +20,7 @@
*/
namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\Proxy\ProxyFactory;
/**
* Special EntityManager mock used for testing purposes.
......@@ -27,6 +28,7 @@ namespace Doctrine\Tests\Mocks;
class EntityManagerMock extends \Doctrine\ORM\EntityManager
{
private $_uowMock;
private $_proxyFactoryMock;
private $_idGenerators = array();
/**
......@@ -48,6 +50,16 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager
{
$this->_uowMock = $uow;
}
public function setProxyFactory($proxyFactory)
{
$this->_proxyFactoryMock = $proxyFactory;
}
public function getProxyFactory()
{
return isset($this->_proxyFactoryMock) ? $this->_proxyFactoryMock : parent::getProxyFactory();
}
/**
* Mock factory method to create an EntityManager.
......@@ -87,4 +99,4 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager
return parent::getIdGenerator($className);
}
*/
}
\ No newline at end of file
}
......@@ -24,7 +24,6 @@ class AllTests
$suite->addTestSuite('Doctrine\Tests\ORM\CommitOrderCalculatorTest');
$suite->addTestSuite('Doctrine\Tests\ORM\QueryBuilderTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Proxy\ProxyClassGeneratorTest');
$suite->addTest(Query\AllTests::suite());
$suite->addTest(Hydration\AllTests::suite());
$suite->addTest(Entity\AllTests::suite());
......
......@@ -36,6 +36,7 @@ class AllTests
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManySelfReferentialAssociationTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ReferenceProxyTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\LifecycleCallbackTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\StandardEntityPersisterTest');
$suite->addTest(Locking\AllTests::suite());
......
......@@ -65,8 +65,21 @@ class OneToOneBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctional
$this->assertEquals('paypal', $customer->getCart()->getPayment());
}
public function testLazyLoad() {
$this->markTestSkipped();
public function testLazyLoadsObjectsOnTheOwningSide() {
$this->_createFixture();
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$metadata->getAssociationMapping('customer')->fetchMode = AssociationMapping::FETCH_LAZY;
$query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCart c');
$result = $query->getResultList();
$cart = $result[0];
$this->assertTrue($cart->getCustomer() instanceof ECommerceCustomer);
$this->assertEquals('Giorgio', $cart->getCustomer()->getName());
}
public function testLazyLoadsObjectsOnTheInverseSide() {
$this->_createFixture();
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer');
......
......@@ -58,8 +58,7 @@ class OneToOneUnidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctiona
$this->assertEquals(1, $product->getShipping()->getDays());
}
public function testLazyLoad() {
$this->markTestSkipped();
public function testLazyLoadsObjects() {
$this->_createFixture();
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
......@@ -73,6 +72,17 @@ class OneToOneUnidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctiona
$this->assertEquals(1, $product->getShipping()->getDays());
}
public function testDoesNotLazyLoadObjectsIfConfigurationDoesNotAllowIt() {
$this->_createFixture();
$this->_em->getConfiguration()->setAllowPartialObjects(true);
$query = $this->_em->createQuery('select p from Doctrine\Tests\Models\ECommerce\ECommerceProduct p');
$result = $query->getResultList();
$product = $result[0];
$this->assertNull($product->getShipping());
}
protected function _createFixture()
{
$product = new ECommerceProduct;
......
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceCart;
use Doctrine\Tests\Models\ECommerce\ECommerceCustomer;
use Doctrine\ORM\Mapping\AssociationMapping;
require_once __DIR__ . '/../../TestInit.php';
/**
* Tests capabilities of the persister.
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
*/
class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('ecommerce');
parent::setUp();
}
public function testAcceptsForeignKeysAsCriteria() {
$customer = new ECommerceCustomer();
$customer->setName('John Doe');
$cart = new ECommerceCart();
$cart->setPayment('Credit card');
$customer->setCart($cart);
$this->_em->persist($customer);
$this->_em->flush();
$this->_em->clear();
unset($cart);
$persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$newCart = new ECommerceCart();
$persister->load(array('customer_id' => $customer->getId()), $newCart);
$this->assertEquals('Credit card', $newCart->getPayment());
}
}
......@@ -4,6 +4,8 @@ namespace Doctrine\Tests\ORM\Hydration;
use Doctrine\Tests\Mocks\HydratorMockStatement;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Mapping\AssociationMapping;
require_once __DIR__ . '/../../TestInit.php';
......@@ -98,6 +100,50 @@ class ObjectHydratorTest extends HydrationTestCase
$this->assertEquals('Cool things II.', $result[3]->topic);
}
/**
* Select p from \Doctrine\Tests\Models\ECommerce\ECommerceProduct p
*/
public function testCreatesProxyForLazyLoadingWithForeignKeys()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\ECommerce\ECommerceProduct', 'p');
$rsm->addFieldResult('p', 'p__id', 'id');
$rsm->addFieldResult('p', 'p__name', 'name');
$rsm->addFieldResult('p', 'p__shipping_id', 'shipping_id');
// Faked result set
$resultSet = array(
array(
'p__id' => '1',
'p__name' => 'Doctrine Book',
'p__shipping_id' => 42
)
);
// mocking the proxy factory
$proxyFactory = $this->getMock('Doctrine\ORM\Proxy\ProxyFactory', array('getAssociationProxy'), array(), '', false, false, false);
$proxyFactory->expects($this->once())
->method('getAssociationProxy')
->with($this->isInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct'),
$this->isInstanceOf('Doctrine\ORM\Mapping\OneToOneMapping'),
array('shipping_id' => 42));
$this->_em->setProxyFactory($proxyFactory);
// configuring lazy loading
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$metadata->getAssociationMapping('shipping')->fetchMode = AssociationMapping::FETCH_LAZY;
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(1, count($result));
$this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\ECommerce\ECommerceProduct);
}
/**
* select u.id, u.status, p.phonenumber, upper(u.name) nameUpper from User u
* join u.phonenumbers p
......@@ -679,4 +725,4 @@ class ObjectHydratorTest extends HydrationTestCase
++$rowNum;
}
}
}
\ No newline at end of file
}
......@@ -14,7 +14,6 @@ require_once __DIR__ . '/../../TestInit.php';
class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
{
public function testGetMetadataForSingleClass()
{
$driverMock = new DriverMock();
......@@ -38,6 +37,11 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
// and a mapped association
$cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'Other', 'mappedBy' => 'this'));
// and an association on the owning side
$joinColumns = array(
array('name' => 'other_id', 'referencedColumnName' => 'id')
);
$cm1->mapOneToOne(array('fieldName' => 'association', 'targetEntity' => 'Other', 'joinColumns' => $joinColumns));
// and an id generator type
$cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
......@@ -49,13 +53,14 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(array(), $cm1->parentClasses);
$this->assertEquals(ClassMetadata::INHERITANCE_TYPE_NONE, $cm1->inheritanceType);
$this->assertTrue($cm1->hasField('name'));
$this->assertEquals(1, count($cm1->associationMappings));
$this->assertEquals(2, count($cm1->associationMappings));
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $cm1->generatorType);
// Go
$cm1 = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\TestEntity1');
$this->assertEquals(array(), $cm1->parentClasses);
$this->assertEquals(array('other_id'), $cm1->joinColumnNames);
$this->assertTrue($cm1->hasField('name'));
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_SEQUENCE, $cm1->generatorType);
}
......@@ -93,4 +98,5 @@ class TestEntity1
private $id;
private $name;
private $other;
}
\ No newline at end of file
private $association;
}
......@@ -62,11 +62,22 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
public function testAllowsIdempotentCreationOfReferenceProxyClass()
{
$proxyClass = $this->_generator->generateReferenceProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
$theSameProxyClass = $this->_generator->generateReferenceProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
$originalClassName = 'Doctrine\Tests\Models\ECommerce\ECommerceFeature';
$proxyClass = $this->_generator->generateReferenceProxyClass($originalClassName);
$theSameProxyClass = $this->_generator->generateReferenceProxyClass($originalClassName);
$this->assertEquals($proxyClass, $theSameProxyClass);
}
public function testRegeneratesMetadataAfterIdempotentCreation()
{
$originalClassName = 'Doctrine\Tests\Models\ECommerce\ECommerceFeature';
$metadataFactory = $this->_emMock->getMetadataFactory();
$proxyClass = $this->_generator->generateReferenceProxyClass($originalClassName);
$metadataFactory->setMetadataFor($proxyClass, null);
$theSameProxyClass = $this->_generator->generateReferenceProxyClass($originalClassName);
$this->assertNotNull($metadataFactory->getMetadataFor($theSameProxyClass));
}
public function testReferenceProxyRequiresPersisterInTheConstructor()
{
$proxyClass = $this->_generator->generateReferenceProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
......@@ -140,22 +151,23 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
$this->assertNotEquals($referenceProxyClass, $associationProxyClass);
}
public function testAssociationProxyRequiresEntityManagerAndAssociationAndOwnerInTheConstructor()
public function testAssociationProxyRequiresEntityManagerAssociationOwnerAndForeignKeysInTheConstructor()
{
$proxyClass = $this->_generator->generateAssociationProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
$product = new ECommerceProduct;
$proxy = new $proxyClass($this->_emMock, $this->_getAssociationMock(), $product);
$proxy = new $proxyClass($this->_emMock, $this->_getAssociationMock(), $product, array());
}
public function testAssociationProxyDelegatesLoadingToTheAssociation()
{
$proxyClass = $this->_generator->generateAssociationProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
$product = new ECommerceProduct;
$foreignKeys = array('customer_id' => 42);
$assoc = $this->_getAssociationMock();
$proxy = new $proxyClass($this->_emMock, $assoc, $product);
$proxy = new $proxyClass($this->_emMock, $assoc, $product, $foreignKeys);
$assoc->expects($this->any())
->method('load')
->with($product, $this->isInstanceOf($proxyClass), $this->isInstanceOf('Doctrine\Tests\Mocks\EntityManagerMock'));
->with($product, $this->isInstanceOf($proxyClass), $this->isInstanceOf('Doctrine\Tests\Mocks\EntityManagerMock'), $foreignKeys);
$proxy->getDescription();
}
......@@ -163,7 +175,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
{
$proxyClass = $this->_generator->generateAssociationProxyClass('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
$assoc = $this->_getAssociationMock();
$proxy = new $proxyClass($this->_emMock, $assoc, null);
$proxy = new $proxyClass($this->_emMock, $assoc, null, array());
$assoc->expects($this->once())
->method('load');
......@@ -171,7 +183,6 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
$proxy->getDescription();
}
protected function _getAssociationMock()
{
$assoc = $this->getMock('Doctrine\ORM\Mapping\AssociationMapping', array('load'), array(), '', false, false, false);
......
......@@ -36,7 +36,10 @@ class OrmTestCase extends DoctrineTestCase
'password' => 'wayne'
);
}
return \Doctrine\ORM\EntityManager::create($conn, $config, $eventManager);
if (is_array($conn)) {
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager);
}
return \Doctrine\Tests\Mocks\EntityManagerMock::create($conn, $config, $eventManager);
}
private static function getSharedMetadataCacheImpl()
......
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