Module   F
last analyzed

Complexity

Total Complexity 62

Size/Duplication

Total Lines 378
Duplicated Lines 0 %

Test Coverage

Coverage 66.41%

Importance

Changes 0
Metric Value
wmc 62
eloc 154
c 0
b 0
f 0
dl 0
loc 378
ccs 87
cts 131
cp 0.6641
rs 3.44

18 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 4 1
A getAllEntityModuleInfo() 0 9 3
A getEntitiesInfo() 0 14 5
A initFromDb() 0 4 1
A getEntityInfo() 0 3 1
A getModuleOwner() 0 3 1
A isModuleActive() 0 13 4
A getModuleId() 0 3 1
A getModuleName() 0 3 1
A getSharingModuleList() 0 10 4
A getAllModuleNames() 0 3 1
A getSqlForNameInDisplayFormat() 0 16 3
A getActionId() 0 20 6
A getModuleMeta() 0 25 4
F getQuickCreateModules() 0 64 16
A createModuleMetaFile() 0 20 4
A changeType() 0 5 4
A getAllModuleNamesFilter() 0 7 2

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace App;
4
5
/**
6
 * Modules basic class.
7
 *
8
 * @package App
9
 *
10
 * @copyright YetiForce S.A.
11
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
12
 * @author    Mariusz Krzaczkowski <[email protected]>
13
 * @author    Radosław Skrzypczak <[email protected]>
14
 */
