Test Setup Failed
Pull Request — developer (#302)
by Arkadiusz
33:24
created

Language   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 242
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 0
Metric Value
wmc 42
lcom 2
cbo 5
dl 0
loc 242
rs 9.0399
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
B translate() 0 24 7
A translateArgs() 0 9 3
B getLanguage() 0 18 7
A getLanguageTranslatedString() 0 13 3
A getModuleStringsFromFile() 0 10 3
A loadLanguageFile() 0 14 4
A jstranslate() 0 13 3
A getAllLanguages() 0 10 4
A getShortLanguageName() 0 5 1
A export() 0 16 3
A translateModule() 0 8 2
A getDisplayName() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like Language 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 Language, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Language controller class.
4
 *
5
 * @copyright YetiForce Sp. z o.o.
6
 * @license   YetiForce Public License 3.0 (licenses/LicenseEN.txt or yetiforce.com)
7
 * @author    Mariusz Krzaczkowski <[email protected]>
8
 */
9
10
namespace App;
11
12
class Language
0 ignored issues
show
Coding Style introduced by
Language does not seem to conform to the naming convention (Utils?$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
13
{
14
	/**
15
	 * Language files format.
16
	 */
17
	const FORMAT = 'json';
18
19
	//Contains module language translations
20
	protected static $languageContainer = [];
21
	protected static $modules = false;
22
23
	/**
24
	 * Functions that gets translated string.
25
	 *
26
	 * @param string $key             - string which need to be translated
27
	 * @param string $module          - module scope in which the translation need to be check
28
	 * @param string $currentLanguage
29
	 *
30
	 * @return string - translated string
31
	 */
32
	public static function translate(string $key, string $module = 'Basic', string $currentLanguage = ''): string
33
	{
34
		if (empty($currentLanguage)) {
35
			$currentLanguage = static::getLanguage();
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $currentLanguage. This often makes code more readable.
Loading history...
36
		}
37
		//decoding for Start Date & Time and End Date & Time
38
		if (!\is_array($key)) {
39
			$key = html_entity_decode($key);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $key. This often makes code more readable.
Loading history...
40
		}
41
		$translatedString = static::getLanguageTranslatedString($currentLanguage, $key, $module);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type array; however, App\Language::getLanguageTranslatedString() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
42
		// label not found in users language pack, then check in the default language pack(config.inc.php)
43
		if (null === $translatedString) {
44
			$defaultLanguage = Config::get('language');
45
			if (!empty($defaultLanguage) && 0 !== strcasecmp($defaultLanguage, $currentLanguage)) {
46
				$translatedString = static::getLanguageTranslatedString($defaultLanguage, $key, $module);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type array; however, App\Language::getLanguageTranslatedString() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
47
			}
48
		}
49
50
		// If translation is not found then return label
51
		if (null === $translatedString) {
52
			$translatedString = $key;
53
		}
54
		return $translatedString;
55
	}
56
57
	/**
58
	 * Functions that gets translated string by $args.
59
	 *
60
	 * @param string $key        - string which need to be translated
61
	 * @param string $moduleName - module scope in which the translation need to be check
62
	 *
63
	 * @return string - translated string
64
	 */
65
	public static function translateArgs(string $key, string $moduleName = 'Basic'): string
66
	{
67
		$formattedString = static::translate($key, $moduleName);
68
		$args = \array_slice(\func_get_args(), 2);
69
		if (\is_array($args) && !empty($args)) {
70
			$formattedString = \call_user_func_array('vsprintf', [$formattedString, $args]);
71
		}
72
		return $formattedString;
73
	}
74
75
	/**
76
	 * Function that returns current language.
77
	 *
78
	 * @return string
79
	 */
80
	public static function getLanguage()
81
	{
82
		$userInstance = User::getUser();
83
		$language = '';
84
		if ($userInstance && $userInstance->has('language') && !empty($userInstance->get('language'))) {
85
			$language = $userInstance->get('language');
86
		} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
87
			foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $code) {
88
				if (isset(static::getAllLanguages()[$code])) {
89
					$language = $code;
90
				}
91
				break;
92
			}
93
		} else {
94
			$language = Config::get('language');
95
		}
96
		return $language;
97
	}
98
99
	/**
100
	 * Function returns language specific translated string.
101
	 *
102
	 * @param string $language - en_us etc
103
	 * @param string $key      - label
104
	 * @param string $module   - module name
105
	 *
106
	 * @return string translated string or null if translation not found
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
107
	 */
108
	public static function getLanguageTranslatedString(string $language, string $key, string $module = 'Basic')
109
	{
110
		$moduleStrings = self::getModuleStringsFromFile($language, $module);
111
		if (!empty($moduleStrings['php'][$key])) {
112
			return stripslashes($moduleStrings['php'][$key]);
113
		}
114
115
		$commonStrings = self::getModuleStringsFromFile($language);
116
		if (!empty($commonStrings['php'][$key])) {
117
			return stripslashes($commonStrings['php'][$key]);
118
		}
119
		return null;
120
	}
121
122
	public static function getModuleStringsFromFile(string $language, string $module = 'Basic')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
123
	{
124
		if (empty(self::$languageContainer[$language][$module])) {
125
			static::loadLanguageFile($language, $module);
126
		}
127
		if (isset(self::$languageContainer[$language][$module])) {
128
			return self::$languageContainer[$language][$module];
129
		}
130
		return [];
131
	}
132
133
	/**
134
	 * Load language file from JSON.
135
	 *
136
	 * @param string $language
137
	 * @param string $moduleName
138
	 *
139
	 * @return void
140
	 */
141
	public static function loadLanguageFile(string $language, string $moduleName = 'Basic')
142
	{
143
		if (!isset(static::$languageContainer[$language][$moduleName])) {
144
			static::$languageContainer[$language][$moduleName] = [];
145
			$file = \DIRECTORY_SEPARATOR . 'languages' . \DIRECTORY_SEPARATOR . $language . \DIRECTORY_SEPARATOR . $moduleName . '.' . static::FORMAT;
146
			$langFile = ROOT_DIRECTORY . $file;
147
			if (file_exists($langFile)) {
148
				static::$languageContainer[$language][$moduleName] = Json::decode(file_get_contents($langFile), true) ?? [];
149
				Cache::save('LanguageFiles', $language . $moduleName, static::$languageContainer[$language][$moduleName], Cache::LONG);
150
			}
151
		} elseif (Cache::has('LanguageFiles', $language . $moduleName)) {
152
			static::$languageContainer[$language][$moduleName] = Cache::get('LanguageFiles', $language . $moduleName);
153
		}
154
	}
155
156
	/**
157
	 * Functions that gets translated string for Client side.
158
	 *
159
	 * @param <String> $key      - string which need to be translated
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
160
	 * @param <String> $module   - module scope in which the translation need to be check
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
161
	 * @param mixed    $language
162
	 *
163
	 * @return <String> - translated string
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
164
	 */
165
	public static function jstranslate($language, $key, $module = 'Basic')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
166
	{
167
		$moduleStrings = self::getModuleStringsFromFile($language, $module);
168
		if (!empty($moduleStrings['js'][$key])) {
169
			return $moduleStrings['js'][$key];
170
		}
171
172
		$commonStrings = self::getModuleStringsFromFile($language);
173
		if (!empty($commonStrings['js'][$key])) {
174
			return $commonStrings['js'][$key];
175
		}
176
		return $key;
177
	}
178
179
	/**
180
	 * Function to returns all language information.
181
	 *
182
	 * @return array
183
	 */
184
	public static function getAllLanguages(): array
185
	{
186
		$languagess = [];
187
		foreach (new \DirectoryIterator(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR . 'languages' . \DIRECTORY_SEPARATOR) as $level) {
188
			if ($level->isDir() && !$level->isDot()) {
189
				$languagess[$level->getFileName()] = self::getDisplayName($level->getFileName());
190
			}
191
		}
192
		return $languagess;
193
	}
194
195
	/**
196
	 * Function that returns current language short name.
197
	 *
198
	 * @return <String> -
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
199
	 */
200
	public static function getShortLanguageName()
201
	{
202
		$language = self::getLanguage();
203
		return substr($language, 0, 2);
204
	}
205
206
	/**
207
	 * Function returns module strings.
208
	 *
209
	 * @param <String> $module - module Name
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
210
	 * @param  <String> languageStrings or jsLanguageStrings
211
	 * @param mixed $type
212
	 *
213
	 * @return <Array>
0 ignored issues
show
Documentation introduced by
The doc-type <Array> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
214
	 */
215
	public static function export($module, $type = 'php')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
216
	{
217
		$language = self::getLanguage();
218
		$exportLangString = [];
219
220
		$moduleStrings = self::getModuleStringsFromFile($language, $module);
221
		if (!empty($moduleStrings[$type])) {
222
			$exportLangString = $moduleStrings[$type];
223
		}
224
225
		$commonStrings = self::getModuleStringsFromFile($language);
226
		if (!empty($commonStrings[$type])) {
227
			$exportLangString += $commonStrings[$type];
228
		}
229
		return $exportLangString;
230
	}
231
232
	public static function translateModule($module)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
233
	{
234
		if (!self::$modules) {
235
			$userInstance = User::getUser();
236
			self::$modules = $userInstance->getModulesList();
237
		}
238
		return self::$modules[$module] ?? $module;
239
	}
240
241
	/**
242
	 * Get display language name.
243
	 *
244
	 * @param string $prefix
245
	 *
246
	 * @return string
247
	 */
248
	public static function getDisplayName(string $prefix): string
249
	{
250
		return Utils::mbUcfirst(locale_get_region($prefix) === strtoupper(locale_get_primary_language($prefix)) ? locale_get_display_language($prefix, $prefix) : locale_get_display_name($prefix, $prefix));
251
	}
252
253
}
254