CRMEntity   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Test Coverage

Coverage 58.25%

Importance

Changes 0
Metric Value
wmc 40
eloc 89
c 0
b 0
f 0
dl 0
loc 230
ccs 60
cts 103
cp 0.5825
rs 9.2

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setRelationTables() 0 16 2
A getLockFields() 0 6 2
A getJoinClause() 0 9 3
B moduleHandler() 0 7 7
A init() 0 3 1
C retrieveEntityInfo() 0 54 14
A trackUnLinkedInfo() 0 4 1
A __construct() 0 3 1
A createColumnAliasForField() 0 3 1
A trackLinkedInfo() 0 4 1
B getInstance() 0 25 7

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
 /* * *******************************************************************************
4
 * The contents of this file are subject to the SugarCRM Public License Version 1.1.2
5
 * ("License"); You may not use this file except in compliance with the
6
 * License. You may obtain a copy of the License at http://www.sugarcrm.com/SPL
7
 * Software distributed under the License is distributed on an  "AS IS"  basis,
8
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9
 * the specific language governing rights and limitations under the License.
10
 * The Original Code is:  SugarCRM Open Source
11
 * The Initial Developer of the Original Code is SugarCRM, Inc.
12
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.;
13
 * All Rights Reserved.
14
 * Contributor(s): YetiForce S.A.
15
 * ****************************************************************************** */
16
/* * *******************************************************************************
17
 * $Header: /advent/projects/wesat/vtiger_crm/vtigercrm/data/CRMEntity.php,v 1.16 2005/04/29 04:21:31 mickie Exp $
18
 * Description:  Defines the base class for all data entities used throughout the
19
 * application.  The base class including its methods and variables is designed to
20
 * be overloaded with module-specific methods and variables particular to the
21
 * module's base entity class.
22
 * ****************************************************************************** */
