Passed
Push — developer ( 6b5868...bed0f9 )
by Radosław
22:42 queued 03:39
created

Fixer::baseModuleTools()   C

Complexity

Conditions 15
Paths 140

Size

Total Lines 41
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 240

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 28
c 1
b 0
f 0
dl 0
loc 41
ccs 0
cts 26
cp 0
rs 5.5833
cc 15
nc 140
nop 0
crap 240

How to fix   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
 * File that repaire structure and data in database.
5
 *
6
 * @package App
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Mariusz Krzaczkowski <[email protected]>
11
 */
12
13
namespace App\Db;
14
15
/**
16
 * Class that repair structure and data in database.
17
 */
18
class Fixer
19
{
20
	/**
21
	 * Add missing entries in vtiger_profile2field.
22
	 */
23
	public static function profileField(): int
24
	{
25
		\App\Log::trace('Entering ' . __METHOD__);
26
		$i = 0;
27
		$profileIds = \vtlib\Profile::getAllIds();
28
		$dbCommand = \App\Db::getInstance()->createCommand();
29
		foreach ($profileIds as $profileId) {
30
			$subQuery = (new \App\Db\Query())->select(['fieldid'])->from('vtiger_profile2field')->where(['profileid' => $profileId]);
31
			$query = (new \App\Db\Query())->select(['tabid', 'fieldid'])->from('vtiger_field')->where(['not in', 'vtiger_field.fieldid', $subQuery]);
32
			$data = $query->createCommand()->queryAllByGroup(2);
33
			foreach ($data as $tabId => $fieldIds) {
34
				foreach ($fieldIds as $fieldId) {
35
					$isExists = (new \App\Db\Query())->from('vtiger_profile2field')->where(['profileid' => $profileId, 'fieldid' => $fieldId])->exists();
36
					if (!$isExists) {
37
						$dbCommand->insert('vtiger_profile2field', ['profileid' => $profileId, 'tabid' => $tabId, 'fieldid' => $fieldId, 'visible' => 0, 'readonly' => 0])->execute();
38
						++$i;
39
					}
40
				}
41
			}
42
		}
43
		\App\Log::trace('Exiting ' . __METHOD__);
44
		return $i;
45
	}
46
47
	/**
48
	 * Add missing entries in vtiger_profile2utility.
49
	 */
50
	public static function baseModuleTools(): int
51
	{
52
		$i = 0;
53
		$allUtility = $missing = $curentProfile2utility = [];
54
		foreach ((new \App\Db\Query())->from('vtiger_profile2utility')->all() as $row) {
55
			$curentProfile2utility[$row['profileid']][$row['tabid']][$row['activityid']] = true;
56
			$allUtility[$row['tabid']][$row['activityid']] = true;
57
		}
58
		$profileIds = \vtlib\Profile::getAllIds();
59
		$moduleIds = (new \App\Db\Query())->select(['tabid'])->from('vtiger_tab')->where(['isentitytype' => 1])->column();
60
		$baseActionIds = array_map('App\Module::getActionId', \Settings_ModuleManager_Module_Model::$baseModuleTools);
61
		$exceptions = \Settings_ModuleManager_Module_Model::getBaseModuleToolsExceptions();
62
		foreach ($profileIds as $profileId) {
63
			foreach ($moduleIds as $moduleId) {
64
				foreach ($baseActionIds as $actionId) {
65
					if (!isset($curentProfile2utility[$profileId][$moduleId][$actionId])) {
66
						$missing["$profileId:$moduleId:$actionId"] = ['profileid' => $profileId, 'tabid' => $moduleId, 'activityid' => $actionId];
67
					}
68
				}
69
				if (isset($allUtility[$moduleId])) {
70
					foreach ($allUtility[$moduleId] as $actionId => $value) {
71
						if (!isset($curentProfile2utility[$profileId][$moduleId][$actionId])) {
72
							$missing["$profileId:$moduleId:$actionId"] = ['profileid' => $profileId, 'tabid' => $moduleId, 'activityid' => $actionId];
73
						}
74
					}
75
				}
76
			}
77
		}
78
		$dbCommand = \App\Db::getInstance()->createCommand();
79
		foreach ($missing as $row) {
80
			if (isset($exceptions[$row['tabid']]['allowed'])) {
81
				if (!isset($exceptions[$row['tabid']]['allowed'][$row['activityid']])) {
82
					continue;
83
				}
84
			} elseif (isset($exceptions[$row['tabid']]['notAllowed']) && (false === $exceptions[$row['tabid']]['notAllowed'] || isset($exceptions[$row['tabid']]['notAllowed'][$row['activityid']]))) {
85
				continue;
86
			}
87
			$dbCommand->insert('vtiger_profile2utility', ['profileid' => $row['profileid'], 'tabid' => $row['tabid'], 'activityid' => $row['activityid'], 'permission' => 1])->execute();
88
			++$i;
89
		}
90
		return $i;
91
	}
92
93
	/**
94
	 * Add missing entries in vtiger_profile2standardpermissions.
95
	 */
96
	public static function baseModuleActions(): int
97
	{
98
		$i = 0;
99
		$curentProfile = [];
100
		foreach ((new \App\Db\Query())->from('vtiger_profile2standardpermissions')->all() as $row) {
101
			$curentProfile[$row['profileid']][$row['tabid']][$row['operation']] = $row['permissions'];
102
		}
103
		$moduleIds = (new \App\Db\Query())->select(['tabid'])->from('vtiger_tab')->where(['isentitytype' => 1])->column();
104
		$dbCommand = \App\Db::getInstance()->createCommand();
105
		foreach (\vtlib\Profile::getAllIds() as $profileId) {
106
			foreach ($moduleIds as $moduleId) {
107
				foreach (\Vtiger_Action_Model::$standardActions as $actionId => $actionName) {
108
					if (!isset($curentProfile[$profileId][$moduleId][$actionId])) {
109
						$dbCommand->insert('vtiger_profile2standardpermissions', ['profileid' => $profileId, 'tabid' => $moduleId, 'operation' => $actionId, 'permissions' => 1])->execute();
110
						++$i;
111
					}
112
				}
113
			}
114
		}
115
		return $i;
116
	}
117
118
	/**
119
	 * Fixes the maximum value allowed for fields.
120
	 *
121
	 * @param array $conditions Additional query conditions
122
	 *
123
	 * @return int[]
124
	 */
125
	public static function maximumFieldsLength(array $conditions = []): array
126
	{
127
		$typesNotSupported = ['datetime', 'date', 'year', 'timestamp', 'time'];
128
		$uiTypeNotSupported = [30];
129
		$updated = $requiresVerification = $typeNotFound = $notSupported = 0;
130
		$db = \App\Db::getInstance();
131
		$dbCommand = $db->createCommand();
132
		$schema = $db->getSchema();
133
		$query = (new \App\Db\Query())->select(['tablename', 'columnname', 'fieldid', 'maximumlength', 'uitype'])->from('vtiger_field');
134
		if ($conditions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $conditions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
135
			$query->andWhere($conditions);
136
		}
137
		$dataReader = $query->createCommand()->query();
138
		while ($field = $dataReader->read()) {
139
			$column = $schema->getTableSchema($field['tablename'])->columns[$field['columnname']];
140
			preg_match('/^([\w\-]+)/i', $column->dbType, $matches);
141
			$type = $matches[1] ?? $column->type;
142
			if (\in_array($type, $typesNotSupported) || \in_array($field['uitype'], $uiTypeNotSupported)) {
143
				++$notSupported;
144
				continue;
145
			}
146
			if (isset(\Vtiger_Field_Model::$uiTypeMaxLength[$field['uitype']])) {
147
				$range = \Vtiger_Field_Model::$uiTypeMaxLength[$field['uitype']];
148
			} elseif (isset(\Vtiger_Field_Model::$typesMaxLength[$type])) {
149
				$range = \Vtiger_Field_Model::$typesMaxLength[$type];
150
			} else {
151
				switch ($type) {
152
					case 'binary':
153
					case 'string':
154
					case 'varchar':
155
					case 'varbinary':
156
						$range = (int) $column->size;
157
						break;
158
					case 'bigint':
159
					case 'mediumint':
160
						\App\Log::error("Type not allowed: {$field['tablename']}.{$field['columnname']} |uitype: {$field['uitype']} |maximumlength: {$field['maximumlength']} |type:{$type}|{$column->type}|{$column->dbType}", __METHOD__);
161
						break;
162
					case 'integer':
163
					case 'int':
164
						if ($column->unsigned) {
165
							$range = '4294967295';
166
							if (7 == $field['uitype'] || 1 == $field['uitype']) {
167
								$range = '0,' . $range;
168
							}
169
						} else {
170
							$range = '-2147483648,2147483647';
171
						}
172
						break;
173
					case 'smallint':
174
						if ($column->unsigned) {
175
							$range = '65535';
176
							if (7 == $field['uitype'] || 1 == $field['uitype']) {
177
								$range = '0,' . $range;
178
							}
179
						} else {
180
							$range = '-32768,32767';
181
						}
182
						break;
183
					case 'tinyint':
184
						if ($column->unsigned) {
185
							$range = '255';
186
							if (7 == $field['uitype'] || 1 == $field['uitype']) {
187
								$range = '0,' . $range;
188
							}
189
						} else {
190
							$range = '-128,127';
191
						}
192
						break;
193
					case 'decimal':
194
						$range = 10 ** (((int) $column->size) - ((int) $column->scale)) - 1;
195
						if ($column->unsigned) {
196
							$range = '0,' . $range;
197
						}
198
						break;
199
					default:
200
						$range = false;
201
						break;
202
				}
203
			}
204
			$update = false;
205
			if (false === $range) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $range does not seem to be defined for all execution paths leading up to this point.
Loading history...
206
				\App\Log::warning("Type not found: {$field['tablename']}.{$field['columnname']} |uitype: {$field['uitype']} |maximumlength: {$field['maximumlength']} |type:{$type}|{$column->type}|{$column->dbType}", __METHOD__);
207
				++$typeNotFound;
208
			} elseif ($field['maximumlength'] != $range) {
209
				if (\in_array($field['uitype'], [1, 2, 7, 9, 10, 16, 52, 53, 56, 71, 72, 120, 156, 300, 308, 317, 327])) {
210
					$update = true;
211
				} else {
212
					\App\Log::warning("Requires verification: {$field['tablename']}.{$field['columnname']} |uitype: {$field['uitype']} |maximumlength: {$field['maximumlength']} <> {$range} |type:{$type}|{$column->type}|{$column->dbType}", __METHOD__);
213
					++$requiresVerification;
214
				}
215
			}
216
			if ($update && false !== $range) {
217
				$dbCommand->update('vtiger_field', ['maximumlength' => $range], ['fieldid' => $field['fieldid']])->execute();
218
				++$updated;
219
				\App\Log::trace("Updated: {$field['tablename']}.{$field['columnname']} |maximumlength:  before:{$field['maximumlength']} after: $range |type:{$type}|{$column->type}|{$column->dbType}", __METHOD__);
220
			}
221
		}
222
		return ['NotSupported' => $notSupported, 'TypeNotFound' => $typeNotFound, 'RequiresVerification' => $requiresVerification, 'Updated' => $updated];
223
	}
