Skip to content

Commit

Permalink
Merge a0a0d49 into cd2591c
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonterando committed Jul 3, 2020
2 parents cd2591c + a0a0d49 commit ba2155d
Show file tree
Hide file tree
Showing 14 changed files with 930 additions and 207 deletions.
80 changes: 80 additions & 0 deletions docs/book/v2/static-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,86 @@ return [
];
```

## Mapped Document Roots

The `Mezzio\Swoole\StaticResourceHandler\FileLocationRepository` implements the `Mezzio\Swoole\StaticResourceHandler\FileLocationRepositoryInterface` to maintain an association of URI prefixes with file directories. A module can designate the URL prefix `/my-module` to refer to files located in its `templates` directory.

An example use case would be if you have a module that contains a template, and that template relies on assets like JavaScript files, CSS files, etc. Instead of copying those assets to a public directory configured in `document-root`, you can leave the files in the module, and access them using a defined URI prefix.

To accomplish this:

1. Define what your URI prefix will be (ex. /my-module)
2. Update your template/s attributes like `href` and `src` to use the prefix (ex. `<script src='/my-module/style.css'></script>`)
3. In the factory of your handler, or whatever is rendering the template, set up the linkage between the prefix and the directory where your assets are located.

### Mapped Document Roots - Example

Assume you have a module, AwesomeModule, which has a handler called "HomeHandler", which renders the 'home' template. You designate the prefix, `/awesome-home` for rendering the assets. The structure of your module looks like this:

```
AwesomeModule
├── src
| ├── Handler
| | ├── HomeHandler.php
| | ├── HomeHandlerFactory.php
| ├── ConfigProvider.php
├── templates
│ ├── home
| | ├── home.html
| | ├── style.css
│ ├── layouts
```

In your `home.html` template, you can refer to the `style.css` file as follows:

```
<link href="/awesome-home/style.css" rel="stylesheet" type="text/css">
```

In your module's ConfigProvider, you can add a configuration setting as follows:
```php
public function __invoke() : array
{
return [
'mezzio-swoole' => [
'swoole-http-server' => [
'static-files' => [
'mapped-document-roots' => [
'awseome-home' => __DIR__ . '/../../templates/home'
]
]
]
]
];
}
```

Alterantively, in the factory of the handler, you can create an assignment for `/awesome-home` to your modules's `templates/home` directory.
This approach could be useful if the directory of the assets isn't know until runtime.

```php
use Psr\Container\ContainerInterface;
use Mezzio\Template\TemplateRendererInterface;
use Mezzio\Swoole\StaticResourceHandler\FileLocationRepositoryInterface;

