Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace FrameworkX;

use FrameworkX\Io\LogStreamHandler;
use FrameworkX\Io\MiddlewareHandler;
use FrameworkX\Io\ReactiveHandler;
use FrameworkX\Io\RedirectHandler;
Expand Down Expand Up @@ -126,7 +127,7 @@ public function __construct(...$middleware)

$this->router = $router;
$this->handler = new MiddlewareHandler($handlers);
$this->sapi = \PHP_SAPI === 'cli' ? new ReactiveHandler($container->getEnv('X_LISTEN')) : new SapiHandler();
$this->sapi = $container->getSapi();
}

/**
Expand Down
25 changes: 25 additions & 0 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace FrameworkX;

use FrameworkX\Io\LogStreamHandler;
use FrameworkX\Io\ReactiveHandler;
use FrameworkX\Io\RouteHandler;
use FrameworkX\Io\SapiHandler;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;

Expand Down Expand Up @@ -166,13 +169,28 @@ public function getObject(string $class) /*: object (PHP 7.2+) */
return $this; // @phpstan-ignore-line returns instanceof `T`
} elseif ($class === RouteHandler::class) {
return new RouteHandler($this); // @phpstan-ignore-line returns instanceof `T`
} elseif ($class === ReactiveHandler::class) {
return new ReactiveHandler(new LogStreamHandler('php://output'), $this->getEnv('X_LISTEN')); // @phpstan-ignore-line returns instanceof `T`
}
return new $class();
}

return $this->loadObject($class);
}

/**
* [Internal] Get SAPI handler from container
*
* @return ReactiveHandler|SapiHandler
* @throws \TypeError if container config or factory returns an unexpected type
* @throws \Throwable if container factory function throws unexpected exception
* @internal
*/
public function getSapi() /*: ReactiveHandler|SapiHandler (PHP 8.0+) */
{
return $this->getObject(\PHP_SAPI === 'cli' ? ReactiveHandler::class : SapiHandler::class);
}

/**
* @template T of object
* @param class-string<T> $name
Expand All @@ -186,6 +204,13 @@ private function loadObject(string $name, int $depth = 64) /*: object (PHP 7.2+)
{
\assert(\is_array($this->container));

if ($name === ReactiveHandler::class && !\array_key_exists(ReactiveHandler::class, $this->container)) {
// special case: create ReactiveHandler with X_LISTEN environment variable
$this->container[ReactiveHandler::class] = static function (?string $X_LISTEN = null): ReactiveHandler {
return new ReactiveHandler(new LogStreamHandler('php://output'), $X_LISTEN);
};
}

if (\array_key_exists($name, $this->container)) {
if (\is_string($this->container[$name])) {
if ($depth < 1) {
Expand Down
6 changes: 3 additions & 3 deletions src/Io/ReactiveHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ class ReactiveHandler
/** @var string */
private $listenAddress;

public function __construct(?string $listenAddress)
/** @throws void */
public function __construct(LogStreamHandler $logger, ?string $listenAddress)
{
/** @throws void */
$this->logger = new LogStreamHandler('php://output');
$this->logger = $logger;
$this->listenAddress = $listenAddress ?? '127.0.0.1:8080';
}

Expand Down
36 changes: 26 additions & 10 deletions tests/AppTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,27 @@ public function testConstructWithContainerMockAssignsDefaultHandlersFromContaine
$errorHandler = new ErrorHandler();
$routeHandler = $this->createMock(RouteHandler::class);

$sapi = $this->createMock(ReactiveHandler::class);

$container = $this->createMock(Container::class);
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
[AccessLogHandler::class, $accessLogHandler],
[ErrorHandler::class, $errorHandler],
[RouteHandler::class, $routeHandler],
]);

$container->expects($this->once())->method('getSapi')->willReturn($sapi);
assert($container instanceof Container);

$app = new App($container);

$ref = new \ReflectionProperty($app, 'sapi');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ret = $ref->getValue($app);

$this->assertSame($sapi, $ret);

$ref = new ReflectionProperty($app, 'handler');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
Expand All @@ -127,6 +138,14 @@ public function testConstructWithContainerInstanceAssignsDefaultHandlersAndConta
$container = new Container([]);
$app = new App($container);

$ref = new \ReflectionProperty($app, 'sapi');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ret = $ref->getValue($app);

$this->assertSame($container->getSapi(), $ret);

$ref = new ReflectionProperty($app, 'handler');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
Expand Down Expand Up @@ -900,19 +919,16 @@ public function testConstructWithContainerWithListenAddressWillPassListenAddress
$this->assertEquals('0.0.0.0:8081', $listenAddress);
}

