Passed
Push — developer ( 5f736c...9195d5 )
by Mariusz
18:14
created

Module::getDefaultModule()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 12
ccs 0
cts 2
cp 0
rs 9.6111
c 0
b 0
f 0
cc 5
nc 4
nop 0
crap 30
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 5.0 (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 default module name.
136
	 *
137
	 * @return string
138
	 */
139
	public static function getDefaultModule(): string
140
	{
141
		$moduleName = \App\Config::main('default_module') ?: 'Home';
142
		if (!\App\Privilege::isPermitted($moduleName)) {
143
			foreach (\vtlib\Functions::getAllModules(true, false, 0) as $module) {
144
				if (\App\Privilege::isPermitted($module['name'])) {
145
					$moduleName = $module['name'];
146
					break;
147
				}
148
			}
149
		}
150
		return $moduleName;
151
	}
152
153
	/**
154
	 * Get module owner by module id.
155
	 *
156
	 * @param int $tabId
157
	 *
158
	 * @return int
159
	 */
160
	public static function getModuleOwner($tabId)
161
	{
162
		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...
163
	}
164 2
165
	/**
166 2
	 * Get all module names.
167 2
	 *
168 2
	 * @return string[]
169 2
	 */
170 2
	public static function getAllModuleNames()
171
	{
172
		return static::$tabdataCache['tabName'];
173 2
	}
174
175
	/**
176
	 * Function to get the list of module for which the user defined sharing rules can be defined.
177
	 *
178
	 * @param array $eliminateModules
179
	 *
180
	 * @return array
181
	 */
182
	public static function getSharingModuleList($eliminateModules = false)
183
	{
184
		$modules = \vtlib\Functions::getAllModules(true, true, 0, false, 0);
185
		$sharingModules = [];
186
		foreach ($modules as $row) {
187
			if (!$eliminateModules || !\in_array($row['name'], $eliminateModules)) {
188
				$sharingModules[] = $row['name'];
189
			}
190
		}
191
		return $sharingModules;
192
	}
193
194
	/**
195
	 * Get sql for name in display format.
196
	 *
197
	 * @param string $moduleName
198
	 *
199
	 * @return string
200
	 */
201
	public static function getSqlForNameInDisplayFormat($moduleName)
202
	{
203
		$db = \App\Db::getInstance();
204
		$entityFieldInfo = static::getEntityInfo($moduleName);
205
		$fieldsName = $entityFieldInfo['fieldnameArr'];
206
		if (\count($fieldsName) > 1) {
207
			$sqlString = 'CONCAT(';
208 16
			foreach ($fieldsName as &$column) {
209
				$sqlString .= "{$db->quoteTableName($entityFieldInfo['tablename'])}.{$db->quoteColumnName($column)},' ',";
210 16
			}
211 6
			$formattedName = new \yii\db\Expression(rtrim($sqlString, ',\' \',') . ')');
212
		} else {
213 12
			$fieldsName = array_pop($fieldsName);
214 6
			$formattedName = "{$db->quoteTableName($entityFieldInfo['tablename'])}.{$db->quoteColumnName($fieldsName)}";
215
		}
216 7
		return $formattedName;
217 7
	}
218 7
219
	/**
220 7
	 * Function to get a action id for a given action name.
221
	 *
222
	 * @param string $action
223 7
	 *
224 7
	 * @return int|null
225
	 */
226 7
	public static function getActionId($action)
227 7
	{
228
		if (empty($action)) {
229
			return null;
230
		}
231
		if (Cache::has('getActionId', $action)) {
232
			return Cache::get('getActionId', $action);
233
		}
234
		$actionIds = static::$tabdataCache['actionId'];
235 7
		if (isset($actionIds[$action])) {
236
			$actionId = $actionIds[$action];
237 7
		}
238 7
		if (empty($actionId)) {
239 7
			$actionId = (new Db\Query())->select(['actionid'])->from('vtiger_actionmapping')->where(['actionname' => $action])->scalar();
240 7
		}
241 7
		if (is_numeric($actionId)) {
242 7
			$actionId = (int) $actionId;
243
		}
244
		Cache::save('getActionId', $action, $actionId, Cache::LONG);
245 7
		return $actionId;
246 7
	}
247 7
248 7
	/**
249 7
	 * Get module meta data.
250 7
	 *
251 7
	 * @return array
252
	 */
253
	public static function getModuleMeta()
254
	{
255 7
		$tabNames = $tabPresence = $tabOwned = [];
256 7
		$allModules = \vtlib\Functions::getAllModules(false, true);
257 7
		foreach ($allModules as $moduleInfo) {
258 7
			$tabNames[$moduleInfo['name']] = $tabId = (int) $moduleInfo['tabid'];
259 7
			$tabPresence[$tabId] = $moduleInfo['presence'];
260
			$tabOwned[$tabId] = $moduleInfo['ownedby'];
261
		}
262
		//Constructing the actionname=>actionid array
263
		$actionAll = [];
264
		$dataReader = (new Db\Query())->from(['vtiger_actionmapping'])->createCommand()->query();
265
		while ($row = $dataReader->read()) {
266
			$actionname = $row['actionname'];
267
			$actionAll[$actionname] = $actionid = (int) $row['actionid'];
268 7
			if (0 === (int) $row['securitycheck']) {
269
				$actionSecure[$actionid] = $actionname;
270 7
			}
271 7
		}
272 7
		return [
273 7
			'tabId' => $tabNames,
274 7
			'tabPresence' => $tabPresence,
275 7
			'tabOwnedby' => $tabOwned,
276 7
			'actionId' => $actionAll,
277 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...
278
		];
279
	}
280
281
	/**
282
	 * Function to create file about modules.
283
	 *
284
	 * @throws \App\Exceptions\NoPermitted
285
	 */
286 7
	public static function createModuleMetaFile()
287
	{
288
		Cache::delete('moduleTabs', 'all');
289 7
		Cache::delete('getTrackingModules', 'all');
290 7
		$filename = ROOT_DIRECTORY . '/user_privileges/tabdata.php';
291
		if (file_exists($filename)) {
292
			if (is_writable($filename)) {
293
				$moduleMeta = static::getModuleMeta();
294
				$content = '$tab_seq_array=' . Utils::varExport($moduleMeta['tabPresence']) . ";\n";
295
				$content .= 'return ' . Utils::varExport($moduleMeta) . ";\n";
296
				if (!Utils::saveToFile($filename, $content)) {
297
					throw new Exceptions\NoPermitted("Cannot write file ($filename)");
298
				}
299
			} else {
300
				Log::error("The file $filename is not writable");
301
			}
302
		} else {
303
			Log::error("The file $filename does not exist");
304
		}
305
		static::initFromDb();
306
		register_shutdown_function(function () {
307
			try {
308
				YetiForce\Shop::generateCache();
309
			} catch (\Throwable $e) {
310
				\App\Log::error($e->getMessage() . PHP_EOL . $e->__toString());
311
				throw $e;
312
			}
313
		});
314
	}
315
316
	/**
317
	 * Function changes the module type.
318
	 *
319
	 * @param string $moduleName
320
	 * @param int    $type
321
	 */
322
	public static function changeType(string $moduleName, int $type)
323
	{
324
		$moduleModel = \Vtiger_Module_Model::getInstance($moduleName);
325
		if ($moduleModel && $moduleModel->changeType($type) && PrivilegeUtil::modifyPermissions($moduleName, ['RecordPdfInventory'], \Vtiger_Module_Model::ADVANCED_TYPE === $type)) {
326
			UserPrivilegesFile::recalculateAll();
327
		}
328
	}
329
330
	/**
331
	 * Get all module names by filter.
332
	 *
333
	 * @param bool     $isEntityType
334
	 * @param bool     $showRestricted
335
	 * @param bool|int $presence
336
	 *
337
	 * @return string[]
338
	 */
339
	public static function getAllModuleNamesFilter($isEntityType = true, $showRestricted = false, $presence = false): array
340
	{
341
		$modules = [];
342
		foreach (\vtlib\Functions::getAllModules($isEntityType, $showRestricted, $presence) as $value) {
343
			$modules[$value['name']] = Language::translate($value['name'], $value['name']);
344
		}
345
		return $modules;
346
	}
347
348
	/**
349
	 * Function to get the list of all accessible modules for Quick Create.
350
	 *
351
	 * @param bool $restrictList
352
	 * @param bool $tree
353
	 *
354
	 * @return array List of Vtiger_Module_Model instances
355
	 */
356
	public static function getQuickCreateModules($restrictList = false, $tree = false): array
357
	{
358
		$restrictListString = $restrictList ? 1 : 0;
359
		if ($tree) {
360
			$userModel = \App\User::getCurrentUserModel();
361
			$quickCreateModulesTreeCache = \App\Cache::get('getQuickCreateModules', 'tree' . $restrictListString . $userModel->getDetail('roleid'));
362
			if (false !== $quickCreateModulesTreeCache) {
363
				return $quickCreateModulesTreeCache;
364
			}
365
		} else {
366
			$quickCreateModules = \App\Cache::get('getQuickCreateModules', $restrictListString);
367
			if (false !== $quickCreateModules) {
368
				return $quickCreateModules;
369
			}
370
		}
371
372
		$userPrivModel = \Users_Privileges_Model::getCurrentUserPrivilegesModel();
373
374
		$query = new \App\Db\Query();
375
		$query->select(['vtiger_tab.*'])->from('vtiger_field')
376
			->innerJoin('vtiger_tab', 'vtiger_tab.tabid = vtiger_field.tabid')
377
			->where(['<>', 'vtiger_tab.presence', 1]);
378
		if ($tree) {
379
			$query->andWhere(['<>', 'vtiger_tab.name', 'Users']);
380
		} else {
381
			$query->andWhere(['quickcreate' => [0, 2]])
382
				->andWhere(['<>', 'vtiger_tab.type', 1]);
383
		}
384
		if ($restrictList) {
385
			$query->andWhere(['not in', 'vtiger_tab.name', ['ModComments', 'PriceBooks', 'CallHistory', 'OSSMailView']]);
386
		}
387
		$quickCreateModules = [];
388
		$dataReader = $query->distinct()->createCommand()->query();
389
		while ($row = $dataReader->read()) {
390
			if ($userPrivModel->hasModuleActionPermission($row['tabid'], 'CreateView')) {
391
				$moduleModel = \Vtiger_Module_Model::getInstanceFromArray($row);
392
				$quickCreateModules[$row['name']] = $moduleModel;
393
			}
394
		}
395
		if ($tree) {
396
			$menu = \Vtiger_Menu_Model::getAll();
397
			$quickCreateModulesTree = [];
398
			foreach ($menu as $parent) {
399
				if (!empty($parent['childs'])) {
400
					$items = [];
401
					foreach ($parent['childs'] as $child) {
402
						if (isset($quickCreateModules[$child['mod']])) {
403
							$items[$quickCreateModules[$child['mod']]->name] = $quickCreateModules[$child['mod']];
404
							unset($quickCreateModules[$child['mod']]);
405
						}
406
					}
407
					if (!empty($items)) {
408
						$quickCreateModulesTree[] = ['name' => $parent['name'], 'icon' => $parent['icon'], 'modules' => $items];
409
					}
410
				}
411
			}
412
			if (!empty($quickCreateModules)) {
413
				$quickCreateModulesTree[] = ['name' => 'LBL_OTHER', 'icon' => 'yfm-Other', 'modules' => $quickCreateModules];
414
			}
415
			\App\Cache::save('getQuickCreateModules', 'tree' . $restrictListString . $userPrivModel->get('roleid'), $quickCreateModulesTree);
416
			return $quickCreateModulesTree;
417
		}
418
		\App\Cache::save('getQuickCreateModules', $restrictListString, $quickCreateModules);
419
		return $quickCreateModules;
420
	}
421
422
	/**
423
	 * Get a list of modules with permissions.
424
	 *
425
	 * @param bool $isEntityType   Only entity type
426
	 * @param bool $showRestricted Show restricted
427
	 * @param bool $hasPermission  Must have access to the module
428
	 *
429
	 * @return \Generator
430
	 */
431
	public static function getModulesList(bool $isEntityType = true, bool $showRestricted = false, bool $hasPermission = true): \Generator
432
	{
433
		$userPrivModel = \Users_Privileges_Model::getCurrentUserPrivilegesModel();
434
		foreach (\vtlib\Functions::getAllModules($isEntityType, $showRestricted, 0) as $module) {
435
			if (!$hasPermission || ($hasPermission && $userPrivModel->hasModuleActionPermission($module['name'], 'DetailView'))) {
436
				yield $module;
437
			}
438
		}
439
	}
440
}
441
442
Module::init();
443