Functions::throwNewException()   F
last analyzed

Complexity

Conditions 20
Paths 300

Size

Total Lines 62
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 320.5349

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
dl 0
loc 62
ccs 3
cts 33
cp 0.0909
rs 2.0833
c 1
b 0
f 0
cc 20
nc 300
nop 3
crap 320.5349

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
 /* +**********************************************************************************
4
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
5
 * ("License"); You may not use this file except in compliance with the License
6
 * The Original Code is:  vtiger CRM Open Source
7
 * The Initial Developer of the Original Code is vtiger.
8
 * Portions created by vtiger are Copyright (C) vtiger.
9
 * All Rights Reserved.
10
 * Contributor(s): YetiForce S.A.
11
 * ********************************************************************************** */
12
13
namespace vtlib;
14
15
class Functions
16 21
{
17
	public static function getAllModules($isEntityType = true, $showRestricted = false, $presence = false, $colorActive = false, $ownedby = false)
18 21
	{
19 15
		if (\App\Cache::has('moduleTabs', 'all')) {
20
			$moduleList = \App\Cache::get('moduleTabs', 'all');
21 14
		} else {
22 14
			$moduleList = [];
23 14
			$rows = (new \App\Db\Query())->from('vtiger_tab')->all();
24 14
			foreach ($rows as $row) {
25 11
				if (!\App\Cache::has('moduleTabById', $row['tabid'])) {
26
					\App\Cache::save('moduleTabById', $row['tabid'], $row);
27 14
				}
28 11
				if (!\App\Cache::has('moduleTabByName', $row['name'])) {
29
					\App\Cache::save('moduleTabByName', $row['name'], $row);
30 14
				}
31 14
				$row['tabid'] = (int) $row['tabid'];
32 14
				$row['presence'] = (int) $row['presence'];
33 14
				$row['tabsequence'] = (int) $row['tabsequence'];
34 14
				$row['customized'] = (int) $row['customized'];
35 14
				$row['ownedby'] = (int) $row['ownedby'];
36 14
				$row['isentitytype'] = (int) $row['isentitytype'];
37 14
				$row['coloractive'] = (int) $row['coloractive'];
38 14
				$row['type'] = (int) $row['type'];
39 14
				$row['premium'] = (int) $row['premium'];
40
				$moduleList[$row['tabid']] = $row;
41 14
			}
42
			\App\Cache::save('moduleTabs', 'all', $moduleList);
43 21
		}
44 21
		$restrictedModules = ['Dashboard', 'ModComments'];
45 21
		foreach ($moduleList as $id => $module) {
46 14
			if (!$showRestricted && \in_array($module['name'], $restrictedModules)) {
47
				unset($moduleList[$id]);
48 21
			}
49 13
			if ($isEntityType && 0 === (int) $module['isentitytype']) {
50
				unset($moduleList[$id]);
51 21
			}
52 2
			if (false !== $presence && (int) $module['presence'] !== $presence) {
53
				unset($moduleList[$id]);
54 21
			}
55
			if (false !== $colorActive && 1 !== (int) $module['coloractive']) {
56
				unset($moduleList[$id]);
57 21
			}
58 2
			if (false !== $ownedby && (int) $module['ownedby'] !== $ownedby) {
59
				unset($moduleList[$id]);
60
			}
61 21
		}
62
		return $moduleList;
63
	}
64 84
65
	public static function getModuleData($mixed)
66 84
	{
67
		if (empty($mixed)) {
68
			\App\Log::error(__METHOD__ . ' - Required parameter missing');
69
70
			return false;
71 84
		}
72 84
		$id = $name = null;
73 69
		if (is_numeric($mixed)) {
74 69
			$id = $mixed;
75 47
			if (\App\Cache::has('moduleTabById', $mixed)) {
76
				return \App\Cache::get('moduleTabById', $mixed);
77
			}
78 58
		} else {
79 58
			$name = (string) $mixed;
80 32
			if (\App\Cache::has('moduleTabByName', $name)) {
81
				return \App\Cache::get('moduleTabByName', $name);
82
			}
83 59
		}
84 59
		$moduleList = [];
85 59
		$rows = (new \App\Db\Query())->from('vtiger_tab')->all();
86 59
		foreach ($rows as $row) {
87 59
			\App\Cache::save('moduleTabById', $row['tabid'], $row);
88 59
			\App\Cache::save('moduleTabByName', $row['name'], $row);
89
			$moduleList[$row['tabid']] = $row;
90 59
		}
91 59
		\App\Cache::save('moduleTabs', 'all', $moduleList);
92 34
		if ($name && \App\Cache::has('moduleTabByName', $name)) {
93
			return \App\Cache::get('moduleTabByName', $name);
94 26
		}
95
		return $id ? \App\Cache::get('moduleTabById', $id) : null;
96
	}
97
98
	// MODULE RECORD
99
	protected static $crmRecordIdMetadataCache = [];
100
101
	/**
102
	 * Clear cache meta data for records.
103
	 *
104
	 * @param int $id
105 1
	 */
106
	public static function clearCacheMetaDataRecord($id)
107 1
	{
108 1
		if (isset(static::$crmRecordIdMetadataCache[$id])) {
109
			unset(static::$crmRecordIdMetadataCache[$id]);
110 1
		}
111
	}
112
113
	/**
114
	 * Function gets record metadata.
115
	 *
116
	 * @param array|int $mixedid
117
	 *
118
	 * @return array
119 26
	 */
120
	public static function getCRMRecordMetadata($mixedid)
121 26
	{
122
		$multimode = \is_array($mixedid);
123 26
124 26
		$ids = $multimode ? $mixedid : [$mixedid];
125 26
		$missing = [];
126 26
		foreach ($ids as $id) {
127 9
			if ($id && !isset(self::$crmRecordIdMetadataCache[$id])) {
128
				$missing[] = $id;
129
			}
130 26
		}
131 9
		if ($missing) {
132 9
			$query = (new \App\Db\Query())
133 9
				->select(['crmid', 'setype', 'deleted', 'smcreatorid', 'smownerid', 'createdtime', 'private'])
134 9
				->from('vtiger_crmentity')
135 9
				->where(['in', 'crmid', $missing]);
136 9
			$dataReader = $query->createCommand()->query();
137 8
			while ($row = $dataReader->read()) {
138 8
				$row['deleted'] = (int) $row['deleted'];
139 8
				$row['smownerid'] = (int) $row['smownerid'];
140 8
				$row['smcreatorid'] = (int) $row['smcreatorid'];
141 8
				$row['crmid'] = (int) $row['crmid'];
142 8
				$row['private'] = (int) $row['private'];
143
				self::$crmRecordIdMetadataCache[$row['crmid']] = $row;
144
			}
145 26
		}
146 26
		$result = [];
147 26
		foreach ($ids as $id) {
148 19
			if (isset(self::$crmRecordIdMetadataCache[$id])) {
149
				$result[$id] = self::$crmRecordIdMetadataCache[$id];
150 8
			} else {
151
				$result[$id] = null;
152
			}
153 26
		}
154
		return $multimode ? $result : array_shift($result);
155
	}
156 1
157
	public static function getCRMRecordLabel($id, $default = '')
158 1
	{
159
		$label = \App\Record::getLabel($id);
160 1
161
		return empty($label) ? $default : $label;
162
	}
163
164
	/**
165
	 * Function to gets mudule field ID.
166
	 *
167
	 * @param int|string $moduleId
168
	 * @param int|string $mixed
169
	 * @param bool       $onlyactive
170
	 *
171 5821
	 * @return bool|int
172
	 */
173 5821
	public static function getModuleFieldId($moduleId, $mixed, $onlyactive = true)
174 2
	{
175
		$field = \App\Field::getFieldInfo($mixed, $moduleId);
176 5821
177 5821
		if ($field && $onlyactive && ('0' !== $field['presence'] && '2' !== $field['presence'])) {
178 49
			$field = null;
179 49
		}
180 49
		return $field ? $field['fieldid'] : false;
181 49
	}
182 49
183 49
	// Utility
184 49
	public static function formatDecimal($value)
185 49
	{
186
		$fld_value = explode('.', $value);
187 49
		if (!empty($fld_value[1])) {
188 49
			$fld_value = rtrim($value, '0');
189
			$value = rtrim($fld_value, '.');
190 5821
		}
191 1
		return $value;
192
	}
193 5821
194
	public static function fromHtmlPopup($string, $encode = true)
195
	{
196
		$popup_toHtml = [
197
			'"' => '&quot;',
198
			"'" => '&#039;',
199
		];
200
		if ($encode && \is_string($string)) {
201
			$string = addslashes(str_replace(array_values($popup_toHtml), array_keys($popup_toHtml), $string));
202
		}
203
		return $string;
204
	}
205
206
	public static function br2nl($str)
207
	{
208
		$str = preg_replace("/(\r\n)/", '\\r\\n', $str);
209
		$str = preg_replace("/'/", ' ', $str);
210
		return preg_replace('/"/', ' ', $str);
211
	}
212
213
	public static function suppressHTMLTags($string)
214
	{
215
		return preg_replace(['/</', '/>/', '/"/'], ['&lt;', '&gt;', '&quot;'], $string);
216 1
	}
217
218 1
	/**    Function used to retrieve a single field value from database.
219 1
	 * @param string $tableName - tablename from which we will retrieve the field value
220 1
	 * @param string $fieldName - fieldname to which we want to get the value from database
221 1
	 * @param string $idName    - idname which is the name of the entity id in the table like, inoviceid, etc.,
222
	 * @param int    $id        - entity id
223 1
	 *                          return mixed $fieldval  - field value of the needed fieldname from database will be returned
224
	 */
225
	public static function getSingleFieldValue($tableName, $fieldName, $idName, $id)
226
	{
227
		return (new \App\Db\Query())->select([$fieldName])->from($tableName)->where([$idName => $id])->scalar();
228
	}
229
230
	/**     function used to change the Type of Data for advanced filters in custom view and Reports.
231
	 * *     @param string $table_name - tablename value from field table
232
	 * *     @param string $column_nametable_name - columnname value from field table
233
	 * *     @param string $type_of_data - current type of data of the field. It is to return the same TypeofData
234
	 * *            if the  field is not matched with the $new_field_details array.
235
	 * *     return string $type_of_data - If the string matched with the $new_field_details array then the Changed
236
	 * *           typeofdata will return, else the same typeofdata will return.
237
	 * *
238
	 * *     EXAMPLE: If you have a field entry like this:
239
	 * *
240
	 * *        fieldlabel         | typeofdata | tablename            | columnname       |
241
	 * *            -------------------+------------+----------------------+------------------+
242
	 * *        Potential Name     | I~O        | vtiger_quotes        | potentialid      |
243
	 * *
244
	 * *     Then put an entry in $new_field_details  like this:
245
	 * *
246
	 * *                "vtiger_quotes:potentialid"=>"V",
247
	 * *
248
	 * *    Now in customview and report's advance filter this field's criteria will be show like string.
249
	 * @param mixed $column_name
250
	 * */
251
	public static function transformFieldTypeOfData($table_name, $column_name, $type_of_data)
252
	{
253
		$field = $table_name . ':' . $column_name;
254
		//Add the field details in this array if you want to change the advance filter field details
255
256
		static $new_field_details = [
257
			//Contacts Related Fields
258
			'vtiger_contactdetails:parentid' => 'V',
259
			'vtiger_contactsubdetails:birthday' => 'D',
260
			'vtiger_contactdetails:email' => 'V',
261
			'vtiger_contactdetails:secondaryemail' => 'V',
262
			//Account Related Fields
263
			'vtiger_account:parentid' => 'V',
264
			'vtiger_account:email1' => 'V',
265
			'vtiger_account:email2' => 'V',
266
			//Lead Related Fields
267
			'vtiger_leaddetails:email' => 'V',
268
			'vtiger_leaddetails:secondaryemail' => 'V',
269
			//Documents Related Fields
270
			'vtiger_senotesrel:crmid' => 'V',
271
			//HelpDesk Related Fields
272
			'vtiger_troubletickets:parent_id' => 'V',
273
			'vtiger_troubletickets:product_id' => 'V',
274
			//Product Related Fields
275
			'vtiger_products:discontinued' => 'C',
276
			'vtiger_products:vendor_id' => 'V',
277
			'vtiger_products:parentid' => 'V',
278
			//Faq Related Fields
279
			'vtiger_faq:product_id' => 'V',
280
			//Vendor Related Fields
281
			'vtiger_vendor:email' => 'V',
282
			//Campaign Related Fields
283
			'vtiger_campaign:product_id' => 'V',
284 14
			//Related List Entries(For Report Module)
285
			'vtiger_activityproductrel:activityid' => 'V',
286 14
			'vtiger_activityproductrel:productid' => 'V',
287
			'vtiger_campaign_records:campaignid' => 'V',
288
			'vtiger_campaign_records:crmid' => 'V',
289 14
			'vtiger_pricebookproductrel:pricebookid' => 'V',
290
			'vtiger_pricebookproductrel:productid' => 'V',
291
			'vtiger_senotesrel:crmid' => 'V',
292
			'vtiger_senotesrel:notesid' => 'V',
293
			'vtiger_seproductsrel:crmid' => 'V',
294
			'vtiger_seproductsrel:productid' => 'V',
295
			'vtiger_pricebook:currency_id' => 'V',
296
		];
297
298
		//If the Fields details does not match with the array, then we return the same typeofdata
299
		if (isset($new_field_details[$field])) {
300
			$type_of_data = $new_field_details[$field];
301
		}
302
		return $type_of_data;
303
	}
304
305
	public static function getArrayFromValue($values)
306
	{
307
		if (\is_array($values)) {
308
			return $values;
309
		}
310
		if ('' === $values) {
311
			return [];
312
		}
313
		if (false === strpos($values, ',')) {
314
			$array[] = $values;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$array was never initialized. Although not strictly required by PHP, it is generally a good practice to add $array = array(); before regardless.
Loading history...
315
		} else {
316
			$array = explode(',', $values);
317
		}
318
		return $array;
319
	}
320
321
	public static function throwNewException($e, $die = true, $messageHeader = 'LBL_ERROR')
322
	{
323
		if (!headers_sent() && \App\Config::security('cspHeaderActive')) {
324
			header("content-security-policy: default-src 'self' 'nonce-" . \App\Session::get('CSP_TOKEN') . "'; object-src 'none';base-uri 'self'; frame-ancestors 'self';");
0 ignored issues
show
Bug introduced by
Are you sure App\Session::get('CSP_TOKEN') of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

324
			header("content-security-policy: default-src 'self' 'nonce-" . /** @scrutinizer ignore-type */ \App\Session::get('CSP_TOKEN') . "'; object-src 'none';base-uri 'self'; frame-ancestors 'self';");
Loading history...
325
		}
326
		$message = \is_object($e) ? $e->getMessage() : $e;
327
		$code = 500;
328
		if (!\is_array($message)) {
329
			if (false === strpos($message, '||')) {
330
				$message = \App\Language::translateSingleMod($message, 'Other.Exceptions');
331
			} else {
332 14
				$params = explode('||', $message);
333 6
				$label = \App\Language::translateSingleMod(array_shift($params), 'Other.Exceptions');
334
				$params = array_pad($params, substr_count($label, '%'), '');
335 14
				$message = \call_user_func_array('vsprintf', [$label, $params]);
336
			}
337
		}
338
		if ('API' === \App\Process::$requestMode) {
339
			throw new \App\Exceptions\ApiException($message, 401);
340
		}
341
		if (\App\Request::_isAjax() && \App\Request::_isJSON()) {
0 ignored issues
show
Bug introduced by
The method _isJSON() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

341
		if (\App\Request::_isAjax() && \App\Request::/** @scrutinizer ignore-call */ _isJSON()) {
Loading history...
Bug introduced by
The method _isAjax() does not exist on App\Request. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

341
		if (\App\Request::/** @scrutinizer ignore-call */ _isAjax() && \App\Request::_isJSON()) {
Loading history...
342
			$response = new \Vtiger_Response();
343
			$response->setEmitType(\Vtiger_Response::$EMIT_JSON);
344
345
			if (\is_object($e)) {
346
				$response->setException($e);
347
			} else {
348
				$trace = '';
349
				if (\App\Config::debug('DISPLAY_EXCEPTION_BACKTRACE') && \is_object($e)) {
350
					$trace = str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', "->{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}");
351
				}
352
				$response->setError($code, $message, $trace);
353
			}
354
			$response->emit();
355
		} else {
356
			if (\PHP_SAPI !== 'cli') {
357
				if (\App\Config::debug('DISPLAY_EXCEPTION_BACKTRACE') && \is_object($e)) {
358
					$message = [
359
						'message' => $message,
360
						'trace' => str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', "-> {$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"),
361
					];
362
					$code = $e->getCode();
363
				}
364
				http_response_code($code);
365
				$viewer = new \Vtiger_Viewer();
366
				$viewer->assign('MESSAGE', \Config\Debug::$EXCEPTION_ERROR_TO_SHOW ? $message : \App\Language::translate('ERR_OCCURRED_ERROR'));
367
				$viewer->assign('MESSAGE_EXPANDED', \is_array($message));
368
				$viewer->assign('HEADER_MESSAGE', \App\Language::translate($messageHeader));
369
				$viewer->view('Exceptions/ExceptionError.tpl', 'Vtiger');
370
			} else {
371
				echo(\Config\Debug::$EXCEPTION_ERROR_TO_SHOW ? $message : \App\Language::translate('ERR_OCCURRED_ERROR')) . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure Config\Debug::EXCEPTION_...e('ERR_OCCURRED_ERROR') of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

371
				echo(/** @scrutinizer ignore-type */ \Config\Debug::$EXCEPTION_ERROR_TO_SHOW ? $message : \App\Language::translate('ERR_OCCURRED_ERROR')) . PHP_EOL;
Loading history...
372
			}
373
		}
374
		if ($die) {
375
			trigger_error(print_r($message, true), E_USER_ERROR);
376
			if (\is_object($message)) {
377
				throw new $message();
378
			}
379
			if (\is_array($message)) {
380
				throw new \App\Exceptions\AppException($message['message']);
381
			}
382
			throw new \App\Exceptions\AppException($message);
383
		}
384
	}
385
386
	/**
387
	 * Get html rr plain text.
388
	 *
389
	 * @param string $content
390
	 *
391
	 * @return string
392
	 */
393
	public static function getHtmlOrPlainText(string $content)
394
	{
395
		if (\App\Utils::isHtml($content)) {
396
			$content = \App\Purifier::decodeHtml($content);
397
		} else {
398
			$content = nl2br($content);
399
		}
400
		return $content;
401
	}
402
403
	/**
404
	 * Function to delete files and dirs.
405
	 *
406
	 * @param string $src
407
	 * @param bool   $outsideRoot
408
	 */
409
	public static function recurseDelete($src, $outsideRoot = false): int
410
	{
411
		$rootDir = ($outsideRoot || 0 === strpos($src, ROOT_DIRECTORY)) ? '' : ROOT_DIRECTORY . \DIRECTORY_SEPARATOR;
412
		if (!file_exists($rootDir . $src)) {
413
			return 0;
414
		}
415
		$i = 0;
416
		if (is_dir($rootDir . $src)) {
417
			foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($rootDir . $src, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST) as $filename => $file) {
418
				if ($file->isFile()) {
419
					unlink($filename);
420
					++$i;
421
				} else {
422
					rmdir($filename);
423
				}
424
			}
425
			rmdir($rootDir . $src);
426
		} else {
427
			unlink($rootDir . $src);
428
			++$i;
429
		}
430
		return $i;
431
	}
432
433
	/**
434
	 * The function copies files.
435
	 *
436
	 * @param string $src
437
	 * @param string $dest
438
	 *
439
	 * @return int
440 7
	 */
441
	public static function recurseCopy($src, $dest)
442 7
	{
443 7
		$rootDir = ROOT_DIRECTORY . \DIRECTORY_SEPARATOR;
444 2
		if (!file_exists($rootDir . $src)) {
445
			return 0;
446 6
		}
447 6
		if ($dest && '/' !== substr($dest, -1) && '\\' !== substr($dest, -1)) {
448 6
			$dest = $dest . \DIRECTORY_SEPARATOR;
449 6
		}
450
		$i = 0;
451 4
		$dest = $rootDir . $dest;
452
		foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($src, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) {
453
			if ($item->isDir() && !file_exists($dest . $iterator->getSubPathName())) {
0 ignored issues
show
Bug introduced by
The method getSubPathName() does not exist on RecursiveIteratorIterator. ( Ignorable by Annotation )

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

453
			if ($item->isDir() && !file_exists($dest . $iterator->/** @scrutinizer ignore-call */ getSubPathName())) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
454 6
				mkdir($dest . $iterator->getSubPathName(), 0755);
455
			} elseif (!$item->isDir()) {
456
				copy($item->getRealPath(), $dest . $iterator->getSubPathName());
457
				++$i;
458 6
			}
459
		}
460
		return $i;
461
	}
462
463
	/**
464
	 * Parse bytes.
465
	 *
466
	 * @param mixed $str
467
	 *
468
	 * @return float
469
	 */
470
	public static function parseBytes($str): float
471
	{
472
		if (is_numeric($str)) {
473
			return (float) $str;
474
		}
475
		$bytes = 0;
476
		if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs)) {
477
			$bytes = (float) ($regs[1]);
478
			switch (strtolower($regs[2])) {
479
				case 'g':
480
				case 'gb':
481
					$bytes *= 1073741824;
482
					break;
483
				case 'm':
484
				case 'mb':
485
					$bytes *= 1048576;
486
					break;
487
				case 'k':
488
				case 'kb':
489
					$bytes *= 1024;
490 13
					break;
491
				default:
492 13
					break;
493 13
			}
494
		}
495
		return (float) $bytes;
496
	}
