Skip to content

Commit 800cb4a

Browse files
committed
Cleanups
1 parent 1811e61 commit 800cb4a

File tree

11 files changed

+232
-86
lines changed

11 files changed

+232
-86
lines changed

example/bare-minimal-json-server.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
// Standard composer autoloader
4+
require __DIR__ . '/../vendor/autoload.php';
5+
6+
// Create a React EventLoop
7+
$loop = React\EventLoop\Factory::create();
8+
9+
// Application context will be accessible everywhere
10+
// @See \PhpBg\MiniHttpd\Middleware\ContextTrait to retrieve it easily
11+
$applicationContext = new \PhpBg\MiniHttpd\Model\ApplicationContext();
12+
13+
// Default renderer
14+
$applicationContext->defaultRenderer = new \PhpBg\MiniHttpd\Renderer\Json();
15+
16+
// Define a single route
17+
$applicationContext->routes = [
18+
'/' => new \PhpBg\MiniHttpd\Model\Route(function () {
19+
return ['hello' => 'world'];
20+
}, $applicationContext->defaultRenderer)
21+
];
22+
23+
// PSR3 logger
24+
$applicationContext->logger = new \PhpBg\MiniHttpd\Logger\Console(\Psr\Log\LogLevel::DEBUG);
25+
26+
// Create a default application stack
27+
$server = \PhpBg\MiniHttpd\ServerFactory::create($applicationContext);
28+
29+
// Listen on port 8080
30+
$socket = new React\Socket\Server(8080, $loop);
31+
$server->listen($socket);
32+
$applicationContext->logger->notice("Server started");
33+
34+
// now just open your browser and go to http://localhost:8080
35+
$loop->run();
Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<?php
22

3-
ini_set('memory_limit', '64M');
4-
3+
// Standard composer autoloader
54
require __DIR__ . '/../vendor/autoload.php';
65

76
// Manual requires for demo purpose.
@@ -16,7 +15,7 @@
1615
// Redirection example
1716
'/' => new \PhpBg\MiniHttpd\Model\Route(function () {
1817
throw new \PhpBg\MiniHttpd\HttpException\RedirectException('/demo');
19-
}, $jsonRenderer),
18+
}),
2019

