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