Implemented service provider functionality
This commit is contained in:
parent
783c58611a
commit
d49e49c364
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Application config
|
||||||
|
|
||||||
|
return [
|
||||||
|
// Service providers
|
||||||
|
'providers' => [
|
||||||
|
],
|
||||||
|
];
|
|
@ -26,6 +26,13 @@ require_once __DIR__ . '/autoload.php';
|
||||||
$app = new Application(realpath(__DIR__ . DIRECTORY_SEPARATOR . '..'));
|
$app = new Application(realpath(__DIR__ . DIRECTORY_SEPARATOR . '..'));
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap application
|
||||||
|
*/
|
||||||
|
$appConfig = $app->make(Config::class);
|
||||||
|
$appConfig->set(app('path.config') . '/app.php');
|
||||||
|
$app->bootstrap($appConfig);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load configuration
|
* Load configuration
|
||||||
*/
|
*/
|
||||||
|
@ -40,6 +47,10 @@ if (file_exists(__DIR__ . '/../config/config.php')) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure application
|
||||||
|
*/
|
||||||
date_default_timezone_set($config->get('timezone'));
|
date_default_timezone_set($config->get('timezone'));
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +66,7 @@ $app->instance('request', $request);
|
||||||
/**
|
/**
|
||||||
* Check for maintenance
|
* Check for maintenance
|
||||||
*/
|
*/
|
||||||
if ($config->get('maintenance')) {
|
if ($app->get('config')->get('maintenance')) {
|
||||||
echo file_get_contents(__DIR__ . '/../templates/maintenance.html');
|
echo file_get_contents(__DIR__ . '/../templates/maintenance.html');
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ function gettext_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
gettext_locale();
|
gettext_locale();
|
||||||
bindtextdomain('default', realpath(__DIR__ . '/../../locale'));
|
bindtextdomain('default', app('path.lang'));
|
||||||
bind_textdomain_codeset('default', 'UTF-8');
|
bind_textdomain_codeset('default', 'UTF-8');
|
||||||
textdomain('default');
|
textdomain('default');
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
namespace Engelsystem;
|
namespace Engelsystem;
|
||||||
|
|
||||||
|
use Engelsystem\Config\Config;
|
||||||
use Engelsystem\Container\Container;
|
use Engelsystem\Container\Container;
|
||||||
|
use Engelsystem\Container\ServiceProvider;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
class Application extends Container
|
class Application extends Container
|
||||||
|
@ -10,6 +12,16 @@ class Application extends Container
|
||||||
/** @var string|null */
|
/** @var string|null */
|
||||||
protected $appPath = null;
|
protected $appPath = null;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
protected $isBootstrapped = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered service providers
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $serviceProviders = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application constructor.
|
* Application constructor.
|
||||||
*
|
*
|
||||||
|
@ -36,15 +48,73 @@ class Application extends Container
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param string|ServiceProvider $provider
|
||||||
|
* @return ServiceProvider
|
||||||
|
*/
|
||||||
|
public function register($provider)
|
||||||
|
{
|
||||||
|
if (is_string($provider)) {
|
||||||
|
$provider = $this->get($provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->serviceProviders[] = $provider;
|
||||||
|
|
||||||
|
$provider->register();
|
||||||
|
|
||||||
|
if ($this->isBootstrapped) {
|
||||||
|
$this->call([$provider, 'boot']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boot service providers
|
||||||
|
*
|
||||||
|
* @param Config|null $config
|
||||||
|
*/
|
||||||
|
public function bootstrap(Config $config = null)
|
||||||
|
{
|
||||||
|
if ($this->isBootstrapped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config instanceof Config) {
|
||||||
|
foreach ($config->get('providers', []) as $provider) {
|
||||||
|
$this->register($provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->serviceProviders as $provider) {
|
||||||
|
$this->call([$provider, 'boot']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->isBootstrapped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerPaths()
|
||||||
|
{
|
||||||
|
$appPath = $this->appPath;
|
||||||
|
|
||||||
|
$this->instance('path', $appPath);
|
||||||
|
$this->instance('path.config', $appPath . DIRECTORY_SEPARATOR . 'config');
|
||||||
|
$this->instance('path.lang', $appPath . DIRECTORY_SEPARATOR . 'locale');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set app base path
|
||||||
|
*
|
||||||
* @param string $appPath
|
* @param string $appPath
|
||||||
* @return static
|
* @return static
|
||||||
*/
|
*/
|
||||||
public function setAppPath($appPath)
|
public function setAppPath($appPath)
|
||||||
{
|
{
|
||||||
|
$appPath = realpath($appPath);
|
||||||
$appPath = rtrim($appPath, DIRECTORY_SEPARATOR);
|
$appPath = rtrim($appPath, DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
$this->appPath = $appPath;
|
$this->appPath = $appPath;
|
||||||
$this->instance('path', $appPath);
|
|
||||||
|
$this->registerPaths();
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -56,4 +126,12 @@ class Application extends Container
|
||||||
{
|
{
|
||||||
return $this->appPath;
|
return $this->appPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isBooted()
|
||||||
|
{
|
||||||
|
return $this->isBootstrapped;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Container;
|
||||||
|
|
||||||
|
use Engelsystem\Application;
|
||||||
|
|
||||||
|
abstract class ServiceProvider
|
||||||
|
{
|
||||||
|
/** @var Application */
|
||||||
|
protected $app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServiceProvider constructor.
|
||||||
|
*
|
||||||
|
* @param Application $app
|
||||||
|
*/
|
||||||
|
public function __construct(Application $app)
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register container bindings
|
||||||
|
*/
|
||||||
|
public function register() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after other services had been registered
|
||||||
|
*/
|
||||||
|
public function boot() { }
|
||||||
|
}
|
|
@ -23,6 +23,15 @@ function app($id = null)
|
||||||
return Application::getInstance()->get($id);
|
return Application::getInstance()->get($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function base_path($path = '')
|
||||||
|
{
|
||||||
|
return app('path') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get or set config values
|
* Get or set config values
|
||||||
*
|
*
|
||||||
|
@ -46,6 +55,15 @@ function config($key = null, $default = null)
|
||||||
return $config->get($key, $default);
|
return $config->get($key, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function config_path($path = '')
|
||||||
|
{
|
||||||
|
return app('path.config') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param mixed $default
|
* @param mixed $default
|
||||||
|
@ -78,22 +96,6 @@ function session($key = null, $default = null)
|
||||||
return $session->get($key, $default);
|
return $session->get($key, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $template
|
|
||||||
* @param mixed[] $data
|
|
||||||
* @return Renderer|string
|
|
||||||
*/
|
|
||||||
function view($template = null, $data = null)
|
|
||||||
{
|
|
||||||
$renderer = app('renderer');
|
|
||||||
|
|
||||||
if (is_null($template)) {
|
|
||||||
return $renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $renderer->render($template, $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param array $parameters
|
* @param array $parameters
|
||||||
|
@ -109,3 +111,19 @@ function url($path = null, $parameters = [])
|
||||||
|
|
||||||
return $urlGenerator->to($path, $parameters);
|
return $urlGenerator->to($path, $parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $template
|
||||||
|
* @param mixed[] $data
|
||||||
|
* @return Renderer|string
|
||||||
|
*/
|
||||||
|
function view($template = null, $data = null)
|
||||||
|
{
|
||||||
|
$renderer = app('renderer');
|
||||||
|
|
||||||
|
if (is_null($template)) {
|
||||||
|
return $renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $renderer->render($template, $data);
|
||||||
|
}
|
||||||
|
|
|
@ -3,19 +3,23 @@
|
||||||
namespace Engelsystem\Test\Config;
|
namespace Engelsystem\Test\Config;
|
||||||
|
|
||||||
use Engelsystem\Application;
|
use Engelsystem\Application;
|
||||||
|
use Engelsystem\Config\Config;
|
||||||
use Engelsystem\Container\Container;
|
use Engelsystem\Container\Container;
|
||||||
|
use Engelsystem\Container\ServiceProvider;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PHPUnit_Framework_MockObject_MockObject;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
use ReflectionClass;
|
||||||
|
|
||||||
class ApplicationTest extends TestCase
|
class ApplicationTest extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Application::__construct
|
* @covers \Engelsystem\Application::__construct
|
||||||
* @covers \Engelsystem\Application::registerBaseBindings
|
* @covers \Engelsystem\Application::registerBaseBindings
|
||||||
*/
|
*/
|
||||||
public function testConstructor()
|
public function testConstructor()
|
||||||
{
|
{
|
||||||
$app = new Application();
|
$app = new Application('.');
|
||||||
|
|
||||||
$this->assertInstanceOf(Container::class, $app);
|
$this->assertInstanceOf(Container::class, $app);
|
||||||
$this->assertInstanceOf(ContainerInterface::class, $app);
|
$this->assertInstanceOf(ContainerInterface::class, $app);
|
||||||
|
@ -27,4 +31,141 @@ class ApplicationTest extends TestCase
|
||||||
$this->assertSame($app, Application::getInstance());
|
$this->assertSame($app, Application::getInstance());
|
||||||
$this->assertSame($app, Container::getInstance());
|
$this->assertSame($app, Container::getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Application::setAppPath
|
||||||
|
* @covers \Engelsystem\Application::registerPaths
|
||||||
|
* @covers \Engelsystem\Application::path
|
||||||
|
*/
|
||||||
|
public function testAppPath()
|
||||||
|
{
|
||||||
|
$app = new Application();
|
||||||
|
|
||||||
|
$this->assertFalse($app->has('path'));
|
||||||
|
|
||||||
|
$app->setAppPath('.');
|
||||||
|
$this->assertTrue($app->has('path'));
|
||||||
|
$this->assertTrue($app->has('path.config'));
|
||||||
|
$this->assertTrue($app->has('path.lang'));
|
||||||
|
|
||||||
|
$this->assertEquals(realpath('.'), $app->path());
|
||||||
|
$this->assertEquals(realpath('.') . '/config', $app->get('path.config'));
|
||||||
|
|
||||||
|
$app->setAppPath('./../');
|
||||||
|
$this->assertEquals(realpath('../') . '/config', $app->get('path.config'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Application::register
|
||||||
|
*/
|
||||||
|
public function testRegister()
|
||||||
|
{
|
||||||
|
$app = new Application();
|
||||||
|
|
||||||
|
$serviceProvider = $this->mockServiceProvider($app, ['register']);
|
||||||
|
$serviceProvider->expects($this->once())
|
||||||
|
->method('register');
|
||||||
|
|
||||||
|
$app->register($serviceProvider);
|
||||||
|
|
||||||
|
$anotherServiceProvider = $this->mockServiceProvider($app, ['register', 'boot']);
|
||||||
|
$anotherServiceProvider->expects($this->once())
|
||||||
|
->method('register');
|
||||||
|
$anotherServiceProvider->expects($this->once())
|
||||||
|
->method('boot');
|
||||||
|
|
||||||
|
$app->bootstrap();
|
||||||
|
$app->register($anotherServiceProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Application::register
|
||||||
|
*/
|
||||||
|
public function testRegisterBoot()
|
||||||
|
{
|
||||||
|
$app = new Application();
|
||||||
|
$app->bootstrap();
|
||||||
|
|
||||||
|
$serviceProvider = $this->mockServiceProvider($app, ['register', 'boot']);
|
||||||
|
$serviceProvider->expects($this->once())
|
||||||
|
->method('register');
|
||||||
|
$serviceProvider->expects($this->once())
|
||||||
|
->method('boot');
|
||||||
|
|
||||||
|
$app->register($serviceProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Application::register
|
||||||
|
*/
|
||||||
|
public function testRegisterClassName()
|
||||||
|
{
|
||||||
|
$app = new Application();
|
||||||
|
|
||||||
|
$mockClassName = $this->getMockClass(ServiceProvider::class);
|
||||||
|
$serviceProvider = $this->getMockBuilder($mockClassName)
|
||||||
|
->setConstructorArgs([$app])
|
||||||
|
->setMethods(['register'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$serviceProvider->expects($this->once())
|
||||||
|
->method('register');
|
||||||
|
|
||||||
|
$app->instance($mockClassName, $serviceProvider);
|
||||||
|
$app->register($mockClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Application::bootstrap
|
||||||
|
* @covers \Engelsystem\Application::isBooted
|
||||||
|
*/
|
||||||
|
public function testBootstrap()
|
||||||
|
{
|
||||||
|
/** @var PHPUnit_Framework_MockObject_MockObject|Application $app */
|
||||||
|
$app = $this->getMockBuilder(Application::class)
|
||||||
|
->setMethods(['register'])
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$serviceProvider = $this->mockServiceProvider($app, ['boot']);
|
||||||
|
$serviceProvider->expects($this->once())
|
||||||
|
->method('boot');
|
||||||
|
|
||||||
|
$app->expects($this->once())
|
||||||
|
->method('register')
|
||||||
|
->with($serviceProvider);
|
||||||
|
|
||||||
|
$config = $this->getMockBuilder(Config::class)
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$config->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with('providers')
|
||||||
|
->willReturn([$serviceProvider]);
|
||||||
|
|
||||||
|
$property = (new ReflectionClass($app))->getProperty('serviceProviders');
|
||||||
|
$property->setAccessible(true);
|
||||||
|
$property->setValue($app, [$serviceProvider]);
|
||||||
|
|
||||||
|
$app->bootstrap($config);
|
||||||
|
|
||||||
|
$this->assertTrue($app->isBooted());
|
||||||
|
|
||||||
|
// Run bootstrap another time to ensure that providers are registered only once
|
||||||
|
$app->bootstrap($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Application $app
|
||||||
|
* @param array $methods
|
||||||
|
* @return PHPUnit_Framework_MockObject_MockObject|ServiceProvider
|
||||||
|
*/
|
||||||
|
protected function mockServiceProvider(Application $app, $methods = [])
|
||||||
|
{
|
||||||
|
$serviceProvider = $this->getMockBuilder(ServiceProvider::class)
|
||||||
|
->setConstructorArgs([$app])
|
||||||
|
->setMethods($methods)
|
||||||
|
->getMockForAbstractClass();
|
||||||
|
|
||||||
|
return $serviceProvider;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue