ResolvingCallbackTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <?php
  2. namespace Illuminate\Tests\Container;
  3. use Illuminate\Container\Container;
  4. use PHPUnit\Framework\TestCase;
  5. use stdClass;
  6. class ResolvingCallbackTest extends TestCase
  7. {
  8. public function testResolvingCallbacksAreCalledForSpecificAbstracts()
  9. {
  10. $container = new Container;
  11. $container->resolving('foo', function ($object) {
  12. return $object->name = 'taylor';
  13. });
  14. $container->bind('foo', function () {
  15. return new stdClass;
  16. });
  17. $instance = $container->make('foo');
  18. $this->assertSame('taylor', $instance->name);
  19. }
  20. public function testResolvingCallbacksAreCalled()
  21. {
  22. $container = new Container;
  23. $container->resolving(function ($object) {
  24. return $object->name = 'taylor';
  25. });
  26. $container->bind('foo', function () {
  27. return new stdClass;
  28. });
  29. $instance = $container->make('foo');
  30. $this->assertSame('taylor', $instance->name);
  31. }
  32. public function testResolvingCallbacksAreCalledForType()
  33. {
  34. $container = new Container;
  35. $container->resolving(stdClass::class, function ($object) {
  36. return $object->name = 'taylor';
  37. });
  38. $container->bind('foo', function () {
  39. return new stdClass;
  40. });
  41. $instance = $container->make('foo');
  42. $this->assertSame('taylor', $instance->name);
  43. }
  44. public function testResolvingCallbacksShouldBeFiredWhenCalledWithAliases()
  45. {
  46. $container = new Container;
  47. $container->alias(stdClass::class, 'std');
  48. $container->resolving('std', function ($object) {
  49. return $object->name = 'taylor';
  50. });
  51. $container->bind('foo', function () {
  52. return new stdClass;
  53. });
  54. $instance = $container->make('foo');
  55. $this->assertSame('taylor', $instance->name);
  56. }
  57. public function testResolvingCallbacksAreCalledOnceForImplementation()
  58. {
  59. $container = new Container;
  60. $callCounter = 0;
  61. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  62. $callCounter++;
  63. });
  64. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  65. $container->make(ResolvingImplementationStub::class);
  66. $this->assertEquals(1, $callCounter);
  67. $container->make(ResolvingImplementationStub::class);
  68. $this->assertEquals(2, $callCounter);
  69. }
  70. public function testGlobalResolvingCallbacksAreCalledOnceForImplementation()
  71. {
  72. $container = new Container;
  73. $callCounter = 0;
  74. $container->resolving(function () use (&$callCounter) {
  75. $callCounter++;
  76. });
  77. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  78. $container->make(ResolvingImplementationStub::class);
  79. $this->assertEquals(1, $callCounter);
  80. $container->make(ResolvingContractStub::class);
  81. $this->assertEquals(2, $callCounter);
  82. }
  83. public function testResolvingCallbacksAreCalledOnceForSingletonConcretes()
  84. {
  85. $container = new Container;
  86. $callCounter = 0;
  87. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  88. $callCounter++;
  89. });
  90. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  91. $container->bind(ResolvingImplementationStub::class);
  92. $container->make(ResolvingImplementationStub::class);
  93. $this->assertEquals(1, $callCounter);
  94. $container->make(ResolvingImplementationStub::class);
  95. $this->assertEquals(2, $callCounter);
  96. $container->make(ResolvingContractStub::class);
  97. $this->assertEquals(3, $callCounter);
  98. }
  99. public function testResolvingCallbacksCanStillBeAddedAfterTheFirstResolution()
  100. {
  101. $container = new Container;
  102. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  103. $container->make(ResolvingImplementationStub::class);
  104. $callCounter = 0;
  105. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  106. $callCounter++;
  107. });
  108. $container->make(ResolvingImplementationStub::class);
  109. $this->assertEquals(1, $callCounter);
  110. }
  111. public function testResolvingCallbacksAreCanceledWhenInterfaceGetsBoundToSomeOtherConcrete()
  112. {
  113. $container = new Container;
  114. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  115. $callCounter = 0;
  116. $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) {
  117. $callCounter++;
  118. });
  119. $container->make(ResolvingContractStub::class);
  120. $this->assertEquals(1, $callCounter);
  121. $container->bind(ResolvingContractStub::class, ResolvingImplementationStubTwo::class);
  122. $container->make(ResolvingContractStub::class);
  123. $this->assertEquals(1, $callCounter);
  124. }
  125. public function testResolvingCallbacksAreCalledOnceForStringAbstractions()
  126. {
  127. $container = new Container;
  128. $callCounter = 0;
  129. $container->resolving('foo', function () use (&$callCounter) {
  130. $callCounter++;
  131. });
  132. $container->bind('foo', ResolvingImplementationStub::class);
  133. $container->make('foo');
  134. $this->assertEquals(1, $callCounter);
  135. $container->make('foo');
  136. $this->assertEquals(2, $callCounter);
  137. }
  138. public function testResolvingCallbacksForConcretesAreCalledOnceForStringAbstractions()
  139. {
  140. $container = new Container;
  141. $callCounter = 0;
  142. $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) {
  143. $callCounter++;
  144. });
  145. $container->bind('foo', ResolvingImplementationStub::class);
  146. $container->bind('bar', ResolvingImplementationStub::class);
  147. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  148. $container->make(ResolvingImplementationStub::class);
  149. $this->assertEquals(1, $callCounter);
  150. $container->make('foo');
  151. $this->assertEquals(2, $callCounter);
  152. $container->make('bar');
  153. $this->assertEquals(3, $callCounter);
  154. $container->make(ResolvingContractStub::class);
  155. $this->assertEquals(4, $callCounter);
  156. }
  157. public function testResolvingCallbacksAreCalledOnceForImplementation2()
  158. {
  159. $container = new Container;
  160. $callCounter = 0;
  161. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  162. $callCounter++;
  163. });
  164. $container->bind(ResolvingContractStub::class, function () {
  165. return new ResolvingImplementationStub;
  166. });
  167. $container->make(ResolvingContractStub::class);
  168. $this->assertEquals(1, $callCounter);
  169. $container->make(ResolvingImplementationStub::class);
  170. $this->assertEquals(2, $callCounter);
  171. $container->make(ResolvingImplementationStub::class);
  172. $this->assertEquals(3, $callCounter);
  173. $container->make(ResolvingContractStub::class);
  174. $this->assertEquals(4, $callCounter);
  175. }
  176. public function testRebindingDoesNotAffectResolvingCallbacks()
  177. {
  178. $container = new Container;
  179. $callCounter = 0;
  180. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  181. $callCounter++;
  182. });
  183. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  184. $container->bind(ResolvingContractStub::class, function () {
  185. return new ResolvingImplementationStub;
  186. });
  187. $container->make(ResolvingContractStub::class);
  188. $this->assertEquals(1, $callCounter);
  189. $container->make(ResolvingImplementationStub::class);
  190. $this->assertEquals(2, $callCounter);
  191. $container->make(ResolvingImplementationStub::class);
  192. $this->assertEquals(3, $callCounter);
  193. $container->make(ResolvingContractStub::class);
  194. $this->assertEquals(4, $callCounter);
  195. }
  196. public function testParametersPassedIntoResolvingCallbacks()
  197. {
  198. $container = new Container;
  199. $container->resolving(ResolvingContractStub::class, function ($obj, $app) use ($container) {
  200. $this->assertInstanceOf(ResolvingContractStub::class, $obj);
  201. $this->assertInstanceOf(ResolvingImplementationStubTwo::class, $obj);
  202. $this->assertSame($container, $app);
  203. });
  204. $container->afterResolving(ResolvingContractStub::class, function ($obj, $app) use ($container) {
  205. $this->assertInstanceOf(ResolvingContractStub::class, $obj);
  206. $this->assertInstanceOf(ResolvingImplementationStubTwo::class, $obj);
  207. $this->assertSame($container, $app);
  208. });
  209. $container->afterResolving(function ($obj, $app) use ($container) {
  210. $this->assertInstanceOf(ResolvingContractStub::class, $obj);
  211. $this->assertInstanceOf(ResolvingImplementationStubTwo::class, $obj);
  212. $this->assertSame($container, $app);
  213. });
  214. $container->bind(ResolvingContractStub::class, ResolvingImplementationStubTwo::class);
  215. $container->make(ResolvingContractStub::class);
  216. }
  217. public function testResolvingCallbacksAreCallWhenRebindHappenForResolvedAbstract()
  218. {
  219. $container = new Container;
  220. $callCounter = 0;
  221. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  222. $callCounter++;
  223. });
  224. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  225. $container->make(ResolvingContractStub::class);
  226. $this->assertEquals(1, $callCounter);
  227. $container->bind(ResolvingContractStub::class, ResolvingImplementationStubTwo::class);
  228. $this->assertEquals(2, $callCounter);
  229. $container->make(ResolvingImplementationStubTwo::class);
  230. $this->assertEquals(3, $callCounter);
  231. $container->bind(ResolvingContractStub::class, function () {
  232. return new ResolvingImplementationStubTwo;
  233. });
  234. $this->assertEquals(4, $callCounter);
  235. $container->make(ResolvingContractStub::class);
  236. $this->assertEquals(5, $callCounter);
  237. }
  238. public function testRebindingDoesNotAffectMultipleResolvingCallbacks()
  239. {
  240. $container = new Container;
  241. $callCounter = 0;
  242. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  243. $callCounter++;
  244. });
  245. $container->resolving(ResolvingImplementationStubTwo::class, function () use (&$callCounter) {
  246. $callCounter++;
  247. });
  248. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  249. // it should call the callback for interface
  250. $container->make(ResolvingContractStub::class);
  251. $this->assertEquals(1, $callCounter);
  252. // it should call the callback for interface
  253. $container->make(ResolvingImplementationStub::class);
  254. $this->assertEquals(2, $callCounter);
  255. // should call the callback for the interface it implements
  256. // plus the callback for ResolvingImplementationStubTwo.
  257. $container->make(ResolvingImplementationStubTwo::class);
  258. $this->assertEquals(4, $callCounter);
  259. }
  260. public function testResolvingCallbacksAreCalledForInterfaces()
  261. {
  262. $container = new Container;
  263. $callCounter = 0;
  264. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  265. $callCounter++;
  266. });
  267. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  268. $container->make(ResolvingContractStub::class);
  269. $this->assertEquals(1, $callCounter);
  270. }
  271. public function testResolvingCallbacksAreCalledForConcretesWhenAttachedOnInterface()
  272. {
  273. $container = new Container;
  274. $callCounter = 0;
  275. $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) {
  276. $callCounter++;
  277. });
  278. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  279. $container->make(ResolvingContractStub::class);
  280. $this->assertEquals(1, $callCounter);
  281. $container->make(ResolvingImplementationStub::class);
  282. $this->assertEquals(2, $callCounter);
  283. }
  284. public function testResolvingCallbacksAreCalledForConcretesWhenAttachedOnConcretes()
  285. {
  286. $container = new Container;
  287. $callCounter = 0;
  288. $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) {
  289. $callCounter++;
  290. });
  291. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  292. $container->make(ResolvingContractStub::class);
  293. $this->assertEquals(1, $callCounter);
  294. $container->make(ResolvingImplementationStub::class);
  295. $this->assertEquals(2, $callCounter);
  296. }
  297. public function testResolvingCallbacksAreCalledForConcretesWithNoBinding()
  298. {
  299. $container = new Container;
  300. $callCounter = 0;
  301. $container->resolving(ResolvingImplementationStub::class, function () use (&$callCounter) {
  302. $callCounter++;
  303. });
  304. $container->make(ResolvingImplementationStub::class);
  305. $this->assertEquals(1, $callCounter);
  306. $container->make(ResolvingImplementationStub::class);
  307. $this->assertEquals(2, $callCounter);
  308. }
  309. public function testResolvingCallbacksAreCalledForInterFacesWithNoBinding()
  310. {
  311. $container = new Container;
  312. $callCounter = 0;
  313. $container->resolving(ResolvingContractStub::class, function () use (&$callCounter) {
  314. $callCounter++;
  315. });
  316. $container->make(ResolvingImplementationStub::class);
  317. $this->assertEquals(1, $callCounter);
  318. $container->make(ResolvingImplementationStub::class);
  319. $this->assertEquals(2, $callCounter);
  320. }
  321. public function testAfterResolvingCallbacksAreCalledOnceForImplementation()
  322. {
  323. $container = new Container;
  324. $callCounter = 0;
  325. $container->afterResolving(ResolvingContractStub::class, function () use (&$callCounter) {
  326. $callCounter++;
  327. });
  328. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  329. $container->make(ResolvingImplementationStub::class);
  330. $this->assertEquals(1, $callCounter);
  331. $container->make(ResolvingContractStub::class);
  332. $this->assertEquals(2, $callCounter);
  333. }
  334. public function testBeforeResolvingCallbacksAreCalled()
  335. {
  336. // Given a call counter initialized to zero.
  337. $container = new Container;
  338. $callCounter = 0;
  339. // And a contract/implementation stub binding.
  340. $container->bind(ResolvingContractStub::class, ResolvingImplementationStub::class);
  341. // When we add a before resolving callback that increment the counter by one.
  342. $container->beforeResolving(ResolvingContractStub::class, function () use (&$callCounter) {
  343. $callCounter++;
  344. });
  345. // Then resolving the implementation stub increases the counter by one.
  346. $container->make(ResolvingImplementationStub::class);
  347. $this->assertEquals(1, $callCounter);
  348. // And resolving the contract stub increases the counter by one.
  349. $container->make(ResolvingContractStub::class);
  350. $this->assertEquals(2, $callCounter);
  351. }
  352. public function testGlobalBeforeResolvingCallbacksAreCalled()
  353. {
  354. // Given a call counter initialized to zero.
  355. $container = new Container;
  356. $callCounter = 0;
  357. // When we add a global before resolving callback that increment that counter by one.
  358. $container->beforeResolving(function () use (&$callCounter) {
  359. $callCounter++;
  360. });
  361. // Then resolving anything increases the counter by one.
  362. $container->make(ResolvingImplementationStub::class);
  363. $this->assertEquals(1, $callCounter);
  364. }
  365. }
  366. interface ResolvingContractStub
  367. {
  368. //
  369. }
  370. class ResolvingImplementationStub implements ResolvingContractStub
  371. {
  372. //
  373. }
  374. class ResolvingImplementationStubTwo implements ResolvingContractStub
  375. {
  376. //
  377. }