mirror of
https://github.com/shlinkio/shlink.git
synced 2025-03-14 04:00:57 +03:00
Merge pull request #485 from acelaya-forks/feature/base-path
Feature/base path
This commit is contained in:
commit
452612ee00
9 changed files with 158 additions and 5 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
@ -168,4 +168,8 @@ return [
|
|||
'servers' => env('REDIS_SERVERS'),
|
||||
],
|
||||
|
||||
'router' => [
|
||||
'base_path' => env('BASE_PATH', ''),
|
||||
],
|
||||
|
||||
];
|
||||
|
|
35
module/Core/src/Config/BasePathPrefixer.php
Normal file
35
module/Core/src/Config/BasePathPrefixer.php
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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' => [
|
91
module/Core/test/Config/BasePathPrefixerTest.php
Normal file
91
module/Core/test/Config/BasePathPrefixerTest.php
Normal 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',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -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));
|
Loading…
Add table
Reference in a new issue