497
498
	/**
499
	 * Show bytes.
500
	 *
501
	 * @param mixed       $bytes
502
	 * @param string|null $unit
503
	 *
504
	 * @return string
505
	 */
506
	public static function showBytes($bytes, &$unit = null): string
507
	{
508
		$bytes = self::parseBytes($bytes);
509
		if ($bytes >= 1073741824) {
510
			$unit = 'GB';
511
			$gb = $bytes / 1073741824;
512
			$str = sprintf($gb >= 10 ? '%d ' : '%.2f ', $gb) . $unit;
513
		} elseif ($bytes >= 1048576) {
514
			$unit = 'MB';
515
			$mb = $bytes / 1048576;
516
			$str = sprintf($mb >= 10 ? '%d ' : '%.2f ', $mb) . $unit;
517
		} elseif ($bytes >= 1024) {
518 13
			$unit = 'KB';
519
			$str = sprintf('%d ', round($bytes / 1024)) . $unit;
520 13
		} else {
521 13
			$unit = 'B';
522
			$str = sprintf('%d ', $bytes) . $unit;
523
		}
524
		return $str;
525 13
	}
526
527
	public static function getMinimizationOptions($type = 'js')
528
	{
529 13
		switch ($type) {
530 7
			case 'js':
531 7
				$return = \App\Config::developer('MINIMIZE_JS');
532
				break;
533 7
			case 'css':
534 7
				$return = \App\Config::developer('MINIMIZE_CSS');
535
				break;
536 13
			default:
537
				break;
538
		}
539
		return $return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $return does not seem to be defined for all execution paths leading up to this point.
Loading history...
540
	}