2120
// Inline callable example, that return an array rendered as JSON
2221
'/api/task/get' => new \PhpBg\MiniHttpd\Model\Route(function () use ($taskController) {
@@ -32,8 +31,8 @@
3231
'/demo' => new \PhpBg\MiniHttpd\Model\Route(new Demo(), new \PhpBg\MiniHttpd\Renderer\Phtml\Phtml(__DIR__ . '/pages/layout.phtml')),
3332
];
3433

35-
// Application context will be injected in a request attribute.
36-
// See \PhpBg\MiniHttpd\Middleware\ContextTrait to retrieve it easily
34+
// Application context will be accessible everywhere
35+
// @See \PhpBg\MiniHttpd\Middleware\ContextTrait to retrieve it easily
3736
$applicationContext = new \PhpBg\MiniHttpd\Model\ApplicationContext();
3837

3938
// You may require loop for async tasks
@@ -43,60 +42,25 @@
4342
$applicationContext->options = [];
4443
$applicationContext->routes = $routes;
4544

46-
// Public path is where static files are served from
45+
// Public path is where static files are served from (optional)
4746
$applicationContext->publicPath = __DIR__ . '/public';
4847

4948
// You can share your PSR3 logger here
5049
$applicationContext->logger = new \PhpBg\MiniHttpd\Logger\Console(\Psr\Log\LogLevel::DEBUG);
5150

52-
$mimeDb = new \PhpBg\MiniHttpd\MimeDb\MimeDb($applicationContext->logger);
53-
54-
$server = new \React\Http\Server([
55-
// Log all incoming requests
56-
new \PhpBg\MiniHttpd\Middleware\LogRequest($applicationContext->logger),
57-
58-
// Make application context and request context available to all middlewares. Allow data exchanging between middlewares
59-
new \PhpBg\MiniHttpd\Middleware\Context($applicationContext),
60-
61-
// Decode once uri path
62-
new \PhpBg\MiniHttpd\Middleware\UriPath(),
63-
64-
// Convert (some) PSR-7 bodies to react streams
65-
new \PhpBg\MiniHttpd\Middleware\ResponseBodyToReactStream(),
66-
67-
// Compress compressible responses
68-
new \PhpBg\MiniHttpd\Middleware\GzipResponse($mimeDb->getCompressible()),
51+
$applicationContext->defaultRenderer = $jsonRenderer;
6952

70-
// Serve static files
71-
new \PhpBg\MiniHttpd\Middleware\StaticContent($applicationContext->publicPath, $applicationContext->logger),
53+
$server = \PhpBg\MiniHttpd\ServerFactory::create($applicationContext);
7254

73-
// Prepare fore rendering
74-
new \PhpBg\MiniHttpd\Middleware\Render($jsonRenderer),
75-
76-
// Log exceptions
77-
new \PhpBg\MiniHttpd\Middleware\LogError($applicationContext->logger),
78-
79-
// Calculate route
80-
new \PhpBg\MiniHttpd\Middleware\Route(),
81-
82-
// Auto render PHTML files
83-
new \PhpBg\MiniHttpd\Middleware\AutoPhtml(),
84-
85-
// Run route selected
86-
new \PhpBg\MiniHttpd\Middleware\Run()
87-
]);
88-
89-
// Log server errors
90-
$server->on('error', function($exception) use ($applicationContext) {
91-
$applicationContext->logger->error('', ['exception' => $exception]);
92-
});
93-
94-
// Run server on port 8080
95-
// just open your browser and go to http://localhost:8080
55+
// Listen on port 8080
56+
// If you want to listen on all interfaces, then use 'tcp://0.0.0.0:8080'
57+
// @see \React\Socket\TcpServer and @see \React\Socket\SecureServer for more options
9658
$socket = new React\Socket\Server(8080, $loop);
9759
$server->listen($socket);
9860
if (extension_loaded('xdebug')) {
9961
$applicationContext->logger->warning('The "xdebug" extension is loaded, this has a major impact on performance.');
10062
}
10163
$applicationContext->logger->notice("Server started");
64+
65+
// now just open your browser and go to http://localhost:8080
10266
$loop->run();

example/pages/Demo.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ new Vue({
2626
}
2727
});
2828

