FileResolver.php 5.54 KB
Newer Older
1
<?php
2
/**
3
 * Copyright (c) by the ACP3 Developers.
4
 * See the LICENSE file at the top-level module directory for licencing details.
5 6
 */

7 8 9 10 11
namespace ACP3\Core\Assets;

use ACP3\Core;

/**
12
 * Class FileResolver
13 14
 * @package ACP3\Core\Assets
 */
15
class FileResolver
16 17 18 19 20
{
    /**
     * @var \ACP3\Core\XML
     */
    protected $xml;
21 22 23 24
    /**
     * @var \ACP3\Core\Environment\ApplicationPath
     */
    protected $appPath;
25 26 27 28
    /**
     * @var \ACP3\Core\Assets\Cache
     */
    protected $resourcesCache;
29
    /**
30
     * @var \ACP3\Core\Modules\Vendor
31 32
     */
    protected $vendors;
33 34 35 36 37 38 39 40 41 42 43
    /**
     * @var array
     */
    protected $cachedPaths = [];
    /**
     * @var bool
     */
    protected $newAssetPathsAdded = false;
    /**
     * @var string
     */
44
    protected $designAssetsPath;
45 46

    /**
47 48 49
     * @param \ACP3\Core\XML                         $xml
     * @param \ACP3\Core\Assets\Cache                $resourcesCache
     * @param \ACP3\Core\Environment\ApplicationPath $appPath
50
     * @param \ACP3\Core\Modules\Vendor              $vendors
51 52 53
     */
    public function __construct(
        Core\XML $xml,
54
        Core\Assets\Cache $resourcesCache,
55
        Core\Environment\ApplicationPath $appPath,
56
        Core\Modules\Vendor $vendors
Tino Goratsch's avatar
Tino Goratsch committed
57
    ) {
58 59
        $this->xml = $xml;
        $this->resourcesCache = $resourcesCache;
60
        $this->appPath = $appPath;
61
        $this->vendors = $vendors;
62 63 64 65 66 67 68 69 70
        $this->cachedPaths = $resourcesCache->getCache();
    }

    /**
     * Write newly added assets paths into the cache
     */
    public function __destruct()
    {
        if ($this->newAssetPathsAdded === true) {
71
            $this->resourcesCache->saveCache($this->cachedPaths);
72 73 74 75
        }
    }

    /**
Tino Goratsch's avatar
Tino Goratsch committed
76 77 78 79
     * @param string $modulePath
     * @param string $designPath
     * @param string $dir
     * @param string $file
80 81 82 83 84
     *
     * @return string
     */
    public function getStaticAssetPath($modulePath, $designPath, $dir = '', $file = '')
    {
85
        if ($this->needsTrailingSlash($modulePath)) {
86 87
            $modulePath .= '/';
        }
88
        if ($this->needsTrailingSlash($designPath)) {
89 90 91 92 93 94
            $designPath .= '/';
        }
        if (!empty($dir) && !preg_match('=/$=', $dir)) {
            $dir .= '/';
        }

95
        $systemAssetPath = $this->appPath->getModulesDir() . $modulePath . $dir . $file;
96

Tino Goratsch's avatar
Tino Goratsch committed
97 98 99 100
        // Return early, if the path has been already cached
        if (isset($this->cachedPaths[$systemAssetPath])) {
            return $this->cachedPaths[$systemAssetPath];
        }
101

Tino Goratsch's avatar
Tino Goratsch committed
102
        return $this->resolveAssetPath($modulePath, $designPath, $dir, $file);
103 104
    }

105 106 107 108
    /**
     * @param string $path
     * @return bool
     */
109
    protected function needsTrailingSlash($path)
110
    {
111
        return $path !== '' && strpos($path, '.') === false && !preg_match('=/$=', $path);
112 113
    }

114
    /**
Tino Goratsch's avatar
Tino Goratsch committed
115 116
     * @param string $modulePath
     * @param string $designPath
117 118
     * @param string $dir
     * @param string $file
119 120 121
     *
     * @return string
     */
Tino Goratsch's avatar
Tino Goratsch committed
122
    private function resolveAssetPath($modulePath, $designPath, $dir, $file)
123
    {
124 125 126 127
        if ($this->designAssetsPath === null) {
            $this->designAssetsPath = $this->appPath->getDesignPathInternal();
        }

128 129 130 131 132 133 134 135 136 137 138
        $assetPath = '';
        $designAssetPath = $this->designAssetsPath . $designPath . $dir . $file;

        // A theme has overridden a static asset of a module
        if (is_file($designAssetPath) === true) {
            $assetPath = $designAssetPath;
        } else {
            $designInfo = $this->xml->parseXmlFile($this->designAssetsPath . '/info.xml', '/design');

            // Recursively iterate over the nested themes
            if (!empty($designInfo['parent'])) {
139
                $this->designAssetsPath = $this->appPath->getDesignRootPathInternal() . $designInfo['parent'] . '/';
140
                $assetPath = $this->getStaticAssetPath($modulePath, $designPath, $dir, $file);
141
                $this->designAssetsPath = $this->appPath->getDesignPathInternal();
142
                return $assetPath;
143 144 145
            }

            // No overrides have been found -> iterate over all possible module namespaces
146
            foreach (array_reverse($this->vendors->getVendors()) as $vendor) {
147
                $moduleAssetPath = $this->appPath->getModulesDir() . $vendor . '/' . $modulePath . $dir . $file;
148 149 150 151 152 153 154
                if (is_file($moduleAssetPath) === true) {
                    $assetPath = $moduleAssetPath;
                    break;
                }
            }
        }

155
        $systemAssetPath = $this->appPath->getModulesDir() . $modulePath . $dir . $file;
156 157 158 159 160 161 162
        $this->cachedPaths[$systemAssetPath] = $assetPath;
        $this->newAssetPathsAdded = true;

        return $assetPath;
    }

    /**
Tino Goratsch's avatar
Tino Goratsch committed
163
     * @param string $template
164 165 166 167 168 169 170
     *
     * @return string
     */
    public function resolveTemplatePath($template)
    {
        // A path without any slash was given -> has to be the layout file of the current design
        if (strpos($template, '/') === false) {
171
            return $this->getStaticAssetPath('', '', '', $template);
172 173 174 175 176 177 178
        } else {
            // Split the template path in its components
            $fragments = explode('/', ucfirst($template));

            if (isset($fragments[2])) {
                $fragments[1] = ucfirst($fragments[1]);
            }
179
            $modulesPath = $fragments[0] . '/Resources/';
180 181 182 183 184 185 186 187 188 189
            $designPath = $fragments[0];
            $template = $fragments[1];
            if (isset($fragments[2])) {
                $template .= '/' . $fragments[2];
            }

            return $this->getStaticAssetPath($modulesPath, $designPath, 'View', $template);
        }
    }
}