|
1
|
|
|
<?php |
|
2
|
|
|
/* +*********************************************************************************** |
|
3
|
|
|
* The contents of this file are subject to the vtiger CRM Public License Version 1.0 |
|
4
|
|
|
* ("License"); You may not use this file except in compliance with the License |
|
5
|
|
|
* The Original Code is: vtiger CRM Open Source |
|
6
|
|
|
* The Initial Developer of the Original Code is vtiger. |
|
7
|
|
|
* Portions created by vtiger are Copyright (C) vtiger. |
|
8
|
|
|
* All Rights Reserved. |
|
9
|
|
|
* Contributor(s): YetiForce S.A. |
|
10
|
|
|
* *********************************************************************************** */ |
|
11
|
|
|
|
|
12
|
|
|
class Vtiger_Save_Action extends \App\Controller\Action |
|
13
|
|
|
{ |
|
14
|
|
|
use \App\Controller\ExposeMethod; |
|
15
|
|
|
/** |
|
16
|
|
|
* Record model instance. |
|
17
|
|
|
* |
|
18
|
|
|
* @var Vtiger_Record_Model |
|
19
|
|
|
*/ |
|
20
|
|
|
protected $record; |
|
21
|
|
|
|
|
22
|
|
|
/** {@inheritdoc} */ |
|
23
|
|
|
public function __construct() |
|
24
|
|
|
{ |
|
25
|
|
|
parent::__construct(); |
|
26
|
|
|
$this->exposeMethod('preSaveValidation'); |
|
27
|
|
|
$this->exposeMethod('recordChanger'); |
|
28
|
|
|
} |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* Function to check permission. |
|
32
|
|
|
* |
|
33
|
|
|
* @param \App\Request $request |
|
34
|
|
|
* |
|
35
|
|
|
* @throws \App\Exceptions\NoPermittedToRecord |
|
36
|
|
|
*/ |
|
37
|
|
|
public function checkPermission(App\Request $request) |
|
38
|
|
|
{ |
|
39
|
|
|
$moduleName = $request->getModule(); |
|
40
|
|
|
if ($request->isEmpty('record', true)) { |
|
41
|
|
|
$this->record = Vtiger_Record_Model::getCleanInstance($moduleName); |
|
42
|
|
|
if (!$this->record->isCreatable()) { |
|
43
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
44
|
|
|
} |
|
45
|
|
|
} else { |
|
46
|
|
|
$recordId = $request->getInteger('record'); |
|
47
|
|
|
if (!\App\Privilege::isPermitted($moduleName, 'DetailView', $recordId)) { |
|
48
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
49
|
|
|
} |
|
50
|
|
|
$this->record = Vtiger_Record_Model::getInstanceById($recordId, $moduleName); |
|
51
|
|
|
if ('recordChanger' !== $request->getMode() && !$this->record->isEditable()) { |
|
52
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
53
|
|
|
} |
|
54
|
|
|
} |
|
55
|
|
|
if ($request->getBoolean('_isDuplicateRecord') && !\App\Privilege::isPermitted($moduleName, 'DetailView', $request->getInteger('_duplicateRecord'))) { |
|
56
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
57
|
|
|
} |
|
58
|
|
|
if ($request->has('recordConverter') && !\App\RecordConverter::getInstanceById($request->getInteger('recordConverter'))->isPermitted($request->getInteger('sourceRecord'))) { |
|
59
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
60
|
|
|
} |
|
61
|
|
|
if ($request->getBoolean('relationOperation') && !\App\Privilege::isPermitted($request->getByType('sourceModule', 2), 'DetailView', $request->getInteger('sourceRecord'))) { |
|
62
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
63
|
|
|
} |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* Process. |
|
68
|
|
|
* |
|
69
|
|
|
* @param \App\Request $request |
|
70
|
|
|
*/ |
|
71
|
|
|
public function process(App\Request $request) |
|
72
|
|
|
{ |
|
73
|
|
|
if ($mode = $request->getMode()) { |
|
74
|
|
|
$this->invokeExposedMethod($mode, $request); |
|
75
|
|
|
} else { |
|
76
|
|
|
$this->saveRecord($request); |
|
77
|
|
|
if ($request->getBoolean('relationOperation')) { |
|
78
|
|
|
$loadUrl = Vtiger_Record_Model::getInstanceById($request->getInteger('sourceRecord'), $request->getByType('sourceModule', 2))->getDetailViewUrl(); |
|
79
|
|
|
} elseif ($request->getBoolean('returnToList')) { |
|
80
|
|
|
$loadUrl = $this->record->getModule()->getListViewUrl(); |
|
81
|
|
|
} else { |
|
82
|
|
|
$this->record->clearPrivilegesCache(); |
|
83
|
|
|
if ($this->record->isViewable()) { |
|
84
|
|
|
$loadUrl = $this->record->getDetailViewUrl(); |
|
85
|
|
|
} else { |
|
86
|
|
|
$loadUrl = $this->record->getModule()->getDefaultUrl(); |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
header("location: $loadUrl"); |
|
90
|
|
|
} |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
/** {@inheritdoc} */ |
|
94
|
|
|
public function saveRecord(App\Request $request) |
|
95
|
|
|
{ |
|
96
|
|
|
$this->getRecordModelFromRequest($request); |
|
97
|
|
|
$eventHandler = $this->record->getEventHandler(); |
|
98
|
|
|
$skipHandlers = $request->getArray('skipHandlers', \App\Purifier::ALNUM, [], \App\Purifier::INTEGER); |
|
99
|
|
|
foreach ($eventHandler->getHandlers(\App\EventHandler::EDIT_VIEW_PRE_SAVE) as $handler) { |
|
100
|
|
|
$handlerId = $handler['eventhandler_id']; |
|
101
|
|
|
$response = $eventHandler->triggerHandler($handler); |
|
102
|
|
|
|
|
103
|
|
|
if (!($response['result'] ?? null) && (!isset($response['hash'], $skipHandlers[$handlerId]) || $skipHandlers[$handlerId] !== $response['hash'])) { |
|
104
|
|
|
throw new \App\Exceptions\NoPermittedToRecord($response['message'] ?? 'ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
105
|
|
|
} |
|
106
|
|
|
} |
|
107
|
|
|
if (!$request->isEmpty('fromView') && 'MassQuickCreate' === $request->getByType('fromView')) { |
|
108
|
|
|
$this->multiSave($request); |
|
109
|
|
|
} else { |
|
110
|
|
|
$this->record->save(); |
|
111
|
|
|
if ($request->has('recordConverter')) { |
|
112
|
|
|
$converter = \App\RecordConverter::getInstanceById($request->getInteger('recordConverter'))->set('sourceRecord', $request->getInteger('sourceRecord')); |
|
113
|
|
|
$eventHandler->setParams(['converter' => $converter]); |
|
114
|
|
|
$eventHandler->trigger(\App\EventHandler::RECORD_CONVERTER_AFTER_SAVE); |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
|
|
if ($request->getBoolean('relationOperation')) { |
|
118
|
|
|
$relationId = $request->isEmpty('relationId') ? false : $request->getInteger('relationId'); |
|
119
|
|
|
if ($relationModel = Vtiger_Relation_Model::getInstance(Vtiger_Module_Model::getInstance($request->getByType('sourceModule', 2)), $this->record->getModule(), $relationId)) { |
|
120
|
|
|
$relationModel->addRelation($request->getInteger('sourceRecord'), $this->record->getId()); |
|
121
|
|
|
} |
|
122
|
|
|
} |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* Function to get the record model based on the request parameters. |
|
127
|
|
|
* |
|
128
|
|
|
* @param \App\Request $request |
|
129
|
|
|
* |
|
130
|
|
|
* @return Vtiger_Record_Model or Module specific Record Model instance |
|
131
|
|
|
*/ |
|
132
|
|
|
protected function getRecordModelFromRequest(App\Request $request) |
|
133
|
|
|
{ |
|
134
|
|
|
if (empty($this->record)) { |
|
135
|
|
|
$this->record = $request->isEmpty('record', true) ? Vtiger_Record_Model::getCleanInstance($request->getModule()) : Vtiger_Record_Model::getInstanceById($request->getInteger('record'), $request->getModule()); |
|
136
|
|
|
} |
|
137
|
|
|
$fieldModelList = $this->record->getModule()->getFields(); |
|
138
|
|
|
foreach ($fieldModelList as $fieldName => $fieldModel) { |
|
139
|
|
|
if (!$fieldModel->isWritable()) { |
|
140
|
|
|
continue; |
|
141
|
|
|
} |
|
142
|
|
|
if ($request->has($fieldName)) { |
|
143
|
|
|
$fieldModel->getUITypeModel()->setValueFromRequest($request, $this->record); |
|
144
|
|
|
} |
|
145
|
|
|
} |
|
146
|
|
|
if ($request->has('inventory') && $this->record->getModule()->isInventory()) { |
|
147
|
|
|
$this->record->initInventoryDataFromRequest($request); |
|
148
|
|
|
} |
|
149
|
|
|
$fromView = $request->has('fromView') ? $request->getByType('fromView') : ($request->isEmpty('record', true) ? 'Create' : 'Edit'); |
|
150
|
|
|
$fieldsDependency = \App\FieldsDependency::getByRecordModel($fromView, $this->record); |
|
151
|
|
|
if ($fields = array_merge($fieldsDependency['hide']['frontend'], $fieldsDependency['hide']['backend'])) { |
|
152
|
|
|
foreach ($fields as $fieldName) { |
|
153
|
|
|
$this->record->revertPreviousValue($fieldName); |
|
154
|
|
|
} |
|
155
|
|
|
} |
|
156
|
|
|
return $this->record; |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
/** |
|
160
|
|
|
* Validation before saving. |
|
161
|
|
|
* |
|
162
|
|
|
* @param App\Request $request |
|
163
|
|
|
*/ |
|
164
|
|
|
public function preSaveValidation(App\Request $request) |
|
165
|
|
|
{ |
|
166
|
|
|
$this->getRecordModelFromRequest($request); |
|
167
|
|
|
$eventHandler = $this->record->getEventHandler(); |
|
168
|
|
|
$result = []; |
|
169
|
|
|
$skipHandlers = $request->getArray('skipHandlers', \App\Purifier::ALNUM, [], \App\Purifier::INTEGER); |
|
170
|
|
|
foreach ($eventHandler->getHandlers(\App\EventHandler::EDIT_VIEW_PRE_SAVE) as $handler) { |
|
171
|
|
|
$handlerId = $handler['eventhandler_id']; |
|
172
|
|
|
$handlerResponse = $eventHandler->triggerHandler($handler); |
|
173
|
|
|
if (!($handlerResponse['result'] ?? null) && (!isset($handlerResponse['hash'], $skipHandlers[$handlerId]) || $skipHandlers[$handlerId] !== $handlerResponse['hash'])) { |
|
174
|
|
|
$result[$handlerId] = $handlerResponse; |
|
175
|
|
|
if ('confirm' === ($handlerResponse['type'] ?? '')) { |
|
176
|
|
|
break; |
|
177
|
|
|
} |
|
178
|
|
|
} |
|
179
|
|
|
} |
|
180
|
|
|
$response = new Vtiger_Response(); |
|
181
|
|
|
$response->setEmitType(Vtiger_Response::$EMIT_JSON); |
|
182
|
|
|
$response->setResult($result); |
|
183
|
|
|
$response->emit(); |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* Quick change of record value. |
|
188
|
|
|
* |
|
189
|
|
|
* @param App\Request $request |
|
190
|
|
|
*/ |
|
191
|
|
|
public function recordChanger(App\Request $request) |
|
192
|
|
|
{ |
|
193
|
|
|
$this->getRecordModelFromRequest($request); |
|
194
|
|
|
$id = $request->getInteger('id'); |
|
195
|
|
|
$field = App\Field::getQuickChangerFields($this->record->getModule()->getId())[$id] ?? false; |
|
196
|
|
|
if (!$field || !App\Field::checkQuickChangerConditions($field, $this->record)) { |
|
|
|
|
|
|
197
|
|
|
throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406); |
|
198
|
|
|
} |
|
199
|
|
|
$fields = $this->record->getModule()->getFields(); |
|
200
|
|
|
foreach ($field['values'] as $fieldName => $value) { |
|
201
|
|
|
if (isset($fields[$fieldName]) && $fields[$fieldName]->isEditable()) { |
|
202
|
|
|
$this->record->set($fieldName, $value); |
|
203
|
|
|
} |
|
204
|
|
|
} |
|
205
|
|
|
$this->record->save(); |
|
206
|
|
|
$response = new Vtiger_Response(); |
|
207
|
|
|
$response->setEmitType(Vtiger_Response::$EMIT_JSON); |
|
208
|
|
|
$response->setResult(true); |
|
209
|
|
|
$response->emit(); |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
/** |
|
213
|
|
|
* Multiple record save mode. |
|
214
|
|
|
* |
|
215
|
|
|
* @param App\Request $request |
|
216
|
|
|
* |
|
217
|
|
|
* @return void |
|
218
|
|
|
*/ |
|
219
|
|
|
protected function multiSave(App\Request $request): void |
|
220
|
|
|
{ |
|
221
|
|
|
$moduleName = $request->getByType('module', 'Alnum'); |
|
222
|
|
|
$multiSaveField = $request->getByType('multiSaveField', 'Alnum'); |
|
223
|
|
|
$sourceModule = $request->getByType('sourceModule', 'Alnum'); |
|
224
|
|
|
$sourceView = $request->getByType('sourceView'); |
|
225
|
|
|
if ('ListView' === $sourceView) { |
|
226
|
|
|
$request->set('module', $sourceModule); |
|
227
|
|
|
$ids = Vtiger_Mass_Action::getRecordsListFromRequest($request); |
|
228
|
|
|
$request->set('module', $moduleName); |
|
229
|
|
|
} elseif ('RelatedListView' === $sourceView) { |
|
230
|
|
|
$request->set('module', $request->getByType('relatedModule', 'Alnum')); |
|
231
|
|
|
$request->set('relatedModule', $request->getByType('sourceModule', 'Alnum')); |
|
232
|
|
|
$request->set('record', $request->getByType('relatedRecord', 'Alnum')); |
|
233
|
|
|
$ids = Vtiger_RelationAjax_Action::getRecordsListFromRequest($request); |
|
234
|
|
|
$request->set('module', $moduleName); |
|
235
|
|
|
} |
|
236
|
|
|
foreach ($ids as $id) { |
|
|
|
|
|
|
237
|
|
|
$recordModel = \Vtiger_Record_Model::getCleanInstance($this->record->getModuleName()); |
|
238
|
|
|
$recordModel->setData($this->record->getData()); |
|
239
|
|
|
$recordModel->ext = $this->record->ext; |
|
240
|
|
|
$recordModel->set($multiSaveField, $id); |
|
241
|
|
|
$recordModel->save(); |
|
242
|
|
|
} |
|
243
|
|
|
} |
|
244
|
|
|
} |
|
245
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.