class AwesomeHomeHandlerFactory
{
public function __invoke(ContainerInterface $container) : DocumentationViewHandler
{
// Establish location for the home template assets
$repo = $container->get(FileLocationRepositoryInterface::class);
$repo->addMappedDocumentRoot('awesome-home',
realpath(__DIR__ . '/../../templates/home'));

return new AwesomeHomeHandler(
$container->get(TemplateRendererInterface::class)
);
}
}
```

When the template renders, the client will request `/awesome-home/style.css`, which the StaticResourceHandler will now retrieve from the `templates/home` folder of the module.

## Writing Middleware

Static resource middleware must implement
Expand Down
11 changes: 8 additions & 3 deletions src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
use Mezzio\Swoole\HotCodeReload\FileWatcherInterface;
use Mezzio\Swoole\HotCodeReload\Reloader;
use Mezzio\Swoole\HotCodeReload\ReloaderFactory;
use Mezzio\Swoole\StaticResourceHandler\FileLocationRepository;
use Mezzio\Swoole\StaticResourceHandler\FileLocationRepositoryFactory;
use Mezzio\Swoole\StaticResourceHandler\FileLocationRepositoryInterface;
use Psr\Http\Message\ServerRequestInterface;
use Swoole\Http\Server as SwooleHttpServer;

Expand Down Expand Up @@ -76,14 +79,16 @@ public function getDependencies() : array
StaticResourceHandler::class => StaticResourceHandlerFactory::class,
SwooleHttpServer::class => HttpServerFactory::class,
Reloader::class => ReloaderFactory::class,
FileLocationRepository::class => FileLocationRepositoryFactory::class,
],
'invokables' => [
InotifyFileWatcher::class => InotifyFileWatcher::class,
],
'aliases' => [
RequestHandlerRunner::class => SwooleRequestHandlerRunner::class,
StaticResourceHandlerInterface::class => StaticResourceHandler::class,
FileWatcherInterface::class => InotifyFileWatcher::class,
RequestHandlerRunner::class => SwooleRequestHandlerRunner::class,
StaticResourceHandlerInterface::class => StaticResourceHandler::class,
FileWatcherInterface::class => InotifyFileWatcher::class,
FileLocationRepositoryInterface::class => FileLocationRepository::class,

// Legacy Zend Framework aliases
\Zend\Expressive\Swoole\Command\ReloadCommand::class => Command\ReloadCommand::class,
Expand Down
30 changes: 15 additions & 15 deletions src/StaticResourceHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,50 @@

use Swoole\Http\Request as SwooleHttpRequest;
use Swoole\Http\Response as SwooleHttpResponse;
use Mezzio\Swoole\StaticResourceHandler\FileLocationRepositoryInterface;

use function is_callable;
use function is_dir;
use function sprintf;

class StaticResourceHandler implements StaticResourceHandlerInterface
{
/**
* @var string
* Middleware to execute when serving a static resource.
*
* @var StaticResourceHandler\MiddlewareInterface[]
*/
private $docRoot;
private $middleware;

/**
* Middleware to execute when serving a static resource.
*
* @var StaticResourceHandler\MiddlewareInterface[]
* @var StaticResourceHandler\FileLocationRepositoryInterface[]
*/
private $middleware;
private $fileLocationRepo;

/**
* @throws Exception\InvalidStaticResourceMiddlewareException for any
* non-callable middleware encountered.
*/
public function __construct(
string $docRoot,
FileLocationRepositoryInterface $fileLocationRepo,
array $middleware = []
) {
if (! is_dir($docRoot)) {
throw new Exception\InvalidArgumentException(sprintf(
'The document root "%s" does not exist; please check your configuration.',
$docRoot
));
}
$this->validateMiddleware($middleware);

$this->docRoot = $docRoot;
$this->middleware = $middleware;
$this->fileLocationRepo = $fileLocationRepo;
}

public function processStaticResource(
SwooleHttpRequest $request,
SwooleHttpResponse $response
) : ?StaticResourceHandler\StaticResourceResponse {
$filename = $this->docRoot . $request->server['request_uri'];
$filename = $this->fileLocationRepo->findFile(
$request->server['request_uri']
);
if (! $filename) {
return null;
}

$middleware = new StaticResourceHandler\MiddlewareQueue($this->middleware);
$staticResourceResponse = $middleware($request, $filename);
Expand Down
5 changes: 0 additions & 5 deletions src/StaticResourceHandler/ContentTypeFilterMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

use Swoole\Http\Request;

use function file_exists;
use function pathinfo;

use const PATHINFO_EXTENSION;
Expand Down Expand Up @@ -148,10 +147,6 @@ private function cacheFile(string $fileName) : bool
return false;
}

if (! file_exists($fileName)) {
return false;
}

$this->cacheTypeFile[$fileName] = $this->typeMap[$type];
return true;
}
Expand Down
121 changes: 121 additions & 0 deletions src/StaticResourceHandler/FileLocationRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

/**
* @see https://github.com/mezzio/mezzio-swoole for the canonical source repository
* @copyright https://github.com/mezzio/mezzio-swoole/blob/master/COPYRIGHT.md
* @license https://github.com/mezzio/mezzio-swoole/blob/master/LICENSE.md New BSD License
*/

declare(strict_types=1);

namespace Mezzio\Swoole\StaticResourceHandler;

use InvalidArgumentException;

class FileLocationRepository implements FileLocationRepositoryInterface
{
/**
* @var array
* Associative array of URI prefixes and directories
*/
private $mappedDocRoots = [];

/**
* Initialize repository with default mapped document roots
*/
public function __construct(array $mappedDocRoots)
{
// Set up any mapped document roots, validating prefixes and directories
foreach ($mappedDocRoots as $prefix => $directory) {
if (is_array($directory)) {
foreach ($directory as $d) {
$this->addMappedDocumentRoot($prefix, $d);
}
} else {
$this->addMappedDocumentRoot($prefix, $directory);
}
}
}

/**
* Add the specified directory to list of mapped directories
*/
public function addMappedDocumentRoot(string $prefix, string $directory): void
{
$valPrefix = $this->validatePrefix($prefix);
$valDirectory = $this->validateDirectory($directory, $valPrefix);

if (array_key_exists($valPrefix, $this->mappedDocRoots)) {
$dirs = &$this->mappedDocRoots[$valPrefix];
if (! in_array($valDirectory, $dirs)) {
$dirs[] = $valDirectory;
}
} else {
$this->mappedDocRoots[$valPrefix] = [$valDirectory];
}
}

/**
* Validate prefix, ensuring it is non-empty and starts and ends with a slash
*/
private function validatePrefix(string $prefix): string
{
if (empty($prefix)) {
// For the default prefix, set it to a slash to get matching to work
$prefix = '/';
} else {
if ($prefix[0] != '/') {
$prefix = "/$prefix";
}
if ($prefix[-1] != '/') {
$prefix .= '/';
}
}
return $prefix;
}

/**
* Validate directory, ensuring it exists and
*/
private function validateDirectory(string $directory, string $prefix): string
{
if (! is_dir($directory)) {
throw new InvalidArgumentException(sprintf(
'The document root for "%s", "%s", does not exist; please check your configuration.',
empty($prefix) ? "(Default)" : $prefix,
$directory
));
}
if ($directory[-1] != '/') {
$directory .= '/';
}
return $directory;
}

/**
* Return the mapped document roots
*/
public function listMappedDocumentRoots(): array
{
return $this->mappedDocRoots;
}

/**
* Searches for the specified file in mapped document root
* directories; returns the location if found, or null if not
*/
public function findFile(string $filename): ?string
{
foreach ($this->mappedDocRoots as $prefix => $directories) {
foreach ($directories as $directory) {
if (stripos($filename, $prefix) == 0) {
$mappedFileName = $directory . substr($filename, strlen($prefix));
if (file_exists($mappedFileName)) {
return $mappedFileName;
}
}
}
}
return null;
}
}
46 changes: 46 additions & 0 deletions src/StaticResourceHandler/FileLocationRepositoryFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/**
* @see https://github.com/mezzio/mezzio-swoole for the canonical source repository
* @copyright https://github.com/mezzio/mezzio-swoole/blob/master/COPYRIGHT.md
* @license https://github.com/mezzio/mezzio-swoole/blob/master/LICENSE.md New BSD License
*/

declare(strict_types=1);

namespace Mezzio\Swoole\StaticResourceHandler;

use Psr\Container\ContainerInterface;
use InvalidArgumentException;
use function getcwd;

class FileLocationRepositoryFactory
{
/**
* Create a file location repository, initializing with the static files setting configured by mezzio-swoole
*/
public function __invoke(ContainerInterface $container) : FileLocationRepository
{
// Build list of document roots mapped to the default document root directory
$configDocRoots = $container->get('config')
['mezzio-swoole']['swoole-http-server']['static-files']['document-root']
?? getcwd() . '/public';
$isArray = \is_array($configDocRoots);

$mappedDocRoots = ($isArray && (count($configDocRoots) > 0))
|| ((! $isArray) && strlen(strval($configDocRoots)) > 0)
? ['/' => $configDocRoots]
: [];

// Add any configured mapped document roots
$configMappedDocRoots = $container->get('config')
['mezzio-swoole']['swoole-http-server']['static-files']['mapped-document-roots']
?? [];

if (count($configMappedDocRoots) > 0) {
$mappedDocRoots = array_merge($mappedDocRoots, $configMappedDocRoots);
}

return new FileLocationRepository($mappedDocRoots);
}
}
22 changes: 22 additions & 0 deletions src/StaticResourceHandler/FileLocationRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/**
* @see https://github.com/mezzio/mezzio-swoole for the canonical source repository
* @copyright https://github.com/mezzio/mezzio-swoole/blob/master/COPYRIGHT.md
* @license https://github.com/mezzio/mezzio-swoole/blob/master/LICENSE.md New BSD License
*/

declare(strict_types=1);

namespace Mezzio\Swoole\StaticResourceHandler;

/**
* Interface to implement a repository for storing the association
* between the start of a URI (prefix) and directory
*/
interface FileLocationRepositoryInterface
{
public function addMappedDocumentRoot(string $prefix, string $directory): void;
public function listMappedDocumentRoots(): array;
public function findFile(string $filename): ?string;
}

0 comments on commit ba2155d

Please sign in to comment.