Vtiger_Menu_Model::getBreadcrumbs()   F
last analyzed

Complexity

Conditions 42
Paths 15608

Size

Total Lines 111
Code Lines 82

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 1806

Importance

Changes 0
Metric Value
eloc 82
dl 0
loc 111
ccs 0
cts 76
cp 0
rs 0
c 0
b 0
f 0
cc 42
nc 15608
nop 1
crap 1806

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
 * Vtiger menu model class.
5
 *
6
 * @package Model
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
10
 */
11
class Vtiger_Menu_Model
12
{
13
	/**
14
	 * Static Function to get all the accessible menu models with/without ordering them by sequence.
15
	 *
16
	 * @return array
17
	 */
18
	public static function getAll(): array
19
	{
20
		$userPrivModel = Users_Privileges_Model::getCurrentUserPrivilegesModel();
21
		$roleMenu = 'user_privileges/menu_' . filter_var($userPrivModel->get('roleid'), FILTER_SANITIZE_NUMBER_INT) . '.php';
22
		if (file_exists($roleMenu)) {
23
			require $roleMenu;
24
		} else {
25
			require 'user_privileges/menu_0.php';
26
		}
27
		if (0 === \count($menus)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $menus seems to be never defined.
Loading history...
28
			require 'user_privileges/menu_0.php';
29
		}
30
		return \Settings_Menu_Record_Model::parseToDisplay($menus);
31
	}
32
33
	public static function vtranslateMenu($key, $module)
34
	{
35
		$string = \App\Language::translateSingleMod($key, 'Other.Menu');
36
		if ($string !== $key) {
37
			return $string;
38
		}
39
		return \App\Language::translate($key, $module);
40
	}
41
42
	public static function getBreadcrumbs($pageTitle = false)
43
	{
44
		$breadcrumbs = [];
45
		$request = App\Request::init();
46
		$userPrivModel = Users_Privileges_Model::getCurrentUserPrivilegesModel();
47
		$roleMenu = 'user_privileges/menu_' . filter_var($userPrivModel->get('roleid'), FILTER_SANITIZE_NUMBER_INT) . '.php';
48
		if (file_exists($roleMenu)) {
49
			require $roleMenu;
50
		} else {
51
			require 'user_privileges/menu_0.php';
52
		}
53
		if (empty($menus)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $menus does not exist. Did you maybe mean $menu?
Loading history...
54
			require 'user_privileges/menu_0.php';
55
		}
56
		$moduleName = $request->getModule();
57
		$view = $request->getByType('view', 'Alnum');
58
		$parent = $request->getByType('parent', 'Alnum');
59
		$mid = $request->isEmpty('mid', 'Alnum') ? null : $request->getInteger('mid');
0 ignored issues
show
Bug introduced by
'Alnum' of type string is incompatible with the type boolean expected by parameter $emptyFunction of App\Request::isEmpty(). ( Ignorable by Annotation )

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

59
		$mid = $request->isEmpty('mid', /** @scrutinizer ignore-type */ 'Alnum') ? null : $request->getInteger('mid');
Loading history...
60
		if ('Settings' !== $parent) {
61
			$parent = (!$parent && $mid) ? ($parentList[$mid]['parent'] ?? null) : $parent;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parentList does not exist. Did you maybe mean $parent?
Loading history...
Bug Best Practice introduced by
The expression $mid of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
62
			if (empty($parent)) {
63
				foreach ($parentList as &$parentItem) {
64
					if ($moduleName === $parentItem['mod']) {
65
						$parent = $parentItem['parent'];
66
						break;
67
					}
68
				}
69
			}
70
			$parentMenu = self::getParentMenu($parentList, $parent, $moduleName);
71
			if (\count($parentMenu) > 0) {
72
				$breadcrumbs = array_reverse($parentMenu);
73
			}
74
			if ('AppComponents' !== $moduleName) {
75
				$moduleModel = Vtiger_Module_Model::getInstance($moduleName);
76
				if ($moduleModel && $moduleModel->getDefaultUrl()) {
77
					if ($mid) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mid of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
78
						$url = $menus[$mid]['dataurl'] ?? $parentList[$mid]['dataurl'] ?? $moduleModel->getDefaultUrl();
79
					} else {
80
						$url = $moduleModel->getDefaultUrl();
81
					}
82
					$breadcrumbs[] = [
83
						'name' => \App\Language::translate($moduleName, $moduleName),
84
						'url' => $url,
85
					];
86
				} else {
87
					$breadcrumbs[] = [
88
						'name' => \App\Language::translate($moduleName, $moduleName),
89
					];
90
				}
91
			}
92
			if ($pageTitle) {
93
				$breadcrumbs[] = ['name' => $pageTitle];
94
			} elseif ('Edit' === $view && $request->isEmpty('record')) {
95
				$breadcrumbs[] = ['name' => App\Language::translate('LBL_VIEW_CREATE', $moduleName)];
96
			} elseif (!empty($view) && 'index' !== $view && 'Index' !== $view) {
97
				$breadcrumbs[] = ['name' => App\Language::translate('LBL_VIEW_' . strtoupper($view), $moduleName)];
98
			} elseif (empty($view)) {
99
				$breadcrumbs[] = ['name' => App\Language::translate('LBL_HOME', $moduleName)];
100
			}
101
			if ($moduleModel && !$request->isEmpty('record', true) && $moduleModel->isEntityModule()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $moduleModel does not seem to be defined for all execution paths leading up to this point.
Loading history...
102
				$recordLabel = vtlib\Functions::getCRMRecordLabel($request->getInteger('record'));
103
				if (!empty($recordLabel)) {
104
					$breadcrumbs[] = ['name' => $recordLabel];
105
				}
106
			}
107
		} elseif ('Settings' === $parent) {
108
			$qualifiedModuleName = $request->getModule(false);
109
			$breadcrumbs[] = [
110
				'name' => \App\Language::translate('LBL_VIEW_SETTINGS', $qualifiedModuleName),
111
				'url' => 'index.php?module=Vtiger&parent=Settings&view=Index',
112
				'icon' => 'fas fa-cog fa-fw',
113
			];
114
			$menu = Settings_Vtiger_MenuItem_Model::getAll();
115
			foreach ($menu as $menuModel) {
116
				if ($menuModel->isPermitted() && (
117
						(($request->has('record') || 'Edit' === $view) && $menuModel->getModuleName() === $qualifiedModuleName)
118
						|| $menuModel->isSelected($moduleName, $view, $request->getMode())
119
					)
120
				) {
121
					$parent = $menuModel->getBlock();
122
					$breadcrumbs[] = [
123
						'name' => App\Language::translate($parent->getLabel(), $qualifiedModuleName),
124
						'icon' => $parent->get('icon'),
125
					];
126
					$breadcrumbs[] = [
127
						'name' => App\Language::translate($menuModel->get('name'), $qualifiedModuleName),
128
						'url' => $menuModel->getUrl(),
129
						'icon' => $menuModel->get('iconpath'),
130
					];
131
					break;
132
				}
133
			}
134
			if (\is_array($pageTitle)) {
135
				foreach ($pageTitle as $title) {
136
					$breadcrumbs[] = $title;
137
				}
138
			} else {
139
				if ($pageTitle) {
140
					$breadcrumbs[] = ['name' => App\Language::translate($pageTitle, $qualifiedModuleName)];
141
				} elseif ('Edit' === $view && $request->isEmpty('record') && $request->isEmpty('parent_roleid')) {
142
					$breadcrumbs[] = ['name' => App\Language::translate('LBL_VIEW_CREATE', $qualifiedModuleName)];
143
				}
144
				if (!$request->isEmpty('record') && 'Users' === $moduleName) {
145
					$recordLabel = \App\Fields\Owner::getUserLabel($request->getInteger('record'));
146
					if (!empty($recordLabel)) {
147
						$breadcrumbs[] = ['name' => $recordLabel];
148
					}
149
				}
150
			}
151
		}
152
		return $breadcrumbs;
153
	}
