Merge pull request #13983 from seamuslee001/new_coder_tests
[civicrm-core.git] / CRM / Profile / Page / Dynamic.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
34/**
35 * Create a page for displaying CiviCRM Profile Fields.
36 *
37 * Heart of this class is the run method which checks
38 * for action type and then displays the appropriate
39 * page.
40 *
41 */
42class CRM_Profile_Page_Dynamic extends CRM_Core_Page {
43
44 /**
fe482240 45 * The contact id of the person we are viewing.
6a488035
TO
46 *
47 * @var int
6a488035
TO
48 */
49 protected $_id;
50
51 /**
fe482240 52 * The profile group are are interested in.
6a488035
TO
53 *
54 * @var int
6a488035
TO
55 */
56 protected $_gid;
57
58 /**
fe482240 59 * The profile types we restrict this page to display.
6a488035
TO
60 *
61 * @var string
6a488035
TO
62 */
63 protected $_restrict;
64
65 /**
fe482240 66 * Should we bypass permissions.
6a488035
TO
67 *
68 * @var boolean
6a488035
TO
69 */
70 protected $_skipPermission;
71
72 /**
73 * Store profile ids if multiple profile ids are passed using comma separated.
74 * Currently lets implement this functionality only for dialog mode
75 */
be2fb01f 76 protected $_profileIds = [];
6a488035
TO
77
78 /**
79 * Contact profile having activity fields?
80 *
81 * @var string
82 */
83 protected $_isContactActivityProfile = FALSE;
84
85 /**
fe482240 86 * Activity Id connected to the profile.
6a488035
TO
87 *
88 * @var string
89 */
90 protected $_activityId = NULL;
91
92 protected $_multiRecord = NULL;
93
94 protected $_recordId = NULL;
366fe2a3 95
6a488035
TO
96 /*
97 * fetch multirecord as well as non-multirecord fields
98 */
99 protected $_allFields = NULL;
100
101 /**
fe482240 102 * Class constructor.
6a488035 103 *
68c9fb83
TO
104 * @param int $id
105 * The contact id.
106 * @param int $gid
107 * The group id.
6a488035 108 *
77b97be7
EM
109 * @param $restrict
110 * @param bool $skipPermission
111 * @param null $profileIds
112 *
113 * @return \CRM_Profile_Page_Dynamic
6a488035 114 */
00be9182 115 public function __construct($id, $gid, $restrict, $skipPermission = FALSE, $profileIds = NULL) {
6a488035
TO
116 parent::__construct();
117
118 $this->_id = $id;
119 $this->_gid = $gid;
120 $this->_restrict = $restrict;
121 $this->_skipPermission = $skipPermission;
122
123 if (!array_key_exists('multiRecord', $_GET)) {
124 $this->set('multiRecord', NULL);
125 }
126 if (!array_key_exists('recordId', $_GET)) {
127 $this->set('recordId', NULL);
128 }
129 if (!array_key_exists('allFields', $_GET)) {
130 $this->set('allFields', NULL);
131 }
366fe2a3 132
6a488035
TO
133 //specifies the action being done on a multi record field
134 $multiRecordAction = CRM_Utils_Request::retrieve('multiRecord', 'String', $this);
366fe2a3 135
dc98079b 136 $this->_multiRecord = (!is_numeric($multiRecordAction)) ? CRM_Core_Action::resolve($multiRecordAction) : $multiRecordAction;
6a488035
TO
137 if ($this->_multiRecord) {
138 $this->set('multiRecord', $this->_multiRecord);
139 }
366fe2a3 140
6a488035 141 if ($this->_multiRecord & CRM_Core_Action::VIEW) {
353ffa53 142 $this->_recordId = CRM_Utils_Request::retrieve('recordId', 'Positive', $this);
6a488035
TO
143 $this->_allFields = CRM_Utils_Request::retrieve('allFields', 'Integer', $this);
144 }
366fe2a3 145
6a488035
TO
146 if ($profileIds) {
147 $this->_profileIds = $profileIds;
148 }
149 else {
be2fb01f 150 $this->_profileIds = [$gid];
6a488035
TO
151 }
152
153 $this->_activityId = CRM_Utils_Request::retrieve('aid', 'Positive', $this, FALSE, 0, 'GET');
154 if (is_numeric($this->_activityId)) {
155 $latestRevisionId = CRM_Activity_BAO_Activity::getLatestActivityId($this->_activityId);
156 if ($latestRevisionId) {
157 $this->_activityId = $latestRevisionId;
158 }
159 }
160 $this->_isContactActivityProfile = CRM_Core_BAO_UFField::checkContactActivityProfileType($this->_gid);
161 }
162
163 /**
164 * Get the action links for this page.
165 *
a6c01b45 166 * @return array
6a488035 167 */
00be9182 168 public function &actionLinks() {
6a488035
TO
169 return NULL;
170 }
171
172 /**
173 * Run the page.
174 *
175 * This method is called after the page is created. It checks for the
176 * type of action and executes that action.
177 *
6a488035 178 */
00be9182 179 public function run() {
6a488035
TO
180 $template = CRM_Core_Smarty::singleton();
181 if ($this->_id && $this->_gid) {
182
183 // first check that id is part of the limit group id, CRM-4822
184 $limitListingsGroupsID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup',
185 $this->_gid,
186 'limit_listings_group_id'
187 );
188 $config = CRM_Core_Config::singleton();
189 if ($limitListingsGroupsID) {
190
191 if (!CRM_Contact_BAO_GroupContact::isContactInGroup($this->_id,
353ffa53
TO
192 $limitListingsGroupsID
193 )
194 ) {
6a488035
TO
195 CRM_Utils_System::setTitle(ts('Profile View - Permission Denied'));
196 return CRM_Core_Session::setStatus(ts('You do not have permission to view this contact record. Contact the site administrator if you need assistance.'), ts('Permission Denied'), 'error');
197 }
198 }
199
200 $session = CRM_Core_Session::singleton();
201 $userID = $session->get('userID');
202
942d2374 203 $this->_isPermissionedChecksum = $allowPermission = FALSE;
6a488035 204 $permissionType = CRM_Core_Permission::VIEW;
942d2374 205 if (CRM_Core_Permission::check('administer users') || CRM_Core_Permission::check('view all contacts') || CRM_Contact_BAO_Contact_Permission::allow($this->_id)) {
c5c263ca 206 $allowPermission = TRUE;
942d2374 207 }
6a488035
TO
208 if ($this->_id != $userID) {
209 // do not allow edit for anon users in joomla frontend, CRM-4668, unless u have checksum CRM-5228
210 if ($config->userFrameworkFrontend) {
211 $this->_isPermissionedChecksum = CRM_Contact_BAO_Contact_Permission::validateOnlyChecksum($this->_id, $this, FALSE);
942d2374
WA
212 if (!$this->_isPermissionedChecksum) {
213 $this->_isPermissionedChecksum = $allowPermission;
214 }
6a488035
TO
215 }
216 else {
217 $this->_isPermissionedChecksum = CRM_Contact_BAO_Contact_Permission::validateChecksumContact($this->_id, $this, FALSE);
218 }
219 }
220 // CRM-10853
221 // Users with create or edit permission should be allowed to view their own profile
222 if ($this->_id == $userID || $this->_isPermissionedChecksum) {
223 if (!CRM_Core_Permission::check('profile view')) {
224 if (CRM_Core_Permission::check('profile create') || CRM_Core_Permission::check('profile edit')) {
225 $this->_skipPermission = TRUE;
226 }
227 }
228 }
229
230 // make sure we dont expose all fields based on permission
231 $admin = FALSE;
942d2374 232 if ((!$config->userFrameworkFrontend && $allowPermission) ||
6a488035
TO
233 $this->_id == $userID ||
234 $this->_isPermissionedChecksum
235 ) {
236 $admin = TRUE;
237 }
238
be2fb01f 239 $values = [];
6a488035
TO
240 $fields = CRM_Core_BAO_UFGroup::getFields($this->_profileIds, FALSE, CRM_Core_Action::VIEW,
241 NULL, NULL, FALSE, $this->_restrict,
242 $this->_skipPermission, NULL,
243 $permissionType
244 );
245
246 if ($this->_multiRecord & CRM_Core_Action::VIEW && $this->_recordId && !$this->_allFields) {
247 CRM_Core_BAO_UFGroup::shiftMultiRecordFields($fields, $multiRecordFields);
248 $fields = $multiRecordFields;
249 }
250 if ($this->_isContactActivityProfile && $this->_gid) {
251 $errors = CRM_Profile_Form::validateContactActivityProfile($this->_activityId, $this->_id, $this->_gid);
252 if (!empty($errors)) {
253 CRM_Core_Error::fatal(array_pop($errors));
254 }
255 }
256
257 //reformat fields array
258 foreach ($fields as $name => $field) {
259 // also eliminate all formatting fields
260 if (CRM_Utils_Array::value('field_type', $field) == 'Formatting') {
261 unset($fields[$name]);
262 }
263
264 // make sure that there is enough permission to expose this field
265 if (!$admin && $field['visibility'] == 'User and User Admin Only') {
266 unset($fields[$name]);
267 }
268 }
269
270 if ($this->_isContactActivityProfile) {
be2fb01f 271 $contactFields = $activityFields = [];
6a488035
TO
272
273 foreach ($fields as $fieldName => $field) {
274 if (CRM_Utils_Array::value('field_type', $field) == 'Activity') {
275 $activityFields[$fieldName] = $field;
276 }
277 else {
278 $contactFields[$fieldName] = $field;
279 }
280 }
281
282 CRM_Core_BAO_UFGroup::getValues($this->_id, $contactFields, $values);
283 if ($this->_activityId) {
284 CRM_Core_BAO_UFGroup::getValues(
285 NULL,
286 $activityFields,
287 $values,
288 TRUE,
be2fb01f 289 [['activity_id', '=', $this->_activityId, 0, 0]]
6a488035
TO
290 );
291 }
292 }
293 else {
294 $customWhereClause = NULL;
295 if ($this->_multiRecord & CRM_Core_Action::VIEW && $this->_recordId) {
296 if ($this->_allFields) {
297 $copyFields = $fields;
298 CRM_Core_BAO_UFGroup::shiftMultiRecordFields($copyFields, $multiRecordFields);
299 $fieldKey = key($multiRecordFields);
0db6c3e1
TO
300 }
301 else {
6a488035
TO
302 $fieldKey = key($fields);
303 }
304 if ($fieldID = CRM_Core_BAO_CustomField::getKeyID($fieldKey)) {
305 $tableColumnGroup = CRM_Core_BAO_CustomField::getTableColumnGroup($fieldID);
306 $columnName = "{$tableColumnGroup[0]}.id";
307 $customWhereClause = $columnName . ' = ' . $this->_recordId;
308 }
309 }
310 CRM_Core_BAO_UFGroup::getValues($this->_id, $fields, $values, TRUE, NULL, FALSE, $customWhereClause);
311 }
312
313 // $profileFields array can be used for customized display of field labels and values in Profile/View.tpl
be2fb01f
CW
314 $profileFields = [];
315 $labels = [];
6a488035
TO
316
317 foreach ($fields as $name => $field) {
50bf705c
KJ
318 //CRM-14338
319 // Create a unique, non-empty index for each field.
320 $index = $field['title'];
ae93a14f
TO
321 if ($index === '') {
322 $index = ' ';
dc98079b
TO
323 }
324 while (array_key_exists($index, $labels)) {
50bf705c 325 $index .= ' ';
dc98079b 326 }
50bf705c
KJ
327
328 $labels[$index] = preg_replace('/\s+|\W+/', '_', $name);
6a488035
TO
329 }
330
331 foreach ($values as $title => $value) {
be2fb01f 332 $profileFields[$labels[$title]] = [
6a488035
TO
333 'label' => $title,
334 'value' => $value,
be2fb01f 335 ];
6a488035
TO
336 }
337
338 $template->assign_by_ref('row', $values);
339 $template->assign_by_ref('profileFields', $profileFields);
340 }
341
342 $name = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid, 'name');
46312a4d 343 $this->assign('ufGroupName', $name);
a8387f19 344 CRM_Utils_Hook::viewProfile($name);
6a488035
TO
345
346 if (strtolower($name) == 'summary_overlay') {
347 $template->assign('overlayProfile', TRUE);
348 }
349
350 if (($this->_multiRecord & CRM_Core_Action::VIEW) && $this->_recordId && !$this->_allFields) {
351 $fieldDetail = reset($fields);
352 $fieldId = CRM_Core_BAO_CustomField::getKeyID($fieldDetail['name']);
be2fb01f 353 $customGroupDetails = CRM_Core_BAO_CustomGroup::getGroupTitles([$fieldId]);
fcc8f207 354 $multiRecTitle = $customGroupDetails[$fieldId]['groupTitle'];
0db6c3e1
TO
355 }
356 else {
6a488035
TO
357 $title = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid, 'title');
358 }
359
360 //CRM-4131.
361 $displayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_id, 'display_name');
362 if ($displayName) {
363 $session = CRM_Core_Session::singleton();
364 $config = CRM_Core_Config::singleton();
365 if ($session->get('userID') &&
366 CRM_Core_Permission::check('access CiviCRM') &&
367 CRM_Contact_BAO_Contact_Permission::allow($session->get('userID'), CRM_Core_Permission::VIEW) &&
368 !$config->userFrameworkFrontend
369 ) {
370 $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "action=view&reset=1&cid={$this->_id}", TRUE);
371 $this->assign('displayName', $displayName);
372 $displayName = "<a href=\"$contactViewUrl\">{$displayName}</a>";
373 }
374 $title .= ' - ' . $displayName;
375 }
376
be2fb01f 377 $title = isset($multiRecTitle) ? ts('View %1 Record', [1 => $multiRecTitle]) : $title;
6a488035
TO
378 CRM_Utils_System::setTitle($title);
379
380 // invoke the pagRun hook, CRM-3906
381 CRM_Utils_Hook::pageRun($this);
382
8aac22c8 383 return trim($template->fetch($this->getHookedTemplateFileName()));
6a488035
TO
384 }
385
ffd93213
EM
386 /**
387 * @param string $suffix
388 *
389 * @return null|string
390 */
00be9182 391 public function checkTemplateFileExists($suffix = '') {
6a488035
TO
392 if ($this->_gid) {
393 $templateFile = "CRM/Profile/Page/{$this->_gid}/Dynamic.{$suffix}tpl";
394 $template = CRM_Core_Page::getTemplate();
395 if ($template->template_exists($templateFile)) {
396 return $templateFile;
397 }
398
399 // lets see if we have customized by name
400 $ufGroupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid, 'name');
401 if ($ufGroupName) {
402 $templateFile = "CRM/Profile/Page/{$ufGroupName}/Dynamic.{$suffix}tpl";
403 if ($template->template_exists($templateFile)) {
404 return $templateFile;
405 }
406 }
407 }
408 return NULL;
409 }
410
ffd93213 411 /**
fe482240 412 * Use the form name to create the tpl file name.
ffd93213
EM
413 *
414 * @return string
ffd93213 415 */
00be9182 416 public function getTemplateFileName() {
6a488035
TO
417 $fileName = $this->checkTemplateFileExists();
418 return $fileName ? $fileName : parent::getTemplateFileName();
419 }
420
ffd93213
EM
421 /**
422 * Default extra tpl file basically just replaces .tpl with .extra.tpl
423 * i.e. we dont override
424 *
425 * @return string
ffd93213 426 */
00be9182 427 public function overrideExtraTemplateFileName() {
6a488035
TO
428 $fileName = $this->checkTemplateFileExists('extra.');
429 return $fileName ? $fileName : parent::overrideExtraTemplateFileName();
430 }
96025800 431
6a488035 432}