Passed
Push — master ( 58c3a9...cf78d0 )
by Alexander
01:26
created

Aliases::__set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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