Merge pull request #349 from MyIgel/master

Changed container to Illuminate/Container and added service providers
This commit is contained in:
msquare 2017-11-12 13:25:56 +01:00 committed by GitHub
commit ebc973bf22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 1668 additions and 410 deletions

90
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,90 @@
image: php
cache:
paths:
- .composer
services:
- mysql:5.6
variables:
MYSQL_DATABASE: engelsystem
MYSQL_USER: engel
MYSQL_PASSWORD: engelsystem
COMPOSER_HOME: .composer
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
before_script:
# Fix permissions after gitlab messed them up
- find . -type f -exec chmod 644 {} \;
- find . -type d -exec chmod 755 {} \;
# Install required Packages
- apt update -yqq
- apt install -yqq git unzip mysql-client
- docker-php-ext-install pdo pdo_mysql gettext
# Install xdebug
- pecl install xdebug
- docker-php-ext-enable xdebug
# MySQL DB
- mysql -h mysql -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < db/install.sql
- mysql -h mysql -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < db/update.sql
# Install Composer
- curl -sS https://getcomposer.org/installer | php -- --no-ansi --install-dir /usr/local/bin/ --filename composer
- /usr/local/bin/composer --no-ansi install
.test_template: &test_definition
artifacts:
name: "${CI_JOB_NAME}_${CI_PROJECT_ID}_${PHP_VERSION}"
expire_in: 1 week
paths:
- ./coverage/
coverage: '/^\s*Lines:\s*(\d+(?:\.\d+)?%)/'
script: vendor/bin/phpunit --colors=never --coverage-text --coverage-html ./coverage/
test:7.0:
image: php:7.0
<<: *test_definition
test:7.1:
image: php:7.1
<<: *test_definition
deploy_staging:
stage: deploy
only:
- master
script:
- |-
if [ -z "${SSH_PRIVATE_KEY}" ] || [ -z "${REMOTE}" ] || [ -z "${REMOTE_PATH}" ]; then
echo "Skipping deployment";
exit
fi
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" | sed -e 's/\r//g' > ~/.ssh/id_ed25519
- chmod 600 ~/.ssh/id_ed25519
- apt update && apt install -yqq rsync openssh-client
- /usr/local/bin/composer --no-ansi install --no-dev
- /usr/local/bin/composer --no-ansi dump-autoload --optimize
- echo "syncing ${PWD}/ to ${REMOTE}:${REMOTE_PATH}/${CI_JOB_ID}-${CI_COMMIT_SHA}/"
- |-
rsync -vAax --exclude '.git*' --exclude .composer/ \
-e "ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
./ "${REMOTE}:${REMOTE_PATH}/${CI_JOB_ID}-${CI_COMMIT_SHA}/"
- |-
ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE}" "
set -e
if [[ -f \"${REMOTE_PATH}/current/config/config.php\" ]]; then
echo \"Config backup\"
cp \"${REMOTE_PATH}/current/config/config.php\" config.php
fi
echo \"Changing symlink\"
unlink \"${REMOTE_PATH}/current\"
ln -s \"${REMOTE_PATH}/${CI_JOB_ID}-${CI_COMMIT_SHA}\" \"${REMOTE_PATH}/current\"
if [[ -f config.php ]]; then
echo \"Restoring config\"
cp config.php \"${REMOTE_PATH}/current/config/config.php\"
fi
"

View File

@ -15,11 +15,12 @@
],
"require": {
"php": ">=7.0.0",
"erusev/parsedown": "1.6.*",
"twbs/bootstrap": "^3.3",
"symfony/http-foundation": "^3.3",
"erusev/parsedown": "^1.6",
"illuminate/container": "5.5.*",
"psr/container": "^1.0",
"psr/log": "^1.0"
"psr/log": "^1.0",
"symfony/http-foundation": "^3.3",
"twbs/bootstrap": "^3.3"
},
"require-dev": {
"phpunit/phpunit": "^6.3"

17
config/app.php Normal file
View File

@ -0,0 +1,17 @@
<?php
// Application config
return [
// Service 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,
\Engelsystem\Http\RequestServiceProvider::class,
\Engelsystem\Http\SessionServiceProvider::class,
],
];

View File

@ -5,10 +5,10 @@
return [
// MySQL-Connection Settings
'database' => [
'host' => 'localhost',
'user' => 'root',
'pw' => '',
'db' => 'engelsystem',
'host' => env('MYSQL_HOST', (env('CI', false) ? 'mysql' : 'localhost')),
'user' => env('MYSQL_USER', 'root'),
'pw' => env('MYSQL_PASSWORD', ''),
'db' => env('MYSQL_DATABASE', 'engelsystem'),
],
// For accessing stats

View File

@ -205,7 +205,7 @@ DROP TABLE IF EXISTS `NewsComments`;
CREATE TABLE `NewsComments` (
`ID` bigint(11) NOT NULL,
`Refid` int(11) NOT NULL DEFAULT '0',
`Datum` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`Datum` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`Text` text NOT NULL,
`UID` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -395,7 +395,7 @@ CREATE TABLE `User` (
`Sprache` char(64) NOT NULL,
`Menu` char(1) NOT NULL DEFAULT 'L',
`lastLogIn` int(11) NOT NULL,
`CreateDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`CreateDate` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`Art` varchar(30) DEFAULT NULL,
`kommentar` text,
`Hometown` varchar(255) NOT NULL DEFAULT '',

View File

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

61
includes/engelsystem.php Normal file
View File

@ -0,0 +1,61 @@
<?php
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Exceptions\Handler as ExceptionHandler;
/**
* This file includes all needed functions, connects to the db etc.
*/
require_once __DIR__ . '/autoload.php';
/**
* Include legacy code
*/
require __DIR__ . '/includes.php';
/**
* Initialize and bootstrap the application
*/
$app = new Application(realpath(__DIR__ . DIRECTORY_SEPARATOR . '..'));
$appConfig = $app->make(Config::class);
$appConfig->set(require config_path('app.php'));
$app->bootstrap($appConfig);
/**
* Configure application
*/
date_default_timezone_set($app->get('config')->get('timezone'));
if (config('environment') == 'development') {
$errorHandler = $app->get('error.handler');
$errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT);
ini_set('display_errors', true);
error_reporting(E_ALL);
} else {
ini_set('display_errors', false);
}
/**
* Check for maintenance
*/
if ($app->get('config')->get('maintenance')) {
echo file_get_contents(__DIR__ . '/../templates/maintenance.html');
die();
}
/**
* Init translations
*/
gettext_init();
/**
* Init authorization
*/
load_auth();

View File

@ -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');
}

View File

@ -1,115 +1,5 @@
<?php
use Engelsystem\Application;
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 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.
*/
require_once __DIR__ . '/autoload.php';
/**
* Initialize the application
*/
$app = Application::getInstance();
/**
* 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'
));
}
date_default_timezone_set($config->get('timezone'));
/**
* Initialize Request
*
* @var Request $request
*/
$request = Request::createFromGlobals();
$app->instance('request', $request);
/**
* Check for maintenance
*/
if ($config->get('maintenance')) {
echo file_get_contents(__DIR__ . '/../templates/maintenance.html');
die();
}
/**
* Register UrlGenerator
*/
$urlGenerator = new UrlGenerator();
$app->instance('routing.urlGenerator', $urlGenerator);
/**
* 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->instance(LoggerInterface::class, $logger);
$app->instance(EngelsystemLogger::class, $logger);
/**
* Include legacy code
*/
@ -194,17 +84,3 @@ $includeFiles = [
foreach ($includeFiles as $file) {
require_once realpath($file);
}
/**
* Init application
*/
$sessionStorage = (PHP_SAPI != 'cli' ? new NativeSessionStorage(['cookie_httponly' => true]) : new MockArraySessionStorage());
$session = new Session($sessionStorage);
$app->instance('session', $session);
$session->start();
$request->setSession($session);
gettext_init();
load_auth();

View File

@ -481,9 +481,10 @@ function Shift_create($shift)
`URL`,
`PSID`,
`created_by_user_id`,
`edited_at_timestamp`,
`created_at_timestamp`
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
',
[
$shift['shifttype_id'],
@ -495,6 +496,7 @@ function Shift_create($shift)
$shift['PSID'],
$user['UID'],
time(),
time(),
]
);

View File

@ -59,7 +59,7 @@ function User_unconfirmed_AngelTypes($user)
AND `UserAngelTypes`.`supporter`=TRUE
AND `AngelTypes`.`restricted`=TRUE
AND `UnconfirmedMembers`.`confirm_user_id` IS NULL
GROUP BY `UserAngelTypes`.`angeltype_id`
GROUP BY `UserAngelTypes`.`angeltype_id`, `UserAngelTypes`.`id`
ORDER BY `AngelTypes`.`name`
', [$user['UID']]);
}

View File

@ -109,7 +109,7 @@ function load_days()
$days = DB::select('
SELECT DISTINCT DATE(FROM_UNIXTIME(`start`)) AS `id`, DATE(FROM_UNIXTIME(`start`)) AS `name`
FROM `Shifts`
ORDER BY `start`
ORDER BY `id`, `name`
');
$days = array_map('array_shift', $days);

View File

@ -1,5 +1,5 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="./includes/autoload.php"
bootstrap="./tests/autoload.php"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.3/phpunit.xsd"
colors="true"
>
@ -13,7 +13,6 @@
</testsuites>
<filter>
<whitelist>
<directory>./include/</directory>
<directory>./src/</directory>
</whitelist>
</filter>

View File

@ -1,6 +1,8 @@
<?php
require_once realpath(__DIR__ . '/../includes/engelsystem_provider.php');
use Engelsystem\Http\Request;
require_once realpath(__DIR__ . '/../includes/engelsystem.php');
$free_pages = [
'admin_event_config',
@ -25,6 +27,8 @@ $page = '';
$title = '';
$content = '';
/** @var Request $request */
$request = $app->get('request');
$page = $request->query->get('p');
if (empty($page)) {
$page = $request->path();

View File

@ -2,24 +2,136 @@
namespace Engelsystem;
use Engelsystem\Config\Config;
use Engelsystem\Container\Container;
use Engelsystem\Container\ServiceProvider;
use Psr\Container\ContainerInterface;
class Application extends Container
{
public function __construct()
/** @var string|null */
protected $appPath = null;
/** @var bool */
protected $isBootstrapped = false;
/**
* Registered service providers
*
* @var array
*/
protected $serviceProviders = [];
/**
* Application constructor.
*
* @param string $appPath
*/
public function __construct($appPath = null)
{
if (!is_null($appPath)) {
$this->setAppPath($appPath);
}
$this->registerBaseBindings();
}
protected function registerBaseBindings()
{
self::setInstance($this);
static::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);
$this->bind(ContainerInterface::class, Application::class);
}
/**
* @param string|ServiceProvider $provider
* @return ServiceProvider
*/
public function register($provider)
{
if (is_string($provider)) {
$provider = $this->make($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->registerPaths();
return $this;
}
/**
* @return string|null
*/
public function path()
{
return $this->appPath;
}
/**
* @return bool
*/
public function isBooted()
{
return $this->isBootstrapped;
}
}

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

@ -2,115 +2,9 @@
namespace Engelsystem\Container;
use Psr\Container\ContainerExceptionInterface;
use Illuminate\Container\Container as IlluminateContainer;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
class Container implements ContainerInterface
class Container extends IlluminateContainer implements ContainerInterface
{
/**
* The globally available container
*
* @var static
*/
protected static $instance;
/**
* Contains the shared instances
*
* @var mixed[]
*/
protected $instances = [];
/**
* Finds an entry of the container by its identifier and returns it
*
* @param string $id Identifier of the entry to look for
*
* @throws NotFoundExceptionInterface No entry was found for **this** identifier
* @throws ContainerExceptionInterface Error while retrieving the entry
*
* @return mixed Entry
*/
public function get($id)
{
if ($this->has($id)) {
return $this->resolve($id);
}
throw new NotFoundException(sprintf('The entry with the id "%s" could not be found', $id));
}
/**
* Register a shared entry in the container
*
* @param string $abstract Identifier of the entry to set
* @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;
}
/**
* Returns true if the container can return an entry for the given identifier
* Returns false otherwise
*
* `has($id)` returning true does not mean that `get($id)` will not throw an exception
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`
*
* @param string $id Identifier of the entry to look for
*
* @return bool
*/
public function has($id)
{
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 self
*/
public static function getInstance()
{
if (is_null(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}
/**
* Set the globally available instance of the container
*
* @param Container $container
*/
public static function setInstance(Container $container)
{
static::$instance = $container;
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace Engelsystem\Container;
use Exception;
use Psr\Container\ContainerExceptionInterface;
class ContainerException extends Exception implements ContainerExceptionInterface
{
}

View File

@ -1,10 +0,0 @@
<?php
namespace Engelsystem\Container;
use Psr\Container\NotFoundExceptionInterface;
class NotFoundException extends ContainerException implements NotFoundExceptionInterface
{
}

View File

@ -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() { }
}

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,14 @@
<?php
namespace Engelsystem\Http;
use Engelsystem\Container\ServiceProvider;
class RequestServiceProvider extends ServiceProvider
{
public function register()
{
$request = $this->app->call([Request::class, 'createFromGlobals']);
$this->app->instance('request', $request);
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace Engelsystem\Http;
use Engelsystem\Container\ServiceProvider;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
class SessionServiceProvider extends ServiceProvider
{
public function register()
{
$sessionStorage = $this->getSessionStorage();
$this->app->instance('session.storage', $sessionStorage);
$this->app->bind(SessionStorageInterface::class, 'session.storage');
$session = $this->app->make(Session::class);
$this->app->instance('session', $session);
/** @var Request $request */
$request = $this->app->get('request');
$request->setSession($session);
$session->start();
}
/**
* Returns the session storage
*
* @return SessionStorageInterface
*/
protected function getSessionStorage()
{
if ($this->isCli()) {
return $this->app->make(MockArraySessionStorage::class);
}
return $this->app->make(NativeSessionStorage::class, ['options' => ['cookie_httponly' => true]]);
}
/**
* Test if is called from cli
*
* @return bool
*/
protected function isCli()
{
return PHP_SAPI == 'cli';
}
}

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

@ -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,30 @@ 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
* @return mixed
*/
function env($key, $default = null)
{
$value = getenv($key);
if ($value === false) {
return $default;
}
return $value;
}
/**
* @param string $key
* @param mixed $default
@ -78,22 +111,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 +126,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);
}

View File

@ -0,0 +1,40 @@
<?php
namespace Engelsystem\Test\Feature\Database;
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Database\DatabaseServiceProvider;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
class DatabaseServiceProviderTest extends DatabaseTest
{
/**
* @covers \Engelsystem\Database\DatabaseServiceProvider::register()
*/
public function testRegister()
{
/** @var MockObject|Config $config */
$config = $this->getMockBuilder(Config::class)
->getMock();
/** @var 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();
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Engelsystem\Test\Feature\Database;
use PHPUnit\Framework\TestCase;
abstract class DatabaseTest extends TestCase
{
/**
* Returns the database config
*
* @return string[]
*/
protected 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

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test\Logger;
namespace Engelsystem\Test\Feature\Logger;
use Engelsystem\Logger\EngelsystemLogger;
use PHPUnit\Framework\TestCase;
@ -12,7 +12,7 @@ class EngelsystemLoggerTest extends TestCase
{
public static function setUpBeforeClass()
{
require_once __DIR__ . '/../../../includes/engelsystem_provider.php';
require_once __DIR__ . '/../../../includes/engelsystem.php';
}
/**

View File

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test;
namespace Engelsystem\Test\Feature\Model;
use PHPUnit\Framework\TestCase;
use Psr\Log\LogLevel;
@ -9,7 +9,7 @@ class LogEntriesModelTest extends TestCase
{
public static function setUpBeforeClass()
{
require_once __DIR__ . '/../../../includes/engelsystem_provider.php';
require_once __DIR__ . '/../../../includes/engelsystem.php';
}
public function testCreateLogEntry()

View File

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test;
namespace Engelsystem\Test\Feature\Model;
use PHPUnit\Framework\TestCase;
@ -10,7 +10,7 @@ class RoomModelTest extends TestCase
public static function setUpBeforeClass()
{
require_once __DIR__ . '/../../../includes/engelsystem_provider.php';
require_once __DIR__ . '/../../../includes/engelsystem.php';
}
public function create_Room()

View File

@ -1,21 +1,25 @@
<?php
namespace Engelsystem\Test\Config;
namespace Engelsystem\Test\Unit;
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);
@ -24,6 +28,144 @@ class ApplicationTest extends TestCase
$this->assertSame($app, $app->get(Container::class));
$this->assertSame($app, $app->get(Application::class));
$this->assertSame($app, $app->get(ContainerInterface::class));
$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;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Engelsystem\Test\Unit\Config;
use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Config\ConfigServiceProvider;
use Engelsystem\Test\Unit\ServiceProviderTest;
use PHPUnit_Framework_MockObject_MockObject;
class ConfigServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Config\ConfigServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|Config $config */
$config = $this->getMockBuilder(Config::class)
->getMock();
$app = $this->getApp(['make', 'instance', 'get']);
Application::setInstance($app);
$this->setExpects($app, 'make', [Config::class], $config);
$this->setExpects($app, 'instance', ['config', $config]);
$this->setExpects($app, 'get', ['path.config'], __DIR__ . '/../../../config', $this->atLeastOnce());
$this->setExpects($config, 'set', null, null, $this->exactly(2));
$this->setExpects($config, 'get', [null], []);
$configFile = __DIR__ . '/../../../config/config.php';
$configExists = file_exists($configFile);
if (!$configExists) {
file_put_contents($configFile, '<?php return [];');
}
$serviceProvider = new ConfigServiceProvider($app);
$serviceProvider->register();
if (!$configExists) {
unlink($configFile);
}
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test\Config;
namespace Engelsystem\Test\Unit\Config;
use Engelsystem\Config\Config;
use PHPUnit\Framework\TestCase;

View File

@ -1,104 +0,0 @@
<?php
namespace Engelsystem\Test\Config;
use Engelsystem\Container\Container;
use PHPUnit\Framework\TestCase;
class ContainerTest extends TestCase
{
/**
* @covers \Engelsystem\Container\Container::get
*/
public function testGet()
{
$container = new Container();
$class = new class
{
};
$container->instance('foo', $class);
$this->assertSame($class, $container->get('foo'));
}
/**
* @covers \Engelsystem\Container\Container::get
* @expectedException \Engelsystem\Container\NotFoundException
*/
public function testGetException()
{
$container = new Container();
$container->get('not.registered.service');
}
/**
* @covers \Engelsystem\Container\Container::instance
* @covers \Engelsystem\Container\Container::resolve
*/
public function testInstance()
{
$container = new Container();
$class = new class
{
};
$container->instance('foo', $class);
$this->assertSame($class, $container->get('foo'));
}
/**
* @covers \Engelsystem\Container\Container::has
*/
public function testHas()
{
$container = new Container();
$this->assertFalse($container->has('test'));
$class = new class
{
};
$container->instance('test', $class);
$this->assertTrue($container->has('test'));
}
/**
* @covers \Engelsystem\Container\Container::singleton
*/
public function testSingleton()
{
$container = new Container();
$class = new class
{
};
$container->singleton('foo', $class);
$this->assertSame($class, $container->get('foo'));
$this->assertSame($class, $container->get('foo'));
}
/**
* @covers \Engelsystem\Container\Container::setInstance
* @covers \Engelsystem\Container\Container::getInstance
*/
public function testContainerSingleton()
{
// Ensure that no container has been initialized
$reflection = new \ReflectionProperty(Container::class, 'instance');
$reflection->setAccessible(true);
$reflection->setValue(null, null);
$reflection->setAccessible(false);
$container0 = new Container();
$container = Container::getInstance();
$this->assertNotSame($container0, $container);
$container1 = new Container;
Container::setInstance($container1);
$this->assertSame($container1, Container::getInstance());
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Engelsystem\Test\Unit\Container;
use Engelsystem\Container\ServiceProvider;
use Engelsystem\Test\Unit\Container\Stub\ServiceProviderImplementation;
use Engelsystem\Test\Unit\ServiceProviderTest;
class ConfigServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Container\ServiceProvider::__construct
*/
public function testRegister()
{
$app = $this->getApp();
$serviceProvider = new ServiceProviderImplementation($app);
$this->assertInstanceOf(ServiceProvider::class, $serviceProvider);
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace Engelsystem\Test\Unit\Container\Stub;
use Engelsystem\Container\ServiceProvider;
class ServiceProviderImplementation extends ServiceProvider
{
}

View File

@ -0,0 +1,37 @@
<?php
namespace Engelsystem\Test\Unit\Database;
use Engelsystem\Config\Config;
use Engelsystem\Database\DatabaseServiceProvider;
use Engelsystem\Test\Unit\ServiceProviderTest;
use Exception;
use PHPUnit_Framework_MockObject_MockObject;
class DatabaseServiceProviderTest extends ServiceProviderTest
{
/**
* @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();
$app = $this->getApp(['get']);
$this->setExpects($app, 'get', ['config'], $config);
$this->setExpects($config, 'get', ['database'], [
'host' => 'localhost',
'db' => 'database',
'user' => 'user',
'pw' => 'password',
], $this->atLeastOnce());
$this->expectException(Exception::class);
$serviceProvider = new DatabaseServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,192 @@
<?php
namespace Engelsystem\Test\Unit\Database;
use Engelsystem\Database\Db;
use PDO;
use PDOStatement;
use PHPUnit\Framework\TestCase;
use ReflectionObject;
use Throwable;
class DbTest extends TestCase
{
/**
* @covers \Engelsystem\Database\Db::connect()
*/
public function testConnect()
{
$result = Db::connect('mysql:host=localhost;dbname=someTestDatabaseThatDoesNotExist;charset=utf8');
$this->assertFalse($result);
$result = Db::connect('sqlite::memory:');
$this->assertTrue($result);
}
/**
* @covers \Engelsystem\Database\Db::query()
*/
public function testQuery()
{
$stm = Db::query('SELECT * FROM test_data');
$this->assertEquals('00000', $stm->errorCode());
$stm = Db::query('SELECT * FROM test_data WHERE id = ?', [4]);
$this->assertEquals('00000', $stm->errorCode());
}
/**
* @covers \Engelsystem\Database\Db::unprepared()
*/
public function testUnprepared()
{
$return = Db::unprepared('SELECT * FROM test_data WHERE id = 3');
$this->assertTrue($return);
}
/**
* @covers \Engelsystem\Database\Db::select()
*/
public function testSelect()
{
$return = Db::select('SELECT * FROM test_data');
$this->assertTrue(count($return) > 3);
$return = Db::select('SELECT * FROM test_data WHERE id = ?', [2]);
$this->assertCount(1, $return);
}
/**
* @covers \Engelsystem\Database\Db::selectOne()
*/
public function testSelectOne()
{
$return = Db::selectOne('SELECT * FROM test_data');
$this->assertEquals('Foo', $return['data']);
$return = Db::selectOne('SELECT * FROM test_data WHERE id = -1');
$this->assertEmpty($return);
$return = Db::selectOne('SELECT * FROM test_data WHERE id = ?', [3]);
$return = array_pop($return);
$this->assertTrue(!is_array($return));
}
/**
* @covers \Engelsystem\Database\Db::insert()
*/
public function testInsert()
{
$count = Db::insert("INSERT INTO test_data (id, data) VALUES (5, 'Some random text'), (6, 'another text')");
$this->assertEquals(2, $count);
$count = Db::insert('INSERT INTO test_data(id, data) VALUES (:id, :alias)', ['id' => 7, 'alias' => 'Blafoo']);
$this->assertEquals(1, $count);
}
/**
* @covers \Engelsystem\Database\Db::update()
*/
public function testUpdate()
{
$count = Db::update("UPDATE test_data SET data='NOPE' WHERE data LIKE '%Replaceme%'");
$this->assertEquals(3, $count);
$count = Db::update("UPDATE test_data SET data=? WHERE data LIKE '%NOPE%'", ['Some random text!']);
$this->assertEquals(3, $count);
}
/**
* @covers \Engelsystem\Database\Db::delete()
*/
public function testDelete()
{
$count = Db::delete('DELETE FROM test_data WHERE id=1');
$this->assertEquals(1, $count);
$count = Db::delete('DELETE FROM test_data WHERE data LIKE ?', ['%Replaceme%']);
$this->assertEquals(3, $count);
}
/**
* @covers \Engelsystem\Database\Db::statement()
*/
public function testStatement()
{
$return = Db::statement('SELECT * FROM test_data WHERE id = 3');
$this->assertTrue($return);
$return = Db::statement('SELECT * FROM test_data WHERE id = ?', [2]);
$this->assertTrue($return);
}
/**
* @covers \Engelsystem\Database\Db::getError()
*/
public function testGetError()
{
try {
Db::statement('foo');
} catch (Throwable $e) {
}
$error = Db::getError();
$this->assertTrue(is_array($error));
$this->assertEquals('near "foo": syntax error', $error[2]);
$db = new Db();
$refObject = new ReflectionObject($db);
$refProperty = $refObject->getProperty('stm');
$refProperty->setAccessible(true);
$refProperty->setValue(null, null);
$error = Db::getError();
$this->assertEquals([-1, null, null], $error);
}
/**
* @covers \Engelsystem\Database\Db::getPdo()
*/
public function testGetPdo()
{
$pdo = Db::getPdo();
$this->assertInstanceOf(PDO::class, $pdo);
}
/**
* @covers \Engelsystem\Database\Db::getStm()
*/
public function testGetStm()
{
$stm = Db::getStm();
$this->assertInstanceOf(PDOStatement::class, $stm);
}
/**
* Setup in memory database
*/
protected function setUp()
{
Db::connect('sqlite::memory:');
Db::getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Db::query(
'
CREATE TABLE test_data(
id INT PRIMARY KEY NOT NULL,
data TEXT NOT NULL
);
');
Db::query('CREATE UNIQUE INDEX test_data_id_uindex ON test_data (id);');
Db::insert("
INSERT INTO test_data (id, data)
VALUES
(1, 'Foo'),
(2, 'Bar'),
(3, 'Batz'),
(4, 'Lorem ipsum dolor sit'),
(10, 'Replaceme ipsum dolor sit amet'),
(11, 'Lorem Replaceme dolor sit amet'),
(12, 'Lorem ipsum Replaceme sit amet')
;");
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Engelsystem\Test\Unit\Exceptions;
use Engelsystem\Exceptions\ExceptionsServiceProvider;
use Engelsystem\Exceptions\Handler as ExceptionHandler;
use Engelsystem\Test\Unit\ServiceProviderTest;
use PHPUnit_Framework_MockObject_MockObject;
class ExceptionsServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|ExceptionHandler $exceptionHandler */
$exceptionHandler = $this->getMockBuilder(ExceptionHandler::class)
->getMock();
$app = $this->getApp();
$this->setExpects($app, 'make', [ExceptionHandler::class], $exceptionHandler);
$this->setExpects($app, 'instance', ['error.handler', $exceptionHandler]);
$serviceProvider = new ExceptionsServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test\Config;
namespace Engelsystem\Test\Unit;
use Engelsystem\Application;
use Engelsystem\Config\Config;
@ -9,6 +9,7 @@ use Engelsystem\Http\Request;
use Engelsystem\Renderer\Renderer;
use Engelsystem\Routing\UrlGenerator;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
use Symfony\Component\HttpFoundation\Session\Session;
class HelpersTest extends TestCase
@ -28,6 +29,25 @@ class HelpersTest extends TestCase
$this->assertEquals($class, app('some.name'));
}
/**
* @covers \base_path()
*/
public function testBasePath()
{
/** @var MockObject|Application $app */
$app = $this->getMockBuilder(Container::class)
->getMock();
Application::setInstance($app);
$app->expects($this->atLeastOnce())
->method('get')
->with('path')
->willReturn('/foo/bar');
$this->assertEquals('/foo/bar', base_path());
$this->assertEquals('/foo/bar/bla-foo.conf', base_path('bla-foo.conf'));
}
/**
* @covers \config
*/
@ -53,6 +73,39 @@ class HelpersTest extends TestCase
$this->assertEquals(['user' => 'FooBar'], config('mail'));
}
/**
* @covers \config_path()
*/
public function testConfigPath()
{
/** @var MockObject|Application $app */
$app = $this->getMockBuilder(Container::class)
->getMock();
Application::setInstance($app);
$app->expects($this->atLeastOnce())
->method('get')
->with('path.config')
->willReturn('/foo/conf');
$this->assertEquals('/foo/conf', config_path());
$this->assertEquals('/foo/conf/bar.php', config_path('bar.php'));
}
/**
* @covers \env
*/
public function testEnv()
{
putenv('envTestVar=someContent');
$env = env('envTestVar');
$this->assertEquals('someContent', $env);
$env = env('someRandomEnvVarThatShouldNeverExist', 'someDefaultValue');
$this->assertEquals('someDefaultValue', $env);
}
/**
* @covers \request
*/
@ -132,7 +185,7 @@ class HelpersTest extends TestCase
/**
* @param string $alias
* @param object $object
* @return Application|\PHPUnit_Framework_MockObject_MockObject
* @return Application|MockObject
*/
protected function getAppMock($alias, $object)
{

View File

@ -0,0 +1,29 @@
<?php
namespace Engelsystem\Test\Unit\Http;
use Engelsystem\Http\Request;
use Engelsystem\Http\RequestServiceProvider;
use Engelsystem\Test\Unit\ServiceProviderTest;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
class RequestServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Http\RequestServiceProvider::register()
*/
public function testRegister()
{
/** @var MockObject|Request $request */
$request = $this->getMockBuilder(Request::class)
->getMock();
$app = $this->getApp(['call', 'instance']);
$this->setExpects($app, 'call', [[Request::class, 'createFromGlobals']], $request);
$this->setExpects($app, 'instance', ['request', $request]);
$serviceProvider = new RequestServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace Engelsystem\Test\Unit\Http;
use Engelsystem\Http\Request;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
class RequestTest extends TestCase
{
/**
* @covers \Engelsystem\Http\Request::postData
*/
public function testPostData()
{
$request = new Request(
['foo' => 'I\'m a test!'],
['foo' => 'bar']
);
$this->assertEquals('bar', $request->postData('foo'));
$this->assertEquals('LoremIpsum', $request->postData('test-key', 'LoremIpsum'));
}
/**
* @covers \Engelsystem\Http\Request::input
*/
public function testInput()
{
$request = new Request(
['foo' => 'I\'m a test!'],
['foo' => 'bar']
);
$this->assertEquals('I\'m a test!', $request->input('foo'));
$this->assertEquals('LoremIpsum', $request->input('test-key', 'LoremIpsum'));
}
/**
* @covers \Engelsystem\Http\Request::has
*/
public function testHas()
{
$request = new Request([
'foo' => 'I\'m a test!',
'bar' => '',
]);
$this->assertTrue($request->has('foo'));
$this->assertFalse($request->has('bar'));
}
/**
* @covers \Engelsystem\Http\Request::path
*/
public function testPath()
{
/** @var MockObject|Request $request */
$request = $this
->getMockBuilder(Request::class)
->setMethods(['getPathInfo'])
->getMock();
$request
->expects($this->atLeastOnce())
->method('getPathInfo')
->willReturnOnConsecutiveCalls(
'/foo',
'/'
);
$this->assertEquals('foo', $request->path());
$this->assertEquals('/', $request->path());
}
/**
* @covers \Engelsystem\Http\Request::url
*/
public function testUrl()
{
/** @var MockObject|Request $request */
$request = $this
->getMockBuilder(Request::class)
->setMethods(['getUri'])
->getMock();
$request
->expects($this->atLeastOnce())
->method('getUri')
->willReturnOnConsecutiveCalls(
'http://foo.bar/bla/foo/',
'https://lorem.ipsum/dolor/sit?amet=consetetur&sadipscing=elitr'
);
$this->assertEquals('http://foo.bar/bla/foo', $request->url());
$this->assertEquals('https://lorem.ipsum/dolor/sit', $request->url());
}
}

View File

@ -0,0 +1,126 @@
<?php
namespace Engelsystem\Test\Unit\Http;
use Engelsystem\Http\Request;
use Engelsystem\Http\SessionServiceProvider;
use Engelsystem\Test\Unit\ServiceProviderTest;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface as StorageInterface;
class SessionServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Http\SessionServiceProvider::register()
* @covers \Engelsystem\Http\SessionServiceProvider::getSessionStorage()
*/
public function testRegister()
{
$app = $this->getApp(['make', 'instance', 'bind', 'get']);
$sessionStorage = $this->getMockForAbstractClass(StorageInterface::class);
$sessionStorage2 = $this->getMockForAbstractClass(StorageInterface::class);
$session = $this->getSessionMock();
$request = $this->getRequestMock();
/** @var MockObject|SessionServiceProvider $serviceProvider */
$serviceProvider = $this->getMockBuilder(SessionServiceProvider::class)
->setConstructorArgs([$app])
->setMethods(['isCli'])
->getMock();
$serviceProvider->expects($this->exactly(2))
->method('isCli')
->willReturnOnConsecutiveCalls(true, false);
$app->expects($this->exactly(4))
->method('make')
->withConsecutive(
[MockArraySessionStorage::class],
[Session::class],
[NativeSessionStorage::class, ['options' => ['cookie_httponly' => true]]],
[Session::class]
)
->willReturnOnConsecutiveCalls(
$sessionStorage,
$session,
$sessionStorage2,
$session
);
$app->expects($this->atLeastOnce())
->method('instance')
->withConsecutive(
['session.storage', $sessionStorage],
['session', $session]
);
$this->setExpects($app, 'bind', [StorageInterface::class, 'session.storage'], null, $this->atLeastOnce());
$this->setExpects($app, 'get', ['request'], $request, $this->atLeastOnce());
$this->setExpects($request, 'setSession', [$session], null, $this->atLeastOnce());
$this->setExpects($session, 'start', null, null, $this->atLeastOnce());
$serviceProvider->register();
$serviceProvider->register();
}
/**
* @covers \Engelsystem\Http\SessionServiceProvider::isCli()
*/
public function testIsCli()
{
$app = $this->getApp(['make', 'instance', 'bind', 'get']);
$sessionStorage = $this->getMockForAbstractClass(StorageInterface::class);
$session = $this->getSessionMock();
$request = $this->getRequestMock();
$app->expects($this->exactly(2))
->method('make')
->withConsecutive(
[MockArraySessionStorage::class],
[Session::class]
)
->willReturnOnConsecutiveCalls(
$sessionStorage,
$session
);
$app->expects($this->exactly(2))
->method('instance')
->withConsecutive(
['session.storage', $sessionStorage],
['session', $session]
);
$this->setExpects($app, 'bind', [StorageInterface::class, 'session.storage']);
$this->setExpects($app, 'get', ['request'], $request);
$this->setExpects($request, 'setSession', [$session]);
$this->setExpects($session, 'start');
$serviceProvider = new SessionServiceProvider($app);
$serviceProvider->register();
}
/**
* @return MockObject
*/
private function getSessionMock()
{
return $this->getMockBuilder(Session::class)
->setMethods(['start'])
->getMock();
}
/**
* @return MockObject
*/
private function getRequestMock()
{
return $this->getMockBuilder(Request::class)
->setMethods(['setSession'])
->getMock();
}
}

View File

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

View File

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test\Config;
namespace Engelsystem\Test\Unit\Renderer;
use Engelsystem\Renderer\HtmlEngine;
use PHPUnit\Framework\TestCase;

View File

@ -0,0 +1,81 @@
<?php
namespace Engelsystem\Test\Unit\Renderer;
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

@ -1,10 +1,11 @@
<?php
namespace Engelsystem\Test\Config;
namespace Engelsystem\Test\Unit\Renderer;
use Engelsystem\Renderer\EngineInterface;
use Engelsystem\Renderer\Renderer;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
use Psr\Log\LoggerInterface;
class RendererTest extends TestCase
@ -13,6 +14,7 @@ class RendererTest extends TestCase
{
$renderer = new Renderer();
/** @var MockObject|EngineInterface $nullRenderer */
$nullRenderer = $this->getMockForAbstractClass(EngineInterface::class);
$nullRenderer->expects($this->atLeastOnce())
@ -20,6 +22,7 @@ class RendererTest extends TestCase
->willReturn(false);
$renderer->addRenderer($nullRenderer);
/** @var MockObject|EngineInterface $mockRenderer */
$mockRenderer = $this->getMockForAbstractClass(EngineInterface::class);
$mockRenderer->expects($this->atLeastOnce())
@ -42,6 +45,7 @@ class RendererTest extends TestCase
{
$renderer = new Renderer();
/** @var MockObject|LoggerInterface $loggerMock */
$loggerMock = $this->getMockForAbstractClass(LoggerInterface::class);
$loggerMock
->expects($this->once())

View File

@ -0,0 +1,29 @@
<?php
namespace Engelsystem\Test\Unit\Routing;
use Engelsystem\Routing\RoutingServiceProvider;
use Engelsystem\Routing\UrlGenerator;
use Engelsystem\Test\Unit\ServiceProviderTest;
use PHPUnit_Framework_MockObject_MockObject;
class RoutingServiceProviderTest extends ServiceProviderTest
{
/**
* @covers \Engelsystem\Routing\RoutingServiceProvider::register()
*/
public function testRegister()
{
/** @var PHPUnit_Framework_MockObject_MockObject|UrlGenerator $urlGenerator */
$urlGenerator = $this->getMockBuilder(UrlGenerator::class)
->getMock();
$app = $this->getApp();
$this->setExpects($app, 'make', [UrlGenerator::class], $urlGenerator);
$this->setExpects($app, 'instance', ['routing.urlGenerator', $urlGenerator]);
$serviceProvider = new RoutingServiceProvider($app);
$serviceProvider->register();
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Engelsystem\Test\Config;
namespace Engelsystem\Test\Unit\Routing;
use Engelsystem\Application;
use Engelsystem\Container\Container;

View File

@ -0,0 +1,50 @@
<?php
namespace Engelsystem\Test\Unit;
use Engelsystem\Application;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_Matcher_InvokedRecorder as InvokedRecorder;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
abstract class ServiceProviderTest extends TestCase
{
/**
* @param array $methods
* @return Application|MockObject
*/
protected function getApp($methods = ['make', 'instance'])
{
/** @var MockObject|Application $app */
return $this->getMockBuilder(Application::class)
->setMethods($methods)
->getMock();
}
/**
* @param MockObject $object
* @param string $method
* @param array $arguments
* @param mixed $return
* @param InvokedRecorder $times
*/
protected function setExpects($object, $method, $arguments = null, $return = null, $times = null)
{
if (is_null($times)) {
$times = $this->once();
}
$invocation = $object->expects($times)
->method($method);
if (is_null($arguments)) {
$invocation->withAnyParameters();
} else {
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__ . '/');