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