Commit ed93f2ad authored by Tino Goratsch's avatar Tino Goratsch

Merge branch 'release/v4.26.0'

parents 219a447c 66fbe5dc
Pipeline #19147607 passed with stages
in 10 minutes and 10 seconds
......@@ -16,7 +16,7 @@ interface BootstrapInterface extends HttpKernelInterface
/**
* Contains the current ACP3 version string.
*/
const VERSION = '4.25.7';
const VERSION = '4.26.0';
/**
* Performs some startup checks.
......
......@@ -28,7 +28,7 @@ class Cache
/**
* @return array
*/
public function getCache()
public function getCache(): array
{
if ($this->cache->contains(self::CACHE_ID) === true) {
return $this->cache->fetch(self::CACHE_ID);
......
......@@ -77,7 +77,7 @@ class FileResolver
*
* @return string
*/
public function getStaticAssetPath($modulePath, $designPath, $dir = '', $file = '')
public function getStaticAssetPath(string $modulePath, string $designPath, string $dir = '', string $file = ''): string
{
if ($this->needsTrailingSlash($modulePath)) {
$modulePath .= '/';
......@@ -104,7 +104,7 @@ class FileResolver
*
* @return bool
*/
protected function needsTrailingSlash($path)
protected function needsTrailingSlash(string $path): bool
{
return $path !== '' && \strpos($path, '.') === false && !\preg_match('=/$=', $path);
}
......@@ -117,7 +117,7 @@ class FileResolver
*
* @return string
*/
private function resolveAssetPath($modulePath, $designPath, $dir, $file)
private function resolveAssetPath(string $modulePath, string $designPath, string $dir, string $file): string
{
if ($this->designAssetsPath === null) {
$this->designAssetsPath = $this->appPath->getDesignPathInternal();
......@@ -164,7 +164,7 @@ class FileResolver
*
* @return string
*/
public function resolveTemplatePath($template)
public function resolveTemplatePath(string $template): string
{
// A path without any slash was given -> has to be the layout file of the current design
if (\strpos($template, '/') === false) {
......
......@@ -68,7 +68,11 @@ class Libraries
],
'font-awesome' => [
'enabled' => false,
'css' => 'font-awesome.css',
'css' => [
'fa-brands.css',
'fa-regular.css',
'fontawesome.css',
],
],
];
/**
......@@ -94,7 +98,7 @@ class Libraries
$this->request = $request;
}
public function dispatchAddLibraryEvent()
public function dispatchAddLibraryEvent(): void
{
$this->eventDispatcher->dispatch('core.assets.add_libraries', new AddLibraryEvent($this));
}
......@@ -102,7 +106,7 @@ class Libraries
/**
* @return array
*/
public function getLibraries()
public function getLibraries(): array
{
return $this->libraries;
}
......@@ -113,7 +117,7 @@ class Libraries
*
* @return $this
*/
public function addLibrary($identifier, array $options)
public function addLibrary(string $identifier, array $options): self
{
if (!isset($this->libraries[$identifier])) {
$this->libraries[$identifier] = $options;
......@@ -133,7 +137,7 @@ class Libraries
*
* @return $this
*/
public function enableLibraries(array $libraries)
public function enableLibraries(array $libraries): self
{
foreach ($libraries as $library) {
if (\array_key_exists($library, $this->libraries) === true) {
......@@ -153,7 +157,7 @@ class Libraries
/**
* @return array
*/
public function getEnabledLibraries()
public function getEnabledLibraries(): array
{
$enabledLibraries = [];
foreach ($this->libraries as $library => $values) {
......
......@@ -102,7 +102,7 @@ abstract class AbstractMinifier implements MinifierInterface
*
* @return string
*/
protected function buildCacheId($type, $layout)
protected function buildCacheId(string $type, string $layout): string
{
return 'assets_' . $this->generateFilenameHash($type, $layout);
}
......@@ -113,7 +113,7 @@ abstract class AbstractMinifier implements MinifierInterface
*
* @return string
*/
protected function generateFilenameHash($group, $layout)
protected function generateFilenameHash(string $group, string $layout): string
{
$filename = $this->config->getSettings(Schema::MODULE_NAME)['design'];
$filename .= '_' . $layout;
......@@ -128,12 +128,12 @@ abstract class AbstractMinifier implements MinifierInterface
*
* @return array
*/
abstract protected function processLibraries($layout);
abstract protected function processLibraries(string $layout): array;
/**
* {@inheritdoc}
*/
public function getURI($layout = 'layout')
public function getURI(string $layout = 'layout'): string
{
$debug = $this->environment === 'dev';
$filenameHash = $this->generateFilenameHash($this->getAssetGroup(), $layout);
......@@ -168,7 +168,7 @@ abstract class AbstractMinifier implements MinifierInterface
* @param array $files
* @param string $path
*/
protected function saveMinifiedAsset(array $files, $path)
protected function saveMinifiedAsset(array $files, string $path): void
{
$options = [
'options' => [
......@@ -196,7 +196,7 @@ abstract class AbstractMinifier implements MinifierInterface
*
* @return string
*/
protected function buildAssetPath($debug, $group, $filenameHash, $lastGenerated)
protected function buildAssetPath(bool $debug, string $group, string $filenameHash, int $lastGenerated): string
{
if ($debug === true) {
return 'assets/' . $filenameHash . '.' . $group;
......
......@@ -22,7 +22,7 @@ class CSS extends AbstractMinifier
/**
* {@inheritdoc}
*/
protected function processLibraries($layout)
protected function processLibraries(string $layout): array
{
$cacheId = $this->buildCacheId($this->getAssetGroup(), $layout);
......@@ -40,15 +40,24 @@ class CSS extends AbstractMinifier
/**
* Fetch all stylesheets of the enabled frontend frameworks/libraries.
*/
protected function fetchLibraries()
protected function fetchLibraries(): void
{
foreach ($this->assets->getLibraries() as $library) {
if ($library['enabled'] === true && isset($library[$this->getAssetGroup()]) === true) {
if ($library['enabled'] === false || isset($library[$this->getAssetGroup()]) === false) {
continue;
}
$stylesheets = $library[$this->getAssetGroup()];
if (!\is_array($stylesheets)) {
$stylesheets = [$stylesheets];
}
foreach ($stylesheets as $stylesheet) {
$this->stylesheets[] = $this->fileResolver->getStaticAssetPath(
!empty($library['module']) ? $library['module'] . '/Resources' : $this->systemAssetsModulePath,
!empty($library['module']) ? $library['module'] : $this->systemAssetsDesignPath,
$library['module'] ?? $this->systemAssetsDesignPath,
static::ASSETS_PATH_CSS,
$library[$this->getAssetGroup()]
$stylesheet
);
}
}
......@@ -59,7 +68,7 @@ class CSS extends AbstractMinifier
*
* @param string $layout
*/
protected function fetchThemeStylesheets($layout)
protected function fetchThemeStylesheets(string $layout): void
{
foreach ($this->assets->fetchAdditionalThemeCssFiles() as $file) {
$this->stylesheets[] = $this->fileResolver->getStaticAssetPath(
......@@ -88,7 +97,7 @@ class CSS extends AbstractMinifier
/**
* Fetches the stylesheets of all currently enabled modules.
*/
protected function fetchModuleStylesheets()
protected function fetchModuleStylesheets(): void
{
$modules = $this->modules->getActiveModules();
foreach ($modules as $module) {
......
......@@ -22,7 +22,7 @@ class JavaScript extends AbstractMinifier
/**
* {@inheritdoc}
*/
protected function processLibraries($layout)
protected function processLibraries(string $layout): array
{
$cacheId = $this->buildCacheId($this->getAssetGroup(), $layout);
......@@ -39,7 +39,7 @@ class JavaScript extends AbstractMinifier
/**
* Fetches the javascript files of all enabled frontend frameworks/libraries.
*/
protected function fetchLibraries()
protected function fetchLibraries(): void
{
foreach ($this->assets->getLibraries() as $library) {
if ($library['enabled'] === true && isset($library[$this->getAssetGroup()]) === true) {
......@@ -58,7 +58,7 @@ class JavaScript extends AbstractMinifier
*
* @param string $layout
*/
protected function fetchThemeJavaScript($layout)
protected function fetchThemeJavaScript(string $layout): void
{
foreach ($this->assets->fetchAdditionalThemeJsFiles() as $file) {
$this->javascript[] = $this->fileResolver->getStaticAssetPath('', '', static::ASSETS_PATH_JS, $file);
......
......@@ -16,5 +16,5 @@ interface MinifierInterface
*
* @return string
*/
public function getURI($layout = 'layout');
public function getURI(string $layout = 'layout'): string;
}
......@@ -10,7 +10,7 @@ namespace ACP3\Core\Router;
use ACP3\Core\Environment\ApplicationPath;
use ACP3\Core\Http\RequestInterface;
use ACP3\Core\Settings\SettingsInterface;
use ACP3\Modules\ACP3\System;
use ACP3\Modules\ACP3\System\Installer\Schema;
class Router implements RouterInterface
{
......@@ -28,10 +28,6 @@ class Router implements RouterInterface
* @var SettingsInterface
*/
protected $config;
/**
* @var string
*/
protected $environment;
/**
* Router constructor.
......@@ -39,18 +35,15 @@ class Router implements RouterInterface
* @param RequestInterface $request
* @param ApplicationPath $appPath
* @param SettingsInterface $config
* @param $environment
*/
public function __construct(
RequestInterface $request,
ApplicationPath $appPath,
SettingsInterface $config,
$environment
SettingsInterface $config
) {
$this->request = $request;
$this->appPath = $appPath;
$this->config = $config;
$this->environment = $environment;
}
/**
......@@ -66,6 +59,10 @@ class Router implements RouterInterface
}
}
if ($path === '/') {
$path = '';
}
return $this->addUriPrefix($path, $isAbsolute, $isSecure) . $path;
}
......@@ -74,7 +71,7 @@ class Router implements RouterInterface
*
* @return string
*/
protected function preparePath($path)
protected function preparePath(string $path): string
{
$path = $path . (!\preg_match('/\/$/', $path) ? '/' : '');
if ($path === 'acp/') {
......@@ -94,7 +91,7 @@ class Router implements RouterInterface
*
* @return string
*/
protected function addControllerAndAction($path)
protected function addControllerAndAction(string $path): string
{
$pathArray = \preg_split('=/=', $path, -1, PREG_SPLIT_NO_EMPTY);
$indexes = ($this->isAdminUri($path) === true) ? [2, 3] : [1, 2];
......@@ -105,6 +102,10 @@ class Router implements RouterInterface
}
}
if ($this->isHomepage($path) === true) {
$path = '/';
}
return $path;
}
......@@ -113,19 +114,19 @@ class Router implements RouterInterface
*
* @return bool
*/
protected function isAdminUri($path)
protected function isAdminUri(string $path): bool
{
return \preg_match(self::ADMIN_PANEL_PATTERN, $path) != false;
}
/**
* @param string $path
* @param bool $isAbsolute
* @param bool $isSecure
* @param string $path
* @param bool $isAbsolute
* @param bool|null $isSecure
*
* @return string
*/
protected function addUriPrefix($path, $isAbsolute, $isSecure)
protected function addUriPrefix(string $path, bool $isAbsolute, ?bool $isSecure): string
{
$prefix = '';
if ($isAbsolute === true || $isSecure !== null) {
......@@ -133,7 +134,11 @@ class Router implements RouterInterface
$prefix .= $this->request->getHost();
}
$prefix .= $this->useModRewrite($path) ? $this->appPath->getWebRoot() : $this->appPath->getPhpSelf() . '/';
if ($this->useModRewrite($path) || $path === '') {
$prefix .= $this->appPath->getWebRoot();
} else {
$prefix .= $this->appPath->getPhpSelf() . '/';
}
return $prefix;
}
......@@ -143,7 +148,7 @@ class Router implements RouterInterface
*
* @return string
*/
private function getScheme($isSecure)
private function getScheme(?bool $isSecure): string
{
if ($isSecure === null) {
return $this->request->getScheme() . '://';
......@@ -161,9 +166,19 @@ class Router implements RouterInterface
*
* @return bool
*/
protected function useModRewrite($path)
protected function useModRewrite(string $path): bool
{
return (bool) $this->getSystemSettings()['mod_rewrite'] === true
&& $this->isAdminUri($path) === false;
}
protected function getSystemSettings(): array
{
return $this->config->getSettings(Schema::MODULE_NAME);
}
protected function isHomepage(string $path): bool
{
return (bool) $this->config->getSettings(System\Installer\Schema::MODULE_NAME)['mod_rewrite'] === true &&
$this->isAdminUri($path) === false;
return $path === $this->getSystemSettings()['homepage'];
}
}
......@@ -7,7 +7,6 @@
namespace ACP3\Core\Test;
use ACP3\Core\Environment\ApplicationMode;
use ACP3\Core\Environment\ApplicationPath;
use ACP3\Core\Http\Request;
use ACP3\Core\Router\Router;
......@@ -39,25 +38,15 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$this->router = new Router(
$this->requestMock,
$this->appPathMock,
$this->configMock,
ApplicationMode::PRODUCTION
$this->configMock
);
}
protected function initializeMockObjects()
{
$this->requestMock = $this->getMockBuilder(Request::class)
->disableOriginalConstructor()
->setMethods(['getScheme', 'getHost'])
->getMock();
$this->appPathMock = $this->getMockBuilder(ApplicationPath::class)
->disableOriginalConstructor()
->setMethods(['getWebRoot', 'getPhpSelf'])
->getMock();
$this->configMock = $this->getMockBuilder(SettingsInterface::class)
->disableOriginalConstructor()
->setMethods(['getSettings', 'saveSettings'])
->getMock();
$this->requestMock = $this->createMock(Request::class);
$this->appPathMock = $this->createMock(ApplicationPath::class);
$this->configMock = $this->createMock(SettingsInterface::class);
}
public function testRouteUseNoModRewrite()
......@@ -86,7 +75,7 @@ class RouterTest extends \PHPUnit_Framework_TestCase
* @param int $callCountWebRoot
* @param int $callCountPhpSelf
*/
protected function setAppPathMockExpectations($callCountWebRoot, $callCountPhpSelf)
protected function setAppPathMockExpectations(int $callCountWebRoot, int $callCountPhpSelf)
{
$this->appPathMock->expects($this->exactly($callCountWebRoot))
->method('getWebRoot')
......@@ -97,22 +86,21 @@ class RouterTest extends \PHPUnit_Framework_TestCase
}
/**
* @param int $callCount
* @param bool $useModRewrite
*/
protected function setUpConfigMockExpectations($callCount = 1, $useModRewrite = false)
protected function setUpConfigMockExpectations(bool $useModRewrite = false)
{
$this->configMock->expects($this->exactly($callCount))
$this->configMock->expects($this->atLeastOnce())
->method('getSettings')
->with('system')
->willReturn(['mod_rewrite' => $useModRewrite]);
->willReturn(['mod_rewrite' => $useModRewrite, 'homepage' => 'foo/bar/baz/']);
}
public function testRouteUseModRewrite()
{
$this->setUpRequestMockExpectations();
$this->setAppPathMockExpectations(1, 0);
$this->setUpConfigMockExpectations(1, true);
$this->setUpConfigMockExpectations(true);
$path = 'news/index/index/';
$expected = '/' . $path;
......@@ -160,7 +148,7 @@ class RouterTest extends \PHPUnit_Framework_TestCase
{
$this->setUpRequestMockExpectations();
$this->setAppPathMockExpectations(0, 1);
$this->setUpConfigMockExpectations(1, true);
$this->setUpConfigMockExpectations(true);
$path = 'acp/news/index/index/';
$expected = '/index.php/' . $path;
......@@ -215,4 +203,31 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expected, $this->router->route($path));
}
/**
* @dataProvider homepageRouteDataProvider()
*
* @param string $path
* @param bool $absolute
* @param bool|null $isSecure
* @param string $expected
*/
public function testRouteIsHomepage(string $path, bool $absolute, ?bool $isSecure, string $expected)
{
$this->setUpRequestMockExpectations();
$this->setAppPathMockExpectations(1, 0);
$this->setUpConfigMockExpectations();
$this->assertEquals($expected, $this->router->route($path, $absolute, $isSecure));
}
public function homepageRouteDataProvider(): array
{
return [
['foo/bar/baz', false, null, '/'],
['foo/bar/baz', true, null, 'http://example.com/'],
['foo/bar/baz', true, false, 'http://example.com/'],
['foo/bar/baz', true, true, 'https://example.com/'],
];
}
}
......@@ -55,7 +55,6 @@ services:
- '@core.http.request'
- '@core.environment.application_path'
- '@core.config'
- '%core.environment%'
core.session:
class: ACP3\Core\Session\SessionHandler
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"autoload": {
"psr-4": {
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"suggest": {
"acp3/module-seo": "Provides additional SEO capabilities"
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"autoload": {
"psr-4": {
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7",
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0",
"google/recaptcha": "^1.1.0"
},
"autoload": {
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"autoload": {
"psr-4": {
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"suggest": {
"acp3/module-captcha": "Provides basic protection against spam bots."
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"suggest": {
"acp3/module-captcha": "Provides basic protection against spam bots."
......
......@@ -17,12 +17,12 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",
"acp3/module-errors": "^4.25.7",
"acp3/module-permissions": "^4.25.7",
"acp3/module-system": "^4.25.7",
"acp3/module-users": "^4.25.7"
"acp3/core": "^4.26.0",
"acp3/setup": "^4.26.0",
"acp3/module-errors": "^4.26.0",
"acp3/module-permissions": "^4.26.0",
"acp3/module-system": "^4.26.0",
"acp3/module-users": "^4.26.0"
},
"autoload": {
"psr-4": {
......
......@@ -17,11 +17,11 @@
"prefer-stable": true,
"require": {
"acp3/composer-installer": "^1.0",
"acp3/core": "^4.25.7",
"acp3/setup": "^4.25.7",