Commit cc1f97fd authored by Tino Goratsch's avatar Tino Goratsch

backport the file checker strategies

parent ba911d6d
......@@ -8,37 +8,43 @@
namespace ACP3\Core\Assets;
use ACP3\Core;
use ACP3\Core\Assets\FileResolver\FileCheckerStrategyInterface;
class FileResolver
{
/**
* @var \ACP3\Core\Environment\ApplicationPath
*/
protected $appPath;
private $appPath;
/**
* @var \ACP3\Core\Assets\Cache
*/
protected $resourcesCache;
private $resourcesCache;
/**
* @var array
* @var \ACP3\Core\Modules
*/
protected $cachedPaths = [];
private $modules;
/**
* @var bool
* @var \ACP3\Core\Environment\Theme
*/
protected $newAssetPathsAdded = false;
private $theme;
/**
* @var string
* @var \ACP3\Core\Assets\FileResolver\FileCheckerStrategyInterface[]
*/
protected $designAssetsPath;
private $strategies = [];
/**
* @var \ACP3\Core\Modules
* @var array
*/
private $modules;
private $cachedPaths = [];
/**
* @var \ACP3\Core\Environment\Theme
* @var bool
*/
private $theme;
private $newAssetPathsAdded = false;
/**
* @var string
*/
private $designAssetsPath;
/**
* @var string
*/
......@@ -61,6 +67,9 @@ class FileResolver
$this->cachedPaths = $resourcesCache->getCache();
$this->modules = $modules;
$this->theme = $theme;
$this->addStrategy(new Core\Assets\FileResolver\MinifiedAwareFileCheckerStrategy());
$this->addStrategy(new Core\Assets\FileResolver\StraightFileCheckerStrategy());
}
/**
......@@ -73,6 +82,35 @@ class FileResolver
}
}
public function addStrategy(FileCheckerStrategyInterface $strategy): void
{
$this->strategies[] = $strategy;
}
/**
* @param string $templatePath
*
* @return string
*/
public function resolveTemplatePath(string $templatePath): string
{
// A path without any slash was given -> has to be a layout file of the current design
if (\strpos($templatePath, '/') === false) {
return $this->getStaticAssetPath('', '', '', $templatePath);
}
// Split the template path in its components
$fragments = \explode('/', \ucfirst($templatePath));
if (isset($fragments[2])) {
$fragments[1] = \ucfirst($fragments[1]);
}
$modulesPath = $fragments[0] . '/Resources/';
$designPath = $fragments[0];
$templatePath = \implode('/', \array_slice($fragments, 1));
return $this->getStaticAssetPath($modulesPath, $designPath, 'View', $templatePath);
}
/**
* @param string $modulePath
* @param string $designPath
......@@ -98,13 +136,13 @@ class FileResolver
}
$systemAssetPath = $this->appPath->getModulesDir() . $modulePath . $dir . $file;
if (!isset($this->cachedPaths[$systemAssetPath])) {
$this->cachedPaths[$systemAssetPath] = $this->resolveAssetPath($modulePath, $designPath, $dir, $file);
// Return early, if the path has been already cached
if (isset($this->cachedPaths[$systemAssetPath])) {
return $this->cachedPaths[$systemAssetPath];
$this->newAssetPathsAdded = true;
}
return $this->resolveAssetPath($modulePath, $designPath, $dir, $file);
return $this->cachedPaths[$systemAssetPath] ?: '';
}
/**
......@@ -123,84 +161,85 @@ class FileResolver
* @param string $dir
* @param string $file
*
* @return string
* @return string|null
*/
private function resolveAssetPath(string $modulePath, string $designPath, string $dir, string $file): string
private function resolveAssetPath(string $modulePath, string $designPath, string $dir, string $file): ?string
{
if ($this->designAssetsPath === null) {
$this->resetDesignAssetPath();
$this->resetTheme();
}
$assetPath = '';
$designAssetPath = $this->designAssetsPath . $designPath . $dir . $file;
$assetPath = $this->findAssetInInheritedThemes($modulePath, $designPath, $dir, $file);
// A theme has overridden a static asset of a module
if (\is_file($designAssetPath) === true) {
$assetPath = $designAssetPath;
} else {
$parentThemes = $this->theme->getThemeDependencies($this->currentTheme);
$parentTheme = \next($parentThemes);
return $assetPath ?: $this->findAssetInModules($modulePath, $dir, $file);
}
// Recursively iterate over the nested themes
if ($parentTheme !== false) {
$this->modifyDesignAssetPath($parentTheme);
$assetPath = $this->getStaticAssetPath($modulePath, $designPath, $dir, $file);
$this->resetDesignAssetPath();
/**
* @param string $modulePath
* @param string $designPath
* @param string $dir
* @param string $file
*
* @return string|null
*/
private function findAssetInInheritedThemes(string $modulePath, string $designPath, string $dir, string $file): ?string
{
$designAssetPath = $this->designAssetsPath . $designPath . $dir . $file;
return $assetPath;
}
if (null !== ($resourcePath = $this->findAssetInStrategies($designAssetPath))) {
return $resourcePath;
}
// No overrides have been found -> iterate over all possible module namespaces
$moduleName = \substr($modulePath, 0, \strpos($modulePath, '/'));
$moduleInfo = $this->modules->getModuleInfo($moduleName);
$parentThemes = $this->theme->getThemeDependencies($this->currentTheme);
$parentTheme = \next($parentThemes);
if (!empty($moduleInfo)) {
$moduleAssetPath = $this->appPath->getModulesDir() . $moduleInfo['vendor'] . '/' . $modulePath . $dir . $file;
if (\is_file($moduleAssetPath) === true) {
$assetPath = $moduleAssetPath;
}
}
}
// Recursively iterate over the nested themes
if ($parentTheme !== false) {
$this->changeTheme($parentTheme);
$assetPath = $this->getStaticAssetPath($modulePath, $designPath, $dir, $file);
$this->resetTheme();
$systemAssetPath = $this->appPath->getModulesDir() . $modulePath . $dir . $file;
$this->cachedPaths[$systemAssetPath] = $assetPath;
$this->newAssetPathsAdded = true;
return $assetPath;
}
return $assetPath;
return null;
}
/**
* @param string $template
*
* @return string
*/
public function resolveTemplatePath(string $template): string
private function findAssetInStrategies(string $resourcePath): ?string
{
// A path without any slash was given -> has to be a layout file of the current design
if (\strpos($template, '/') === false) {
return $this->getStaticAssetPath('', '', '', $template);
foreach ($this->strategies as $strategy) {
if ($strategy->isAllowed($resourcePath) && (null !== ($resource = $strategy->findResource($resourcePath)))) {
return $resource;
}
}
// Split the template path in its components
$fragments = \explode('/', \ucfirst($template));
if (isset($fragments[2])) {
$fragments[1] = \ucfirst($fragments[1]);
}
$modulesPath = $fragments[0] . '/Resources/';
$designPath = $fragments[0];
$template = \implode('/', \array_slice($fragments, 1));
return $this->getStaticAssetPath($modulesPath, $designPath, 'View', $template);
return null;
}
private function modifyDesignAssetPath(string $themeName): void
private function changeTheme(string $themeName): void
{
$this->currentTheme = $themeName;
$this->designAssetsPath = $this->appPath->getDesignRootPathInternal() . $themeName . '/';
}
private function resetDesignAssetPath(): void
private function resetTheme(): void
{
$this->modifyDesignAssetPath($this->theme->getCurrentTheme());
$this->changeTheme($this->theme->getCurrentTheme());
}
private function findAssetInModules(string $modulePath, string $dir, string $file): ?string
{
$moduleName = \substr($modulePath, 0, \strpos($modulePath, '/'));
$moduleInfo = $this->modules->getModuleInfo($moduleName);
if (!empty($moduleInfo)) {
$moduleAssetPath = $this->appPath->getModulesDir() . $moduleInfo['vendor'] . '/' . $modulePath . $dir . $file;
if (null !== ($resourcePath = $this->findAssetInStrategies($moduleAssetPath))) {
return $resourcePath;
}
}
return null;
}
}
<?php
/**
* Copyright (c) by the ACP3 Developers.
* See the LICENSE file at the top-level module directory for licensing details.
*/
namespace ACP3\Core\Assets\FileResolver;
interface FileCheckerStrategyInterface
{
public function isAllowed(string $resourcePath): bool;
public function findResource(string $resourcePath): ?string;
}
<?php
/**
* Copyright (c) by the ACP3 Developers.
* See the LICENSE file at the top-level module directory for licensing details.
*/
namespace ACP3\Core\Assets\FileResolver;
class MinifiedAwareFileCheckerStrategy implements FileCheckerStrategyInterface
{
public function findResource(string $resourcePath): ?string
{
$fileExtDot = \strrpos($resourcePath, '.');
$resourcePath = \substr($resourcePath, 0, $fileExtDot) . '.min.css';
if (\is_file($resourcePath)) {
return $resourcePath;
}
return null;
}
public function isAllowed(string $resourcePath): bool
{
return (bool) \preg_match('/.+(?<!\.min)\.css$/', $resourcePath);
}
}
<?php
/**
* Copyright (c) by the ACP3 Developers.
* See the LICENSE file at the top-level module directory for licensing details.
*/
namespace ACP3\Core\Assets\FileResolver;
class StraightFileCheckerStrategy implements FileCheckerStrategyInterface
{
public function findResource(string $resourcePath): ?string
{
if (\is_file($resourcePath)) {
return $resourcePath;
}
return null;
}
public function isAllowed(string $resourcePath): bool
{
return true;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment