add chapter 12 solutions

This commit is contained in:
lubiana 2022-05-31 17:49:17 +02:00 committed by Andre Lubian
parent f857fa4752
commit ebbcc6e7f6
23 changed files with 1998 additions and 0 deletions

View file

@ -0,0 +1,31 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Action;
use Lubian\NoFramework\Service\Time\Clock;
use Lubian\NoFramework\Template\Renderer;
use Psr\Http\Message\ResponseInterface;
final class Hello
{
public function __invoke(
ResponseInterface $response,
Clock $clock,
Renderer $renderer,
string $name = 'Stranger',
): ResponseInterface {
$data = [
'name' => $name,
'time' => $clock->now()
->format('H:i:s'),
];
$content = $renderer->render('hello', $data,);
$body = $response->getBody();
$body->write($content);
return $response->withBody($body)
->withStatus(200);
}
}

View file

@ -0,0 +1,24 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Action;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
final class Other implements RequestHandlerInterface
{
public function __construct(private readonly ResponseInterface $response)
{
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$body = $this->response->getBody();
$body->write('This works too!');
return $this->response->withBody($body)
->withStatus(200);
}
}

View file

@ -0,0 +1,109 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework;
use FastRoute\Dispatcher;
use Invoker\InvokerInterface;
use Laminas\Diactoros\Response;
use Lubian\NoFramework\Exception\InternalServerError;
use Lubian\NoFramework\Exception\MethodNotAllowed;
use Lubian\NoFramework\Exception\NotFound;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Run;
use function assert;
use function error_log;
use function error_reporting;
use function getenv;
use function header;
use function sprintf;
use function strtolower;
use const E_ALL;
require __DIR__ . '/../vendor/autoload.php';
$config = require __DIR__ . '/../config/settings.php';
assert($config instanceof Configuration);
$environment = $config->environment;
error_reporting(E_ALL);
$whoops = new Run;
if ($environment === 'dev') {
$whoops->pushHandler(new PrettyPageHandler);
} else {
$whoops->pushHandler(function (Throwable $t) {
error_log('ERROR: ' . $t->getMessage(), $t->getCode());
echo 'Oooopsie';
});
}
$whoops->register();
$container = require __DIR__ . '/../config/container.php';
assert($container instanceof ContainerInterface);
$request = $container->get(ServerRequestInterface::class);
assert($request instanceof ServerRequestInterface);
$dispatcher = $container->get(Dispatcher::class);
assert($dispatcher instanceof Dispatcher);
$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getUri() ->getPath(),);
try {
switch ($routeInfo[0]) {
case Dispatcher::FOUND:
$routeTarget = $routeInfo[1];
$args = $routeInfo[2];
foreach ($routeInfo[2] as $attributeName => $attributeValue) {
$request = $request->withAttribute($attributeName, $attributeValue);
}
$args['request'] = $request;
$invoker = $container->get(InvokerInterface::class);
assert($invoker instanceof InvokerInterface);
$response = $invoker->call($routeTarget, $args);
assert($response instanceof ResponseInterface);
break;
case Dispatcher::METHOD_NOT_ALLOWED:
throw new MethodNotAllowed;
case Dispatcher::NOT_FOUND:
default:
throw new NotFound;
}
} catch (MethodNotAllowed) {
$response = (new Response)->withStatus(405);
$response->getBody()
->write('Method not Allowed');
} catch (NotFound) {
$response = (new Response)->withStatus(404);
$response->getBody()
->write('Not Found');
} catch (Throwable $t) {
throw new InternalServerError($t->getMessage(), $t->getCode(), $t);
}
foreach ($response->getHeaders() as $name => $values) {
$first = strtolower($name) !== 'set-cookie';
foreach ($values as $value) {
$header = sprintf('%s: %s', $name, $value);
header($header, $first);
$first = false;
}
}
$statusLine = sprintf(
'HTTP/%s %s %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
);
header($statusLine, true, $response->getStatusCode());
echo $response->getBody();

View file

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework;
final class Configuration
{
public function __construct(
public readonly string $environment = 'dev',
public readonly string $routesFile = __DIR__ . '/../config/routes.php',
public readonly string $templateDir = __DIR__ . '/../templates',
public readonly string $templateExtension = '.html',
) {
}
}

View file

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Exception;
use Exception;
final class InternalServerError extends Exception
{
}

View file

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Exception;
use Exception;
final class MethodNotAllowed extends Exception
{
}

View file

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Exception;
use Exception;
final class NotFound extends Exception
{
}

View file

@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Service\Time;
use DateTimeImmutable;
interface Clock
{
public function now(): DateTimeImmutable;
}

View file

@ -0,0 +1,13 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Service\Time;
use DateTimeImmutable;
final class SystemClock implements Clock
{
public function now(): DateTimeImmutable
{
return new DateTimeImmutable;
}
}

View file

@ -0,0 +1,17 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Template;
use Mustache_Engine;
final class MustacheRenderer implements Renderer
{
public function __construct(private readonly Mustache_Engine $engine)
{
}
public function render(string $template, array $data): string
{
return $this->engine->render($template, $data);
}
}

View file

@ -0,0 +1,11 @@
<?php declare(strict_types=1);
namespace Lubian\NoFramework\Template;
interface Renderer
{
/**
* @param array<string, mixed> $data
*/
public function render(string $template, array $data): string;
}