29+
// Global ajax start
30+
$(document).ajaxStart(function() {
31+
app.ajaxError = null;
32+
});
33+
2934
$.ajax({
3035
url: app.apiUrl + "/task/get",
3136
}).done(function(tasks) {

src/Middleware/AutoPhtml.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public function __invoke(ServerRequestInterface $request, callable $next)
4242
{
4343
$result = $next($request);
4444
$context = $this->getContext($request);
45-
if ($context->route->renderer instanceof Phtml && is_object($context->route->handler)) {
45+
$renderer = $context->getRenderer();
46+
if ($renderer instanceof Phtml && is_object($context->route->handler)) {
4647
$rc = new \ReflectionClass(get_class($context->route->handler));
4748
$controllerFilePath = $rc->getFileName();
4849
$controllerFilePathinfo = pathinfo($controllerFilePath);

src/Middleware/Render.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ function ($result) use ($context, $request) {
7373
return $result;
7474
}
7575
$response = $context->getResponse();
76-
return $context->route->renderer->render($request, $response, $context->renderOptions, $result);
76+
$renderer = $this->getRenderer($request);
77+
return $renderer->render($request, $response, $context->renderOptions, $result);
7778
},
7879
function (\Exception $e) use ($request) {
7980
return $this->doRenderException($request, $e);
@@ -84,7 +85,13 @@ function (\Exception $e) use ($request) {
8485
}
8586
}
8687

87-
protected function doRenderException(ServerRequestInterface $request, \Exception $e)
88+
/**
89+
* Render exceptions
90+
* @param ServerRequestInterface $request
91+
* @param \Exception $e
92+
* @return ResponseInterface
93+
*/
94+
protected function doRenderException(ServerRequestInterface $request, \Exception $e): ResponseInterface
8895
{
8996
if ($e instanceof RedirectException) {
9097
$response = $this->getContext($request)->getResponse();
@@ -101,21 +108,14 @@ protected function doRenderException(ServerRequestInterface $request, \Exception
101108

102109
/**
103110
* Return renderer instance to use
104-
*
105111
* Override this if you want another strategy, based for example on request "Accept" header
106112
*
107113
* @param ServerRequestInterface $request
108114
* @return RendererInterface
109115
*/
110116
protected function getRenderer(ServerRequestInterface $request): RendererInterface
111117
{
112-
// Use route renderer if any
113118
$context = $this->getContext($request);
114-
if (isset($context->route->renderer)) {
115-
return $context->route->renderer;
116-
}
117-
118-
// Otherwise use default renderer
119-
return $this->defaultRenderer;
119+
return $context->getRenderer();
120120
}
121121
}

src/Middleware/StaticContent.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@
2626

2727
namespace PhpBg\MiniHttpd\Middleware;
2828

29-
use PhpBg\MiniHttpd\MimeDb\MimeDb;
3029
use Psr\Http\Message\ServerRequestInterface;
31-
use Psr\Log\LoggerInterface;
3230

3331
/**
3432
* Serve static files
@@ -44,15 +42,16 @@ class StaticContent
4442
protected $publicPath;
4543

4644
/**
47-
* @var MimeDb
45+
* @see StaticContent::__construct()
46+
* @var array
4847
*/
49-
protected $mimeDb;
48+
protected $mimeNamesByExtension;
5049

5150
/**
5251
* @param string $publicPath Full path to the directory that contain files to serve. Ex: /var/www/public
53-
* @param LoggerInterface $logger
52+
* @param array $mimeNamesByExtension array of mimes names, by (unique) extension. E.g. ['html' => 'application/html']
5453
*/
55-
public function __construct(string $publicPath, LoggerInterface $logger)
54+
public function __construct(string $publicPath, array $mimeNamesByExtension)
5655
{
5756
if (!is_dir($publicPath)) {
5857
throw new \RuntimeException();
@@ -62,7 +61,7 @@ public function __construct(string $publicPath, LoggerInterface $logger)
6261
throw new \RuntimeException();
6362
}
6463
$this->publicPath = $publicPath;
65-
$this->mimeDb = new MimeDb($logger);
64+
$this->mimeNamesByExtension = $mimeNamesByExtension;
6665
}
6766

6867
public function __invoke(ServerRequestInterface $request, callable $next = null)
@@ -77,9 +76,9 @@ public function __invoke(ServerRequestInterface $request, callable $next = null)
7776
$headers = [
7877
'Cache-Control' => 'public, max-age=31536000' //1 year of cache, make sure you change URLs when changing resources
7978
];
80-
$mime = $this->mimeDb->getFromExtension($extension);
79+
$mime = $this->mimeNamesByExtension[$extension] ?? null;
8180
if ($mime !== null) {
82-
$headers['Content-Type'] = $mime['name'];
81+
$headers['Content-Type'] = $mime;
8382
}
8483
return new \React\Http\Response(
8584
200,

src/MimeDb/MimeDb.php

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
/**
34
* MIT License
45
*
@@ -29,17 +30,24 @@
2930

3031
/**
3132
* Class MimeDb
32-
* Provide mime info based on a file extension
33-
* File extensions having multiple mime types will be ignored
33+
* Provide mime info:
34+
* * mime names
35+
* * file extensions
36+
* * compressible mimes
3437
*
35-
* Inspired from https://github.com/narrowspark/mimetypes and unsing https://github.com/jshttp/mime-db
38+
* Based on https://github.com/jshttp/mime-db
3639
*/
3740
class MimeDb
3841
{
3942
protected $byExtension;
4043

4144
protected $byName;
4245

46+
/**
47+
* MimeDb constructor.
48+
* @param LoggerInterface $logger
49+
* @throws MimeDbException
50+
*/
4351
public function __construct(LoggerInterface $logger)
4452
{
4553
$dbFile = __DIR__ . '/db.json';
@@ -73,9 +81,10 @@ public function __construct(LoggerInterface $logger)
7381
$extensionsWhatever = [];
7482
$this->byExtension = [];
7583
foreach ($extensions as $extension => $extensionList) {
76-
$this->byExtension[$extension] = $this->selectExtensionDescriptor($extension, $extensionList, $extensionsFromIana, $extensionsWhatever);
84+
$selectedDescriptor = $this->selectExtensionDescriptor($extension, $extensionList, $extensionsFromIana, $extensionsWhatever);
85+
$this->byExtension[$extension] = $selectedDescriptor['name'];
7786
};
78-
$logger->debug("MIME extensions",$extensions);
87+
$logger->debug("MIME extensions", $extensions);
7988
$logger->info("MIME: " . count($extensions) . " extensions loaded");
8089
$logger->debug("MIME: following extensions have duplicates resolved with IANA flavor", $extensionsFromIana);
8190
$logger->debug("MIME: following extensions have duplicates resolved randomly", $extensionsWhatever);
@@ -100,27 +109,24 @@ protected function selectExtensionDescriptor(string $extension, array $extension
100109
}
101110

102111
/**
103-
* Return mime descriptor by file extension.
104-
* Mime descriptor is an array containing:
105-
* - name: string: mime type name (aka "content type" in HTTP context). Eg application/json
106-
* - other data described here: https://github.com/jshttp/mime-db
112+
* Return mime names by extension
113+
* E.g. ['html' => 'application/html', ...]
114+
* File extensions having multiple mime types will be resolved with IANA priority.
115+
* Duplicates are logged at init, check your logs
107116
*
108-
* @param string $extension
109-
* @return array|null
117+
* @return array
110118
*/
111-
public function getFromExtension(string $extension)
119+
public function getNamesByExtension(): array
112120
{
113-
if (empty($extension)) {
114-
return null;
115-
}
116-
return $this->byExtension[$extension] ?? null;
121+
return $this->byExtension;
117122
}
118123

119124
/**
120125
* Return compressible mime names
121126
* @return array
122127
*/
123-
public function getCompressible():array {
128+
public function getCompressible(): array
129+
{
124130
$compressible = [];
125131
foreach ($this->byName as $name => $descriptor) {
126132
if (isset($descriptor['compressible']) && $descriptor['compressible']) {

src/Model/ApplicationContext.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@
2626

2727
namespace PhpBg\MiniHttpd\Model;
2828

29+
use PhpBg\MiniHttpd\Renderer\RendererInterface;
2930
use Psr\Log\LoggerInterface;
3031
use React\EventLoop\LoopInterface;
3132

33+
/**
34+
* Common ApplicationContext shared across everybody
35+
* Public fields are not guaranteed to be initialized so please make your checks when accessing them
36+
*/
3237
class ApplicationContext
3338
{
3439
/**
@@ -58,4 +63,9 @@ class ApplicationContext
5863
* @var LoggerInterface
5964
*/
6065
public $logger;
66+
67+
/**
68+
* @var RendererInterface
69+
*/
70+
public $defaultRenderer;
6171
}

src/Model/RequestContext.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
namespace PhpBg\MiniHttpd\Model;
2828

29+
use PhpBg\MiniHttpd\Renderer\RendererInterface;
2930
use Psr\Http\Message\ResponseInterface;
3031
use React\Http\Response;
3132

@@ -94,4 +95,20 @@ public function setResponse(ResponseInterface $response): ResponseInterface
9495
$this->response = $response;
9596
return $this->response;
9697
}
98+
99+
/**
100+
* Return renderer instance to use
101+
*
102+
* @return RendererInterface
103+
*/
104+
public function getRenderer(): RendererInterface
105+
{
106+
// Use route renderer if any
107+
if (isset($this->route->renderer)) {
108+
return $this->route->renderer;
109+
}
110+
111+
// Otherwise use default renderer
112+
return $this->applicationContext->defaultRenderer;
113+
}
97114
}

0 commit comments

Comments
 (0)