23
require_once 'include/utils/CommonUtils.php';
24
require_once 'include/fields/DateTimeField.php';
25
require_once 'include/fields/DateTimeRange.php';
26
require_once 'include/fields/CurrencyField.php';
27
include_once 'modules/Vtiger/CRMEntity.php';
28
require_once 'include/runtime/Cache.php';
29
require_once 'modules/Vtiger/helpers/Util.php';
30
require_once 'modules/PickList/DependentPickListUtils.php';
31
require_once 'modules/Users/Users.php';
32
require_once 'include/Webservices/Utils.php';
33
34
class CRMEntity
35
{
36
	/** @var array */
37
	public $tab_name_index = [];
38
39 15
	/** @var string[] Tables join clause. */
40
	public $tableJoinClause = [
41 15
		'vtiger_entity_stats' => 'LEFT JOIN',
42 15
		'u_yf_openstreetmap' => 'LEFT JOIN',
43
		'u_yf_wapro_records_map' => 'LEFT JOIN',
44 5822
	];
45
46 5822
	/**
47
	 * Constructor which will set the column_fields in this object.
48
	 */
49 5822
	public function __construct()
50 5798
	{
51
		$this->column_fields = vtlib\Deprecated::getColumnFields(static::class);
0 ignored issues
show
Bug Best Practice introduced by
The property column_fields does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
52
	}
53
54 50
	/**
55 1
	 * Get CRMEntity instance.
56
	 *
57
	 * @param string $module
58
	 *
59 1
	 * @return self
60 1
	 */
61
	public static function getInstance(string $module)
62
	{
63 50
		if (is_numeric($module)) {
64 50
			$module = App\Module::getModuleName($module);
0 ignored issues
show
Bug introduced by
$module of type string is incompatible with the type integer expected by parameter $tabId of App\Module::getModuleName(). ( Ignorable by Annotation )

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

64
			$module = App\Module::getModuleName(/** @scrutinizer ignore-type */ $module);
Loading history...
65 50
		}
66
		if (\App\Cache::staticHas('CRMEntity', $module)) {
67 50
			return clone \App\Cache::staticGet('CRMEntity', $module);
68
		}
69
		// File access security check
70
		if (!class_exists($module)) {
71
			if (App\Config::performance('LOAD_CUSTOM_FILES') && file_exists("custom/modules/$module/$module.php")) {
72
				\vtlib\Deprecated::checkFileAccessForInclusion("custom/modules/$module/$module.php");
73
				require_once "custom/modules/$module/$module.php";
74
			} else {
75
				\vtlib\Deprecated::checkFileAccessForInclusion("modules/$module/$module.php");
76
				require_once "modules/$module/$module.php";
77
			}
78
		}
79
		$focus = new $module();
80
		$focus->moduleName = $module;
81
		if (method_exists($focus, 'init')) {
82
			$focus->init();
83
		}
84
		\App\Cache::staticSave('CRMEntity', $module, clone $focus);
85
		return $focus;
86
	}
87
88 18
	/**
89
	 * Loading the system configuration.
90 18
	 *
91
	 * @return void
92
	 */
93
	protected function init(): void
94
	{
95
		$this->tab_name_index += ['u_yf_wapro_records_map' => 'crmid'];
96
	}
97
98
	/**
99 18
	 * Function returns the column alias for a field.
100
	 *
101 18
	 * @param array $fieldInfo - field information
102
	 *
103
	 * @return string field value
104
	 */
105
	protected function createColumnAliasForField(array $fieldInfo)
106
	{
107 18
		return strtolower($fieldInfo['tablename'] . $fieldInfo['fieldname']);
108 18
	}
109
110
	/**
111
	 * Retrieve record information of the module.
112 18
	 *
113
	 * @param int    $record - crmid of record
114
	 * @param string $module - module name
115
	 */
116 18
	public function retrieveEntityInfo(int $record, string $module)
117 18
	{
118 18
		if (!isset($record)) {
119 18
			throw new \App\Exceptions\NoPermittedToRecord('LBL_RECORD_NOT_FOUND');
120 18
		}
121
		if ($cachedModuleFields = \App\Field::getModuleFieldInfosByPresence($module)) {
122 18
			$query = new \App\Db\Query();
123 18
			$tabNameIndex = $this->tab_name_index; // copies-on-write
124
			$requiredTables = $columnClause = [];
125
			foreach ($cachedModuleFields as $fieldInfo) {
126
				if (isset($tabNameIndex[$fieldInfo['tablename']])) {
127
					if (!isset($requiredTables[$fieldInfo['tablename']])) {
128 18
						$requiredTables[$fieldInfo['tablename']] = $tabNameIndex[$fieldInfo['tablename']];
129
					}
130 18
					// Alias prefixed with tablename+fieldname to avoid duplicate column name across tables
131 18
					// fieldname are always assumed to be unique for a module
132 18
					$columnClause[] = $fieldInfo['tablename'] . '.' . $fieldInfo['columnname'] . ' AS ' . $this->createColumnAliasForField($fieldInfo);
133 18
				}
134 18
			}
135 18
			$columnClause[] = 'vtiger_crmentity.deleted';
136 18
			$query->select($columnClause);
137
			$query->from('vtiger_crmentity');
138
			if (isset($requiredTables['vtiger_crmentity'])) {
139
				unset($requiredTables['vtiger_crmentity']);
140 18
			}
141
			foreach ($requiredTables as $tableName => $tableIndex) {
142
				$query->leftJoin($tableName, "vtiger_crmentity.crmid = $tableName.$tableIndex");
143 18
			}
144 18
			$query->where(['vtiger_crmentity.crmid' => $record]);
145 18
			if ('' != $module) {
146
				$query->andWhere(['vtiger_crmentity.setype' => $module]);
147 18
			}
148 18
			$resultRow = $query->one();
149
			if (empty($resultRow)) {
150
				throw new \App\Exceptions\NoPermittedToRecord('ERR_RECORD_NOT_FOUND||' . $record);
151 18
			}
152 18
			foreach ($cachedModuleFields as $fieldInfo) {
153 18
				$fieldvalue = '';
154
				$fieldkey = $this->createColumnAliasForField($fieldInfo);
155 18
				//Note : value is retrieved with a tablename+fieldname as we are using alias while building query
156 18
				if (isset($resultRow[$fieldkey])) {
157
					$fieldvalue = $resultRow[$fieldkey];
158 18
				}
159 18
				if (120 === $fieldInfo['uitype']) {
160 18
					$fieldvalue = \App\Fields\SharedOwner::getById($record);
161 18
					if (\is_array($fieldvalue)) {
162
						$fieldvalue = implode(',', $fieldvalue);
163
					}
164 18
				}
165
				$this->column_fields[$fieldInfo['fieldname']] = $fieldvalue;
0 ignored issues
show
Bug Best Practice introduced by
The property column_fields does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
166
			}
167 18
		}
168 18
		$this->column_fields['record_id'] = $record;
169 18
		$this->column_fields['record_module'] = $module;
170
	}
171
172
	/**
173
	 * Get table join clause by table name.
174
	 *
175
	 * @param string $tableName
176 3
	 *
177
	 * @return string
178 3
	 */
179
	public function getJoinClause($tableName): string
180
	{
181 3
		if (strripos($tableName, 'rel') === (\strlen($tableName) - 3)) {
182
			return 'LEFT JOIN';
183
		}
184 3
		if (isset($this->tableJoinClause[$tableName])) {
185
			return $this->tableJoinClause[$tableName];
186
		}
187
		return 'INNER JOIN';
188
	}
189
190
	/**
191
	 * Function to get the relation tables for related modules.
192
	 *
193
	 * @param string $secModule - $secmodule secondary module name
194
	 *
195
	 * @return array returns the array with table names and fieldnames storing relations
196
	 *               between module and this module
197
	 */
198
	public function setRelationTables($secModule = false)
199
	{
200
		$relTables = [
201
			'Documents' => [
202
				'vtiger_senotesrel' => ['crmid', 'notesid'],
203
				$this->table_name => $this->table_index,
204
			],
205
			'OSSMailView' => [
206
				'vtiger_ossmailview_relation' => ['crmid', 'ossmailviewid'],
207
				$this->table_name => $this->table_index,
208
			],
209
		];
210
		if (false === $secModule) {
211
			return $relTables;
212
		}
213
		return $relTables[$secModule] ?? [];
214
	}
215
216
	/**
217
	 * Function to track when a new record is linked to a given record.
218
	 *
219
	 * @param mixed $crmId
220
	 */
221
	public static function trackLinkedInfo($crmId)
222
	{
223
		$currentTime = date('Y-m-d H:i:s');
224
		\App\Db::getInstance()->createCommand()->update('vtiger_crmentity', ['modifiedtime' => $currentTime, 'modifiedby' => \App\User::getCurrentUserId()], ['crmid' => $crmId])->execute();
225
	}
226
227
	/**
228
	 * Function to track when a record is unlinked to a given record.
229
	 *
230
	 * @param int $crmId
231
	 */
232
	public function trackUnLinkedInfo($crmId)
233
	{
234
		$currentTime = date('Y-m-d H:i:s');
235
		\App\Db::getInstance()->createCommand()->update('vtiger_crmentity', ['modifiedtime' => $currentTime, 'modifiedby' => \App\User::getCurrentUserId()], ['crmid' => $crmId])->execute();
236
	}
237
238
	/**
239
	 * Gets fields to locking record.
240
	 *
241
	 * @return array
242
	 */
243
	public function getLockFields()
244
	{
245
		if (isset($this->lockFields)) {
246
			return $this->lockFields;
247
		}
248
		return [];
249
	}
250
251
	/**
252
	 * Invoked when special actions are performed on the module.
253
	 *
254
	 * @param string $moduleName Module name
255
	 * @param string $eventType  Event Type (module.postinstall, module.disabled, module.enabled, module.preuninstall)
256
	 */
257
	public function moduleHandler($moduleName, $eventType)
258
	{
259
		if ($moduleName && 'module.postinstall' === $eventType) {
260
		} elseif ('module.disabled' === $eventType) {
261
		} elseif ('module.preuninstall' === $eventType) {
262
		} elseif ('module.preupdate' === $eventType) {
263
		} elseif ('module.postupdate' === $eventType) {
264
		}
265
	}
266
}
267