Replace CRM_Utils_Array::value with ?? in variable assignments
[civicrm-core.git] / CRM / Profile / Page / Listings.php
CommitLineData
6a488035 1<?php
6a488035
TO
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/**
20 * This implements the profile page for all contacts. It uses a selector
21 * object to do the actual dispay. The fields displayd are controlled by
abdd5e3e 22 * the admin.
6a488035
TO
23 */
24class CRM_Profile_Page_Listings extends CRM_Core_Page {
25
26 /**
abdd5e3e 27 * All the fields that are listings related.
6a488035
TO
28 *
29 * @var array
6a488035
TO
30 */
31 protected $_fields;
32
33 /**
abdd5e3e 34 * The custom fields for this domain.
6a488035
TO
35 *
36 * @var array
6a488035
TO
37 */
38 protected $_customFields;
39
40 /**
abdd5e3e 41 * The input params from the request.
6a488035
TO
42 *
43 * @var array
6a488035
TO
44 */
45 protected $_params;
46
47 /**
abdd5e3e 48 * The group id that we are editing.
6a488035
TO
49 *
50 * @var int
51 */
52 protected $_gid;
53
54 /**
abdd5e3e 55 * State whether to display search form or not.
6a488035
TO
56 *
57 * @var int
58 */
59 protected $_search;
60
61 /**
abdd5e3e 62 * Should we display a map.
6a488035
TO
63 *
64 * @var int
65 */
66 protected $_map;
67
68 /**
69 * Store profile ids if multiple profile ids are passed using comma separated.
70 * Currently lets implement this functionality only for dialog mode
c86d4e7c 71 * @var array
6a488035 72 */
be2fb01f 73 protected $_profileIds = [];
6a488035
TO
74
75 /**
100fef9d 76 * Extracts the parameters from the request and constructs information for
6a488035
TO
77 * the selector object to do a query
78 *
6a488035 79 */
00be9182 80 public function preProcess() {
6a488035
TO
81
82 $this->_search = TRUE;
83
84 $search = CRM_Utils_Request::retrieve('search', 'Boolean', $this, FALSE, 0, 'GET');
85 if (isset($search) && $search == 0) {
86 $this->_search = FALSE;
87 }
88
89 $this->_gid = $this->get('gid');
90 $this->_profileIds = $this->get('profileIds');
91
92 $gids = explode(',', CRM_Utils_Request::retrieve('gid', 'String', CRM_Core_DAO::$_nullObject, FALSE, 0, 'GET'));
93
94 if ((count($gids) > 1) && !$this->_profileIds && empty($this->_profileIds)) {
95 if (!empty($gids)) {
96 foreach ($gids as $pfId) {
97 $this->_profileIds[] = CRM_Utils_Type::escape($pfId, 'Positive');
98 }
99 }
100
101 // check if we are rendering mixed profiles
102 if (CRM_Core_BAO_UFGroup::checkForMixProfiles($this->_profileIds)) {
103 CRM_Core_Error::fatal(ts('You cannot combine profiles of multiple types.'));
104 }
105
106 $this->_gid = $this->_profileIds[0];
107 $this->set('profileIds', $this->_profileIds);
108 $this->set('gid', $this->_gid);
109 }
110
111 if (!$this->_gid) {
112 $this->_gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE, 0, 'GET');
113 }
114
115 if (empty($this->_profileIds)) {
116 $gids = $this->_gid;
117 }
118 else {
119 $gids = $this->_profileIds;
120 }
121
122 $this->_fields = CRM_Core_BAO_UFGroup::getListingFields(CRM_Core_Action::UPDATE,
123 CRM_Core_BAO_UFGroup::PUBLIC_VISIBILITY | CRM_Core_BAO_UFGroup::LISTINGS_VISIBILITY,
124 FALSE, $gids, FALSE, 'Profile',
125 CRM_Core_Permission::SEARCH
126 );
127
128 $this->_customFields = CRM_Core_BAO_CustomField::getFieldsForImport(NULL, FALSE, FALSE, FALSE, TRUE, TRUE);
be2fb01f 129 $this->_params = [];
6a488035 130
be2fb01f 131 $resetArray = [
353ffa53
TO
132 'group',
133 'tag',
134 'preferred_communication_method',
135 'do_not_phone',
136 'do_not_email',
137 'do_not_mail',
138 'do_not_sms',
139 'do_not_trade',
140 'gender',
be2fb01f 141 ];
6a488035
TO
142
143 foreach ($this->_fields as $name => $field) {
8cc574cf 144 if ((substr($name, 0, 6) == 'custom') && !empty($field['is_search_range'])) {
3130209f
CW
145 $from = CRM_Utils_Request::retrieve($name . '_from', 'String', $this);
146 $to = CRM_Utils_Request::retrieve($name . '_to', 'String', $this);
be2fb01f 147 $value = [];
6a488035 148 if ($from && $to) {
2c30b3f4 149 $value[$name . '_from'] = $from;
150 $value[$name . '_to'] = $to;
6a488035
TO
151 }
152 elseif ($from) {
2c30b3f4 153 $value[$name . '_from'] = $from;
6a488035
TO
154 }
155 elseif ($to) {
2c30b3f4 156 $value[$name . '_to'] = $to;
6a488035
TO
157 }
158 }
159 elseif ((substr($name, 0, 7) == 'custom_') &&
160 (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField',
161 substr($name, 7), 'html_type'
162 ) == 'TextArea')
163 ) {
164 $value = trim(CRM_Utils_Request::retrieve($name, 'String',
353ffa53
TO
165 $this, FALSE, NULL, 'REQUEST'
166 ));
6a488035
TO
167 if (!empty($value) &&
168 !((substr($value, 0, 1) == '%') &&
169 (substr($value, -1, 1) == '%')
170 )
171 ) {
172 $value = '%' . $value . '%';
173 }
174 }
175 elseif (CRM_Utils_Array::value('html_type', $field) == 'Multi-Select State/Province'
176 || CRM_Utils_Array::value('html_type', $field) == 'Multi-Select Country'
177 ) {
178 $value = CRM_Utils_Request::retrieve($name, 'String', $this, FALSE, NULL, 'REQUEST');
179 if (!is_array($value)) {
180 $value = explode(CRM_Core_DAO::VALUE_SEPARATOR, substr($value, 1, -1));
181 }
182 }
183 elseif ($name == 'contact_sub_type') {
184 $v = CRM_Utils_Request::retrieve($name, 'String', $this, FALSE, NULL, 'REQUEST');
185 if ($v && !is_array($v)) {
186 $v = explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($v, CRM_Core_DAO::VALUE_SEPARATOR));
187 }
188 if (!empty($v)) {
189 foreach ($v as $item) {
190 $value[$item] = 1;
191 }
192 }
193 }
194 else {
195 $value = CRM_Utils_Request::retrieve($name, 'String',
196 $this, FALSE, NULL, 'REQUEST'
197 );
198 }
199
200 if (($name == 'group' || $name == 'tag') && !empty($value) && !is_array($value)) {
201 $v = explode(',', $value);
be2fb01f 202 $value = [];
6a488035
TO
203 foreach ($v as $item) {
204 $value[$item] = 1;
205 }
206 }
207
9c1bc317 208 $customField = $this->_customFields[$name] ?? NULL;
6a488035 209
8cc574cf 210 if (!empty($_POST) && empty($_POST[$name])) {
6a488035
TO
211 if ($customField) {
212 // reset checkbox/radio because a form does not send null checkbox values
213 if (in_array($customField['html_type'],
be2fb01f 214 ['Multi-Select', 'CheckBox', 'Multi-Select State/Province', 'Multi-Select Country', 'Radio', 'Select']
353ffa53 215 )) {
abdd5e3e 216 // only reset on a POST submission if we don't see any value
6a488035
TO
217 $value = NULL;
218 $this->set($name, $value);
219 }
220 }
221 elseif (in_array($name, $resetArray)) {
222 $value = NULL;
223 $this->set($name, $value);
224 }
225 }
226
227 if (isset($value) && $value != NULL) {
228 if (!is_array($value)) {
229 $value = trim($value);
230 }
3130209f
CW
231 $operator = CRM_Utils_Request::retrieve($name . '_operator', 'String', $this);
232 if ($operator) {
233 $this->_params[$name . '_operator'] = $operator;
234 }
2c30b3f4 235 if ((substr($name, 0, 6) == 'custom') && !empty($field['is_search_range'])) {
236 $this->_params += $value;
237 }
238 else {
239 $this->_params[$name] = $this->_fields[$name]['value'] = $value;
240 }
6a488035
TO
241 }
242 }
243
244 // set the prox params
245 // need to ensure proximity searching is enabled
be2fb01f 246 $proximityVars = [
353ffa53
TO
247 'street_address',
248 'city',
249 'postal_code',
250 'state_province_id',
251 'country_id',
252 'distance',
253 'distance_unit',
be2fb01f 254 ];
6a488035
TO
255 foreach ($proximityVars as $var) {
256 $value = CRM_Utils_Request::retrieve("prox_{$var}",
257 'String',
258 $this, FALSE, NULL, 'REQUEST'
259 );
260 if ($value) {
261 $this->_params["prox_{$var}"] = $value;
262 }
263 }
264
6a488035
TO
265 // set the params in session
266 $session = CRM_Core_Session::singleton();
267 $session->set('profileParams', $this->_params);
268 }
269
270 /**
100fef9d 271 * Run this page (figure out the action needed and perform it).
6a488035 272 *
6a488035 273 */
00be9182 274 public function run() {
6a488035
TO
275 $this->preProcess();
276
277 $this->assign('recentlyViewed', FALSE);
c5c263ca
AH
278 // override later (if possible):
279 $this->assign('ufGroupName', 'unknown');
6a488035
TO
280
281 if ($this->_gid) {
282 $ufgroupDAO = new CRM_Core_DAO_UFGroup();
283 $ufgroupDAO->id = $this->_gid;
284 if (!$ufgroupDAO->find(TRUE)) {
285 CRM_Core_Error::fatal();
286 }
287 }
288
289 if ($this->_gid) {
290 // set the title of the page
291 if ($ufgroupDAO->title) {
292 CRM_Utils_System::setTitle($ufgroupDAO->title);
293 }
46312a4d
TO
294 if ($ufgroupDAO->name) {
295 $this->assign('ufGroupName', $ufgroupDAO->name);
296 }
6a488035
TO
297 }
298
299 $this->assign('isReset', TRUE);
300
301 $formController = new CRM_Core_Controller_Simple('CRM_Profile_Form_Search',
302 ts('Search Profile'),
303 CRM_Core_Action::ADD
304 );
305 $formController->setEmbedded(TRUE);
306 $formController->set('gid', $this->_gid);
307 $formController->process();
308
309 $searchError = FALSE;
310 // check if there is a POST
311 if (!empty($_POST)) {
312 if ($formController->validate() !== TRUE) {
313 $searchError = TRUE;
314 }
315 }
316
317 // also get the search tpl name
8aac22c8 318 $this->assign('searchTPL', $formController->getHookedTemplateFileName());
6a488035
TO
319
320 $this->assign('search', $this->_search);
321
322 // search if search returned a form error?
8cc574cf 323 if ((empty($_GET['reset']) || !empty($_GET['force'])) &&
6a488035
TO
324 !$searchError
325 ) {
326 $this->assign('isReset', FALSE);
327
328 $gidString = $this->_gid;
329 if (empty($this->_profileIds)) {
330 $gids = $this->_gid;
331 }
332 else {
333 $gids = $this->_profileIds;
334 $gidString = implode(',', $this->_profileIds);
335 }
336
353ffa53 337 $map = 0;
6a488035
TO
338 $linkToUF = 0;
339 $editLink = FALSE;
340 if ($this->_gid) {
353ffa53 341 $map = $ufgroupDAO->is_map;
6a488035
TO
342 $linkToUF = $ufgroupDAO->is_uf_link;
343 $editLink = $ufgroupDAO->is_edit_link;
344 }
345
346 if ($map) {
347 $this->assign('mapURL',
348 CRM_Utils_System::url('civicrm/profile/map',
349 "map=1&gid={$gidString}&reset=1"
350 )
351 );
352 }
a7488080 353 if (!empty($this->_params['group'])) {
6a488035
TO
354 foreach ($this->_params['group'] as $key => $val) {
355 if (!$val) {
356 unset($this->_params['group'][$key]);
357 }
358 }
359 }
360
361 // the selector will override this if the user does have
362 // edit permissions as determined by the mask, CRM-4341
363 // do not allow edit for anon users in joomla frontend, CRM-4668
364 $config = CRM_Core_Config::singleton();
365 if (!CRM_Core_Permission::check('access CiviCRM') ||
366 $config->userFrameworkFrontend == 1
367 ) {
368 $editLink = FALSE;
369 }
370
371 $selector = new CRM_Profile_Selector_Listings($this->_params, $this->_customFields, $gids,
372 $map, $editLink, $linkToUF
373 );
374
375 $controller = new CRM_Core_Selector_Controller($selector,
376 $this->get(CRM_Utils_Pager::PAGE_ID),
377 $this->get(CRM_Utils_Sort::SORT_ID),
378 CRM_Core_Action::VIEW,
379 $this,
380 CRM_Core_Selector_Controller::TEMPLATE
381 );
382 $controller->setEmbedded(TRUE);
383 $controller->run();
384 }
385
abdd5e3e 386 //CRM-6862 -run form controller after
6a488035
TO
387 //selector, since it erase $_POST
388 $formController->run();
389
390 return parent::run();
391 }
392
393 /**
fe482240 394 * Get the list of contacts for a profile.
6a488035 395 *
100fef9d 396 * @param int $gid
77b97be7
EM
397 *
398 * @return array
6a488035 399 */
c3c3e099 400 public static function getProfileContact($gid) {
6a488035
TO
401 $session = CRM_Core_Session::singleton();
402 $params = $session->get('profileParams');
403
be2fb01f
CW
404 $details = [];
405 $ufGroupParam = ['id' => $gid];
6a488035
TO
406 CRM_Core_BAO_UFGroup::retrieve($ufGroupParam, $details);
407
408 // make sure this group can be mapped
409 if (!$details['is_map']) {
410 CRM_Core_Error::statusBounce(ts('This profile does not have the map feature turned on.'));
411 }
412
9c1bc317 413 $groupId = $details['limit_listings_group_id'] ?? NULL;
6a488035
TO
414
415 // add group id to params if a uf group belong to a any group
416 if ($groupId) {
a7488080 417 if (!empty($params['group'])) {
6a488035
TO
418 $params['group'][$groupId] = 1;
419 }
420 else {
be2fb01f 421 $params['group'] = [$groupId => 1];
6a488035
TO
422 }
423 }
424
425 $fields = CRM_Core_BAO_UFGroup::getListingFields(
426 CRM_Core_Action::VIEW,
427 CRM_Core_BAO_UFGroup::PUBLIC_VISIBILITY | CRM_Core_BAO_UFGroup::LISTINGS_VISIBILITY,
428 FALSE,
429 $gid
430 );
431
432 $returnProperties = CRM_Contact_BAO_Contact::makeHierReturnProperties($fields);
433 $returnProperties['contact_type'] = 1;
434 $returnProperties['sort_name'] = 1;
435
436 $queryParams = CRM_Contact_BAO_Query::convertFormValues($params, 1);
437 $query = new CRM_Contact_BAO_Query($queryParams, $returnProperties, $fields);
438
439 $additionalWhereClause = 'contact_a.is_deleted = 0';
440
441 $ids = $query->searchQuery(0, 0, NULL,
442 FALSE, FALSE, FALSE,
443 TRUE, FALSE,
444 $additionalWhereClause
445 );
446
447 $contactIds = explode(',', $ids);
448
449 return $contactIds;
450 }
451
ffd93213
EM
452 /**
453 * @param string $suffix
454 *
455 * @return null|string
456 */
00be9182 457 public function checkTemplateFileExists($suffix = '') {
6a488035
TO
458 if ($this->_gid) {
459 $templateFile = "CRM/Profile/Page/{$this->_gid}/Listings.{$suffix}tpl";
460 $template = CRM_Core_Page::getTemplate();
461 if ($template->template_exists($templateFile)) {
462 return $templateFile;
463 }
464
465 // lets see if we have customized by name
466 $ufGroupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_gid, 'name');
467 if ($ufGroupName) {
468 $templateFile = "CRM/Profile/Page/{$ufGroupName}/Listings.{$suffix}tpl";
469 if ($template->template_exists($templateFile)) {
470 return $templateFile;
471 }
472 }
473 }
474 return NULL;
475 }
476
ffd93213 477 /**
fe482240 478 * Use the form name to create the tpl file name.
ffd93213
EM
479 *
480 * @return string
ffd93213 481 */
00be9182 482 public function getTemplateFileName() {
6a488035
TO
483 $fileName = $this->checkTemplateFileExists();
484 return $fileName ? $fileName : parent::getTemplateFileName();
485 }
486
ffd93213
EM
487 /**
488 * Default extra tpl file basically just replaces .tpl with .extra.tpl
489 * i.e. we dont override
490 *
491 * @return string
ffd93213 492 */
00be9182 493 public function overrideExtraTemplateFileName() {
6a488035
TO
494 $fileName = $this->checkTemplateFileExists('extra.');
495 return $fileName ? $fileName : parent::overrideExtraTemplateFileName();
496 }
96025800 497
6a488035 498}