public function testRunWillExecuteRunOnSapiHandler(): void
public function testRunWillExecuteRunOnSapiHandlerFromContainer(): void
{
$app = new App();

$sapi = $this->createMock(ReactiveHandler::class);
$sapi->expects($this->once())->method('run');

// $app->sapi = $sapi;
$ref = new \ReflectionProperty($app, 'sapi');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ref->setValue($app, $sapi);
$container = new Container([
ReactiveHandler::class => $sapi
]);

$app = new App($container);

$app->run();
}
Expand Down
130 changes: 128 additions & 2 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use FrameworkX\AccessLogHandler;
use FrameworkX\Container;
use FrameworkX\ErrorHandler;
use FrameworkX\Io\LogStreamHandler;
use FrameworkX\Io\ReactiveHandler;
use FrameworkX\Io\RouteHandler;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
Expand Down Expand Up @@ -2636,7 +2638,7 @@ public function testGetObjectReturnsDefaultRouteHandlerInstance(): void
$this->assertInstanceOf(RouteHandler::class, $router);

$ref = new \ReflectionProperty($router, 'container');
if (\PHP_VERSION_ID < 801000) {
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ret = $ref->getValue($router);
Expand Down Expand Up @@ -2702,7 +2704,7 @@ public function testGetObjectReturnsDefaultRouteHandlerInstanceIfPsrContainerHas
$this->assertInstanceOf(RouteHandler::class, $router);

$ref = new \ReflectionProperty($router, 'container');
if (\PHP_VERSION_ID < 801000) {
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ret = $ref->getValue($router);
Expand Down Expand Up @@ -2823,6 +2825,130 @@ public function testGetObjectThrowsIfPsrContainerReturnsWrongType(): void
$container->getObject(AccessLogHandler::class);
}

public function testGetSapiReturnsDefaultReactiveHandlerInstance(): void
{
$container = new Container([]);

$sapi = $container->getSapi();

$this->assertInstanceOf(ReactiveHandler::class, $sapi);

$ref = new \ReflectionProperty($sapi, 'listenAddress');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$listenAddress = $ref->getValue($sapi);

$this->assertEquals('127.0.0.1:8080', $listenAddress);
}

public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithCustomListenAddress(): void
{
$container = new Container([
'X_LISTEN' => '127.0.0.1:8081'
]);

$sapi = $container->getSapi();

$this->assertInstanceOf(ReactiveHandler::class, $sapi);

$ref = new \ReflectionProperty($sapi, 'listenAddress');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$listenAddress = $ref->getValue($sapi);

$this->assertEquals('127.0.0.1:8081', $listenAddress);
}

public function testGetSapiTwiceReturnsSameReactiveHandlerInstance(): void
{
$container = new Container([]);

$sapi = $container->getSapi();

$this->assertSame($sapi, $container->getSapi());
}

public function testGetSapiReturnsReactiveHandlerInstanceFromConfig(): void
{
$sapi = new ReactiveHandler(new LogStreamHandler('php://output'), null);

$container = new Container([
ReactiveHandler::class => $sapi
]);

$ret = $container->getSapi();

$this->assertSame($sapi, $ret);
}

public function testGetSapiReturnsReactiveHandlerInstanceFromPsrContainer(): void
{
$sapi = new ReactiveHandler(new LogStreamHandler('php://output'), null);

$psr = $this->createMock(ContainerInterface::class);
$psr->expects($this->once())->method('has')->with(ReactiveHandler::class)->willReturn(true);
$psr->expects($this->once())->method('get')->with(ReactiveHandler::class)->willReturn($sapi);

assert($psr instanceof ContainerInterface);
$container = new Container($psr);

$ret = $container->getSapi();

$this->assertSame($sapi, $ret);
}

public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithDefaultListenAddressIfPsrContainerHasNoEntry(): void
{
$psr = $this->createMock(ContainerInterface::class);
$psr->expects($this->exactly(2))->method('has')->willReturnMap([
[ReactiveHandler::class, false],
['X_LISTEN', false],
]);
$psr->expects($this->never())->method('get');

assert($psr instanceof ContainerInterface);
$container = new Container($psr);

$sapi = $container->getSapi();

$this->assertInstanceOf(ReactiveHandler::class, $sapi);

$ref = new \ReflectionProperty($sapi, 'listenAddress');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$listenAddress = $ref->getValue($sapi);

$this->assertEquals('127.0.0.1:8080', $listenAddress);
}

public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithCustomListenAddressIfPsrContainerHasNoEntryButCustomListenAddress(): void
{
$psr = $this->createMock(ContainerInterface::class);
$psr->expects($this->exactly(2))->method('has')->willReturnMap([
[ReactiveHandler::class, false],
['X_LISTEN', true],
]);
$psr->expects($this->once())->method('get')->with('X_LISTEN')->willReturn('127.0.0.1:8081');

assert($psr instanceof ContainerInterface);
$container = new Container($psr);

$sapi = $container->getSapi();

$this->assertInstanceOf(ReactiveHandler::class, $sapi);

$ref = new \ReflectionProperty($sapi, 'listenAddress');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$listenAddress = $ref->getValue($sapi);

$this->assertEquals('127.0.0.1:8081', $listenAddress);
}

public function testInvokeContainerAsMiddlewareReturnsFromNextRequestHandler(): void
{
$request = new ServerRequest('GET', 'http://example.com/');
Expand Down
Loading