Using pimple as my DI container, I have been bravely refactoring small classes to rely on DI injection, eliminating the hard-coded dependencies I could see would be easily removed.
My methodology for this task is very simple, but I have no clue if it is proper as I have very little experience with DI and Unit-testing aside from what I learned here in past month.
I created a class, ContainerFactory that subclasses pimple, and in that subclass have created methods that simply returns container for specific object.
The constructor calls the proper creator method depending on type:
function __construct($type=null, $mode = null){
if(isset($type)){
switch ($type) {
case 'DataFactory':
$this->buildDataFactoryContainer($mode);
break;
case 'DbConnect':
$this->buildDbConnectContainer($mode);
break;
default:
return false;
}
}
}
The method signature for container object creation is as follows:
public function buildDataFactoryContainer($mode=null)
The idea being that I can set $mode to test when calling this container, and have it load test values instead of actual runtime settings. I wanted to avoid writing separate container classes for testing, and this is an easy way I thought to not have test related code all over.
I could instead have subclassed ContainerFactory ie: ContainerFactoryTesting extends ContainerFactory
and override in that instead of mixing test code with app code and cluttering method signatures with $mode=null, but that is not the point of this post. Moving on, to create a container for a particular object, I simply do this:
// returns container with DataFactory dependencies, holds $db and $logger objects.
$dataFactoryContainer = new ContainerFactory('DataFactory');
// returns container with test settings.
$dataFactoryTestContainer = new ContainerFactory('DataFactory','test');
// returns container with DbConnect dependencies, holds dbconfig and $logger objects.
$dbConnectContainer = new ContainerFactory('DbConnect');
I just ran into an issue that makes me suspect that the strategy I am building upon is flawed.
Looking at the above, DataFactory contains $db object that holds database connections. I am now refactoring out this dbclass to remove its dependencies on a $registry object, but how will I create $dataFactoryContainer, when I add $db object that needs $dbConnectContainer?
For example, in datafactory container I add a dbconnect instance, but IT will now need a container passed to it ...
I realise my English is not that great and hope I have explained well enough for a fellow SO'er to understand.
My question is two-fold, how do you guys handle creating objects for dependencies that themselves contain dependencies, in a simple manner?
And .. how do you separate container configuration for creation of objects for testing purposes?
As always, any comment or link to relevant post appreciated.