Completed
Branch 6.0 (d30585)
by yun
04:17
created

Lang   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 34.18%

Importance

Changes 0
Metric Value
dl 0
loc 259
rs 9.1199
c 0
b 0
f 0
ccs 27
cts 79
cp 0.3418
wmc 41
lcom 1
cbo 3

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __make() 0 4 1
A setLangSet() 0 4 1
A getLangSet() 0 4 1
A defaultLangSet() 0 4 1
B load() 0 22 6
B parse() 0 18 7
A has() 0 11 4
B get() 0 40 9
B detect() 0 29 8
A saveToCookie() 0 6 2

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
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 = [];
51
52
    /**
53
     * 当前语言
54
     * @var string
55
     */
56
    private $range = 'zh-cn';
57
58
    /**
59
     * 构造方法
60
     * @access public
61
     * @param array $config
62
     */
63 3
    public function __construct(array $config = [])
64
    {
65 3
        $this->config = array_merge($this->config, array_change_key_case($config));
66 3
        $this->range  = $this->config['default_lang'];
67 3
    }
68
69 3
    public static function __make(Config $config)
70
    {
71 3
        return new static($config->get('lang'));
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 3
    public function defaultLangSet()
101
    {
102 3
        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 3
    public function load($file, $range = ''): array
113
    {
114 3
        $range = $range ?: $this->range;
115 3
        if (!isset($this->lang[$range])) {
116 3
            $this->lang[$range] = [];
117
        }
118
119 3
        $lang = [];
120
121 3
        foreach ((array) $file as $name) {
122 3
            if (is_file($name)) {
123 3
                $result = $this->parse($name);
124 3
                $lang   = array_change_key_case($result) + $lang;
125
            }
126
        }
127
128 3
        if (!empty($lang)) {
129 3
            $this->lang[$range] = $lang + $this->lang[$range];
130
        }
131
132 3
        return $this->lang[$range];
133
    }
134
135
    /**
136
     * 解析语言文件
137
     * @access protected
138
     * @param string $file 语言文件名
139
     * @return array
140
     */
141 3
    protected function parse(string $file): array
142
    {
143 3
        $type = pathinfo($file, PATHINFO_EXTENSION);
144
145 2
        switch ($type) {
146 3
            case 'php':
147 3
                $result = include $file;
148 3
                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 3
        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
            [$name1, $name2] = explode('.', $name, 2);
0 ignored issues
show
Bug introduced by
The variable $name1 does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $name2 does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
173
            return isset($this->lang[$range][strtolower($name1)][$name2]);
174
        }
175
176
        return isset($this->lang[$range][strtolower($name)]);
177
    }
178
179
    /**
180
     * 获取语言定义(不区分大小写)
181
     * @access public
182
     * @param string|null $name  语言变量
183
     * @param array       $vars  变量替换
184
     * @param string      $range 语言作用域
185
     * @return mixed
186
     */
187
    public function get(string $name = null, array $vars = [], string $range = '')
188
    {
189
        $range = $range ?: $this->range;
190
191
        // 空参数返回所有定义
192
        if (is_null($name)) {
193
            return $this->lang[$range] ?? [];
194
        }
195
196
        if ($this->config['allow_group'] && strpos($name, '.')) {
197
            [$name1, $name2] = explode('.', $name, 2);
0 ignored issues
show
Bug introduced by
The variable $name1 does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $name2 does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
198
199
            $value = $this->lang[$range][strtolower($name1)][$name2] ?? $name;
200
        } else {
201
            $value = $this->lang[$range][strtolower($name)] ?? $name;
202
        }
203
204
        // 变量解析
205
        if (!empty($vars) && is_array($vars)) {
206
            /**
207
             * Notes:
208
             * 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0
209
             * 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数
210
             */
211
            if (key($vars) === 0) {
212
                // 数字索引解析
213
                array_unshift($vars, $value);
214
                $value = call_user_func_array('sprintf', $vars);
215
            } else {
216
                // 关联索引解析
217
                $replace = array_keys($vars);
218
                foreach ($replace as &$v) {
219
                    $v = "{:{$v}}";
220
                }
221
                $value = str_replace($replace, $vars, $value);
222
            }
223
        }
224
225
        return $value;
226
    }
227
228
    /**
229
     * 自动侦测设置获取语言选择
230
     * @access public
231
     * @param Request $request
232
     * @return string
233
     */
234
    public function detect(Request $request): string
235
    {
236
        // 自动侦测设置获取语言选择
237
        $langSet = '';
238
239
        if ($request->get($this->config['detect_var'])) {
240
            // url中设置了语言变量
241
            $langSet = strtolower($request->get($this->config['detect_var']));
242
        } elseif ($request->cookie($this->config['cookie_var'])) {
243
            // Cookie中设置了语言变量
244
            $langSet = strtolower($request->cookie($this->config['cookie_var']));
245
        } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
246
            // 自动侦测浏览器语言
247
            $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
248
            if ($match) {
249
                $langSet = strtolower($matches[1]);
250
                if (isset($this->config['accept_language'][$langSet])) {
251
                    $langSet = $this->config['accept_language'][$langSet];
252
                }
253
            }
254
        }
255
256
        if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
257
            // 合法的语言
258
            $this->range = $langSet;
259
        }
260
261
        return $this->range;
262
    }
263
264
    /**
265
     * 保存当前语言到Cookie
266
     * @access public
267
     * @param Cookie $cookie Cookie对象
268
     * @return void
269
     */
270
    public function saveToCookie(Cookie $cookie)
271
    {
272
        if ($this->config['use_cookie']) {
273
            $cookie->set($this->config['cookie_var'], $this->range);
274
        }
275
    }
276
277
}
278