Passed
Push — developer ( 93fd72...dc274f )
by Radosław
18:31
created

VTUpdateRelatedFieldTask   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 36
eloc 94
dl 0
loc 164
ccs 0
cts 62
cp 0
rs 9.52
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
D doTask() 0 60 19
A getContents() 0 5 1
B setDataFromRequest() 0 25 7
B updateRecords() 0 26 8
A getFieldNames() 0 3 1
1
<?php
2
/**
3
 * Update Related Field Task Handler Class.
4
 *
5
 * @copyright YetiForce S.A.
6
 * @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
7
 * @author Mariusz Krzaczkowski <[email protected]>
8
 * @author Radosław Skrzypczak <[email protected]>
9
 */
10
require_once 'modules/com_vtiger_workflow/VTWorkflowUtils.php';
11
12
class VTUpdateRelatedFieldTask extends VTTask
13
{
14
	public $executeImmediately = false;
15
16
	/** {@inheritdoc} */
17
	public function getFieldNames()
18
	{
19
		return ['field_value_mapping', 'conditions'];
20
	}
21
22
	/**
23
	 * Execute task.
24
	 *
25
	 * @param Vtiger_Record_Model $recordModel
26
	 */
27
	public function doTask($recordModel)
28
	{
29
		$fieldValueMapping = [];
30
		if (!empty($this->field_value_mapping)) {
31
			$fieldValueMapping = \App\Json::decode($this->field_value_mapping);
0 ignored issues
show
Bug Best Practice introduced by
The property field_value_mapping does not exist on VTUpdateRelatedFieldTask. Did you maybe forget to declare it?
Loading history...
32
		}
33
		if (!\App\Json::isEmpty($this->conditions)) {
0 ignored issues
show
Bug Best Practice introduced by
The property conditions does not exist on VTUpdateRelatedFieldTask. Did you maybe forget to declare it?
Loading history...
34
			$conditions = \App\Json::decode($this->conditions) ?: [];
35
		}
36
		if (!empty($fieldValueMapping)) {
37
			foreach ($fieldValueMapping as $fieldInfo) {
38
				$fieldValue = trim($fieldInfo['value']);
39
				switch ($fieldInfo['valuetype']) {
40
					case 'fieldname':
41
						$fieldValue = $recordModel->get($fieldValue);
42
						break;
43
					case 'expression':
44
						require_once 'modules/com_vtiger_workflow/expression_engine/include.php';
45
46
						$parser = new VTExpressionParser(new VTExpressionSpaceFilter(new VTExpressionTokenizer($fieldValue)));
47
						$expression = $parser->expression();
48
						$exprEvaluater = new VTFieldExpressionEvaluater($expression);
49
						$fieldValue = $exprEvaluater->evaluate($recordModel);
50
						break;
51
					default:
52
						if (preg_match('/([^:]+):boolean$/', $fieldValue, $match)) {
53
							$fieldValue = $match[1];
54
							if ('true' == $fieldValue) {
55
								$fieldValue = '1';
56
							} else {
57
								$fieldValue = '0';
58
							}
59
						}
60
						break;
61
				}
62
				$relatedData = explode('::', $fieldInfo['fieldname']);
63
				if (2 === \count($relatedData)) {
64
					if (!empty($fieldValue) || 0 == $fieldValue) {
65
						$this->updateRecords($recordModel, $relatedData, $fieldValue);
66
					}
67
				} else {
68
					$recordId = $recordModel->get($relatedData[0]);
69
					if ($recordId && \App\Record::isExists($recordId)) {
70
						$relRecordModel = Vtiger_Record_Model::getInstanceById($recordId, $relatedData[1]);
71
						if (($condition = $conditions[$fieldInfo['fieldname']] ?? []) && !\App\Condition::checkConditions($condition, $relRecordModel)) {
72
							continue;
73
						}
74
						$fieldModel = $relRecordModel->getField($relatedData[2]);
75
						if ($fieldModel->isEditable()) {
76
							$fieldModel->getUITypeModel()->validate($fieldValue);
77
							$relRecordModel->set($relatedData[2], $fieldValue);
78
							if (false !== $relRecordModel->getPreviousValue($relatedData[2])) {
79
								$relRecordModel->setHandlerExceptions(['disableHandlerClasses' => ['Vtiger_Workflow_Handler']]);
80
								$relRecordModel->save();
81
							}
82
						} else {
83
							\App\Log::warning('No permissions to edit field: ' . $fieldModel->getName());
84
						}
85
					} else {
86
						\App\Log::warning('Record not found: ' . $recordId);
87
					}
88
				}
89
			}
90
		}
91
	}
92
93
	/**
94
	 * Update related records by releted module.
95
	 *
96
	 * @param Vtiger_Record_Model $recordModel
97
	 * @param string[]            $relatedData
98
	 * @param string              $fieldValue
99
	 *
100
	 * @return bool
101
	 */
102
	private function updateRecords($recordModel, $relatedData, $fieldValue)
103
	{
104
		$relatedModuleName = $relatedData[0];
105
		$relatedFieldName = $relatedData[1];
106
		$targetModel = Vtiger_RelationListView_Model::getInstance($recordModel, $relatedModuleName);
107
		if (!$targetModel || !$targetModel->getRelationModel()) {
0 ignored issues
show
introduced by
$targetModel is of type Vtiger_RelationListView_Model, thus it always evaluated to true.
Loading history...
108
			return false;
109
		}
110
		$queryGenerator = $targetModel->getRelationQuery(true);
111
		if (!\App\Json::isEmpty($this->conditions) && ($conditions = \App\Json::decode($this->conditions)[implode('::', $relatedData)] ?? [])) {
0 ignored issues
show
Bug Best Practice introduced by
The property conditions does not exist on VTUpdateRelatedFieldTask. Did you maybe forget to declare it?
Loading history...
112
			$queryGenerator->setConditions($conditions);
0 ignored issues
show
Bug introduced by
The method setConditions() does not exist on App\Db\Query. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

112
			$queryGenerator->/** @scrutinizer ignore-call */ 
113
                    setConditions($conditions);
Loading history...
113
		}
114
		$dataReader = $queryGenerator->clearFields()->setFields(['id'])->createQuery()->select(['vtiger_crmentity.crmid'])
0 ignored issues
show
Bug introduced by
The method setFields() does not exist on App\Db\Query. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

114
		$dataReader = $queryGenerator->clearFields()->/** @scrutinizer ignore-call */ setFields(['id'])->createQuery()->select(['vtiger_crmentity.crmid'])
Loading history...
Bug introduced by
The method clearFields() does not exist on App\Db\Query. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

114
		$dataReader = $queryGenerator->/** @scrutinizer ignore-call */ clearFields()->setFields(['id'])->createQuery()->select(['vtiger_crmentity.crmid'])
Loading history...
115
			->createCommand()->query();
116
		while ($recordId = $dataReader->readColumn(0)) {
117
			$recordModel = Vtiger_Record_Model::getInstanceById($recordId, $relatedModuleName);
118
			$fieldModel = $recordModel->getField($relatedFieldName);
119
			if ($fieldModel->isEditable()) {
120
				$fieldModel->getUITypeModel()->validate($fieldValue);
121
				$recordModel->set($relatedFieldName, $fieldValue);
122
				if (false !== $recordModel->getPreviousValue($relatedFieldName)) {
123
					$recordModel->setHandlerExceptions(['disableHandlerClasses' => ['Vtiger_Workflow_Handler']]);
124
					$recordModel->save();
125
				}
126
			} else {
127
				\App\Log::warning('No permissions to edit field: ' . $fieldModel->getName());
128
			}
129
		}
130
	}
131
132
	/**
133
	 * Function to get contents of this task.
134
	 *
135
	 * @param Vtiger_Record_Model $recordModel
136
	 *
137
	 * @return bool contents
138
	 */
139
	public function getContents($recordModel)
140
	{
141
		$this->contents = true;
0 ignored issues
show
Documentation Bug introduced by
It seems like true of type true is incompatible with the declared type Vtiger_Record_Model of property $contents.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
142
143
		return $this->contents;
144
	}
145
146
	/**
147
	 * Sets data from request.
148
	 *
149
	 * @param App\Request $request
150
	 */
151
	public function setDataFromRequest(App\Request $request)
152
	{
153
		foreach ($this->getFieldNames() as $fieldName) {
154
			if ($request->has($fieldName)) {
155
				switch ($fieldName) {
156
					case 'conditions':
157
						$data = $request->getArray($fieldName, \App\Purifier::TEXT);
158
						foreach ($data as &$condition) {
159
							$condition = \App\Condition::getConditionsFromRequest($condition);
160
						}
161
						$value = \App\Json::encode($data);
162
						break;
163
					case 'field_value_mapping':
164
						$values = \App\Json::decode($request->getRaw($fieldName));
165
						if (\is_array($values)) {
166
							$value = \App\Json::encode($values);
167
						} else {
168
							$value = $request->getRaw($fieldName);
169
						}
170
						break;
171
					default:
172
						$value = '';
173
						break;
174
				}
175
				$this->{$fieldName} = $value;
176
			}
177
		}
178
	}
179
}
180