Merge pull request #485 from acelaya-forks/feature/base-path

Feature/base path
This commit is contained in:
Alejandro Celaya 2019-09-13 20:54:45 +02:00 committed by GitHub
commit 452612ee00
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 158 additions and 5 deletions

View file

@ -8,7 +8,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
#### Added
* *Nothing*
* [#482](https://github.com/shlinkio/shlink/issues/482) Added support to serve shlink under a sub path.
The `router.base_path` config option can be defined now to set the base path from which shlink is served.
```php
return [
'router' => [
'base_path' => '/foo/bar',
],
];
```
This option will also be available on shlink-installer 1.3.0, so the installer will ask for it. It can also be provided for the docker image as the `BASE_PATH` env var.
#### Changed

View file

@ -6,6 +6,8 @@ use Zend\Expressive\Router\FastRouteRouter;
return [
'router' => [
'base_path' => '',
'fastroute' => [
FastRouteRouter::CONFIG_CACHE_ENABLED => true,
FastRouteRouter::CONFIG_CACHE_FILE => 'data/cache/fastroute_cached_routes.php',

View file

@ -28,5 +28,6 @@ return (new ConfigAggregator\ConfigAggregator([
? new ConfigAggregator\PhpFileProvider('config/test/*.global.php')
: new ConfigAggregator\ZendConfigProvider('config/params/{generated_config.php,*.config.{php,json}}'),
], 'data/cache/app_config.php', [
Core\SimplifiedConfigParser::class,
Core\Config\SimplifiedConfigParser::class,
Core\Config\BasePathPrefixer::class,
]))->getMergedConfig();

View file

@ -103,6 +103,7 @@ This is the complete list of supported env vars:
* `DELETE_SHORT_URL_THRESHOLD`: The amount of visits on short URLs which will not allow them to be deleted. Defaults to `15`.
* `VALIDATE_URLS`: Boolean which tells if shlink should validate a status 20x (after following redirects) is returned when trying to shorten a URL. Defaults to `true`.
* `NOT_FOUND_REDIRECT_TO`: If a URL is provided here, when a user tries to access an invalid short URL, he/she will be redirected to this value. If this env var is not provided, the user will see a generic `404 - not found` page.
* `BASE_PATH`: The base path from which you plan to serve shlink, in case you don't want to serve it from the root of the domain. Defaults to `''`.
* `REDIS_SERVERS`: A comma-separated list of redis servers where Shlink locks are stored (locks are used to prevent some operations to be run more than once in parallel).
This is important when running more than one Shlink instance ([Multi instance considerations](#multi-instance-considerations)). If not provided, Shlink stores locks on every instance separately.
@ -130,6 +131,7 @@ docker run \
-e VALIDATE_URLS=false \
-e "NOT_FOUND_REDIRECT_TO=https://www.google.com" \
-e "REDIS_SERVERS=tcp://172.20.0.1:6379,tcp://172.20.0.2:6379" \
-e "BASE_PATH=/my-campaign" \
shlinkio/shlink
```

View file

@ -168,4 +168,8 @@ return [
'servers' => env('REDIS_SERVERS'),
],
'router' => [
'base_path' => env('BASE_PATH', ''),
],
];

View file

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Config;
use function Functional\map;
class BasePathPrefixer
{
private const ELEMENTS_WITH_PATH = ['routes', 'middleware_pipeline'];
public function __invoke(array $config): array
{
$basePath = $config['router']['base_path'] ?? '';
$config['url_shortener']['domain']['hostname'] .= $basePath;
foreach (self::ELEMENTS_WITH_PATH as $configKey) {
$config[$configKey] = $this->prefixPathsWithBasePath($configKey, $config, $basePath);
}
return $config;
}
private function prefixPathsWithBasePath(string $configKey, array $config, string $basePath): array
{
return map($config[$configKey] ?? [], function (array $element) use ($basePath) {
if (! isset($element['path'])) {
return $element;
}
$element['path'] = $basePath . $element['path'];
return $element;
});
}
}

View file

@ -1,7 +1,7 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core;
namespace Shlinkio\Shlink\Core\Config;
use Shlinkio\Shlink\Installer\Util\PathCollection;
use Zend\Stdlib\ArrayUtils;
@ -22,6 +22,7 @@ class SimplifiedConfigParser
'db_config' => ['entity_manager', 'connection'],
'delete_short_url_threshold' => ['delete_short_urls', 'visits_threshold'],
'redis_servers' => ['redis', 'servers'],
'base_path' => ['router', 'base_path'],
];
private const SIMPLIFIED_CONFIG_SIDE_EFFECTS = [
'not_found_redirect_to' => [

View file

@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core\Config;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Config\BasePathPrefixer;
class BasePathPrefixerTest extends TestCase
{
/** @var BasePathPrefixer */
private $prefixer;
public function setUp(): void
{
$this->prefixer = new BasePathPrefixer();
}
/**
* @test
* @dataProvider provideConfig
*/
public function parsesConfigAsExpected(
array $originalConfig,
array $expectedRoutes,
array $expectedMiddlewares,
string $expectedHostname
): void {
[
'routes' => $routes,
'middleware_pipeline' => $middlewares,
'url_shortener' => $urlShortener,
] = ($this->prefixer)($originalConfig);
$this->assertEquals($expectedRoutes, $routes);
$this->assertEquals($expectedMiddlewares, $middlewares);
$this->assertEquals([
'domain' => [
'hostname' => $expectedHostname,
],
], $urlShortener);
}
public function provideConfig(): iterable
{
$urlShortener = [
'domain' => [
'hostname' => null,
],
];
yield 'without anything' => [['url_shortener' => $urlShortener], [], [], ''];
yield 'with empty options' => [
[
'routes' => [],
'middleware_pipeline' => [],
'url_shortener' => $urlShortener,
],
[],
[],
'',
];
yield 'with non-empty options' => [
[
'routes' => [
['path' => '/something'],
['path' => '/something-else'],
],
'middleware_pipeline' => [
['with' => 'no_path'],
['path' => '/rest', 'middleware' => []],
],
'url_shortener' => [
'domain' => [
'hostname' => 'doma.in',
],
],
'router' => ['base_path' => '/foo/bar'],
],
[
['path' => '/foo/bar/something'],
['path' => '/foo/bar/something-else'],
],
[
['with' => 'no_path'],
['path' => '/foo/bar/rest', 'middleware' => []],
],
'doma.in/foo/bar',
];
}
}

View file

@ -1,10 +1,10 @@
<?php
declare(strict_types=1);
namespace ShlinkioTest\Shlink\Core;
namespace ShlinkioTest\Shlink\Core\Config;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\SimplifiedConfigParser;
use Shlinkio\Shlink\Core\Config\SimplifiedConfigParser;
use function array_merge;
@ -50,6 +50,7 @@ class SimplifiedConfigParserTest extends TestCase
'password' => 'bar',
'port' => '1234',
],
'base_path' => '/foo/bar',
];
$expected = [
'app_options' => [
@ -96,6 +97,10 @@ class SimplifiedConfigParserTest extends TestCase
'tcp://1.2.2.2:2222',
],
],
'router' => [
'base_path' => '/foo/bar',
],
];
$result = ($this->postProcessor)(array_merge($config, $simplified));