Skip to content

Commit

Permalink
Add missing tests for the resolving callbacks on the container
Browse files Browse the repository at this point in the history
+ bug fix related to multiple calls to resolving callbacks
  • Loading branch information
imanghafoori1 committed Dec 31, 2018
1 parent d329797 commit a002637
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 4 deletions.
13 changes: 9 additions & 4 deletions src/Illuminate/Container/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ class Container implements ArrayAccess, ContainerContract
*/
protected $afterResolvingCallbacks = [];

public $declaredAsClassName = [];

/**
* Define a contextual binding.
*
Expand Down Expand Up @@ -234,6 +236,7 @@ public function bind($abstract, $concrete = null, $shared = false)
// bound into this container to the abstract type and we will just wrap it
// up inside its own Closure to give us more convenience when extending.
if (! $concrete instanceof Closure) {
$this->declaredAsClassName[$abstract] = null;
$concrete = $this->getClosure($abstract, $concrete);
}

Expand Down Expand Up @@ -1011,9 +1014,11 @@ protected function fireResolvingCallbacks($abstract, $object)
{
$this->fireCallbackArray($object, $this->globalResolvingCallbacks);

$this->fireCallbackArray(
$object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks)
);
if (! interface_exists($abstract) || (interface_exists($abstract) && ! array_key_exists($abstract, $this->declaredAsClassName))) {
$this->fireCallbackArray(
$object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks)
);
}

$this->fireAfterResolvingCallbacks($abstract, $object);
}
Expand Down Expand Up @@ -1137,7 +1142,7 @@ public function forgetExtenders($abstract)
*/
protected function dropStaleInstances($abstract)
{
unset($this->instances[$abstract], $this->aliases[$abstract]);
unset($this->instances[$abstract], $this->aliases[$abstract], $this->declaredAsClassName[$abstract]);
}

/**
Expand Down
183 changes: 183 additions & 0 deletions tests/Container/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,189 @@ public function testResolvingCallbacksShouldBeFiredWhenCalledWithAliases()
$this->assertEquals('taylor', $instance->name);
}

public function testResolvingCallbacksAreCalledOnceForImplementation()
{
$container = new Container;

$callCounter = 0;
$container->resolving(IContainerContractStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, ContainerImplementationStub::class);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(1, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);
}

public function testResolvingCallbacksAreCalledOnceForImplementation2()
{
$container = new Container;

$callCounter = 0;
$container->resolving(IContainerContractStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, function () {
return new ContainerImplementationStub;
});

$container->make(IContainerContractStub::class);
$this->assertEquals(1, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(3, $callCounter);

$container->make(IContainerContractStub::class);
$this->assertEquals(4, $callCounter);
}

public function testRebindingDoesNotAffectResolvingCallbacks()
{
$container = new Container;

$callCounter = 0;
$container->resolving(IContainerContractStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, ContainerImplementationStub::class);
$container->bind(IContainerContractStub::class, function () {
return new ContainerImplementationStub;
});

$container->make(IContainerContractStub::class);
$this->assertEquals(1, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(3, $callCounter);

$container->make(IContainerContractStub::class);
$this->assertEquals(4, $callCounter);
}

public function testRebindingDoesNotAffectMultipleResolvingCallbacks()
{
$container = new Container;

$callCounter = 0;

$container->resolving(IContainerContractStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->resolving(ContainerImplementationStubTwo::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, ContainerImplementationStub::class);

// it should call the callback for interface
$container->make(IContainerContractStub::class);
$this->assertEquals(1, $callCounter);

// it should call the callback for interface
$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);

// should call the callback for the interface it implements
// plus the callback for ContainerImplementationStubTwo.
$container->make(ContainerImplementationStubTwo::class);
$this->assertEquals(4, $callCounter);
}

public function testResolvingCallbacksAreCalledForInterfaces()
{
$container = new Container;

$callCounter = 0;
$container->resolving(IContainerContractStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, ContainerImplementationStub::class);

$container->make(IContainerContractStub::class);

$this->assertEquals(1, $callCounter);
}

public function testResolvingCallbacksAreCalledForConcretesWhenAttachedOnInterface()
{
$container = new Container;

$callCounter = 0;
$container->resolving(ContainerImplementationStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, ContainerImplementationStub::class);

$container->make(IContainerContractStub::class);
$this->assertEquals(1, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);
}

public function testResolvingCallbacksAreCalledForConcretesWhenAttachedOnConcretes()
{
$container = new Container;

$callCounter = 0;
$container->resolving(ContainerImplementationStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->bind(IContainerContractStub::class, ContainerImplementationStub::class);

$container->make(IContainerContractStub::class);
$this->assertEquals(1, $callCounter);

$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);
}

public function testResolvingCallbacksAreCalledForConcretesWithNoBinding()
{
$container = new Container;

$callCounter = 0;
$container->resolving(ContainerImplementationStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->make(ContainerImplementationStub::class);
$this->assertEquals(1, $callCounter);
$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);
}

public function testResolvingCallbacksAreCalledForInterFacesWithNoBinding()
{
$container = new Container;

$callCounter = 0;
$container->resolving(IContainerContractStub::class, function ($some) use (&$callCounter) {
$callCounter++;
});

$container->make(ContainerImplementationStub::class);
$this->assertEquals(1, $callCounter);
$container->make(ContainerImplementationStub::class);
$this->assertEquals(2, $callCounter);
}

public function testMakeWithMethodIsAnAliasForMakeMethod()
{
$mock = $this->getMockBuilder(Container::class)
Expand Down

0 comments on commit a002637

Please sign in to comment.