ProxyMagicMethodsTest.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the MIT license. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\Tests\Common\Proxy;
  20. use Doctrine\Common\Proxy\ProxyGenerator;
  21. use Doctrine\Common\Proxy\Proxy;
  22. use Doctrine\Common\Proxy\Exception\UnexpectedValueException;
  23. use PHPUnit_Framework_TestCase;
  24. use ReflectionClass;
  25. /**
  26. * Test for behavior of proxies with inherited magic methods
  27. *
  28. * @author Marco Pivetta <ocramius@gmail.com>
  29. */
  30. class ProxyMagicMethodsTest extends PHPUnit_Framework_TestCase
  31. {
  32. /**
  33. * @var \Doctrine\Common\Proxy\ProxyGenerator
  34. */
  35. protected $proxyGenerator;
  36. /**
  37. * @var LazyLoadableObject|Proxy
  38. */
  39. protected $lazyObject;
  40. protected $identifier = array(
  41. 'publicIdentifierField' => 'publicIdentifierFieldValue',
  42. 'protectedIdentifierField' => 'protectedIdentifierFieldValue',
  43. );
  44. /**
  45. * @var \PHPUnit_Framework_MockObject_MockObject|Callable
  46. */
  47. protected $initializerCallbackMock;
  48. /**
  49. * {@inheritDoc}
  50. */
  51. public function setUp()
  52. {
  53. $this->proxyGenerator = new ProxyGenerator(__DIR__ . '/generated', __NAMESPACE__ . '\\MagicMethodProxy');
  54. }
  55. public static function tearDownAfterClass()
  56. {
  57. }
  58. public function testInheritedMagicGet()
  59. {
  60. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicGetClass');
  61. $proxy = new $proxyClassName(
  62. function (Proxy $proxy, $method, $params) use (&$counter) {
  63. if ( ! in_array($params[0], array('publicField', 'test', 'notDefined'))) {
  64. throw new \InvalidArgumentException('Unexpected access to field "' . $params[0] . '"');
  65. }
  66. $initializer = $proxy->__getInitializer();
  67. $proxy->__setInitializer(null);
  68. $proxy->publicField = 'modifiedPublicField';
  69. $counter += 1;
  70. $proxy->__setInitializer($initializer);
  71. }
  72. );
  73. $this->assertSame('id', $proxy->id);
  74. $this->assertSame('modifiedPublicField', $proxy->publicField);
  75. $this->assertSame('test', $proxy->test);
  76. $this->assertSame('not defined', $proxy->notDefined);
  77. $this->assertSame(3, $counter);
  78. }
  79. /**
  80. * @group DCOM-194
  81. */
  82. public function testInheritedMagicGetByRef()
  83. {
  84. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicGetByRefClass');
  85. /* @var $proxy \Doctrine\Tests\Common\Proxy\MagicGetByRefClass */
  86. $proxy = new $proxyClassName();
  87. $proxy->valueField = 123;
  88. $value = & $proxy->__get('value');
  89. $this->assertSame(123, $value);
  90. $value = 456;
  91. $this->assertSame(456, $proxy->__get('value'), 'Value was fetched by reference');
  92. $this->setExpectedException('InvalidArgumentException');
  93. $undefined = $proxy->nonExisting;
  94. }
  95. public function testInheritedMagicSet()
  96. {
  97. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicSetClass');
  98. $proxy = new $proxyClassName(
  99. function (Proxy $proxy, $method, $params) use (&$counter) {
  100. if ( ! in_array($params[0], array('publicField', 'test', 'notDefined'))) {
  101. throw new \InvalidArgumentException('Unexpected access to field "' . $params[0] . '"');
  102. }
  103. $counter += 1;
  104. }
  105. );
  106. $this->assertSame('id', $proxy->id);
  107. $proxy->publicField = 'publicFieldValue';
  108. $this->assertSame('publicFieldValue', $proxy->publicField);
  109. $proxy->test = 'testValue';
  110. $this->assertSame('testValue', $proxy->testAttribute);
  111. $proxy->notDefined = 'not defined';
  112. $this->assertSame('not defined', $proxy->testAttribute);
  113. $this->assertSame(3, $counter);
  114. }
  115. public function testInheritedMagicSleep()
  116. {
  117. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicSleepClass');
  118. $proxy = new $proxyClassName();
  119. $this->assertSame('defaultValue', $proxy->serializedField);
  120. $this->assertSame('defaultValue', $proxy->nonSerializedField);
  121. $proxy->serializedField = 'changedValue';
  122. $proxy->nonSerializedField = 'changedValue';
  123. $unserialized = unserialize(serialize($proxy));
  124. $this->assertSame('changedValue', $unserialized->serializedField);
  125. $this->assertSame('defaultValue', $unserialized->nonSerializedField, 'Field was not returned by "__sleep"');
  126. }
  127. public function testInheritedMagicWakeup()
  128. {
  129. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicWakeupClass');
  130. $proxy = new $proxyClassName();
  131. $this->assertSame('defaultValue', $proxy->wakeupValue);
  132. $proxy->wakeupValue = 'changedValue';
  133. $unserialized = unserialize(serialize($proxy));
  134. $this->assertSame('newWakeupValue', $unserialized->wakeupValue, '"__wakeup" was called');
  135. $unserialized->__setInitializer(function (Proxy $proxy) {
  136. $proxy->__setInitializer(null);
  137. $proxy->publicField = 'newPublicFieldValue';
  138. });
  139. $this->assertSame('newPublicFieldValue', $unserialized->publicField, 'Proxy can still be initialized');
  140. }
  141. public function testInheritedMagicIsset()
  142. {
  143. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicIssetClass');
  144. $proxy = new $proxyClassName(function (Proxy $proxy, $method, $params) use (&$counter) {
  145. if (in_array($params[0], array('publicField', 'test', 'nonExisting'))) {
  146. $initializer = $proxy->__getInitializer();
  147. $proxy->__setInitializer(null);
  148. $proxy->publicField = 'modifiedPublicField';
  149. $counter += 1;
  150. $proxy->__setInitializer($initializer);
  151. return;
  152. }
  153. throw new \InvalidArgumentException(
  154. sprintf('Should not be initialized when checking isset("%s")', $params[0])
  155. );
  156. });
  157. $this->assertTrue(isset($proxy->id));
  158. $this->assertTrue(isset($proxy->publicField));
  159. $this->assertTrue(isset($proxy->test));
  160. $this->assertFalse(isset($proxy->nonExisting));
  161. $this->assertSame(3, $counter);
  162. }
  163. public function testInheritedMagicClone()
  164. {
  165. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\MagicCloneClass');
  166. $proxy = new $proxyClassName(
  167. null,
  168. function ($proxy) {
  169. $proxy->cloned = true;
  170. }
  171. );
  172. $cloned = clone $proxy;
  173. $this->assertSame('newClonedValue', $cloned->clonedValue);
  174. $this->assertFalse($proxy->cloned);
  175. $this->assertTrue($cloned->cloned);
  176. }
  177. /**
  178. * @group DCOM-175
  179. */
  180. public function testClonesPrivateProperties()
  181. {
  182. $proxyClassName = $this->generateProxyClass(__NAMESPACE__ . '\\SerializedClass');
  183. /* @var $proxy SerializedClass */
  184. $proxy = new $proxyClassName();
  185. $proxy->setFoo(1);
  186. $proxy->setBar(2);
  187. $proxy->setBaz(3);
  188. $unserialized = unserialize(serialize($proxy));
  189. $this->assertSame(1, $unserialized->getFoo());
  190. $this->assertSame(2, $unserialized->getBar());
  191. $this->assertSame(3, $unserialized->getBaz());
  192. }
  193. /**
  194. * @param $className
  195. *
  196. * @return string
  197. */
  198. private function generateProxyClass($className)
  199. {
  200. $proxyClassName = 'Doctrine\\Tests\\Common\\Proxy\\MagicMethodProxy\\__CG__\\' . $className;
  201. if (class_exists($proxyClassName, false)) {
  202. return $proxyClassName;
  203. }
  204. $metadata = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
  205. $metadata
  206. ->expects($this->any())
  207. ->method('getName')
  208. ->will($this->returnValue($className));
  209. $metadata
  210. ->expects($this->any())
  211. ->method('getIdentifier')
  212. ->will($this->returnValue(array('id')));
  213. $metadata
  214. ->expects($this->any())
  215. ->method('getReflectionClass')
  216. ->will($this->returnValue(new ReflectionClass($className)));
  217. $metadata
  218. ->expects($this->any())
  219. ->method('isIdentifier')
  220. ->will($this->returnCallback(function ($fieldName) {
  221. return 'id' === $fieldName;
  222. }));
  223. $metadata
  224. ->expects($this->any())
  225. ->method('hasField')
  226. ->will($this->returnCallback(function ($fieldName) {
  227. return in_array($fieldName, array('id', 'publicField'));
  228. }));
  229. $metadata
  230. ->expects($this->any())
  231. ->method('hasAssociation')
  232. ->will($this->returnValue(false));
  233. $metadata
  234. ->expects($this->any())
  235. ->method('getFieldNames')
  236. ->will($this->returnValue(array('id', 'publicField')));
  237. $metadata
  238. ->expects($this->any())
  239. ->method('getIdentifierFieldNames')
  240. ->will($this->returnValue(array('id')));
  241. $metadata
  242. ->expects($this->any())
  243. ->method('getAssociationNames')
  244. ->will($this->returnValue(array()));
  245. $metadata
  246. ->expects($this->any())
  247. ->method('getTypeOfField')
  248. ->will($this->returnValue('string'));
  249. $this->proxyGenerator->generateProxyClass($metadata, $this->proxyGenerator->getProxyFileName($className));
  250. require_once $this->proxyGenerator->getProxyFileName($className);
  251. return $proxyClassName;
  252. }
  253. }