Added service providers

This commit is contained in:
Igor Scheller 2017-10-31 13:40:13 +01:00
parent fb05a38a96
commit 60fd72cd1a
19 changed files with 573 additions and 83 deletions

View File

@ -5,5 +5,11 @@
return [ return [
// Service providers // Service providers
'providers' => [ 'providers' => [
\Engelsystem\Logger\LoggerServiceProvider::class,
\Engelsystem\Exceptions\ExceptionsServiceProvider::class,
\Engelsystem\Config\ConfigServiceProvider::class,
\Engelsystem\Routing\RoutingServiceProvider::class,
\Engelsystem\Renderer\RendererServiceProvider::class,
\Engelsystem\Database\DatabaseServiceProvider::class,
], ],
]; ];

View File

@ -6,4 +6,4 @@ if (!is_readable(__DIR__ . '/../vendor/autoload.php')) {
} }
// Include composer autoloader // Include composer autoloader
require_once __DIR__ . '/../vendor/autoload.php'; $loader = require __DIR__ . '/../vendor/autoload.php';

View File

@ -2,14 +2,8 @@
use Engelsystem\Application; use Engelsystem\Application;
use Engelsystem\Config\Config; use Engelsystem\Config\Config;
use Engelsystem\Database\Db;
use Engelsystem\Exceptions\Handler as ExceptionHandler; use Engelsystem\Exceptions\Handler as ExceptionHandler;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Logger\EngelsystemLogger;
use Engelsystem\Renderer\HtmlEngine;
use Engelsystem\Renderer\Renderer;
use Engelsystem\Routing\UrlGenerator;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
@ -21,46 +15,27 @@ require_once __DIR__ . '/autoload.php';
/** /**
* Initialize the application * Initialize and bootstrap the application
*/ */
$app = new Application(realpath(__DIR__ . DIRECTORY_SEPARATOR . '..')); $app = new Application(realpath(__DIR__ . DIRECTORY_SEPARATOR . '..'));
/**
* Bootstrap application
*/
$appConfig = $app->make(Config::class); $appConfig = $app->make(Config::class);
$appConfig->set(app('path.config') . '/app.php'); $appConfig->set(require config_path('app.php'));
$app->bootstrap($appConfig); $app->bootstrap($appConfig);
/**
* Load configuration
*/
$config = new Config();
$app->instance('config', $config);
$config->set(require __DIR__ . '/../config/config.default.php');
if (file_exists(__DIR__ . '/../config/config.php')) {
$config->set(array_replace_recursive(
$config->get(null),
require __DIR__ . '/../config/config.php'
));
}
/** /**
* Configure application * Configure application
*/ */
date_default_timezone_set($config->get('timezone')); date_default_timezone_set($app->get('config')->get('timezone'));
if (config('environment') == 'development') {
/** $errorHandler = $app->get('error.handler');
* Initialize Request $errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT);
* ini_set('display_errors', true);
* @var Request $request error_reporting(E_ALL);
*/ } else {
$request = Request::createFromGlobals(); ini_set('display_errors', false);
$app->instance('request', $request); }
/** /**
@ -73,52 +48,12 @@ if ($app->get('config')->get('maintenance')) {
/** /**
* Register UrlGenerator * Initialize Request
*
* @var Request $request
*/ */
$urlGenerator = new UrlGenerator(); $request = Request::createFromGlobals();
$app->instance('routing.urlGenerator', $urlGenerator); $app->instance('request', $request);
/**
* Initialize renderer
*/
$renderer = new Renderer();
$app->instance('renderer', $renderer);
$renderer->addRenderer(new HtmlEngine());
/**
* Register error handler
*/
$errorHandler = new ExceptionHandler();
$app->instance('error.handler', $errorHandler);
if (config('environment') == 'development') {
$errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT);
ini_set('display_errors', true);
error_reporting(E_ALL);
} else {
ini_set('display_errors', false);
}
/**
* Connect to database
*/
Db::connect(
'mysql:host=' . config('database')['host'] . ';dbname=' . config('database')['db'] . ';charset=utf8',
config('database')['user'],
config('database')['pw']
) || die('Error: Unable to connect to database');
Db::getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Db::getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
/**
* Init logger
*/
$logger = new EngelsystemLogger();
$app->instance('logger', $logger);
$app->bind(LoggerInterface::class, 'logger');
$app->bind(EngelsystemLogger::class, 'logger');
/** /**

View File

@ -54,7 +54,7 @@ class Application extends Container
public function register($provider) public function register($provider)
{ {
if (is_string($provider)) { if (is_string($provider)) {
$provider = $this->get($provider); $provider = $this->make($provider);
} }
$this->serviceProviders[] = $provider; $this->serviceProviders[] = $provider;

View File

@ -0,0 +1,26 @@
<?php
namespace Engelsystem\Config;
use Engelsystem\Container\ServiceProvider;
class ConfigServiceProvider extends ServiceProvider
{
public function register()
{
$defaultConfigFile = config_path('config.default.php');
$configFile = config_path('config.php');
$config = $this->app->make(Config::class);
$this->app->instance('config', $config);
$config->set(require $defaultConfigFile);
if (file_exists($configFile)) {
$config->set(array_replace_recursive(
$config->get(null),
require $configFile
));
}
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Engelsystem\Database;
use Engelsystem\Container\ServiceProvider;
use Exception;
use PDO;
class DatabaseServiceProvider extends ServiceProvider
{
public function register()
{
$config = $this->app->get('config');
Db::connect(
'mysql:host=' . $config->get('database')['host'] . ';dbname=' . $config->get('database')['db'] . ';charset=utf8',
$config->get('database')['user'],
$config->get('database')['pw']
) || $this->exitOnError();
Db::getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Db::getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
/**
* @throws Exception
*/
protected function exitOnError()
{
throw new Exception('Error: Unable to connect to database');
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Engelsystem\Exceptions;
use Engelsystem\Container\ServiceProvider;
use Engelsystem\Exceptions\Handler as ExceptionHandler;
class ExceptionsServiceProvider extends ServiceProvider
{
public function register()
{
$errorHandler = $this->app->make(ExceptionHandler::class);
$this->app->instance('error.handler', $errorHandler);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Engelsystem\Logger;
use Engelsystem\Container\ServiceProvider;
use Psr\Log\LoggerInterface;
class LoggerServiceProvider extends ServiceProvider
{
public function register()
{
$logger = $this->app->make(EngelsystemLogger::class);
$this->app->instance('logger', $logger);
$this->app->bind(LoggerInterface::class, 'logger');
$this->app->bind(EngelsystemLogger::class, 'logger');
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Engelsystem\Renderer;
use Engelsystem\Container\ServiceProvider;
class RendererServiceProvider extends ServiceProvider
{
public function register()
{
$this->registerRenderer();
$this->registerHtmlEngine();
}
public function boot()
{
$renderer = $this->app->get('renderer');
foreach ($this->app->tagged('renderer.engine') as $engine) {
$renderer->addRenderer($engine);
}
}
protected function registerRenderer()
{
$renderer = $this->app->make(Renderer::class);
$this->app->instance('renderer', $renderer);
}
protected function registerHtmlEngine()
{
$htmlEngine = $this->app->make(HtmlEngine::class);
$this->app->instance('renderer.htmlEngine', $htmlEngine);
$this->app->tag('renderer.htmlEngine', ['renderer.engine']);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Engelsystem\Routing;
use Engelsystem\Container\ServiceProvider;
class RoutingServiceProvider extends ServiceProvider
{
public function register()
{
$urlGenerator = $this->app->make(UrlGenerator::class);
$this->app->instance('routing.urlGenerator', $urlGenerator);
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace Engelsystem\Test\Database;
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Database\DatabaseServiceProvider;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
class DatabaseServiceProviderConnectionTest extends TestCase
{
/**
* @covers \Engelsystem\Database\DatabaseServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|Config $config */
$config = $this->getMockBuilder(Config::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
$app = $this->getMockBuilder(Application::class)
->setMethods(['get'])
->getMock();
Application::setInstance($app);
$app->expects($this->once())
->method('get')
->with('config')
->willReturn($config);
$config->expects($this->atLeastOnce())
->method('get')
->with('database')
->willReturn($this->getDbConfig());
$serviceProvider = new DatabaseServiceProvider($app);
$serviceProvider->register();
}
private function getDbConfig()
{
$configValues = require __DIR__ . '/../../../config/config.default.php';
$configFile = __DIR__ . '/../../../config/config.php';
if (file_exists($configFile)) {
$configValues = array_replace_recursive($configValues, require $configFile);
}
return $configValues['database'];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace Engelsystem\Test\Config;
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Config\ConfigServiceProvider;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
class ConfigServiceProviderTest extends TestCase
{
/**
* @covers \Engelsystem\Config\ConfigServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|Config $config */
$config = $this->getMockBuilder(Config::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
$app = $this->getMockBuilder(Application::class)
->setMethods(['make', 'instance', 'get'])
->getMock();
Application::setInstance($app);
$app->expects($this->once())
->method('make')
->with(Config::class)
->willReturn($config);
$app->expects($this->once())
->method('instance')
->with('config', $config);
$app->expects($this->atLeastOnce())
->method('get')
->with('path.config')
->willReturn(__DIR__ . '/../../../config');
$config->expects($this->exactly(2))
->method('set')
->withAnyParameters();
$config->expects($this->once())
->method('get')
->with(null)
->willReturn([]);
$serviceProvider = new ConfigServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Engelsystem\Test\Database;
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Database\DatabaseServiceProvider;
use Exception;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
class DatabaseServiceProviderTest extends TestCase
{
/**
* @covers \Engelsystem\Database\DatabaseServiceProvider::register()
* @covers \Engelsystem\Database\DatabaseServiceProvider::exitOnError()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|Config $config */
$config = $this->getMockBuilder(Config::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
$app = $this->getMockBuilder(Application::class)
->setMethods(['get'])
->getMock();
$app->expects($this->once())
->method('get')
->with('config')
->willReturn($config);
$config->expects($this->atLeastOnce())
->method('get')
->with('database')
->willReturn([
'host' => 'localhost',
'db' => 'database',
'user' => 'user',
'pw' => 'password',
]);
$serviceProvider = new DatabaseServiceProvider($app);
$this->expectException(Exception::class);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Engelsystem\Test\Exceptions;
use Engelsystem\Application;
use Engelsystem\Exceptions\ExceptionsServiceProvider;
use Engelsystem\Exceptions\Handler as ExceptionHandler;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
class ExceptionsServiceProviderTest extends TestCase
{
/**
* @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|ExceptionHandler $exceptionHandler */
$exceptionHandler = $this->getMockBuilder(ExceptionHandler::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
$app = $this->getMockBuilder(Application::class)
->setMethods(['make', 'instance'])
->getMock();
$app->expects($this->once())
->method('make')
->with(ExceptionHandler::class)
->willReturn($exceptionHandler);
$app->expects($this->once())
->method('instance')
->with('error.handler', $exceptionHandler);
$serviceProvider = new ExceptionsServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Engelsystem\Test\Logger;
use Engelsystem\Application;
use Engelsystem\Logger\EngelsystemLogger;
use Engelsystem\Logger\LoggerServiceProvider;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
use Psr\Log\LoggerInterface;
class LoggerServiceProviderTest extends TestCase
{
/**
* @covers \Engelsystem\Logger\LoggerServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|EngelsystemLogger $logger */
$logger = $this->getMockBuilder(EngelsystemLogger::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
$app = $this->getMockBuilder(Application::class)
->setMethods(['make', 'instance', 'bind'])
->getMock();
$app->expects($this->once())
->method('make')
->with(EngelsystemLogger::class)
->willReturn($logger);
$app->expects($this->once())
->method('instance')
->with('logger', $logger);
$app->expects($this->atLeastOnce())
->method('bind')
->withConsecutive(
[LoggerInterface::class, 'logger'],
[EngelsystemLogger::class, 'logger']
);
$serviceProvider = new LoggerServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace Engelsystem\Test\Logger;
use Engelsystem\Renderer\EngineInterface;
use Engelsystem\Renderer\HtmlEngine;
use Engelsystem\Renderer\Renderer;
use Engelsystem\Renderer\RendererServiceProvider;
use Engelsystem\Test\Unit\ServiceProviderTest;
use PHPUnit_Framework_MockObject_MockObject;
class RendererServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Renderer\RendererServiceProvider::register()
* @covers \Engelsystem\Renderer\RendererServiceProvider::registerRenderer()
* @covers \Engelsystem\Renderer\RendererServiceProvider::registerHtmlEngine()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|Renderer $renderer */
$renderer = $this->getMockBuilder(Renderer::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|HtmlEngine $htmlEngine */
$htmlEngine = $this->getMockBuilder(HtmlEngine::class)
->getMock();
$app = $this->getApp(['make', 'instance', 'tag']);
$app->expects($this->exactly(2))
->method('make')
->withConsecutive(
[Renderer::class],
[HtmlEngine::class]
)->willReturnOnConsecutiveCalls(
$renderer,
$htmlEngine
);
$app->expects($this->exactly(2))
->method('instance')
->withConsecutive(
['renderer', $renderer],
['renderer.htmlEngine', $htmlEngine]
);
$this->setExpects($app, 'tag', ['renderer.htmlEngine', ['renderer.engine']]);
$serviceProvider = new RendererServiceProvider($app);
$serviceProvider->register();
}
/**
* @covers \Engelsystem\Renderer\RendererServiceProvider::boot()
*/
public function testBoot()
{
/** @var PHPUnit_Framework_MockObject_MockObject|Renderer $renderer */
$renderer = $this->getMockBuilder(Renderer::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|EngineInterface $engine1 */
$engine1 = $this->getMockForAbstractClass(EngineInterface::class);
/** @var PHPUnit_Framework_MockObject_MockObject|EngineInterface $engine2 */
$engine2 = $this->getMockForAbstractClass(EngineInterface::class);
$app = $this->getApp(['get', 'tagged']);
$engines = [$engine1, $engine2];
$this->setExpects($app, 'get', ['renderer'], $renderer);
$this->setExpects($app, 'tagged', ['renderer.engine'], $engines);
$invocation = $renderer
->expects($this->exactly(count($engines)))
->method('addRenderer');
call_user_func_array([$invocation, 'withConsecutive'], $engines);
$serviceProvider = new RendererServiceProvider($app);
$serviceProvider->boot();
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Engelsystem\Test\Routing;
use Engelsystem\Application;
use Engelsystem\Routing\RoutingServiceProvider;
use Engelsystem\Routing\UrlGenerator;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
class RoutingServiceProviderTest extends TestCase
{
/**
* @covers \Engelsystem\Routing\RoutingServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|UrlGenerator $urlGenerator */
$urlGenerator = $this->getMockBuilder(UrlGenerator::class)
->getMock();
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
$app = $this->getMockBuilder(Application::class)
->setMethods(['make', 'instance'])
->getMock();
$app->expects($this->once())
->method('make')
->with(UrlGenerator::class)
->willReturn($urlGenerator);
$app->expects($this->once())
->method('instance')
->with('routing.urlGenerator', $urlGenerator);
$serviceProvider = new RoutingServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Engelsystem\Test\Unit;
use Engelsystem\Application;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
abstract class ServiceProviderTest extends TestCase
{
/**
* @param array $methods
* @return Application|PHPUnit_Framework_MockObject_MockObject
*/
protected function getApp($methods = ['make', 'instance'])
{
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
return $this->getMockBuilder(Application::class)
->setMethods($methods)
->getMock();
}
/**
* @param PHPUnit_Framework_MockObject_MockObject $object
* @param string $method
* @param array $arguments
* @param mixed $return
*/
protected function setExpects($object, $method, $arguments, $return = null)
{
$invocation = $object->expects($this->once())
->method($method);
call_user_func_array([$invocation, 'with'], $arguments);
if (!is_null($return)) {
$invocation->willReturn($return);
}
}
}

8
tests/autoload.php Normal file
View File

@ -0,0 +1,8 @@
<?php
use Composer\Autoload\ClassLoader;
require_once __DIR__ . '/../includes/autoload.php';
/** @var $loader ClassLoader */
$loader->addPsr4('Engelsystem\\Test\\', __DIR__ . '/');