Passed
Pull Request — master (#50)
by Alexander
02:52
created

Theme::getPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
namespace Yiisoft\View;
3
4
use Yiisoft\Files\FileHelper;
5
6
/**
7
 * Theme represents an application theme.
8
 *
9
 * When [[View]] renders a view file, it will check the [[View::theme|active theme]]
10
 * to see if there is a themed version of the view file exists. If so, the themed version will be rendered instead.
11
 *
12
 * A theme is a directory consisting of view files which are meant to replace their non-themed counterparts.
13
 *
14
 * Theme uses [[pathMap]] to achieve the view file replacement:
15
 *
16
 * 1. It first looks for a key in [[pathMap]] that is a substring of the given view file path;
17
 * 2. If such a key exists, the corresponding value will be used to replace the corresponding part
18
 *    in the view file path;
19
 * 3. It will then check if the updated view file exists or not. If so, that file will be used
20
 *    to replace the original view file.
21
 * 4. If Step 2 or 3 fails, the original view file will be used.
22
 *
23
 * For example, if [[pathMap]] is `['@app/views' => '@app/themes/basic']`,
24
 * then the themed version for a view file `@app/views/site/index.php` will be
25
 * `@app/themes/basic/site/index.php`.
26
 *
27
 * It is possible to map a single path to multiple paths. For example,
28
 *
29
 * ```php
30
 * 'pathMap' => [
31
 *     '@app/views' => [
32
 *         '@app/themes/christmas',
33
 *         '@app/themes/basic',
34
 *     ],
35
 * ]
36
 * ```
37
 *
38
 * In this case, the themed version could be either `@app/themes/christmas/site/index.php` or
39
 * `@app/themes/basic/site/index.php`. The former has precedence over the latter if both files exist.
40
 *
41
 * To use a theme, you should configure the [[View::theme|theme]] property of the "view" application
42
 * component like the following:
43
 *
44
 * ```php
45
 * 'view' => [
46
 *     'theme' => [
47
 *         'basePath' => '@app/themes/basic',
48
 *         'baseUrl' => '@web/themes/basic',
49
 *     ],
50
 * ],
51
 * ```
52
 *
53
 * The above configuration specifies a theme located under the "themes/basic" directory of the Web folder
54
 * that contains the entry script of the application. If your theme is designed to handle modules,
55
 * you may configure the [[pathMap]] property like described above.
56
 *
57
 * For more details and usage information on Theme, see the [guide article on theming](guide:output-theming).
58
 */
59
class Theme
60
{
61
    /**
62
     * @var array the mapping between view directories and their corresponding themed versions.
63
     * This property is used by [[applyTo()]] when a view is trying to apply the theme.
64
     * [Path aliases](guide:concept-aliases) can be used when specifying directories.
65
     * If this property is empty or not set, a mapping [[Application::basePath]] to [[basePath]] will be used.
66
     */
67
    private $pathMap;
68
69
    private $baseUrl;
70
71
    private $basePath;
72
73 51
    public function __construct(array $pathMap = [], string $basePath = null, string $baseUrl = null)
74
    {
75 51
        $this->pathMap = $pathMap;
76 51
        $this->basePath = $basePath;
77 51
        $this->baseUrl = rtrim($baseUrl, '/');
78
    }
79
80
    /**
81
     * @return string the base URL (without ending slash) for this theme. All resources of this theme are considered
82
     * to be under this base URL.
83
     */
84 2
    public function getBaseUrl(): ?string
85
    {
86 2
        return $this->baseUrl;
87
    }
88
89
    /**
90
     * @return string the root path of this theme. All resources of this theme are located under this directory.
91
     *
92
     * @see pathMap
93
     */
94 2
    public function getBasePath(): ?string
95
    {
96 2
        return $this->basePath;
97
    }
98
99
    /**
100
     * Converts a file to a themed file if possible.
101
     * If there is no corresponding themed file, the original file will be returned.
102
     *
103
     * @param string $path the file to be themed
104
     *
105
     * @return string the themed file, or the original file if the themed version is not available.
106
     */
107 37
    public function applyTo(string $path): string
108
    {
109 37
        if ($this->pathMap === []) {
110 33
            return $path;
111
        }
112 4
        $path = FileHelper::normalizePath($path);
113 4
        foreach ($this->pathMap as $from => $tos) {
114 4
            if (!is_string($from)) {
115
                throw new \InvalidArgumentException('Pathmap should contain strings');
116
            }
117
118 4
            $from = FileHelper::normalizePath($from) . '/';
119 4
            if (strpos($path, $from) === 0) {
120 4
                $n = strlen($from);
121 4
                foreach ((array)$tos as $to) {
122 4
                    $to = FileHelper::normalizePath($to) . '/';
123 4
                    $file = $to . substr($path, $n);
124 4
                    if (is_file($file)) {
125 3
                        return $file;
126
                    }
127
                }
128
            }
129
        }
130
131 2
        return $path;
132
    }
133
134
    /**
135
     * Converts a relative URL into an absolute URL using [[baseUrl]].
136
     *
137
     * @param string $url the relative URL to be converted.
138
     *
139
     * @return string the absolute URL
140
     */
141 2
    public function getUrl(string $url): string
142
    {
143 2
        if (($baseUrl = $this->getBaseUrl()) !== null) {
144 2
            return $baseUrl . '/' . ltrim($url, '/');
145
        }
146
147
        return $url;
148
    }
149
150
    /**
151
     * Converts a relative file path into an absolute one using [[basePath]].
152
     *
153
     * @param string $path the relative file path to be converted.
154
     *
155
     * @return string the absolute file path
156
     */
157 2
    public function getPath(string $path): string
158
    {
159 2
        if (($basePath = $this->getBasePath()) !== null) {
160 1
            return $basePath . '/' . ltrim($path, '/\\');
161
        }
162
163 1
        return $path;
164
    }
165
}
166