2012-10-20 01:27:53 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Doctrine\Tests\ORM\Proxy;
|
|
|
|
|
2016-05-11 01:55:12 +07:00
|
|
|
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
|
2016-04-11 17:01:55 +01:00
|
|
|
use Doctrine\Common\Proxy\AbstractProxyFactory;
|
2013-05-09 21:11:10 +02:00
|
|
|
use Doctrine\ORM\EntityNotFoundException;
|
2013-01-06 15:11:30 +01:00
|
|
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
2016-06-18 13:01:59 +02:00
|
|
|
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
|
2012-10-20 01:27:53 +02:00
|
|
|
use Doctrine\ORM\Proxy\ProxyFactory;
|
|
|
|
use Doctrine\Tests\Mocks\ConnectionMock;
|
2016-04-11 17:01:55 +01:00
|
|
|
use Doctrine\Tests\Mocks\DriverMock;
|
2012-10-20 01:27:53 +02:00
|
|
|
use Doctrine\Tests\Mocks\EntityManagerMock;
|
|
|
|
use Doctrine\Tests\Mocks\UnitOfWorkMock;
|
2016-12-08 18:01:04 +01:00
|
|
|
use Doctrine\Tests\Models\Company\CompanyEmployee;
|
2016-09-10 20:45:01 +02:00
|
|
|
use Doctrine\Tests\Models\Company\CompanyPerson;
|
2016-12-08 18:01:04 +01:00
|
|
|
use Doctrine\Tests\Models\ECommerce\ECommerceFeature;
|
2016-05-11 01:55:12 +07:00
|
|
|
use Doctrine\Tests\OrmTestCase;
|
2012-10-20 01:27:53 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Test the proxy generator. Its work is generating on-the-fly subclasses of a given model, which implement the Proxy pattern.
|
|
|
|
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
|
|
|
*/
|
2016-05-11 01:55:12 +07:00
|
|
|
class ProxyFactoryTest extends OrmTestCase
|
2012-10-20 01:27:53 +02:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var ConnectionMock
|
|
|
|
*/
|
|
|
|
private $connectionMock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var UnitOfWorkMock
|
|
|
|
*/
|
|
|
|
private $uowMock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var EntityManagerMock
|
|
|
|
*/
|
|
|
|
private $emMock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var \Doctrine\ORM\Proxy\ProxyFactory
|
|
|
|
*/
|
|
|
|
private $proxyFactory;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
protected function setUp()
|
|
|
|
{
|
|
|
|
parent::setUp();
|
2016-12-07 23:33:41 +01:00
|
|
|
$this->connectionMock = new ConnectionMock([], new DriverMock());
|
2012-10-20 01:27:53 +02:00
|
|
|
$this->emMock = EntityManagerMock::create($this->connectionMock);
|
|
|
|
$this->uowMock = new UnitOfWorkMock($this->emMock);
|
|
|
|
$this->emMock->setUnitOfWork($this->uowMock);
|
2013-12-31 12:25:14 +01:00
|
|
|
$this->proxyFactory = new ProxyFactory($this->emMock, sys_get_temp_dir(), 'Proxies', AbstractProxyFactory::AUTOGENERATE_ALWAYS);
|
2012-10-20 01:27:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testReferenceProxyDelegatesLoadingToThePersister()
|
|
|
|
{
|
2016-12-07 23:33:41 +01:00
|
|
|
$identifier = ['id' => 42];
|
2012-10-20 01:27:53 +02:00
|
|
|
$proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature';
|
2016-12-07 23:33:41 +01:00
|
|
|
$persister = $this->getMockBuilder(BasicEntityPersister::class)->setMethods(['load'])->disableOriginalConstructor()->getMock();
|
2016-06-18 13:01:59 +02:00
|
|
|
|
2016-12-08 18:01:04 +01:00
|
|
|
$this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
|
2012-10-20 01:27:53 +02:00
|
|
|
|
2016-12-08 18:01:04 +01:00
|
|
|
$proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, $identifier);
|
2012-10-20 01:27:53 +02:00
|
|
|
|
|
|
|
$persister
|
|
|
|
->expects($this->atLeastOnce())
|
2016-04-11 17:01:55 +01:00
|
|
|
->method('load')
|
|
|
|
->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass))
|
|
|
|
->will($this->returnValue(new \stdClass()));
|
2012-10-20 01:27:53 +02:00
|
|
|
|
|
|
|
$proxy->getDescription();
|
|
|
|
}
|
|
|
|
|
2017-08-16 20:29:27 +09:00
|
|
|
public function testSkipMappedSuperClassesOnGeneration(): void
|
2017-08-16 12:11:03 +09:00
|
|
|
{
|
|
|
|
$cm = new ClassMetadata(\stdClass::class);
|
|
|
|
$cm->isMappedSuperclass = true;
|
|
|
|
|
2017-08-16 15:16:00 +02:00
|
|
|
self::assertSame(
|
|
|
|
0,
|
|
|
|
$this->proxyFactory->generateProxyClasses([$cm]),
|
|
|
|
'No proxies generated.'
|
|
|
|
);
|
2017-08-16 12:11:03 +09:00
|
|
|
}
|
|
|
|
|
2017-08-16 20:29:27 +09:00
|
|
|
/**
|
|
|
|
* @group 6625
|
|
|
|
*/
|
|
|
|
public function testSkipEmbeddableClassesOnGeneration(): void
|
2017-08-16 12:11:03 +09:00
|
|
|
{
|
|
|
|
$cm = new ClassMetadata(\stdClass::class);
|
|
|
|
$cm->isEmbeddedClass = true;
|
|
|
|
|
2017-08-16 15:16:00 +02:00
|
|
|
self::assertSame(
|
|
|
|
0,
|
|
|
|
$this->proxyFactory->generateProxyClasses([$cm]),
|
|
|
|
'No proxies generated.'
|
|
|
|
);
|
2017-08-16 12:11:03 +09:00
|
|
|
}
|
|
|
|
|
2012-10-20 01:27:53 +02:00
|
|
|
/**
|
|
|
|
* @group DDC-1771
|
|
|
|
*/
|
|
|
|
public function testSkipAbstractClassesOnGeneration()
|
|
|
|
{
|
2016-12-08 18:01:04 +01:00
|
|
|
$cm = new ClassMetadata(AbstractClass::class);
|
2016-05-11 01:55:12 +07:00
|
|
|
$cm->initializeReflection(new RuntimeReflectionService());
|
2012-10-20 01:27:53 +02:00
|
|
|
$this->assertNotNull($cm->reflClass);
|
|
|
|
|
2016-12-07 23:33:41 +01:00
|
|
|
$num = $this->proxyFactory->generateProxyClasses([$cm]);
|
2012-10-20 01:27:53 +02:00
|
|
|
|
|
|
|
$this->assertEquals(0, $num, "No proxies generated.");
|
|
|
|
}
|
2013-05-09 21:11:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @group DDC-2432
|
|
|
|
*/
|
|
|
|
public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized()
|
|
|
|
{
|
2016-12-07 23:33:41 +01:00
|
|
|
$persister = $this->getMockBuilder(BasicEntityPersister::class)->setMethods(['load'])->disableOriginalConstructor()->getMock();
|
2016-12-08 18:01:04 +01:00
|
|
|
$this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
|
2013-05-09 21:11:10 +02:00
|
|
|
|
|
|
|
/* @var $proxy \Doctrine\Common\Proxy\Proxy */
|
2016-12-08 18:01:04 +01:00
|
|
|
$proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
|
2013-05-09 21:11:10 +02:00
|
|
|
|
|
|
|
$persister
|
|
|
|
->expects($this->atLeastOnce())
|
|
|
|
->method('load')
|
|
|
|
->will($this->returnValue(null));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$proxy->getDescription();
|
|
|
|
$this->fail('An exception was expected to be raised');
|
|
|
|
} catch (EntityNotFoundException $exception) {
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->assertFalse($proxy->__isInitialized());
|
|
|
|
$this->assertInstanceOf('Closure', $proxy->__getInitializer(), 'The initializer wasn\'t removed');
|
|
|
|
$this->assertInstanceOf('Closure', $proxy->__getCloner(), 'The cloner wasn\'t removed');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @group DDC-2432
|
|
|
|
*/
|
|
|
|
public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized()
|
|
|
|
{
|
2016-12-07 23:33:41 +01:00
|
|
|
$persister = $this->getMockBuilder(BasicEntityPersister::class)->setMethods(['load'])->disableOriginalConstructor()->getMock();
|
2016-12-08 18:01:04 +01:00
|
|
|
$this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
|
2013-05-09 21:11:10 +02:00
|
|
|
|
|
|
|
/* @var $proxy \Doctrine\Common\Proxy\Proxy */
|
2016-12-08 18:01:04 +01:00
|
|
|
$proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
|
2013-05-09 21:11:10 +02:00
|
|
|
|
|
|
|
$persister
|
|
|
|
->expects($this->atLeastOnce())
|
|
|
|
->method('load')
|
|
|
|
->will($this->returnValue(null));
|
|
|
|
|
|
|
|
try {
|
|
|
|
$cloned = clone $proxy;
|
|
|
|
$this->fail('An exception was expected to be raised');
|
|
|
|
} catch (EntityNotFoundException $exception) {
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->assertFalse($proxy->__isInitialized());
|
|
|
|
$this->assertInstanceOf('Closure', $proxy->__getInitializer(), 'The initializer wasn\'t removed');
|
|
|
|
$this->assertInstanceOf('Closure', $proxy->__getCloner(), 'The cloner wasn\'t removed');
|
|
|
|
}
|
2016-04-11 17:01:55 +01:00
|
|
|
|
|
|
|
public function testProxyClonesParentFields()
|
|
|
|
{
|
|
|
|
$companyEmployee = new CompanyEmployee();
|
|
|
|
$companyEmployee->setSalary(1000); // A property on the CompanyEmployee
|
2016-09-10 20:45:01 +02:00
|
|
|
$companyEmployee->setName('Bob'); // A property on the parent class, CompanyPerson
|
2016-04-11 17:01:55 +01:00
|
|
|
|
|
|
|
// Set the id of the CompanyEmployee (which is in the parent CompanyPerson)
|
2016-09-10 20:45:01 +02:00
|
|
|
$property = new \ReflectionProperty(CompanyPerson::class, 'id');
|
2016-04-11 17:01:55 +01:00
|
|
|
|
|
|
|
$property->setAccessible(true);
|
|
|
|
$property->setValue($companyEmployee, 42);
|
|
|
|
|
2016-09-10 20:45:01 +02:00
|
|
|
$classMetaData = $this->emMock->getClassMetadata(CompanyEmployee::class);
|
2016-04-11 17:01:55 +01:00
|
|
|
|
2016-09-10 20:45:01 +02:00
|
|
|
$persister = $this
|
|
|
|
->getMockBuilder(BasicEntityPersister::class)
|
|
|
|
->setMethods(['load', 'getClassMetadata'])
|
|
|
|
->disableOriginalConstructor()
|
|
|
|
->getMock();
|
|
|
|
$this->uowMock->setEntityPersister(CompanyEmployee::class, $persister);
|
2016-04-11 17:01:55 +01:00
|
|
|
|
|
|
|
/* @var $proxy \Doctrine\Common\Proxy\Proxy */
|
2016-09-10 20:45:01 +02:00
|
|
|
$proxy = $this->proxyFactory->getProxy(CompanyEmployee::class, ['id' => 42]);
|
2016-04-11 17:01:55 +01:00
|
|
|
|
|
|
|
$persister
|
2016-09-10 20:45:01 +02:00
|
|
|
->expects(self::atLeastOnce())
|
2016-04-11 17:01:55 +01:00
|
|
|
->method('load')
|
2016-09-10 20:45:01 +02:00
|
|
|
->willReturn($companyEmployee);
|
2016-04-11 17:01:55 +01:00
|
|
|
|
|
|
|
$persister
|
2016-09-10 20:45:01 +02:00
|
|
|
->expects(self::atLeastOnce())
|
2016-04-11 17:01:55 +01:00
|
|
|
->method('getClassMetadata')
|
2016-09-10 20:45:01 +02:00
|
|
|
->willReturn($classMetaData);
|
2016-04-11 17:01:55 +01:00
|
|
|
|
2016-09-10 20:45:01 +02:00
|
|
|
/* @var $cloned CompanyEmployee */
|
2016-04-11 17:01:55 +01:00
|
|
|
$cloned = clone $proxy;
|
|
|
|
|
2016-09-10 20:45:01 +02:00
|
|
|
self::assertSame(42, $cloned->getId(), 'Expected the Id to be cloned');
|
|
|
|
self::assertSame(1000, $cloned->getSalary(), 'Expect properties on the CompanyEmployee class to be cloned');
|
|
|
|
self::assertSame('Bob', $cloned->getName(), 'Expect properties on the CompanyPerson class to be cloned');
|
2016-04-11 17:01:55 +01:00
|
|
|
}
|
2012-10-20 01:27:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
abstract class AbstractClass
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|