Skip to content

Commit

Permalink
extract framework from "kawanamiyuu/htb-feed"
Browse files Browse the repository at this point in the history
  • Loading branch information
kawanamiyuu committed Jul 8, 2020
1 parent 6e7ae57 commit c3685fd
Show file tree
Hide file tree
Showing 13 changed files with 334 additions and 1 deletion.
11 changes: 10 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "k9u/framework",
"type": "library",
"description": "Web Application Framework for PHP.",
"keywords": ["framework", "psr-7", "psr-15"],
"license": "MIT",
"authors": [
{
Expand All @@ -11,7 +12,15 @@
],
"minimum-stability": "stable",
"require": {
"php": "^7.4"
"php": "^7.4",
"laminas/laminas-diactoros": "^2.3",
"laminas/laminas-httphandlerrunner": "^1.2",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0",
"psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0",
"ray/di": "^2.10",
"relay/relay": "^2.1"
},
"require-dev": {
"phpmd/phpmd": "^2.8",
Expand Down
47 changes: 47 additions & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Throwable;

/**
* @SuppressWarnings("PMD.LongVariable")
*/
class Application implements ApplicationInterface
{
private RequestHandlerInterface $requestHandler;

private ExceptionHandlerInterface $exceptionHandler;

private ResponseEmitterInterface $responseEmitter;

/**
* @param RequestHandlerInterface $requestHandler
* @param ExceptionHandlerInterface $exceptionHandler
* @param ResponseEmitterInterface $responseEmitter
*/
public function __construct(
RequestHandlerInterface $requestHandler,
ExceptionHandlerInterface $exceptionHandler,
ResponseEmitterInterface $responseEmitter
) {
$this->requestHandler = $requestHandler;
$this->exceptionHandler = $exceptionHandler;
$this->responseEmitter = $responseEmitter;
}

public function __invoke(ServerRequestInterface $request): void
{
try {
$response = $this->requestHandler->handle($request);
} catch (Throwable $th) {
$response = ($this->exceptionHandler)($th, $request);
}

($this->responseEmitter)($response);
}
}
15 changes: 15 additions & 0 deletions src/ApplicationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ServerRequestInterface;

interface ApplicationInterface
{
/**
* @param ServerRequestInterface $request
*/
public function __invoke(ServerRequestInterface $request): void;
}
29 changes: 29 additions & 0 deletions src/ExceptionHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

class ExceptionHandler implements ExceptionHandlerInterface
{
private ResponseFactoryInterface $responseFactory;

public function __construct(ResponseFactoryInterface $responseFactory)
{
$this->responseFactory = $responseFactory;
}

public function __invoke(Throwable $throwable, ServerRequestInterface $request): ResponseInterface
{
unset($request); // unused

error_log((string) $throwable);

return $this->responseFactory->createResponse(505);
}
}
14 changes: 14 additions & 0 deletions src/ExceptionHandlerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

interface ExceptionHandlerInterface
{
public function __invoke(Throwable $throwable, ServerRequestInterface $request): ResponseInterface;
}
57 changes: 57 additions & 0 deletions src/FrameworkModule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Laminas\Diactoros\ResponseFactory;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Ray\Di\AbstractModule;
use Ray\Di\Scope;

/**
* @SuppressWarnings("PHPMD.CouplingBetweenObjects")
*/
class FrameworkModule extends AbstractModule
{
/**
* @var array<class-string>
*/
private array $middlewares;

/**
* @param array<class-string> $middlewares
* @param AbstractModule|null $module
*/
public function __construct(array $middlewares, AbstractModule $module = null)
{
$this->middlewares = $middlewares;
parent::__construct($module);
}

protected function configure(): void
{
foreach ($this->middlewares as $middleware) {
$this->bind($middleware)->in(Scope::SINGLETON);
}

$this->bind(MiddlewareContainer::class)
->toInstance(new MiddlewareContainer($this->middlewares));

$this->bind(RequestHandlerInterface::class)
->toProvider(RequestHandlerProvider::class)->in(Scope::SINGLETON);

$this->bind(ResponseFactoryInterface::class)
->to(ResponseFactory::class)->in(Scope::SINGLETON);

$this->bind(ExceptionHandlerInterface::class)
->to(ExceptionHandler::class)->in(Scope::SINGLETON);

$this->bind(ResponseEmitterInterface::class)
->to(ResponseEmitter::class)->in(Scope::SINGLETON);

$this->bind(ApplicationInterface::class)
->to(Application::class)->in(Scope::SINGLETON);
}
}
33 changes: 33 additions & 0 deletions src/MiddlewareContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use ArrayIterator;
use IteratorAggregate;
use Traversable;

/**
* @implements \IteratorAggregate<class-string>
*/
class MiddlewareContainer implements IteratorAggregate
{
/**
* @var array<class-string> $middlewares
*/
private array $middlewares;

/**
* @param array<class-string> $middlewares
*/
public function __construct(array $middlewares)
{
$this->middlewares = $middlewares;
}

public function getIterator(): Traversable
{
return new ArrayIterator($this->middlewares);
}
}
33 changes: 33 additions & 0 deletions src/RequestHandlerProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Ray\Di\InjectorInterface;
use Ray\Di\ProviderInterface;
use Relay\Relay;

class RequestHandlerProvider implements ProviderInterface
{
private MiddlewareContainer $middlewareContainer;

private InjectorInterface $injector;

public function __construct(MiddlewareContainer $middlewareContainer, InjectorInterface $injector)
{
$this->middlewareContainer = $middlewareContainer;
$this->injector = $injector;
}

public function get(): RequestHandlerInterface
{
return new Relay($this->middlewareContainer, function ($middleware) {
$instance = $this->injector->getInstance($middleware);
assert($instance instanceof MiddlewareInterface || $instance instanceof RequestHandlerInterface);
return $instance;
});
}
}
16 changes: 16 additions & 0 deletions src/ResponseEmitter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Laminas\HttpHandlerRunner\Emitter\SapiStreamEmitter;
use Psr\Http\Message\ResponseInterface;

class ResponseEmitter implements ResponseEmitterInterface
{
public function __invoke(ResponseInterface $response): void
{
(new SapiStreamEmitter())->emit($response);
}
}
12 changes: 12 additions & 0 deletions src/ResponseEmitterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ResponseInterface;

interface ResponseEmitterInterface
{
public function __invoke(ResponseInterface $response): void;
}
18 changes: 18 additions & 0 deletions tests/FakeMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class FakeMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
return $handler->handle($request);
}
}
27 changes: 27 additions & 0 deletions tests/FakeRequestHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class FakeRequestHandler implements RequestHandlerInterface
{
private ResponseFactoryInterface $responseFactory;

public function __construct(ResponseFactoryInterface $responseFactory)
{
$this->responseFactory = $responseFactory;
}

public function handle(ServerRequestInterface $request): ResponseInterface
{
unset($request); // unused

return $this->responseFactory->createResponse(200);
}
}
23 changes: 23 additions & 0 deletions tests/FrameworkModuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace K9u\Framework;

use PHPUnit\Framework\TestCase;
use Ray\Di\Injector;

class FrameworkModuleTest extends TestCase
{
public function testCompile(): void
{
$injector = new Injector(new FrameworkModule([
FakeMiddleware::class,
FakeRequestHandler::class
]));

$instance = $injector->getInstance(ApplicationInterface::class);

$this->assertInstanceOf(ApplicationInterface::class, $instance);
}
}

0 comments on commit c3685fd

Please sign in to comment.