. */ namespace Doctrine\Tests\Common\Proxy; use Doctrine\Common\Proxy\ProxyGenerator; use Doctrine\Common\Proxy\Proxy; use Doctrine\Common\Proxy\Exception\UnexpectedValueException; use PHPUnit_Framework_TestCase; use ReflectionClass; /** * Test for behavior of proxies with inherited magic methods * * @author Marco Pivetta */ class ProxyMagicMethodsTest extends PHPUnit_Framework_TestCase { /** * @var \Doctrine\Common\Proxy\ProxyGenerator */ protected $proxyGenerator; /** * @var LazyLoadableObject|Proxy */ protected $lazyObject; protected $identifier = array( 'publicIdentifierField' => 'publicIdentifierFieldValue', 'protectedIdentifierField' => 'protectedIdentifierFieldValue', ); /** * @var \PHPUnit_Framework_MockObject_MockObject|Callable */ protected $initializerCallbackMock; /** * {@inheritDoc} */ public function setUp() { $this->proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . '\\MagicMethodProxy'); } public static function tearDownAfterClass() { } public function testInheritedMagicGet() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicGetClass'); $proxy = new $proxyClassName( function (Proxy $proxy, $method, $params) use (&$counter) { if ( ! in_array($params[0], array('publicField', 'test', 'notDefined'))) { throw new \InvalidArgumentException('Unexpected access to field "' . $params[0] . '"'); } $initializer = $proxy->__getInitializer(); $proxy->__setInitializer(null); $proxy->publicField = 'modifiedPublicField'; $counter += 1; $proxy->__setInitializer($initializer); } ); $this->assertSame('id', $proxy->id); $this->assertSame('modifiedPublicField', $proxy->publicField); $this->assertSame('test', $proxy->test); $this->assertSame('not defined', $proxy->notDefined); $this->assertSame(3, $counter); } /** * @group DCOM-194 */ public function testInheritedMagicGetByRef() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicGetByRefClass'); /* @var $proxy \Doctrine\Tests\Common\Proxy\MagicGetByRefClass */ $proxy = new $proxyClassName(); $proxy->valueField = 123; $value = & $proxy->__get('value'); $this->assertSame(123, $value); $value = 456; $this->assertSame(456, $proxy->__get('value'), 'Value was fetched by reference'); $this->setExpectedException('InvalidArgumentException'); $undefined = $proxy->nonExisting; } public function testInheritedMagicSet() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicSetClass'); $proxy = new $proxyClassName( function (Proxy $proxy, $method, $params) use (&$counter) { if ( ! in_array($params[0], array('publicField', 'test', 'notDefined'))) { throw new \InvalidArgumentException('Unexpected access to field "' . $params[0] . '"'); } $counter += 1; } ); $this->assertSame('id', $proxy->id); $proxy->publicField = 'publicFieldValue'; $this->assertSame('publicFieldValue', $proxy->publicField); $proxy->test = 'testValue'; $this->assertSame('testValue', $proxy->testAttribute); $proxy->notDefined = 'not defined'; $this->assertSame('not defined', $proxy->testAttribute); $this->assertSame(3, $counter); } public function testInheritedMagicSleep() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicSleepClass'); $proxy = new $proxyClassName(); $this->assertSame('defaultValue', $proxy->serializedField); $this->assertSame('defaultValue', $proxy->nonSerializedField); $proxy->serializedField = 'changedValue'; $proxy->nonSerializedField = 'changedValue'; $unserialized = unserialize(serialize($proxy)); $this->assertSame('changedValue', $unserialized->serializedField); $this->assertSame('defaultValue', $unserialized->nonSerializedField, 'Field was not returned by "__sleep"'); } public function testInheritedMagicWakeup() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicWakeupClass'); $proxy = new $proxyClassName(); $this->assertSame('defaultValue', $proxy->wakeupValue); $proxy->wakeupValue = 'changedValue'; $unserialized = unserialize(serialize($proxy)); $this->assertSame('newWakeupValue', $unserialized->wakeupValue, '"__wakeup" was called'); $unserialized->__setInitializer(function (Proxy $proxy) { $proxy->__setInitializer(null); $proxy->publicField = 'newPublicFieldValue'; }); $this->assertSame('newPublicFieldValue', $unserialized->publicField, 'Proxy can still be initialized'); } public function testInheritedMagicIsset() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicIssetClass'); $proxy = new $proxyClassName(function (Proxy $proxy, $method, $params) use (&$counter) { if (in_array($params[0], array('publicField', 'test', 'nonExisting'))) { $initializer = $proxy->__getInitializer(); $proxy->__setInitializer(null); $proxy->publicField = 'modifiedPublicField'; $counter += 1; $proxy->__setInitializer($initializer); return; } throw new \InvalidArgumentException( sprintf('Should not be initialized when checking isset("%s")', $params[0]) ); }); $this->assertTrue(isset($proxy->id)); $this->assertTrue(isset($proxy->publicField)); $this->assertTrue(isset($proxy->test)); $this->assertFalse(isset($proxy->nonExisting)); $this->assertSame(3, $counter); } public function testInheritedMagicClone() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicCloneClass'); $proxy = new $proxyClassName( null, function ($proxy) { $proxy->cloned = true; } ); $cloned = clone $proxy; $this->assertSame('newClonedValue', $cloned->clonedValue); $this->assertFalse($proxy->cloned); $this->assertTrue($cloned->cloned); } /** * @group DCOM-175 */ public function testClonesPrivateProperties() { $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\SerializedClass'); /* @var $proxy SerializedClass */ $proxy = new $proxyClassName(); $proxy->setFoo(1); $proxy->setBar(2); $proxy->setBaz(3); $unserialized = unserialize(serialize($proxy)); $this->assertSame(1, $unserialized->getFoo()); $this->assertSame(2, $unserialized->getBar()); $this->assertSame(3, $unserialized->getBaz()); } /** * @param $className * * @return string */ private function generateProxyClass($className) { $proxyClassName = 'Doctrine\\Tests\\Common\\Proxy\\MagicMethodProxy\\__CG__\\' . $className; if (class_exists($proxyClassName, false)) { return $proxyClassName; } $metadata = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata'); $metadata ->expects($this->any()) ->method('getName') ->will($this->returnValue($className)); $metadata ->expects($this->any()) ->method('getIdentifier') ->will($this->returnValue(array('id'))); $metadata ->expects($this->any()) ->method('getReflectionClass') ->will($this->returnValue(new ReflectionClass($className))); $metadata ->expects($this->any()) ->method('isIdentifier') ->will($this->returnCallback(function ($fieldName) { return 'id' === $fieldName; })); $metadata ->expects($this->any()) ->method('hasField') ->will($this->returnCallback(function ($fieldName) { return in_array($fieldName, array('id', 'publicField')); })); $metadata ->expects($this->any()) ->method('hasAssociation') ->will($this->returnValue(false)); $metadata ->expects($this->any()) ->method('getFieldNames') ->will($this->returnValue(array('id', 'publicField'))); $metadata ->expects($this->any()) ->method('getIdentifierFieldNames') ->will($this->returnValue(array('id'))); $metadata ->expects($this->any()) ->method('getAssociationNames') ->will($this->returnValue(array())); $metadata ->expects($this->any()) ->method('getTypeOfField') ->will($this->returnValue('string')); $this->proxyGenerator->generateProxyClass($metadata, $this->proxyGenerator->getProxyFileName($className)); require_once $this->proxyGenerator->getProxyFileName($className); return $proxyClassName; } }