15
class Module
16
{
17
	/**
18
	 * Cache for tabdata.php.
19
	 *
20
	 * @var array
21
	 */
22
	protected static $tabdataCache;
23
24
	/**
25
	 * Init tabdata from file.
26
	 */
27
	public static function init()
28
	{
29
		static::$tabdataCache = require ROOT_DIRECTORY . '/user_privileges/tabdata.php';
30
		static::$tabdataCache['tabName'] = array_flip(static::$tabdataCache['tabId']);
31
	}
32
33
	/**
34
	 * Init tabdata form db.
35 7
	 */
36
	public static function initFromDb()
37 7
	{
38 7
		static::$tabdataCache = static::getModuleMeta();
39 7
		static::$tabdataCache['tabName'] = array_flip(static::$tabdataCache['tabId']);
40
	}
41 5868
42
	/**
43 5868
	 * Gets entity info.
44 5868
	 *
45 5868
	 * @param string $moduleName
46
	 *
47
	 * @return array|null
48
	 */
49
	public static function getEntityInfo(string $moduleName = null): ?array
50 5868
	{
51 5844
		return self::getEntitiesInfo()[$moduleName] ?? null;
52
	}
53
54
	/**
55 62
	 * Gets all entities data.
56 62
	 *
57 62
	 * @param array
58 62
	 */
59 62
	public static function getEntitiesInfo(): array
60 62
	{
61 62
		$cacheName = 'ModuleEntityInfo';
62 62
		if (!Cache::has($cacheName, '')) {
63 62
			$entityInfos = [];
64
			$dataReader = (new \App\Db\Query())->from('vtiger_entityname')->createCommand()->query();
65 62
			while ($row = $dataReader->read()) {
66 62
				$row['fieldnameArr'] = $row['fieldname'] ? explode(',', $row['fieldname']) : [];
67
				$row['searchcolumnArr'] = $row['searchcolumn'] ? explode(',', $row['searchcolumn']) : [];
68
				$entityInfos[$row['modulename']] = $row;
69 62
			}
70
			return Cache::save($cacheName, '', $entityInfos);
0 ignored issues
show
Bug Best Practice introduced by
The expression return App\Cache::save($...Name, '', $entityInfos) returns the type boolean which is incompatible with the type-hinted return array.
Loading history...
71
		}
72
		return Cache::get($cacheName, '');
73
	}
74
75
	public static function getAllEntityModuleInfo($sort = false)
76
	{
77
		$entity = static::getEntitiesInfo();
78
		if ($sort) {
79
			usort($entity, function ($a, $b) {
80
				return $a['sequence'] < $b['sequence'] ? -1 : 1;
81
			});
82
		}
83
		return $entity;
84
	}
85
86
	protected static $isModuleActiveCache = [];
87
88
	/**
89
	 * Function to check whether the module is active.
90
	 *
91
	 * @param string $moduleName
92
	 *
93
	 * @return bool
94 15
	 */
95
	public static function isModuleActive(string $moduleName): bool
96 15
	{
97 15
		if (isset(static::$isModuleActiveCache[$moduleName])) {
98
			return static::$isModuleActiveCache[$moduleName];
99 3
		}
100 1
		if (\in_array($moduleName, ['CustomView', 'Users', 'Import', 'com_vtiger_workflow', 'PickList'])) {
101
			static::$isModuleActiveCache[$moduleName] = true;
102 1
			return true;
103
		}
104 2
		$moduleId = static::getModuleId($moduleName);
105 2
		$isActive = (isset(static::$tabdataCache['tabPresence'][$moduleId]) && 0 == static::$tabdataCache['tabPresence'][$moduleId]);
106 2
		static::$isModuleActiveCache[$moduleName] = $isActive;
107
		return $isActive;
108 2
	}
109
110
	/**
111
	 * Get module id by module name.
112
	 *
113
	 * @param string $moduleName
114
	 *
115
	 * @return bool|int
116
	 */
117
	public static function getModuleId($moduleName)
118 127
	{
119
		return static::$tabdataCache['tabId'][$moduleName] ?? false;
120 127
	}
121
122
	/**
123
	 * Get module nane by module id.
124
	 *
125
	 * @param int $tabId
126
	 *
127
	 * @return bool|string
128
	 */
129
	public static function getModuleName($tabId)
130 446
	{
131
		return static::$tabdataCache['tabName'][$tabId] ?? false;
132 446
	}
133
134
	/**
135
	 * Get module owner by module id.
136
	 *
137
	 * @param int $tabId
138
	 *
139
	 * @return int
140
	 */
141
	public static function getModuleOwner($tabId)
142
	{
143
		return static::$tabdataCache['tabOwnedby'][$tabId] ?? false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::tabdataCa...edby'][$tabId] ?? false could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
144
	}
145
146
	/**
147
	 * Get all module names.
148
	 *
149
	 * @return string[]
150
	 */
151
	public static function getAllModuleNames()
152
	{
153
		return static::$tabdataCache['tabName'];
154
	}
155
156
	/**
157
	 * Function to get the list of module for which the user defined sharing rules can be defined.
158
	 *
159
	 * @param array $eliminateModules
160
	 *
161
	 * @return array
162
	 */
163
	public static function getSharingModuleList($eliminateModules = false)
164 2
	{
165
		$modules = \vtlib\Functions::getAllModules(true, true, 0, false, 0);
166 2
		$sharingModules = [];
167 2
		foreach ($modules as $row) {
168 2
			if (!$eliminateModules || !\in_array($row['name'], $eliminateModules)) {
169 2
				$sharingModules[] = $row['name'];
170 2
			}
171
		}
172
		return $sharingModules;
173 2
	}
174
175
	/**
176
	 * Get sql for name in display format.
177
	 *
178
	 * @param string $moduleName
179
	 *
180
	 * @return string
181
	 */
182
	public static function getSqlForNameInDisplayFormat($moduleName)
183
	{
184
		$db = \App\Db::getInstance();
185
		$entityFieldInfo = static::getEntityInfo($moduleName);
186
		$fieldsName = $entityFieldInfo['fieldnameArr'];
187
		if (\count($fieldsName) > 1) {
188
			$sqlString = 'CONCAT(';
189
			foreach ($fieldsName as &$column) {
190
				$sqlString .= "{$db->quoteTableName($entityFieldInfo['tablename'])}.{$db->quoteColumnName($column)},' ',";
191
			}
192
			$formattedName = new \yii\db\Expression(rtrim($sqlString, ',\' \',') . ')');
193
		} else {
194
			$fieldsName = array_pop($fieldsName);
195
			$formattedName = "{$db->quoteTableName($entityFieldInfo['tablename'])}.{$db->quoteColumnName($fieldsName)}";
196
		}
197
		return $formattedName;
198
	}
199
200
	/**
201
	 * Function to get a action id for a given action name.
202
	 *
203
	 * @param string $action
204
	 *
205
	 * @return int|null
206
	 */
207
	public static function getActionId($action)
208 16
	{
209
		if (empty($action)) {
210 16
			return null;
211 6
		}
212
		if (Cache::has('getActionId', $action)) {
213 12
			return Cache::get('getActionId', $action);
214 6
		}
215
		$actionIds = static::$tabdataCache['actionId'];
216 7
		if (isset($actionIds[$action])) {
217 7
			$actionId = $actionIds[$action];
218 7
		}
219
		if (empty($actionId)) {
220 7
			$actionId = (new Db\Query())->select(['actionid'])->from('vtiger_actionmapping')->where(['actionname' => $action])->scalar();
221
		}
222
		if (is_numeric($actionId)) {
223 7
			$actionId = (int) $actionId;
224 7
		}
225
		Cache::save('getActionId', $action, $actionId, Cache::LONG);
226 7
		return $actionId;
227 7
	}
228
229
	/**
230
	 * Get module meta data.
231
	 *
232
	 * @return array
233
	 */
234
	public static function getModuleMeta()
235 7
	{
236
		$tabNames = $tabPresence = $tabOwned = [];
237 7
		$allModules = \vtlib\Functions::getAllModules(false, true);
238 7
		foreach ($allModules as $moduleInfo) {
239 7
			$tabNames[$moduleInfo['name']] = $tabId = (int) $moduleInfo['tabid'];
240 7
			$tabPresence[$tabId] = $moduleInfo['presence'];
241 7
			$tabOwned[$tabId] = $moduleInfo['ownedby'];
242 7
		}
243
		//Constructing the actionname=>actionid array
244
		$actionAll = [];
245 7
		$dataReader = (new Db\Query())->from(['vtiger_actionmapping'])->createCommand()->query();
246 7
		while ($row = $dataReader->read()) {
247 7
			$actionname = $row['actionname'];
248 7
			$actionAll[$actionname] = $actionid = (int) $row['actionid'];
249 7
			if (0 === (int) $row['securitycheck']) {
250 7
				$actionSecure[$actionid] = $actionname;
251 7
			}
252
		}
253
		return [
254
			'tabId' => $tabNames,
255 7
			'tabPresence' => $tabPresence,
256 7
			'tabOwnedby' => $tabOwned,
257 7
			'actionId' => $actionAll,
258 7
			'actionName' => $actionSecure,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $actionSecure does not seem to be defined for all execution paths leading up to this point.
Loading history...
259 7
		];
260
	}
261
262
	/**
263
	 * Function to create file about modules.
264
	 *
265
	 * @throws \App\Exceptions\NoPermitted
266
	 */
267
	public static function createModuleMetaFile()
268 7
	{
269
		Cache::delete('moduleTabs', 'all');
270 7
		Cache::delete('getTrackingModules', 'all');
271 7
		$filename = ROOT_DIRECTORY . '/user_privileges/tabdata.php';
272 7
		if (file_exists($filename)) {
273 7
			if (is_writable($filename)) {
274 7
				$moduleMeta = static::getModuleMeta();
275 7
				$content = '$tab_seq_array=' . Utils::varExport($moduleMeta['tabPresence']) . ";\n";
276 7
				$content .= 'return ' . Utils::varExport($moduleMeta) . ";\n";
277 7
				if (!Utils::saveToFile($filename, $content)) {
278
					throw new Exceptions\NoPermitted("Cannot write file ($filename)");
279
				}
280
			} else {
281
				Log::error("The file $filename is not writable");
282
			}
283
		} else {
284
			Log::error("The file $filename does not exist");
285
		}
286 7
		static::initFromDb();
287
	}
288
289 7
	/**
290 7
	 * Function changes the module type.
291
	 *
292
	 * @param string $moduleName
293
	 * @param int    $type
294
	 */
295
	public static function changeType(string $moduleName, int $type)
296
	{
297
		$moduleModel = \Vtiger_Module_Model::getInstance($moduleName);
298
		if ($moduleModel && $moduleModel->changeType($type) && PrivilegeUtil::modifyPermissions($moduleName, ['RecordPdfInventory'], \Vtiger_Module_Model::ADVANCED_TYPE === $type)) {
299
			UserPrivilegesFile::recalculateAll();
300
		}
301
	}
302
303
	/**
304
	 * Get all module names by filter.
305
	 *
306
	 * @param bool     $isEntityType
307
	 * @param bool     $showRestricted
308
	 * @param bool|int $presence
309
	 *
310
	 * @return string[]
311
	 */
312
	public static function getAllModuleNamesFilter($isEntityType = true, $showRestricted = false, $presence = false): array
313
	{
314
		$modules = [];
315
		foreach (\vtlib\Functions::getAllModules($isEntityType, $showRestricted, $presence) as $value) {
316
			$modules[$value['name']] = Language::translate($value['name'], $value['name']);
317
		}
318
		return $modules;
319
	}
320
321
	/**
322
	 * Function to get the list of all accessible modules for Quick Create.
323
	 *
324
	 * @param bool $restrictList
325
	 * @param bool $tree
326
	 *
327
	 * @return array List of Vtiger_Module_Model instances
328
	 */
329
	public static function getQuickCreateModules($restrictList = false, $tree = false): array
330
	{
331
		$restrictListString = $restrictList ? 1 : 0;
332
		if ($tree) {
333
			$userModel = \App\User::getCurrentUserModel();
334
			$quickCreateModulesTreeCache = \App\Cache::get('getQuickCreateModules', 'tree' . $restrictListString . $userModel->getDetail('roleid'));
335
			if (false !== $quickCreateModulesTreeCache) {
336
				return $quickCreateModulesTreeCache;
337
			}
338
		} else {
339
			$quickCreateModules = \App\Cache::get('getQuickCreateModules', $restrictListString);
340
			if (false !== $quickCreateModules) {
341
				return $quickCreateModules;
342
			}
343
		}
344
345
		$userPrivModel = \Users_Privileges_Model::getCurrentUserPrivilegesModel();
346
347
		$query = new \App\Db\Query();
348
		$query->select(['vtiger_tab.*'])->from('vtiger_field')
349
			->innerJoin('vtiger_tab', 'vtiger_tab.tabid = vtiger_field.tabid')
350
			->where(['<>', 'vtiger_tab.presence', 1]);
351
		if ($tree) {
352
			$query->andWhere(['<>', 'vtiger_tab.name', 'Users']);
353
		} else {
354
			$query->andWhere(['quickcreate' => [0, 2]])
355
				->andWhere(['<>', 'vtiger_tab.type', 1]);
356
		}
357
		if ($restrictList) {
358
			$query->andWhere(['not in', 'vtiger_tab.name', ['ModComments', 'PriceBooks', 'CallHistory', 'OSSMailView']]);
359
		}
360
		$quickCreateModules = [];
361
		$dataReader = $query->distinct()->createCommand()->query();
362
		while ($row = $dataReader->read()) {
363
			if ($userPrivModel->hasModuleActionPermission($row['tabid'], 'CreateView')) {
364
				$moduleModel = \Vtiger_Module_Model::getInstanceFromArray($row);
365
				$quickCreateModules[$row['name']] = $moduleModel;
366
			}
367
		}
368
		if ($tree) {
369
			$menu = \Vtiger_Menu_Model::getAll();
370
			$quickCreateModulesTree = [];
371
			foreach ($menu as $parent) {
372
				if (!empty($parent['childs'])) {
373
					$items = [];
374
					foreach ($parent['childs'] as $child) {
375
						if (isset($quickCreateModules[$child['mod']])) {
376
							$items[$quickCreateModules[$child['mod']]->name] = $quickCreateModules[$child['mod']];
377
							unset($quickCreateModules[$child['mod']]);
378
						}
379
					}
380
					if (!empty($items)) {
381
						$quickCreateModulesTree[] = ['name' => $parent['name'], 'icon' => $parent['icon'], 'modules' => $items];
382
					}
383
				}
384
			}
385
			if (!empty($quickCreateModules)) {
386
				$quickCreateModulesTree[] = ['name' => 'LBL_OTHER', 'icon' => 'yfm-Other', 'modules' => $quickCreateModules];
387
			}
388
			\App\Cache::save('getQuickCreateModules', 'tree' . $restrictListString . $userPrivModel->get('roleid'), $quickCreateModulesTree);
389
			return $quickCreateModulesTree;
390
		}
391
		\App\Cache::save('getQuickCreateModules', $restrictListString, $quickCreateModules);
392
		return $quickCreateModules;
393
	}
394
}
395
396
Module::init();
397