Skip to content

Commit

Permalink
Fix composite key serialization (#135)
Browse files Browse the repository at this point in the history
Adopt @cevou's solution from #135
  • Loading branch information
ddeboer committed Mar 26, 2015
1 parent f1ae0e3 commit ef54844
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 4 deletions.
20 changes: 18 additions & 2 deletions lib/Doctrine/Common/DataFixtures/ReferenceRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,24 @@ protected function getIdentifier($reference, $uow)
// In case Reference is not yet managed in UnitOfWork
if ( ! $uow->isInIdentityMap($reference)) {
$class = $this->manager->getClassMetadata(get_class($reference));

return $class->getIdentifierValues($reference);

$values = $class->getIdentifierValues($reference);

// See https://github.com/doctrine/data-fixtures/issues/135 and
// https://github.com/doctrine/data-fixtures/issues/167
foreach ($values as $key => $value) {
if (!is_scalar($value)) {
// To prevent "Array to string conversion" in
// UnitOfWork::tryGetById, we can only return a single
// identifier. This does mean that related entities that
// themselves have a composite primary key are unsupported.
$proxyId = $this->getIdentifier($value, $uow);
$keys = array_keys($proxyId);
$values[$key] = $proxyId[$keys[0]];
}
}

return $values;
}

// Dealing with ORM UnitOfWork
Expand Down
21 changes: 21 additions & 0 deletions tests/Doctrine/Tests/Common/DataFixtures/BaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
namespace Doctrine\Tests\Common\DataFixtures;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Tools\Setup;
use PHPUnit_Framework_TestCase;

Expand Down Expand Up @@ -85,4 +86,24 @@ protected function getMockSqliteEntityManager()
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__.'/TestEntity'), true);
return EntityManager::create($dbParams, $config);
}

/**
* Prepare the database schema
*
* @param EntityManager $em
* @param array $entities
*/
protected function prepareSchema(EntityManager $em, array $entities)
{
$schemaTool = new SchemaTool($em);
$schemaTool->dropSchema(array());
$schemaTool->createSchema(
array_map(
function ($entity) use ($em) {
return $em->getClassMetadata($entity);
},
$entities
)
);
}
}
2 changes: 1 addition & 1 deletion tests/Doctrine/Tests/Common/DataFixtures/LoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function testLoadFromDirectory()
$this->assertCount(3, $loader->getFixtures());

$loader->loadFromDirectory(__DIR__.'/TestFixtures');
$this->assertCount(7, $loader->getFixtures());
$this->assertCount(8, $loader->getFixtures());
$this->assertTrue($loader->isTransient('TestFixtures\NotAFixture'));
$this->assertFalse($loader->isTransient('TestFixtures\MyFixture1'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
use Doctrine\Common\DataFixtures\ProxyReferenceRepository;
use Doctrine\Common\DataFixtures\Event\Listener\ORMReferenceListener;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Proxy\Proxy;

/**
* Test ProxyReferenceRepository.
Expand All @@ -33,6 +32,8 @@
class ProxyReferenceRepositoryTest extends BaseTest
{
const TEST_ENTITY_ROLE = 'Doctrine\Tests\Common\DataFixtures\TestEntity\Role';
const TEST_ENTITY_USER = 'Doctrine\Tests\Common\DataFixtures\TestEntity\User';
const TEST_ENTITY_USER_ROLE = 'Doctrine\Tests\Common\DataFixtures\TestEntity\UserRole';

public function testReferenceEntry()
{
Expand Down Expand Up @@ -154,4 +155,41 @@ public function testReferenceMultipleEntries()
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $referenceRepository->getReference('admin'));
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $referenceRepository->getReference('duplicate'));
}

public function testCompositeForeignKeysReconstruction()
{
$em = $this->getMockSqliteEntityManager();
$this->prepareSchema(
$em,
array(
self::TEST_ENTITY_ROLE,
self::TEST_ENTITY_USER,
self::TEST_ENTITY_USER_ROLE
)
);

$referenceRepository = new ProxyReferenceRepository($em);

$roleFixture = new TestFixtures\RoleFixture;
$roleFixture->setReferenceRepository($referenceRepository);
$roleFixture->load($em);

$userFixture = new TestFixtures\UserFixture;
$userFixture->setReferenceRepository($referenceRepository);
$userFixture->load($em);

$userFixture = new TestFixtures\UserRoleFixture;
$userFixture->setReferenceRepository($referenceRepository);
$userFixture->load($em);

$em->clear();

$data = $referenceRepository->serialize();

$referenceRepository = new ProxyReferenceRepository($em);
$referenceRepository->unserialize($data);

$compositeKey = $referenceRepository->getReference('composite-key');
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $compositeKey);
}
}
37 changes: 37 additions & 0 deletions tests/Doctrine/Tests/Common/DataFixtures/TestEntity/UserRole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Doctrine\Tests\Common\DataFixtures\TestEntity;

/**
* @Entity
*/
class UserRole
{
/**
* @ManyToOne(targetEntity="User")
* @Id
*/
private $user;

/**
* @ManyToOne(targetEntity="Role")
* @Id
*/
private $role;

public function __construct(User $user, Role $role)
{
$this->user = $user;
$this->role = $role;
}

public function getUser()
{
return $this->user;
}

public function getRole()
{
return $this->role;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
namespace Doctrine\Tests\Common\DataFixtures\TestFixtures;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Tests\Common\DataFixtures\TestEntity\UserRole;

class UserRoleFixture extends AbstractFixture
{
public function load(ObjectManager $manager)
{
$userRole = new UserRole(
$this->getReference('admin'),
$this->getReference('admin-role')
);

$manager->persist($userRole);
$this->referenceRepository->addReference('composite-key', $userRole);
$manager->flush();
}
}

0 comments on commit ef54844

Please sign in to comment.