154
155
	public static function getParentMenu($parentList, $parent, $module, $return = []): array
0 ignored issues
show
Unused Code introduced by
The parameter $return is not used and could be removed. ( Ignorable by Annotation )

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

155
	public static function getParentMenu($parentList, $parent, $module, /** @scrutinizer ignore-unused */ $return = []): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
	{
157
		$return = [];
158
		if (!empty($parent) && !empty($parentList[$parent])) {
159
			$return[] = [
160
				'name' => self::getLabelToDisplay($parentList[$parent]),
161
				'url' => $parentList[$parent]['dataurl'],
162
			];
163
			if (0 !== $parentList[$parent]['parent'] && \array_key_exists($parentList[$parent]['parent'], $parentList)) {
164
				$return = self::getParentMenu($parentList, $parentList[$parent]['parent'], $module, $return);
165
			}
166
		}
167
		return $return;
168
	}
169
170
	/**
171
	 * Function to get icon of element in menu.
172
	 *
173
	 * @param string|array $menu
174
	 * @param string       $title
175
	 *
176
	 * @return string
177
	 */
178
	public static function getMenuIcon($menu, $title = ''): string
179
	{
180
		if (empty($title) && !empty($menu['label'])) {
181
			$title = self::getLabelToDisplay($menu);
182
		}
183
		if (\is_string($menu)) {
184
			$iconName = \Vtiger_Theme::getImagePath($menu);
185
			if (file_exists($iconName)) {
186
				return '<img src="' . $iconName . '" alt="' . $title . '" title="' . $title . '" class="c-menu__item__icon" />';
0 ignored issues
show
Bug introduced by
Are you sure $iconName of type false|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

186
				return '<img src="' . /** @scrutinizer ignore-type */ $iconName . '" alt="' . $title . '" title="' . $title . '" class="c-menu__item__icon" />';
Loading history...
187
			}
188
		}
189
		if (!empty($menu['icon'])) {
190
			if (false !== strpos($menu['icon'], 'fa-')) {
191
				return '<span class="' . $menu['icon'] . ' c-menu__item__icon"></span>';
192
			}
193
			if (false !== strpos($menu['icon'], 'adminIcon-') || false !== strpos($menu['icon'], 'AdditionalIcon-') || false !== strpos($menu['icon'], 'yfi-') || false !== strpos($menu['icon'], 'yfm-') || false !== strpos($menu['icon'], 'mdi-')) {
194
				return '<span class="c-menu__item__icon ' . $menu['icon'] . '" aria-hidden="true"></span>';
195
			}
196
			$icon = \Vtiger_Theme::getImagePath($menu['icon']);
197
			if ($icon) {
198
				return '<img src="' . $icon . '" alt="' . $title . '" title="' . $title . '" class="c-menu__item__icon" />';
199
			}
200
		}
201
		if (isset($menu['type']) && 'Module' === $menu['type']) {
202
			return '<span class="c-menu__item__icon yfm-' . $menu['mod'] . '" aria-hidden="true"></span>';
203
		}
204
		return '';
205
	}
