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 . '..'));
|
||||
|
||||
|
||||
/**
|
||||
* Bootstrap application
|
||||
*/
|
||||
$appConfig = $app->make(Config::class);
|
||||
$appConfig->set(app('path.config') . '/app.php');
|
||||
$app->bootstrap($appConfig);
|
||||
|
||||
/**
|
||||
* Load configuration
|
||||
*/
|
||||
|
@ -40,6 +47,10 @@ if (file_exists(__DIR__ . '/../config/config.php')) {
|
|||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure application
|
||||
*/
|
||||
date_default_timezone_set($config->get('timezone'));
|
||||
|
||||
|
||||
|
@ -55,7 +66,7 @@ $app->instance('request', $request);
|
|||
/**
|
||||
* Check for maintenance
|
||||
*/
|
||||
if ($config->get('maintenance')) {
|
||||
if ($app->get('config')->get('maintenance')) {
|
||||
echo file_get_contents(__DIR__ . '/../templates/maintenance.html');
|
||||
die();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ function gettext_init()
|
|||
}
|
||||
|
||||
gettext_locale();
|
||||
bindtextdomain('default', realpath(__DIR__ . '/../../locale'));
|
||||
bindtextdomain('default', app('path.lang'));
|
||||
bind_textdomain_codeset('default', 'UTF-8');
|
||||
textdomain('default');
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Engelsystem;
|
||||
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Container\Container;
|
||||
use Engelsystem\Container\ServiceProvider;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class Application extends Container
|
||||
|
@ -10,6 +12,16 @@ class Application extends Container
|
|||
/** @var string|null */
|
||||
protected $appPath = null;
|
||||
|
||||
/** @var bool */
|
||||
protected $isBootstrapped = false;
|
||||
|
||||
/**
|
||||
* Registered service providers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $serviceProviders = [];
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return static
|
||||
*/
|
||||
public function setAppPath($appPath)
|
||||
{
|
||||
$appPath = realpath($appPath);
|
||||
$appPath = rtrim($appPath, DIRECTORY_SEPARATOR);
|
||||
|
||||
$this->appPath = $appPath;
|
||||
$this->instance('path', $appPath);
|
||||
|
||||
$this->registerPaths();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -56,4 +126,12 @@ class Application extends Container
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function base_path($path = '')
|
||||
{
|
||||
return app('path') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set config values
|
||||
*
|
||||
|
@ -46,6 +55,15 @@ function config($key = null, $default = null)
|
|||
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 mixed $default
|
||||
|
@ -78,22 +96,6 @@ function session($key = null, $default = null)
|
|||
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 array $parameters
|
||||
|
@ -109,3 +111,19 @@ function url($path = null, $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;
|
||||
|
||||
use Engelsystem\Application;
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Container\Container;
|
||||
use Engelsystem\Container\ServiceProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit_Framework_MockObject_MockObject;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use ReflectionClass;
|
||||
|
||||
class ApplicationTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Application::__construct
|
||||
* @covers \Engelsystem\Application::registerBaseBindings
|
||||
* @covers \Engelsystem\Application::__construct
|
||||
* @covers \Engelsystem\Application::registerBaseBindings
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$app = new Application();
|
||||
$app = new Application('.');
|
||||
|
||||
$this->assertInstanceOf(Container::class, $app);
|
||||
$this->assertInstanceOf(ContainerInterface::class, $app);
|
||||
|
@ -27,4 +31,141 @@ class ApplicationTest extends TestCase
|
|||
$this->assertSame($app, Application::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