Merge pull request #21550 from demeritcowboy/template-missed
[civicrm-core.git] / CRM / Profile / Form / Edit.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
19 * This class generates form components for custom data
20 *
21 * It delegates the work to lower level subclasses and integrates the changes
22 * back in. It also uses a lot of functionality with the CRM API's, so any change
23 * made here could potentially affect the API etc. Be careful, be aware, use unit tests.
24 *
25 */
26class CRM_Profile_Form_Edit extends CRM_Profile_Form {
27 protected $_postURL = NULL;
28 protected $_cancelURL = NULL;
29 protected $_errorURL = NULL;
30 protected $_context;
31 protected $_blockNo;
32 protected $_prefix;
2b63c577 33 protected $returnExtra;
6a488035
TO
34
35 /**
100fef9d 36 * Pre processing work done here.
6a488035
TO
37 *
38 * @param
39 *
6a488035 40 */
00be9182 41 public function preProcess() {
6a488035
TO
42 $this->_mode = CRM_Profile_Form::MODE_CREATE;
43
e5e3f1ad 44 $this->_onPopupClose = CRM_Utils_Request::retrieve('onPopupClose', 'String', $this);
3a2e7d2b 45 $this->assign('onPopupClose', $this->_onPopupClose);
ac79535c 46
6a488035 47 //set the context for the profile
edc80cda 48 $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
6a488035
TO
49
50 //set the block no
51 $this->_blockNo = CRM_Utils_Request::retrieve('blockNo', 'String', $this);
52
53 //set the prefix
54 $this->_prefix = CRM_Utils_Request::retrieve('prefix', 'String', $this);
55
882a1be2 56 // Fields for the EntityRef widget
2b63c577 57 $this->returnExtra = CRM_Utils_Request::retrieve('returnExtra', 'String', $this);
882a1be2 58
6a488035
TO
59 $this->assign('context', $this->_context);
60
61 if ($this->_blockNo) {
62 $this->assign('blockNo', $this->_blockNo);
63 $this->assign('prefix', $this->_prefix);
64 }
65
66 $this->assign('createCallback', CRM_Utils_Request::retrieve('createCallback', 'String', $this));
67
68 if ($this->get('skipPermission')) {
69 $this->_skipPermission = TRUE;
70 }
71
72 if ($this->get('edit')) {
73 // make sure we have right permission to edit this user
34f493fb 74 $userID = CRM_Core_Session::getLoggedInContactID();
1a447f39
J
75
76 // Set the ID from the query string, otherwise default to the current user
353ffa53 77 $id = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, $userID);
6a488035
TO
78
79 if ($id) {
80 // this is edit mode.
81 $this->_mode = CRM_Profile_Form::MODE_EDIT;
82
83 if ($id != $userID) {
84 // do not allow edit for anon users in joomla frontend, CRM-4668, unless u have checksum CRM-5228
541d99d7 85 // see also CRM-19079 for modifications to the condition
6a488035 86 $config = CRM_Core_Config::singleton();
541d99d7 87 if ($config->userFrameworkFrontend && $config->userSystem->is_joomla) {
6a488035
TO
88 CRM_Contact_BAO_Contact_Permission::validateOnlyChecksum($id, $this);
89 }
90 else {
91 CRM_Contact_BAO_Contact_Permission::validateChecksumContact($id, $this);
92 }
93 $this->_isPermissionedChecksum = TRUE;
94 }
95 }
1a447f39
J
96
97 // CRM-16784: If there is no ID then this can't be an 'edit'
98 else {
e22ec653 99 CRM_Core_Error::statusBounce(ts('No user/contact ID was specified, so the Profile cannot be used in edit mode.'));
1a447f39
J
100 }
101
6a488035
TO
102 }
103
104 parent::preProcess();
105
6a488035 106 // and also the profile is of type 'Profile'
fa1f7018 107 $query = '
2e57a21b
DG
108SELECT module,is_reserved
109 FROM civicrm_uf_group
110 LEFT JOIN civicrm_uf_join ON uf_group_id = civicrm_uf_group.id
74ee0fba 111 WHERE civicrm_uf_group.id = %1
fa1f7018 112';
74ee0fba 113
be2fb01f 114 $params = [1 => [$this->_gid, 'Integer']];
6a488035 115 $dao = CRM_Core_DAO::executeQuery($query, $params);
2e57a21b 116
192e8d1a 117 $isProfile = FALSE;
118 while ($dao->fetch()) {
fa1f7018 119 $isProfile = ($isProfile || ($dao->module === 'Profile'));
192e8d1a 120 }
2e57a21b 121
192e8d1a 122 //Check that the user has the "add contacts" Permission
fa1f7018 123 $canAdd = CRM_Core_Permission::check('add contacts');
2e57a21b 124
192e8d1a 125 //Remove need for Profile module type when using reserved profiles [CRM-14488]
126 if (!$dao->N || (!$isProfile && !($dao->is_reserved && $canAdd))) {
e22ec653 127 CRM_Core_Error::statusBounce(ts('The requested Profile (gid=%1) is not configured to be used for \'Profile\' edit and view forms in its Settings. Contact the site administrator if you need assistance.',
be2fb01f 128 [1 => $this->_gid]
192e8d1a 129 ));
6a488035
TO
130 }
131 }
132
133 /**
fe482240 134 * Build the form object.
6a488035 135 *
6a488035
TO
136 */
137 public function buildQuickForm() {
a3dbd1bc 138 if (empty($this->_ufGroup['id'])) {
e22ec653 139 CRM_Core_Error::statusBounce(ts('Invalid'));
6a488035
TO
140 }
141
142 // set the title
143 if ($this->_multiRecord && $this->_customGroupTitle) {
fa1f7018 144 $this->setTitle(($this->_multiRecord & CRM_Core_Action::UPDATE) ? 'Edit ' . $this->_customGroupTitle . ' Record' : $this->_customGroupTitle);
6a488035 145
0db6c3e1
TO
146 }
147 else {
fa1f7018 148 $this->setTitle(CRM_Core_BAO_UFGroup::getFrontEndTitle($this->_ufGroup['id']));
6a488035 149 }
fa1f7018 150
6a488035
TO
151 $this->assign('recentlyViewed', FALSE);
152
fa1f7018 153 if ($this->_context !== 'dialog') {
a3dbd1bc
TO
154 $this->_postURL = $this->_ufGroup['post_URL'];
155 $this->_cancelURL = $this->_ufGroup['cancel_URL'];
6a488035
TO
156
157 $gidString = $this->_gid;
158 if (!empty($this->_profileIds)) {
159 $gidString = implode(',', $this->_profileIds);
160 }
161
6a488035 162 if (!$this->_postURL) {
fa1f7018 163 if ($this->_context === 'Search') {
6a488035
TO
164 $this->_postURL = CRM_Utils_System::url('civicrm/contact/search');
165 }
166 elseif ($this->_id && $this->_gid) {
167 $urlParams = "reset=1&id={$this->_id}&gid={$gidString}";
168 if ($this->_isContactActivityProfile && $this->_activityId) {
169 $urlParams .= "&aid={$this->_activityId}";
170 }
171 // get checksum if present
172 if ($this->get('cs')) {
173 $urlParams .= "&cs=" . $this->get('cs');
174 }
175 $this->_postURL = CRM_Utils_System::url('civicrm/profile/view', $urlParams);
176 }
177 }
178
179 if (!$this->_cancelURL) {
a3dbd1bc
TO
180 $this->_cancelURL = CRM_Utils_System::url('civicrm/profile',
181 "reset=1&gid={$gidString}"
182 );
6a488035
TO
183 }
184
6a488035
TO
185 // we do this gross hack since qf also does entity replacement
186 $this->_postURL = str_replace('&amp;', '&', $this->_postURL);
187 $this->_cancelURL = str_replace('&amp;', '&', $this->_cancelURL);
188
6a488035 189 // also retain error URL if set
9c1bc317 190 $this->_errorURL = $_POST['errorURL'] ?? NULL;
6a488035
TO
191 if ($this->_errorURL) {
192 // we do this gross hack since qf also does entity replacement
193 $this->_errorURL = str_replace('&amp;', '&', $this->_errorURL);
194 $this->addElement('hidden', 'errorURL', $this->_errorURL);
195 }
196
197 // replace the session stack in case user cancels (and we dont go into postProcess)
198 $session = CRM_Core_Session::singleton();
199 $session->replaceUserContext($this->_postURL);
200 }
201
202 parent::buildQuickForm();
203
fc942baa
CW
204 $this->assign('cancelURL', $this->_cancelURL);
205
c48f851a
SL
206 $cancelButtonValue = !empty($this->_ufGroup['cancel_button_text']) ? $this->_ufGroup['cancel_button_text'] : ts('Cancel');
207 $this->assign('cancelButtonText', $cancelButtonValue);
b3f1028c 208 $this->assign('includeCancelButton', CRM_Utils_Array::value('add_cancel_button', $this->_ufGroup));
c48f851a 209
6a488035
TO
210 if (($this->_multiRecord & CRM_Core_Action::DELETE) && $this->_recordExists) {
211 $this->_deleteButtonName = $this->getButtonName('upload', 'delete');
f7083334
AH
212 $this->addElement('xbutton', $this->_deleteButtonName, ts('Delete'), [
213 'type' => 'submit',
214 'value' => 1,
57c59c34 215 'class' => 'crm-button',
f7083334 216 ]);
6a488035 217
6a488035
TO
218 return;
219 }
220
221 //get the value from session, this is set if there is any file
222 //upload field
223 $uploadNames = $this->get('uploadNames');
224
225 if (!empty($uploadNames)) {
226 $buttonName = 'upload';
227 }
228 else {
229 $buttonName = 'next';
230 }
231
be2fb01f 232 $buttons[] = [
6a488035 233 'type' => $buttonName,
c48f851a 234 'name' => !empty($this->_ufGroup['submit_button_text']) ? $this->_ufGroup['submit_button_text'] : ts('Save'),
6a488035 235 'isDefault' => TRUE,
be2fb01f 236 ];
6a488035 237
6a488035
TO
238 $this->addButtons($buttons);
239
be2fb01f 240 $this->addFormRule(['CRM_Profile_Form', 'formRule'], $this);
6a488035
TO
241 }
242
243 /**
244 * Process the user submitted custom data values.
245 *
d0b58293
EM
246 * @throws \API_Exception
247 * @throws \CRM_Core_Exception
248 * @throws \CiviCRM_API3_Exception
6a488035
TO
249 */
250 public function postProcess() {
251 parent::postProcess();
252
882a1be2 253 // Send back data for the EntityRef widget
2b63c577 254 if ($this->returnExtra) {
be2fb01f 255 $contact = civicrm_api3('Contact', 'getsingle', [
2b63c577
CW
256 'id' => $this->_id,
257 'return' => $this->returnExtra,
be2fb01f 258 ]);
2b63c577
CW
259 foreach (explode(',', $this->returnExtra) as $field) {
260 $field = trim($field);
9c1bc317 261 $this->ajaxResponse['extra'][$field] = $contact[$field] ?? NULL;
2b63c577 262 }
882a1be2 263 }
79ae07d9 264
f90f3ac1 265 // When saving (not deleting) and not in an ajax popup
fa1f7018 266 if (empty($_POST[$this->_deleteButtonName]) && $this->_context !== 'dialog') {
6a488035
TO
267 CRM_Core_Session::setStatus(ts('Your information has been saved.'), ts('Thank you.'), 'success');
268 }
269
270 $session = CRM_Core_Session::singleton();
271 // only replace user context if we do not have a postURL
272 if (!$this->_postURL) {
273 $gidString = $this->_gid;
274 if (!empty($this->_profileIds)) {
275 $gidString = implode(',', $this->_profileIds);
276 }
277
278 $urlParams = "reset=1&id={$this->_id}&gid={$gidString}";
279 if ($this->_isContactActivityProfile && $this->_activityId) {
280 $urlParams .= "&aid={$this->_activityId}";
281 }
282 // Get checksum if present
283 if ($this->get('cs')) {
284 $urlParams .= "&cs=" . $this->get('cs');
285 }
286 // Generate one if needed
287 elseif (!CRM_Contact_BAO_Contact_Permission::allow($this->_id)) {
288 $urlParams .= "&cs=" . CRM_Contact_BAO_Contact_Utils::generateChecksum($this->_id);
289 }
290 $url = CRM_Utils_System::url('civicrm/profile/view', $urlParams);
291 }
292 else {
d0b58293
EM
293 $url = CRM_Core_BAO_MessageTemplate::renderTemplate([
294 'messageTemplate' => ['msg_text' => $this->_postURL],
295 'contactId' => $this->_id,
296 'disableSmarty' => TRUE,
297 ])['text'];
6a488035
TO
298 }
299
300 $session->replaceUserContext($url);
301 }
302
303 /**
fe482240 304 * Intercept QF validation and do our own redirection.
6a488035
TO
305 *
306 * We use this to send control back to the user for a user formatted page
307 * This allows the user to maintain the same state and display the error messages
308 * in their own theme along with any modifications
309 *
310 * This is a first version and will be tweaked over a period of time
311 *
6a488035 312 *
317fceb4 313 * @return bool
a6c01b45 314 * true if no error found
6a488035 315 */
00be9182 316 public function validate() {
6a488035
TO
317 $errors = parent::validate();
318
8cc574cf 319 if (!$errors && !empty($_POST['errorURL'])) {
6a488035
TO
320 $message = NULL;
321 foreach ($this->_errors as $name => $mess) {
322 $message .= $mess;
323 $message .= '<p>';
324 }
325
326 CRM_Utils_System::setUFMessage($message);
327
328 $message = urlencode($message);
329
330 $errorURL = $_POST['errorURL'];
331 if (strpos($errorURL, '?') !== FALSE) {
332 $errorURL .= '&';
333 }
334 else {
335 $errorURL .= '?';
336 }
337 $errorURL .= "gid={$this->_gid}&msg=$message";
338 CRM_Utils_System::redirect($errorURL);
339 }
340
341 return $errors;
342 }
96025800 343
6a488035 344}