224
225
	/**
226
	 * Add missing entries in vtiger_def_org_share and vtiger_org_share_action2tab.
227
	 *
228
	 * @return int
229
	 */
230
	public static function share(): int
231
	{
232
		\App\Log::trace('Entering ' . __METHOD__);
233
		$i = 0;
234
		$dbCommand = \App\Db::getInstance()->createCommand();
235
		$query = (new \App\Db\Query())->select(['tabid'])->from('vtiger_tab')->where(['isentitytype' => 1])
236
			->andWhere(['not in', 'tabid', (new \App\Db\Query())->select(['tabid'])->from('vtiger_def_org_share')]);
237
		foreach ($query->column() as $tabId) {
238
			$dbCommand->insert('vtiger_def_org_share', ['tabid' => $tabId, 'permission' => 3, 'editstatus' => 0])->execute();
239
			++$i;
240
		}
241
		$actionIds = (new \App\Db\Query())->select(['share_action_id'])->from('vtiger_org_share_action_mapping')
242
			->where(['share_action_name' => ['Public: Read Only', 'Public: Read, Create/Edit', 'Public: Read, Create/Edit, Delete', 'Private']])
243
			->column();
244
		$query = (new \App\Db\Query())->select(['tabid'])->from('vtiger_tab')->where(['isentitytype' => 1])
245
			->andWhere(['not in', 'tabid', (new \App\Db\Query())->select(['tabid'])->from('vtiger_org_share_action2tab')]);
246
		foreach ($query->column() as $tabId) {
247
			$insertedData = [];
248
			foreach ($actionIds as $id) {
249
				$insertedData[] = [$id, $tabId];
250
			}
251
			$dbCommand->batchInsert('vtiger_org_share_action2tab', ['share_action_id', 'tabid'], $insertedData)->execute();
252
			++$i;
253
		}
254
		\App\Log::trace('Exiting ' . __METHOD__);
255
		return $i;
256
	}
257
}
258