541
542
	/**
543
	 * Checks if given date is working day, if not returns last working day.
544
	 *
545
	 * @param <Date> $date
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Date> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Date>.
Loading history...
546
	 *
547
	 * @return <Date> - last working y
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Date> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Date>.
Loading history...
548
	 */
549
	public static function getLastWorkingDay($date)
550
	{
551
		if (empty($date)) {
552
			$date = date('Y-m-d');
553
		}
554
		$date = strtotime($date);
555
		if ('Sat' === date('D', $date)) { // switch to friday the day before
556
			$lastWorkingDay = date('Y-m-d', strtotime('-1 day', $date));
557
		} elseif ('Sun' === date('D', $date)) { // switch to friday two days before
558
			$lastWorkingDay = date('Y-m-d', strtotime('-2 day', $date));
559
		} else {
560
			$lastWorkingDay = date('Y-m-d', $date);
561
		}
562
		return $lastWorkingDay;
563
	}
564
565
	/**
566
	 * Function that returns conversion info from default system currency to chosen one.
567
	 *
568
	 * @param <Integer> $currencyId - id of currency for which we want to retrieve conversion rate to default currency
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Integer> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Integer>.
Loading history...
569
	 * @param <Date>    $date       - date of exchange rates, if empty then rate from yesterday
570
	 *
571
	 * @return <Array> - array containing:
0 ignored issues
show
Documentation Bug introduced by
The doc comment <Array> at position 0 could not be parsed: Unknown type name '<' at position 0 in <Array>.
Loading history...
572
	 *                 date - date of rate
573 1
	 *                 value - conversion 1 default currency -> $currencyId
574
	 *                 conversion - 1 $currencyId -> default currency
575 1
	 */