206
207
	/**
208
	 * Get label to display.
209
	 *
210
	 * @param array $row
211
	 *
212
	 * @return string
213
	 */
214
	public static function getLabelToDisplay(array $row): string
215
	{
216
		$name = '';
217
		$type = $row['type'];
218
		if (\is_int($type)) {
219
			$type = \App\Menu::TYPES[$type];
220
			$moduleName = $row['name'];
221
		} else {
222
			$moduleName = $row['mod'] ?? '';
223
		}
224
		switch ($type) {
225
			case 'Module':
226
				$name = self::vtranslateMenu((empty($row['label']) ? $moduleName : $row['label']), $moduleName);
227
				break;
228
			case 'Separator':
229
				$name = self::vtranslateMenu('LBL_SEPARATOR', 'Menu');
230
				break;
231
			case 'QuickCreate':
232
				if ('' != $row['label']) {
233
					$name = self::vtranslateMenu($row['label'], 'Menu');
234
				} else {
235
					$name = \App\Language::translate('LBL_QUICK_CREATE_MODULE', 'Menu') . ': ' . self::vtranslateMenu('SINGLE_' . $moduleName, $moduleName);
236
				}
237
				break;
238
			case 'HomeIcon':
239
				$name = self::vtranslateMenu('LBL_HOME', 'Menu');
240
				break;
241
			case 'CustomFilter':
242
				$cvid = \is_int($row['type']) ? $row['dataurl'] : vtlib\Functions::getQueryParams($row['dataurl'])['viewname'];
243
				$data = \App\CustomView::getCustomViewById($cvid);
244
				$name = self::vtranslateMenu($data['entitytype'], $data['entitytype']) . ': ' . \App\Language::translate($data['viewname'], $data['entitytype']);
245
				break;
246
			case 'RecycleBin':
247
				$name = self::vtranslateMenu($moduleName, $moduleName);
248
				break;
249
			default:
250
				$name = self::vtranslateMenu($row['label'], 'Menu');
251
				break;
252
		}
253
		return $name;
254
	}
255
}
256