Passed
Push — master ( 1e85bd...1e75f7 )
by Alexander
01:42
created

Aliases::isAlias()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
namespace Yiisoft\Aliases;
3
4
final class Aliases
5
{
6
    private $aliases = [];
7
8
    /**
9
     * @param array $config
10
     * @throws \InvalidArgumentException if $path is an invalid alias.
11
     * @see set()
12
     * @see get()
13
     */
14 4
    public function __construct(array $config = [])
15
    {
16 4
        foreach ($config as $alias => $path) {
17 1
            $this->set($alias, $path);
18
        }
19 4
    } 
20
     
21
    /**
22
     * Magic setter to enable simple aliases configuration.
23
     * @param string $name
24
     * @param string $value
25
     */
26
    public function __set($name, $value)
27
    {
28
        $this->set($name, $value);
29
    }
30
31
    /**
32
     * Registers a path alias.
33
     *
34
     * A path alias is a short name representing a long path (a file path, a URL, etc.)
35
     * For example, we use '@yii' as the alias of the path to the Yii framework directory.
36
     *
37
     * A path alias must start with the character '@' so that it can be easily differentiated
38
     * from non-alias paths.
39
     *
40
     * Note that this method does not check if the given path exists or not. All it does is
41
     * to associate the alias with the path.
42
     *
43
     * Any trailing '/' and '\' characters in the given path will be trimmed.
44
     *
45
     * See the [guide article on aliases](guide:concept-aliases) for more information.
46
     *
47
     * @param string $alias the alias name (e.g. "@yii"). It must start with a '@' character.
48
     * It may contain the forward slash '/' which serves as boundary character when performing
49
     * alias translation by [[get()]].
50
     * @param string $path the path corresponding to the alias. If this is null, the alias will
51
     * be removed. Trailing '/' and '\' characters will be trimmed. This can be
52
     *
53
     * - a directory or a file path (e.g. `/tmp`, `/tmp/main.txt`)
54
     * - a URL (e.g. `http://www.yiiframework.com`)
55
     * - a path alias (e.g. `@yii/base`). In this case, the path alias will be converted into the
56
     *   actual path first by calling [[get()]].
57
     *
58
     * @throws \InvalidArgumentException if $path is an invalid alias.
59
     * @see get()
60
     */
61 4
    public function set(string $alias, ?string $path): void
62
    {
63 4
        if (!$this->isAlias($alias)) {
64 1
            $alias = '@' . $alias;
65
        }
66 4
        $pos = strpos($alias, '/');
67 4
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
68 4
        if ($path !== null) {
69 4
            $path = !$this->isAlias($path) ? rtrim($path, '\\/') : $this->get($path);
70 4
            if (!isset($this->aliases[$root])) {
71 4
                if ($pos === false) {
72 3
                    $this->aliases[$root] = $path;
73
                } else {
74 4
                    $this->aliases[$root] = [$alias => $path];
75
                }
76 3
            } elseif (\is_string($this->aliases[$root])) {
77 2
                if ($pos === false) {
78
                    $this->aliases[$root] = $path;
79
                } else {
80 2
                    $this->aliases[$root] = [
81 2
                        $alias => $path,
82 2
                        $root => $this->aliases[$root],
83
                    ];
84
                }
85
            } else {
86 1
                $this->aliases[$root][$alias] = $path;
87 4
                krsort($this->aliases[$root]);
88
            }
89 1
        } elseif (isset($this->aliases[$root])) {
90 1
            if (\is_array($this->aliases[$root])) {
91 1
                unset($this->aliases[$root][$alias]);
92
            } elseif ($pos === false) {
93
                unset($this->aliases[$root]);
94
            }
95
        }
96 4
    }
97
98
    /**
99
     * Translates a path alias into an actual path.
100
     *
101
     * The translation is done according to the following procedure:
102
     *
103
     * 1. If the given alias does not start with '@', it is returned back without change;
104
     * 2. Otherwise, look for the longest registered alias that matches the beginning part
105
     *    of the given alias. If it exists, replace the matching part of the given alias with
106
     *    the corresponding registered path.
107
     * 3. Throw an exception or return false, depending on the `$throwException` parameter.
108
     *
109
     * For example, by default '@yii' is registered as the alias to the Yii framework directory,
110
     * say '/path/to/yii'. The alias '@yii/web' would then be translated into '/path/to/yii/web'.
111
     *
112
     * If you have registered two aliases '@foo' and '@foo/bar'. Then translating '@foo/bar/config'
113
     * would replace the part '@foo/bar' (instead of '@foo') with the corresponding registered path.
114
     * This is because the longest alias takes precedence.
115
     *
116
     * However, if the alias to be translated is '@foo/barbar/config', then '@foo' will be replaced
117
     * instead of '@foo/bar', because '/' serves as the boundary character.
118
     *
119
     * Note, this method does not check if the returned path exists or not.
120
     *
121
     * See the [guide article on aliases](guide:concept-aliases) for more information.
122
     *
123
     * @param string $alias the alias to be translated.
124
     * @param bool $throwException whether to throw an exception if the given alias is invalid.
125
     * If this is false and an invalid alias is given, false will be returned by this method.
126
     * @return string|bool the path corresponding to the alias, false if the root alias is not previously registered.
127
     * @throws \InvalidArgumentException if the alias is invalid while $throwException is true.
128
     * @see setAlias()
129
     */
130 3
    public function get($alias, $throwException = true)
131
    {
132 3
        if (!$this->isAlias($alias)) {
133 1
            return $alias;
134
        }
135
136 3
        $result = $this->findAlias($alias);
137
138 3
        if (\is_array($result)) {
139 3
            return $result['path'];
140
        }
141
142 2
        if ($throwException) {
143 2
            throw new \InvalidArgumentException("Invalid path alias: $alias");
144
        }
145
146 1
        return false;
147
    }
148
149
    /**
150
     * Returns the root alias part of a given alias.
151
     * A root alias is an alias that has been registered via [[setAlias()]] previously.
152
     * If a given alias matches multiple root aliases, the longest one will be returned.
153
     * @param string $alias the alias
154
     * @return string the root alias, or null if no root alias is found
155
     */
156 2
    public function getRoot($alias): ?string
157
    {
158 2
        $result = $this->findAlias($alias);
159 2
        if (\is_array($result)) {
160 2
            $result = $result['root'];
161
        }
162
        
163 2
        return $result;
164
    }
165
166 4
    private function findAlias(string $alias): ?array
167
    {
168 4
        $pos = strpos($alias, '/');
169 4
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
170
171 4
        if (isset($this->aliases[$root])) {
172 4
            if (\is_string($this->aliases[$root])) {
173
                return [
174 3
                    'root' => $root,
175
                    'path' => $pos === false
176 3
                        ? $this->aliases[$root]
177 3
                        : $this->aliases[$root] . substr($alias, $pos)
178
                ];
179
            }
180
181 3
            foreach ($this->aliases[$root] as $name => $path) {
182 3
                if (strpos($alias . '/', $name . '/') === 0) {
183
                    return [
184 3
                        'root' => $name,
185 3
                        'path' => $path . substr($alias, strlen($name))
186
                    ];
187
                }
188
            }
189
        }
190
191 2
        return null;
192
    }
193
194
    public function getAll(): array
195
    {
196
        return $this->aliases;
197
    }
198
199 4
    private function isAlias(string $alias): bool
200
    {
201 4
        return !strncmp($alias, '@', 1);
202
    }
203
}
204