576
	public static function getConversionRateInfo($currencyId, $date = '')
577
	{
578 1
		$defaultCurrencyId = \App\Fields\Currency::getDefault()['id'];
579 1
		$info = [];
580
		if (empty($date)) {
581 1
			$yesterday = date('Y-m-d', strtotime('-1 day'));
582
			$date = self::getLastWorkingDay($yesterday);
583
		}
584 1
		$info['date'] = $date;
585
		if ($currencyId == $defaultCurrencyId) {
586 1
			$info['value'] = 1.0;
587
			$info['conversion'] = 1.0;
588
		} else {
589 2
			$value = \Settings_CurrencyUpdate_Module_Model::getCleanInstance()->getCRMConversionRate($currencyId, $defaultCurrencyId, $date);
590
			$info['value'] = empty($value) ? 1.0 : round($value, 5);
591
			$info['conversion'] = empty($value) ? 1.0 : round(1 / $value, 5);
592 2
		}
593
		return $info;
594
	}
595 2
596
	/**
597
	 * Getting parameters from URL.
598
	 *
599
	 * @param string|null $url
600
	 *
601
	 * @return array
602
	 */
603
	public static function getQueryParams($url): array
604
	{
605
		$queryParams = [];
606
		if (!empty($url) && $queryStr = parse_url(htmlspecialchars_decode($url), PHP_URL_QUERY)) {
607
			parse_str($queryStr, $queryParams);
608
		}
609
610
		return $queryParams;
611
	}
612
613
	public static function arrayDiffAssocRecursive($array1, $array2)
614
	{
615
		$difference = [];
616
		foreach ($array1 as $key => $value) {
617
			if (\is_array($value)) {
618
				if (!isset($array2[$key]) || !\is_array($array2[$key])) {
619
					$difference[$key] = $value;
620
				} else {
621
					$newDiff = self::arrayDiffAssocRecursive($value, $array2[$key]);
622
					if (!empty($newDiff)) {
623
						$difference[$key] = $newDiff;
624
					}
625
				}
626
			} elseif (!\array_key_exists($key, $array2) || $array2[$key] !== $value) {
627
				$difference[$key] = $value;
628
			}
629
		}
630
		return $difference;
631
	}
632
}
633