…, using WhoopsRunFactory for creating WhoopsRun instance, added unit tests
I know this is a major change to your library and comes out of the blue, but I think this could gain some benefits. I'm curious about what you're saying. :)
In the last days I realized, that if I want to integrate franzliedke/whoops-middleware
in one of my projects I would have some problems. My desire is to use franzliedke/whoops-middleware
on development and production environment.
Because of that, I would need the ability to manipulate the creation of Whoops\Run
like in this code example from one of Whoops issues:
error_reporting(E_ALL);
$run = new \Whoops\Run;
if ($debug) {
$run->pushHandler(new \Whoops\Handler\PrettyPageHandler);
assert_options(ASSERT_ACTIVE, true);
} else {
$run->pushHandler(function($e){
$myApp->outputFriendlyError();
$myApp->sendDevEmail();
});
}
$run->register();
But this logic is inside of WhoopsRunner
and cannot be manipulate because of the static call of getWhoopsInstance
from the Middlewares.
So I started to rewrite a little bit to proof my ideas. More and more ideas came into my mind and I came up with a major refactoring. Here is the list of changes I made:
- Using dependency injection to inject components e.g.
WhoopsRunner
instead of calling static methods. This has the advantage to decouple the logic and simpler unit testing.
/**
* @param WhoopsRunner $whoopsRunner
*/
public function __construct(WhoopsRunner $whoopsRunner)
{
$this->whoopsRun = $whoopsRunner;
}
- To circumvent the dependency hell - if a library user wants to use the Middleware without worrying about the creation of
Whoops\Run
and doesn't use a DI-Framework - I added factory methods.
/**
* @return Middleware
*/
public static function createNewInstance()
{
return new Middleware(WhoopsRunner::createNewInstance());
}
- I splitted
WhoopsRunner
into to two sperate components WhoopsRunner
and WhoopsRunFactory
. WhoopsRunFactory
implements WhoopsRunFactoryInterface
which is now a dependency of WhoopsRunner
. WhoopsRunFactory
is responsible for creating instances of Whoops\Run
. Because of that a library user has the possibility to implement WhoopsRunFactoryInterface
on his own, to alter the creation of Whoops\Run
.
interface WhoopsRunFactoryInterface
{
/**
* @param ServerRequestInterface $request
* @return Run
*/
public function getWhoopsInstance(ServerRequestInterface $request);
}
- I wrote unit tests for every component and achieved a 100% code coverage. This needed a little bit of refactoring which is highly related to my the first item of this list. E.g. I implemented a
CliDetector
which is a dependency of WhoopsRunFactory
. It detects if the server api is equal to 'cli'. This gave me the ability to mock CliDetector
and test lines of code in WhoopsRunFactory
which otherwise I could't reach.
class CliDetector
{
/**
* @return bool
*/
public function isCli()
{
return php_sapi_name() === 'cli';
}
}
- To 'hide' components from the library user that are not part of the library interface I moved them into a
insides
directory.
I didn't add more than autogenerated PHPDoc and also didn't adjust the README. Before I would do that, I await your response.