Completed
Pull Request — 6.0 (#2183)
by
unknown
08:51
created

Lang   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Test Coverage

Coverage 28.26%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 95
c 4
b 0
f 0
dl 0
loc 273
ccs 26
cts 92
cp 0.2826
rs 8.64
wmc 47

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __make() 0 3 1
A setLangSet() 0 3 1
B parse() 0 17 7
A defaultLangSet() 0 3 1
A load() 0 21 6
A getLangSet() 0 3 1
A __construct() 0 4 1
B detect() 0 28 8
A saveToCookie() 0 4 2
A has() 0 17 6
C get() 0 50 13

How to fix   Complexity   

Complex Class

Complex classes like Lang often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Lang, and based on these observations, apply Extract Interface, too.

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
/**
16
 * 多语言管理类
17
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
18
 */
19
class Lang
20
{
21
    /**
22
     * 配置参数
23
     * @var array
24
     */
25
    protected $config = [
26
        // 默认语言
27
        'default_lang'    => 'zh-cn',
28
        // 允许的语言列表
29
        'allow_lang_list' => [],
30
        // 是否使用Cookie记录
31
        'use_cookie'      => true,
32
        // 扩展语言包
33
        'extend_list'     => [],
34
        // 多语言cookie变量
35
        'cookie_var'      => 'think_lang',
36
        // 多语言自动侦测变量名
37
        'detect_var'      => 'lang',
38
        // Accept-Language转义为对应语言包名称
39
        'accept_language' => [
40
            'zh-hans-cn' => 'zh-cn',
41
        ],
42
        // 是否支持语言分组
43
        'allow_group'     => false,
44
    ];
45
46
    /**
47
     * 多语言信息
48
     * @var array
49
     */
50
    private $lang = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "lang" must be prefixed with an underscore
Loading history...
51
52
    /**
53
     * 当前语言
54
     * @var string
55
     */
56
    private $range = 'zh-cn';
0 ignored issues
show
Coding Style introduced by
Private member variable "range" must be prefixed with an underscore
Loading history...
57
58
    /**
59
     * 构造方法
60
     * @access public
61
     * @param array $config
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
62
     */
63 1
    public function __construct(array $config = [])
64
    {
65 1
        $this->config = array_merge($this->config, array_change_key_case($config));
66 1
        $this->range  = $this->config['default_lang'];
67 1
    }
68
69 1
    public static function __make(Config $config)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __make()
Loading history...
70
    {
71 1
        return new static($config->get('lang'));
0 ignored issues
show
Bug introduced by
It seems like $config->get('lang') can also be of type null; however, parameter $config of think\Lang::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

71
        return new static(/** @scrutinizer ignore-type */ $config->get('lang'));
Loading history...
72
    }
73
74
    /**
75
     * 设置当前语言
76
     * @access public
77
     * @param string $lang 语言
78
     * @return void
79
     */
80
    public function setLangSet(string $lang): void
81
    {
82
        $this->range = $lang;
83
    }
84
85
    /**
86
     * 获取当前语言
87
     * @access public
88
     * @return string
89
     */
90
    public function getLangSet(): string
91
    {
92
        return $this->range;
93
    }
94
95
    /**
96
     * 获取默认语言
97
     * @access public
98
     * @return string
99
     */
100 1
    public function defaultLangSet()
101
    {
102 1
        return $this->config['default_lang'];
103
    }
104
105
    /**
106
     * 加载语言定义(不区分大小写)
107
     * @access public
108
     * @param string|array $file  语言文件
109
     * @param string       $range 语言作用域
110
     * @return array
111
     */
112 1
    public function load($file, $range = ''): array
113
    {
114 1
        $range = $range ?: $this->range;
115 1
        if (!isset($this->lang[$range])) {
116 1
            $this->lang[$range] = [];
117
        }
118
119 1
        $lang = [];
120
121 1
        foreach ((array) $file as $_file) {
122 1
            if (is_file($_file)) {
123 1
                $result = $this->parse($_file);
124 1
                $lang   = array_change_key_case($result) + $lang;
125
            }
126
        }
127
128 1
        if (!empty($lang)) {
129 1
            $this->lang[$range] = $lang + $this->lang[$range];
130
        }
131
132 1
        return $this->lang[$range];
133
    }
134
135
    /**
136
     * 解析语言文件
137
     * @access protected
138
     * @param string $file 语言文件名
139
     * @return array
140
     */
141 1
    protected function parse(string $file): array
142
    {
143 1
        $type = pathinfo($file, PATHINFO_EXTENSION);
144
145
        switch ($type) {
146 1
            case 'php':
147 1
                $result = include $file;
148 1
                break;
149
            case 'yml':
150
            case 'yaml':
151
                if (function_exists('yaml_parse_file')) {
152
                    $result = yaml_parse_file($file);
153
                }
154
                break;
155
        }
156
157 1
        return isset($result) && is_array($result) ? $result : [];
158
    }
159
160
    /**
161
     * 判断是否存在语言定义(不区分大小写)
162
     * @access public
163
     * @param string|null $name  语言变量
164
     * @param string      $range 语言作用域
165
     * @return bool
166
     */
167
    public function has(string $name, string $range = ''): bool
168
    {
169
        $range = $range ?: $this->range;
170
171
        if ($this->config['allow_group'] && strpos($name, '.')) {
172
            $names = explode('.', $name);
173
            $i = 0;
174
            $temp = $this->lang[$range];
175
            foreach ($names as $key) {
176
                if(!isset($temp[strtolower($key)])) return false;
0 ignored issues
show
Coding Style introduced by
Inline control structures are discouraged
Loading history...
177
                $temp = $temp[strtolower($key)];
178
                $i++;
179
            }
180
            return is_string($temp);
181
        }
182
183
        return isset($this->lang[$range][strtolower($name)]);
184
    }
185
186
    /**
187
     * 获取语言定义(不区分大小写)
188
     * @access public
189
     * @param string|null $name  语言变量
190
     * @param array       $vars  变量替换
191
     * @param string      $range 语言作用域
192
     * @return mixed
193
     */
194
    public function get(string $name = null, array $vars = [], string $range = '')
195
    {
196
        $range = $range ?: $this->range;
197
198
        // 空参数返回所有定义
199
        if (is_null($name)) {
200
            return $this->lang[$range] ?? [];
201
        }
202
203
        if ($this->config['allow_group'] && strpos($name, '.')) {
204
            $names = explode('.', $name);
205
            $i = 0;
206
            $temp = $this->lang[$range];
207
            foreach ($names as $key) {
208
                if(!isset($temp[strtolower($key)])) {
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if(...) {\n"
Loading history...
209
                    $temp = $name;
210
                    break;
211
                }
212
                $temp = $temp[strtolower($key)];
213
                if($i > sizeof($names)) break;
0 ignored issues
show
Coding Style introduced by
Inline control structures are discouraged
Loading history...
214
                $i++;
215
            }
216
217
            $value = is_string($temp) ? $temp : $name;
218
        } else {
219
            $value = $this->lang[$range][strtolower($name)] ?? $name;
220
        }
221
222
        // 变量解析
223
        if (!empty($vars) && is_array($vars)) {
224
            /**
225
             * Notes:
226
             * 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0
227
             * 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数
228
             */
229
            if (key($vars) === 0) {
230
                // 数字索引解析
231
                array_unshift($vars, $value);
232
                $value = call_user_func_array('sprintf', $vars);
233
            } else {
234
                // 关联索引解析
235
                $replace = array_keys($vars);
236
                foreach ($replace as &$v) {
237
                    $v = "{:{$v}}";
238
                }
239
                $value = str_replace($replace, $vars, $value);
240
            }
241
        }
242
243
        return $value;
244
    }
245
246
    /**
247
     * 自动侦测设置获取语言选择
248
     * @access public
249
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
250
     * @return string
251
     */
252
    public function detect(Request $request): string
253
    {
254
        // 自动侦测设置获取语言选择
255
        $langSet = '';
256
257
        if ($request->get($this->config['detect_var'])) {
258
            // url中设置了语言变量
259
            $langSet = strtolower($request->get($this->config['detect_var']));
260
        } elseif ($request->cookie($this->config['cookie_var'])) {
261
            // Cookie中设置了语言变量
262
            $langSet = strtolower($request->cookie($this->config['cookie_var']));
263
        } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
264
            // 自动侦测浏览器语言
265
            $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
266
            if ($match) {
267
                $langSet = strtolower($matches[1]);
268
                if (isset($this->config['accept_language'][$langSet])) {
269
                    $langSet = $this->config['accept_language'][$langSet];
270
                }
271
            }
272
        }
273
274
        if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
275
            // 合法的语言
276
            $this->range = $langSet;
277
        }
278
279
        return $this->range;
280
    }
281
282
    /**
283
     * 保存当前语言到Cookie
284
     * @access public
285
     * @param Cookie $cookie Cookie对象
286
     * @return void
287
     */
288
    public function saveToCookie(Cookie $cookie)
289
    {
290
        if ($this->config['use_cookie']) {
291
            $cookie->set($this->config['cookie_var'], $this->range);
292
        }
293
    }
294
295
}
296