Rejigging router, fixing running tests with slim4

This commit is contained in:
Greyscale 2020-08-06 19:48:55 +02:00
parent df6435ff3c
commit b4ea0ad8a6
4 changed files with 175 additions and 133 deletions

View file

@ -55,7 +55,6 @@ class App
protected Router $router;
protected bool $isSessionsEnabled = true;
protected bool $interrogateControllersComplete = false;
private array $routePaths = [];
private array $viewPaths = [];
private string $cachePath = '/cache';
private array $supportedLanguages = ['en_US'];
@ -64,6 +63,10 @@ class App
public function __construct()
{
if (!ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}
// Configure Dependency Injector
$container = $this->setupContainer();
$this->logger = $container->get(Logger::class);
@ -77,12 +80,6 @@ class App
$this->viewPaths[] = APP_ROOT.'/views/';
$this->viewPaths[] = APP_ROOT.'/src/Views/';
// Configure Router
$this->routePaths = [
APP_ROOT.'/src/Routes.php',
APP_ROOT.'/src/RoutesExtra.php',
];
// Configure Slim
$this->app = AppFactory::create();
$this->app->add(Slim\Views\TwigMiddleware::createFromContainer($this->app));
@ -95,12 +92,6 @@ class App
$this->debugBar['time']->startMeasure('interrogateTranslations', 'Time to interrogate translation files');
$this->interrogateTranslations();
$this->debugBar['time']->stopMeasure('interrogateTranslations');
$this->debugBar['time']->startMeasure('interrogateControllers', 'Time to interrogate controllers for routes');
$this->interrogateControllers();
$this->debugBar['time']->stopMeasure('interrogateControllers');
$this->logger->debug(sprintf('Bootstrap complete in %sms', number_format((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2)));
}
public function getCachePath(): string
@ -357,6 +348,9 @@ class App
} else {
self::$instance = $tempApp;
}
if (!defined('APP_CORE_NAME')) {
define('APP_CORE_NAME', get_class(self::$instance));
}
}
return self::$instance;
@ -375,22 +369,6 @@ class App
return $this->app;
}
public function addRoutePath($path): self
{
if (file_exists($path)) {
$this->routePaths[] = $path;
}
return $this;
}
public function clearRoutePaths(): self
{
$this->routePaths = [];
return $this;
}
public function addViewPath($path)
{
if (file_exists($path)) {
@ -410,21 +388,23 @@ class App
public function loadAllRoutes()
{
$app = $this->getApp();
foreach ($this->routePaths as $path) {
if (file_exists($path)) {
include $path;
}
}
$this->router->populateRoutes($app);
$this->debugBar['time']->startMeasure('interrogateControllers', 'Time to interrogate controllers for routes');
$this->interrogateControllers();
$this->debugBar['time']->stopMeasure('interrogateControllers');
$this->logger->debug(sprintf('Bootstrap complete in %sms', number_format((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2)));
$this->router->populateRoutes($this->getApp());
return $this;
}
public function runHttp(): void
{
$this->loadAllRoutes();
$this->debugBar['time']->startMeasure('runHTTP', 'HTTP runtime');
$this->app->run();
if ($this->debugBar['time']->hasStartedMeasure('runHTTP')) {
$this->debugBar['time']->stopMeasure('runHTTP');
}
@ -503,8 +483,8 @@ class App
}
$this->interrogateControllersComplete = true;
if ($this->environmentService->has('USE_ROUTE_CACHE')
&& 'yes' == strtolower($this->environmentService->get('USE_ROUTE_CACHE'))
if ($this->environmentService->has('ROUTE_CACHE')
&& 'on' == strtolower($this->environmentService->get('ROUTE_CACHE'))
&& $this->router->loadCache()
) {
return;
@ -600,5 +580,9 @@ class App
->weighRoutes()
->cache()
;
$this->logger->debug(sprintf(
'ROUTE_CACHE miss. Perhaps enable ROUTE_CACHE envvar.'
));
}
}

View file

@ -14,6 +14,8 @@ class Router
private CachePoolChain $cachePoolChain;
private int $cacheTTL = 60;
private bool $routesArePopulated = false;
public function __construct(\Redis $redis, Logger $logger, CachePoolChain $cachePoolChain)
{
$this->logger = $logger;
@ -43,6 +45,10 @@ class Router
public function populateRoutes(App $app)
{
if ($this->routesArePopulated) {
return $app;
}
$this->weighRoutes();
if (count($this->routes) > 0) {
foreach ($this->getRoutes() as $route) {
@ -50,6 +56,8 @@ class Router
}
}
$this->routesArePopulated = true;
return $app;
}

View file

@ -2,122 +2,42 @@
namespace Benzine\Tests;
use Benzine\App;
use Benzine\Tests\Traits\AppTestTrait;
use Psr\Http\Message\ResponseInterface;
use Slim\Http\Environment;
use Slim\Http\Headers;
use Slim\Http\Request;
use Slim\Http\RequestBody;
use Slim\Http\Response;
use Slim\Http\Uri;
abstract class RoutesTestCase extends BaseTestCase
{
private $defaultEnvironment = [];
private $defaultHeaders = [];
use AppTestTrait;
public function setUp(): void
{
$this->defaultEnvironment = [
'SCRIPT_NAME' => '/index.php',
'RAND' => rand(0, 100000000),
];
$this->defaultHeaders = [];
parent::setUp();
}
/**
* @param array $post
* @param bool $isJsonRequest
* @param array $extraHeaders
* @deprecated this has been deprecated in favour of the calls inside AppTestTrait
*
* @return ResponseInterface
* @param array $dataOrPost
*/
public function request(
string $method,
string $path,
$post = null,
$isJsonRequest = true,
$extraHeaders = []
) {
/*
* @var \Slim\App $app
* @var \Gone\AppCore\App $applicationInstance
*/
$applicationInstance = App::Instance();
$calledClass = get_called_class();
$dataOrPost = null,
bool $isJsonRequest = true,
array $extraHeaders = []
): ResponseInterface {
$request = $this->createRequest($method, $path);
$slimApp = $applicationInstance->getApp();
if (defined("{$calledClass}")) {
$modelName = $calledClass::MODEL_NAME;
if (file_exists(APP_ROOT."/src/Routes/{$modelName}Route.php")) {
require APP_ROOT."/src/Routes/{$modelName}Route.php";
}
} else {
if (file_exists(APP_ROOT.'/src/Routes.php')) {
require APP_ROOT.'/src/Routes.php';
}
}
if (file_exists(APP_ROOT.'/src/RoutesExtra.php')) {
require APP_ROOT.'/src/RoutesExtra.php';
}
$applicationInstance->getRouter()->populateRoutes();
$headers = array_merge($this->defaultHeaders, $extraHeaders);
$envArray = array_merge($this->defaultEnvironment, $headers);
$envArray = array_merge($envArray, [
'REQUEST_URI' => $path,
'REQUEST_METHOD' => $method,
]);
$env = Environment::mock($envArray);
$uri = Uri::createFromEnvironment($env);
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new RequestBody();
if (!is_array($post) && null != $post) {
$body->write($post);
$body->rewind();
} elseif (is_array($post) && count($post) > 0) {
$body->write(json_encode($post));
$body->rewind();
}
$request = new Request($method, $uri, $headers, $cookies, $serverParams, $body);
if ($isJsonRequest) {
foreach ($extraHeaders as $k => $v) {
$request = $request->withHeader($k, $v);
if ($dataOrPost !== null) {
$dataOrPost = json_decode(json_encode($dataOrPost), true);
$request = $request->withParsedBody($dataOrPost);
}
$request = $request->withHeader('Content-type', 'application/json');
$request = $request->withHeader('Accept', 'application/json');
$request = $request->withHeader('Content-Type', 'application/json');
}
$response = new Response();
// Invoke app
$response = $applicationInstance
->makeClean()
->getApp()
->process($request, $response)
;
$response->getBody()->rewind();
return $response;
}
protected function setEnvironmentVariable($key, $value): self
{
$this->defaultEnvironment[$key] = $value;
return $this;
}
protected function setRequestHeader($header, $value): self
{
$this->defaultHeaders[$header] = $value;
return $this;
return $this->slimApp->handle($request);
}
}

View file

@ -0,0 +1,130 @@
<?php
namespace Benzine\Tests\Traits;
use Benzine\App as BenzineApp;
use DI\Container;
use InvalidArgumentException;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface;
use Slim\App as SlimApp;
use Slim\Psr7\Factory\ServerRequestFactory;
use UnexpectedValueException;
/**
* Container Trait.
*/
trait AppTestTrait
{
protected Container $container;
protected BenzineApp $benzineApp;
protected SlimApp $slimApp;
/**
* Bootstrap app.
*
* @before
*
* @throws UnexpectedValueException
*/
protected function setupContainer(): void
{
$this->benzineApp = require __DIR__.'/../../../../../bootstrap.php';
$this->slimApp = $this->benzineApp->getApp();
$container = $this->slimApp->getContainer();
if ($container === null) {
throw new UnexpectedValueException('Container must be initialized');
}
$this->container = $container;
$this->benzineApp->loadAllRoutes();
}
/**
* Add mock to container.
*
* @param string $class The class or interface
*
* @return MockObject The mock
*/
protected function mock(string $class): MockObject
{
if (!class_exists($class)) {
throw new InvalidArgumentException(sprintf('Class not found: %s', $class));
}
$mock = $this->getMockBuilder($class)
->disableOriginalConstructor()
->getMock()
;
$this->container->set($class, $mock);
return $mock;
}
/**
* Create a server request.
*
* @param string $method The HTTP method
* @param string|UriInterface $uri The URI
* @param array $serverParams The server parameters
*/
protected function createRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
{
return (new ServerRequestFactory())->createServerRequest($method, $uri, $serverParams);
}
/**
* Create a JSON request.
*
* @param string $method The HTTP method
* @param string|UriInterface $uri The URI
* @param null|array $data The json data
*/
protected function createJsonRequest(string $method, $uri, array $data = null): ServerRequestInterface
{
$request = $this->createRequest($method, $uri);
if ($data !== null) {
$request = $request->withParsedBody($data);
}
return $request->withHeader('Content-Type', 'application/json');
}
/**
* Create a form request.
*
* @param string $method The HTTP method
* @param string|UriInterface $uri The URI
* @param null|array $data The form data
*/
protected function createFormRequest(string $method, $uri, array $data = null): ServerRequestInterface
{
$request = $this->createRequest($method, $uri);
if ($data !== null) {
$request = $request->withParsedBody($data);
}
return $request->withHeader('Content-Type', 'application/x-www-form-urlencoded');
}
/**
* Verify that the specified array is an exact match for the returned JSON.
*
* @param ResponseInterface $response The response
* @param array $expected The expected array
*/
protected function assertJsonData(ResponseInterface $response, array $expected): void
{
$actual = (string) $response->getBody();
$this->assertJson($actual);
$this->assertSame($expected, (array) json_decode($actual, true));
}
}