From 8c81adc8e83969e90b4c54daf4a396b1094134ff Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Thu, 31 Aug 2017 17:30:54 +0200 Subject: Implemented container --- includes/engelsystem_provider.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'includes/engelsystem_provider.php') diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php index aed331d4..f3c161a6 100644 --- a/includes/engelsystem_provider.php +++ b/includes/engelsystem_provider.php @@ -1,11 +1,13 @@ instance('container', $container); +$container->instance(ContainerInterface::class, $container); + + /** * Load configuration */ $config = new Config(); -Config::setInstance($config); +$container->instance('config', $config); $config->set(require __DIR__ . '/../config/config.default.php'); if (file_exists(__DIR__ . '/../config/config.php')) { @@ -37,7 +48,8 @@ date_default_timezone_set($config->get('timezone')); * @var Request $request */ $request = Request::createFromGlobals(); -$request::setInstance($request); +$container->instance('request', $request); + /** * Check for maintenance @@ -52,14 +64,15 @@ if ($config->get('maintenance')) { * Initialize renderer */ $renderer = new Renderer(); +$container->instance('renderer', $renderer); $renderer->addRenderer(new HtmlEngine()); -Renderer::setInstance($renderer); /** * Register error handler */ $errorHandler = new ExceptionHandler(); +$container->instance('error.handler', $errorHandler); if (config('environment') == 'development') { $errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT); ini_set('display_errors', true); @@ -171,6 +184,7 @@ foreach ($includeFiles as $file) { * Init application */ $session = new Session(); +$container->instance('session', $session); $session->start(); $request->setSession($session); -- cgit v1.2.3-70-g09d2 From 0ac981876432ff8f7f76ffee8c5102b633d760d4 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 19 Sep 2017 14:50:20 +0200 Subject: Added Application --- includes/engelsystem_provider.php | 19 ++++++++----------- src/Application.php | 25 +++++++++++++++++++++++++ src/Container/Container.php | 35 +++++++++++++++++++++++------------ src/helpers.php | 8 ++++---- 4 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 src/Application.php (limited to 'includes/engelsystem_provider.php') diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php index f3c161a6..e10fdba0 100644 --- a/includes/engelsystem_provider.php +++ b/includes/engelsystem_provider.php @@ -1,13 +1,12 @@ instance('container', $container); -$container->instance(ContainerInterface::class, $container); +$app = Application::getInstance(); /** * Load configuration */ $config = new Config(); -$container->instance('config', $config); +$app->instance('config', $config); $config->set(require __DIR__ . '/../config/config.default.php'); if (file_exists(__DIR__ . '/../config/config.php')) { @@ -48,7 +45,7 @@ date_default_timezone_set($config->get('timezone')); * @var Request $request */ $request = Request::createFromGlobals(); -$container->instance('request', $request); +$app->instance('request', $request); /** @@ -64,7 +61,7 @@ if ($config->get('maintenance')) { * Initialize renderer */ $renderer = new Renderer(); -$container->instance('renderer', $renderer); +$app->instance('renderer', $renderer); $renderer->addRenderer(new HtmlEngine()); @@ -72,7 +69,7 @@ $renderer->addRenderer(new HtmlEngine()); * Register error handler */ $errorHandler = new ExceptionHandler(); -$container->instance('error.handler', $errorHandler); +$app->instance('error.handler', $errorHandler); if (config('environment') == 'development') { $errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT); ini_set('display_errors', true); @@ -184,7 +181,7 @@ foreach ($includeFiles as $file) { * Init application */ $session = new Session(); -$container->instance('session', $session); +$app->instance('session', $session); $session->start(); $request->setSession($session); diff --git a/src/Application.php b/src/Application.php new file mode 100644 index 00000000..674b3869 --- /dev/null +++ b/src/Application.php @@ -0,0 +1,25 @@ +registerBaseBindings(); + } + + protected function registerBaseBindings() + { + self::setInstance($this); + Container::setInstance($this); + $this->instance('app', $this); + $this->instance('container', $this); + $this->instance(Container::class, $this); + $this->instance(Application::class, $this); + $this->instance(ContainerInterface::class, $this); + } +} diff --git a/src/Container/Container.php b/src/Container/Container.php index df2f92fe..9af5c1e6 100644 --- a/src/Container/Container.php +++ b/src/Container/Container.php @@ -48,6 +48,17 @@ class Container implements ContainerInterface * @param mixed $instance Entry */ public function instance($abstract, $instance) + { + $this->singleton($abstract, $instance); + } + + /** + * Register a shared entry as singleton in the container + * + * @param string $abstract + * @param mixed $instance + */ + public function singleton($abstract, $instance) { $this->instances[$abstract] = $instance; } @@ -68,10 +79,21 @@ class Container implements ContainerInterface return isset($this->instances[$id]); } + /** + * Resolve the requested object + * + * @param string $abstract + * @return mixed + */ + protected function resolve($abstract) + { + return $this->instances[$abstract]; + } + /** * Get the globally available instance of the container * - * @return Container + * @return self */ public static function getInstance() { @@ -91,15 +113,4 @@ class Container implements ContainerInterface { static::$instance = $container; } - - /** - * Resolve the requested object - * - * @param string $abstract - * @return mixed - */ - protected function resolve($abstract) - { - return $this->instances[$abstract]; - } } diff --git a/src/helpers.php b/src/helpers.php index 733b902d..b942068f 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -1,15 +1,15 @@ get($id); + return Application::getInstance()->get($id); } /** -- cgit v1.2.3-70-g09d2 From 20a6fa07f8a94a587aa930659d740b1d346dbb8c Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 19 Sep 2017 14:51:46 +0200 Subject: Implemented container --- includes/engelsystem_provider.php | 1 - 1 file changed, 1 deletion(-) (limited to 'includes/engelsystem_provider.php') diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php index e10fdba0..c7734a7c 100644 --- a/includes/engelsystem_provider.php +++ b/includes/engelsystem_provider.php @@ -12,7 +12,6 @@ use Symfony\Component\HttpFoundation\Session\Session; /** * This file includes all needed functions, connects to the db etc. */ - require_once __DIR__ . '/autoload.php'; -- cgit v1.2.3-70-g09d2 From b3b65743cdc534f7632c8e04e80d3489eec9677c Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 19 Sep 2017 18:30:42 +0200 Subject: Added Logger --- composer.json | 3 +- includes/engelsystem_provider.php | 14 ++++ src/Logger/EngelsystemLogger.php | 74 ++++++++++++++++++++ test/Logger/EngelsystemLoggerTest.php | 126 ++++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/Logger/EngelsystemLogger.php create mode 100644 test/Logger/EngelsystemLoggerTest.php (limited to 'includes/engelsystem_provider.php') diff --git a/composer.json b/composer.json index 0769a6b6..35956e20 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "erusev/parsedown": "1.6.*", "twbs/bootstrap": "^3.3", "symfony/http-foundation": "^3.3", - "psr/container": "^1.0" + "psr/container": "^1.0", + "psr/log": "^1.0" }, "require-dev": { "phpunit/phpunit": "^6.3" diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php index c7734a7c..a9305df5 100644 --- a/includes/engelsystem_provider.php +++ b/includes/engelsystem_provider.php @@ -5,9 +5,12 @@ use Engelsystem\Config\Config; use Engelsystem\Database\Db; use Engelsystem\Exceptions\Handler as ExceptionHandler; use Engelsystem\Http\Request; +use Engelsystem\Logger\EngelsystemLogger; use Engelsystem\Renderer\HtmlEngine; use Engelsystem\Renderer\Renderer; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; /** * This file includes all needed functions, connects to the db etc. @@ -89,6 +92,14 @@ Db::connect( 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->instance(LoggerInterface::class, $logger); +$app->instance(EngelsystemLogger::class, $logger); + /** * Include legacy code @@ -180,6 +191,9 @@ foreach ($includeFiles as $file) { * Init application */ $session = new Session(); +if (PHP_SAPI == 'cli') { + $session = new Session(new MockArraySessionStorage()); +} $app->instance('session', $session); $session->start(); $request->setSession($session); diff --git a/src/Logger/EngelsystemLogger.php b/src/Logger/EngelsystemLogger.php new file mode 100644 index 00000000..db46215c --- /dev/null +++ b/src/Logger/EngelsystemLogger.php @@ -0,0 +1,74 @@ +checkLevel($level)) { + throw new InvalidArgumentException(); + } + + $message = $this->interpolate($message, $context); + + LogEntry_create('Logger: ' . $level, $message); + } + + /** + * Interpolates context values into the message placeholders. + * + * @param string $message + * @param array $context + * @return string + */ + protected function interpolate($message, array $context = []) + { + foreach ($context as $key => $val) { + // check that the value can be casted to string + if (is_array($val) || (is_object($val) && !method_exists($val, '__toString'))) { + continue; + } + + // replace the values of the message + $message = str_replace('{' . $key . '}', $val, $message); + } + + return $message; + } + + /** + * @param string $level + * @return bool + */ + protected function checkLevel($level) + { + return in_array($level, $this->allowedLevels); + } +} diff --git a/test/Logger/EngelsystemLoggerTest.php b/test/Logger/EngelsystemLoggerTest.php new file mode 100644 index 00000000..da10800d --- /dev/null +++ b/test/Logger/EngelsystemLoggerTest.php @@ -0,0 +1,126 @@ +assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @dataProvider provideLogLevels + * @param string $level + */ + public function testAllLevels($level) + { + $logger = $this->getLogger(); + + LogEntries_clear_all(); + + $logger->log($level, 'First log message'); + $logger->{$level}('Second log message'); + + $entries = LogEntries(); + $this->assertCount(2, $entries); + } + + /** + * @return string[] + */ + public function provideLogLevels() + { + return [ + [LogLevel::ALERT], + [LogLevel::CRITICAL], + [LogLevel::DEBUG], + [LogLevel::EMERGENCY], + [LogLevel::ERROR], + [LogLevel::INFO], + [LogLevel::NOTICE], + [LogLevel::WARNING], + ]; + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + LogEntries_clear_all(); + + $logger->log(LogLevel::INFO, 'My username is {username}', ['username' => 'Foo']); + + $entry = $this->getLastEntry(); + $this->assertEquals('My username is Foo', $entry['message']); + $this->assertContains(LogLevel::INFO, $entry['nick'], '', true); + + foreach ( + [ + ['Data and {context}', []], + ['Data and ', ['context' => null]], + ['Data and {context}', ['context' => new \stdClass()]], + ] as $data + ) { + list($result, $context) = $data; + + $logger->log(LogLevel::INFO, 'Data and {context}', $context); + + $entry = $this->getLastEntry(); + $this->assertEquals($result, $entry['message']); + } + } + + public function testContextToString() + { + $logger = $this->getLogger(); + LogEntries_clear_all(); + + $mock = $this->getMockBuilder('someDataProvider') + ->setMethods(['__toString']) + ->getMock(); + + $mock->expects($this->atLeastOnce()) + ->method('__toString') + ->will($this->returnValue('FooBar')); + + $logger->log(LogLevel::INFO, 'Some data and {context}', ['context' => $mock]); + + $entry = $this->getLastEntry(); + $this->assertEquals('Some data and FooBar', $entry['message']); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testThrowExceptionOnInvalidLevel() + { + $logger = $this->getLogger(); + + $logger->log('This log level should never be defined', 'Some message'); + } + + /** + * @return array + */ + public function getLastEntry() + { + $entries = LogEntries(); + $entry = array_pop($entries); + + return $entry; + } +} -- cgit v1.2.3-70-g09d2 From 86c0713baa2f616bf1dff6d9dbe0ea68b1c00e91 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Wed, 20 Sep 2017 01:09:11 +0200 Subject: Added helpers unit test --- includes/engelsystem_provider.php | 8 ++ src/Routing/UrlGenerator.php | 2 +- src/helpers.php | 14 ++- tests/Unit/HelpersTest.php | 152 ++++++++++++++++++++++++++++++++ tests/Unit/Routing/UrlGeneratorTest.php | 3 +- 5 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/HelpersTest.php (limited to 'includes/engelsystem_provider.php') diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php index a9305df5..cd22f6a7 100644 --- a/includes/engelsystem_provider.php +++ b/includes/engelsystem_provider.php @@ -8,6 +8,7 @@ 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\Storage\MockArraySessionStorage; @@ -59,6 +60,13 @@ if ($config->get('maintenance')) { } +/** + * Register UrlGenerator + */ +$urlGenerator = new UrlGenerator(); +$app->instance('routing.urlGenerator', $urlGenerator); + + /** * Initialize renderer */ diff --git a/src/Routing/UrlGenerator.php b/src/Routing/UrlGenerator.php index 33eef7b0..6df52425 100644 --- a/src/Routing/UrlGenerator.php +++ b/src/Routing/UrlGenerator.php @@ -9,7 +9,7 @@ class UrlGenerator * @param array $parameters * @return string */ - public static function to($path, $parameters = []) + public function to($path, $parameters = []) { $path = '/' . ltrim($path, '/'); $request = app('request'); diff --git a/src/helpers.php b/src/helpers.php index b942068f..de303963 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -69,7 +69,7 @@ function request($key = null, $default = null) */ function session($key = null, $default = null) { - $session = request()->getSession(); + $session = app('session'); if (is_null($key)) { return $session; @@ -97,9 +97,15 @@ function view($template = null, $data = null) /** * @param string $path * @param array $parameters - * @return string + * @return UrlGenerator|string */ -function url($path, $parameters = []) +function url($path = null, $parameters = []) { - return UrlGenerator::to($path, $parameters); + $urlGenerator = app('routing.urlGenerator'); + + if (is_null($path)) { + return $urlGenerator; + } + + return $urlGenerator->to($path, $parameters); } diff --git a/tests/Unit/HelpersTest.php b/tests/Unit/HelpersTest.php new file mode 100644 index 00000000..d9782888 --- /dev/null +++ b/tests/Unit/HelpersTest.php @@ -0,0 +1,152 @@ +getAppMock('some.name', $class); + + $this->assertEquals($appMock, app()); + $this->assertEquals($class, app('some.name')); + } + + /** + * @covers \config + */ + public function testConfig() + { + $configMock = $this->getMockBuilder(Config::class) + ->getMock(); + + $this->getAppMock('config', $configMock); + $this->assertEquals($configMock, config()); + + $configMock->expects($this->once()) + ->method('set') + ->with(['foo' => 'bar']); + + $this->assertTrue(config(['foo' => 'bar'])); + + $configMock->expects($this->once()) + ->method('get') + ->with('mail') + ->willReturn(['user' => 'FooBar']); + + $this->assertEquals(['user' => 'FooBar'], config('mail')); + } + + /** + * @covers \request + */ + public function testRequest() + { + $requestMock = $this->getMockBuilder(Request::class) + ->getMock(); + + $this->getAppMock('request', $requestMock); + $this->assertEquals($requestMock, request()); + + $requestMock->expects($this->once()) + ->method('input') + ->with('requestKey') + ->willReturn('requestValue'); + + $this->assertEquals('requestValue', request('requestKey')); + } + + /** + * @covers \session + */ + public function testSession() + { + $sessionMock = $this->getMockBuilder(Session::class) + ->getMock(); + + $this->getAppMock('session', $sessionMock); + $this->assertEquals($sessionMock, session()); + + $sessionMock->expects($this->once()) + ->method('get') + ->with('someKey') + ->willReturn('someValue'); + + $this->assertEquals('someValue', session('someKey')); + } + + /** + * @covers \view + */ + public function testView() + { + $rendererMock = $this->getMockBuilder(Renderer::class) + ->getMock(); + + $this->getAppMock('renderer', $rendererMock); + $this->assertEquals($rendererMock, view()); + + $rendererMock->expects($this->once()) + ->method('render') + ->with('template.name', ['template' => 'data']) + ->willReturn('rendered template'); + + $this->assertEquals('rendered template', view('template.name', ['template' => 'data'])); + } + + /** + * @covers \url + */ + public function testUrl() + { + $urlGeneratorMock = $this->getMockBuilder(UrlGenerator::class) + ->getMock(); + + $this->getAppMock('routing.urlGenerator', $urlGeneratorMock); + $this->assertEquals($urlGeneratorMock, url()); + + $urlGeneratorMock->expects($this->once()) + ->method('to') + ->with('foo/bar', ['param' => 'value']) + ->willReturn('http://lorem.ipsum/foo/bar?param=value'); + + $this->assertEquals('http://lorem.ipsum/foo/bar?param=value', url('foo/bar', ['param' => 'value'])); + } + + /** + * @param string $alias + * @param object $object + * @return Application|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getAppMock($alias, $object) + { + $appMock = $this->getMockBuilder(Container::class) + ->getMock(); + + $appMock->expects($this->atLeastOnce()) + ->method('get') + ->with($alias) + ->willReturn($object); + + /** @var $appMock Application */ + Application::setInstance($appMock); + + return $appMock; + } +} diff --git a/tests/Unit/Routing/UrlGeneratorTest.php b/tests/Unit/Routing/UrlGeneratorTest.php index 5b53a04e..fc23520a 100644 --- a/tests/Unit/Routing/UrlGeneratorTest.php +++ b/tests/Unit/Routing/UrlGeneratorTest.php @@ -32,6 +32,7 @@ class UrlGeneratorTest extends TestCase public function testTo($urlToPath, $path, $willReturn, $arguments, $expectedUrl) { $app = new Container(); + $urlGenerator = new UrlGenerator(); Application::setInstance($app); $request = $this->getMockBuilder(Request::class) @@ -44,7 +45,7 @@ class UrlGeneratorTest extends TestCase $app->instance('request', $request); - $url = UrlGenerator::to($urlToPath, $arguments); + $url = $urlGenerator->to($urlToPath, $arguments); $this->assertEquals($expectedUrl, $url); } } -- cgit v1.2.3-70-g09d2 From c6ef1120f82839cbb9d5abee12ab3e4803d5e2cd Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Wed, 20 Sep 2017 11:07:25 +0200 Subject: Set cookie to httponly --- includes/engelsystem_provider.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'includes/engelsystem_provider.php') diff --git a/includes/engelsystem_provider.php b/includes/engelsystem_provider.php index cd22f6a7..0de5e0f5 100644 --- a/includes/engelsystem_provider.php +++ b/includes/engelsystem_provider.php @@ -12,6 +12,7 @@ use Engelsystem\Routing\UrlGenerator; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * This file includes all needed functions, connects to the db etc. @@ -198,10 +199,8 @@ foreach ($includeFiles as $file) { /** * Init application */ -$session = new Session(); -if (PHP_SAPI == 'cli') { - $session = new Session(new MockArraySessionStorage()); -} +$sessionStorage = (PHP_SAPI != 'cli' ? new NativeSessionStorage(['cookie_httponly' => true]) : new MockArraySessionStorage()); +$session = new Session($sessionStorage); $app->instance('session', $session); $session->start(); $request->setSession($session); -- cgit v1.2.3-70-g09d2