Completed
Push — 6.0 ( 487697...a3b118 )
by yun
08:06
created

Lang   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Test Coverage

Coverage 35.9%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 81
c 3
b 0
f 0
dl 0
loc 259
ccs 28
cts 78
cp 0.359
rs 9.2
wmc 40

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setLangSet() 0 3 1
A getLangSet() 0 3 1
A __make() 0 3 1
B detect() 0 27 7
A saveToCookie() 0 4 2
A defaultLangSet() 0 3 1
A __construct() 0 5 1
B parse() 0 17 7
A has() 0 10 4
A load() 0 21 6
B get() 0 39 9

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
     * Request对象
60
     * @var Request
61
     */
62
    protected $request;
63
64
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $config should have a doc-comment as per coding-style.
Loading history...
65
     * 构造方法
66
     * @access public
67
     */
68 6
    public function __construct(Request $request, array $config = [])
69
    {
70 6
        $this->request = $request;
71 6
        $this->config  = array_merge($this->config, array_change_key_case($config));
72 6
        $this->range   = $this->config['default_lang'];
73 6
    }
74
75 6
    public static function __make(Request $request, Config $config)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __make()
Loading history...
76
    {
77 6
        return new static($request, $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

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