Rejigging router, fixing running tests with slim4
This commit is contained in:
parent
df6435ff3c
commit
b4ea0ad8a6
4 changed files with 175 additions and 133 deletions
60
src/App.php
60
src/App.php
|
|
@ -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.'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
130
tests/Traits/AppTestTrait.php
Normal file
130
tests/Traits/AppTestTrait.php
Normal 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));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue