Merge pull request #6553 from sudhabisht/C12658
[civicrm-core.git] / CRM / Mailing / Form / Group.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
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
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * Choose include / exclude groups and mailings
38 *
39 */
40class CRM_Mailing_Form_Group extends CRM_Contact_Form_Task {
41
42 /**
fe482240 43 * The mailing ID of the mailing if we are resuming a mailing.
6a488035
TO
44 *
45 * @var integer
46 */
47 protected $_mailingID;
48
49 /**
fe482240 50 * Set variables up before form is built.
6a488035
TO
51 *
52 * @return void
6a488035
TO
53 */
54 public function preProcess() {
55 if (CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG") {
353ffa53
TO
56 CRM_Core_Error::fatal(ts('The <a href="%1">default mailbox</a> has not been configured. You will find <a href="%2">more info in our online user and administrator guide.</a>', array(
57 1 => CRM_Utils_System::url('civicrm/admin/mailSettings', 'reset=1'),
79d7553f 58 2 => "http://book.civicrm.org/user/advanced-configuration/email-system-configuration/",
353ffa53 59 )));
6a488035
TO
60 }
61
62 $this->_mailingID = CRM_Utils_Request::retrieve('mid', 'Integer', $this, FALSE, NULL);
63
64 // when user come from search context.
65 $this->_searchBasedMailing = CRM_Contact_Form_Search::isSearchContext($this->get('context'));
66 if ($this->_searchBasedMailing) {
67 $searchParams = $this->controller->exportValues();
68 // number of records that were selected - All or Few.
69 $this->_resultSelectOption = $searchParams['radio_ts'];
70 if (CRM_Utils_Array::value('task', $searchParams) == 20) {
71 parent::preProcess();
72 }
73 }
74
75 $session = CRM_Core_Session::singleton();
76 if ($this->_searchBasedMailing) {
77 $config = CRM_Core_Config::singleton();
78 $path = CRM_Utils_Array::value($config->userFrameworkURLVar, $_GET);
79 $qfKey = CRM_Utils_Array::value('qfKey', $_GET);
80 if ($qfKey) {
81 $session->pushUserContext(CRM_Utils_System::url($path, "qfKey=$qfKey"));
82 }
83 else {
84 $session->pushUserContext(CRM_Utils_System::url('civicrm/mailing', 'reset=1'));
85 }
86 }
87 elseif (strpos($session->readUserContext(), 'civicrm/mailing') === FALSE) {
88 // use previous context unless mailing is not schedule, CRM-4290
89 $session->pushUserContext(CRM_Utils_System::url('civicrm/mailing', 'reset=1'));
90 }
91 }
92
93 /**
c490a46a 94 * Set default values for the form.
6a488035
TO
95 * the default values are retrieved from the database
96 *
6a488035 97 *
355ba699 98 * @return void
6a488035 99 */
00be9182 100 public function setDefaultValues() {
6a488035
TO
101 $continue = CRM_Utils_Request::retrieve('continue', 'String', $this, FALSE, NULL);
102
103 $defaults = array();
9d76357a
DG
104 $defaults['dedupe_email'] = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
105 'dedupe_email_default', NULL, FALSE
106 );
6a488035
TO
107 if ($this->_mailingID) {
108 // check that the user has permission to access mailing id
109 CRM_Mailing_BAO_Mailing::checkPermission($this->_mailingID);
110
111 $mailing = new CRM_Mailing_DAO_Mailing();
112 $mailing->id = $this->_mailingID;
113 $mailing->addSelect('name', 'campaign_id');
114 $mailing->find(TRUE);
115
116 $defaults['name'] = $mailing->name;
117 if (!$continue) {
118 $defaults['name'] = ts('Copy of %1', array(1 => $mailing->name));
119 }
120 else {
121 // CRM-7590, reuse same mailing ID if we are continuing
122 $this->set('mailing_id', $this->_mailingID);
123 }
124
125 $defaults['campaign_id'] = $mailing->campaign_id;
126 $defaults['dedupe_email'] = $mailing->dedupe_email;
bac4cd35 127 $defaults['location_type_id'] = $mailing->location_type_id;
128 $defaults['email_selection_method'] = $mailing->email_selection_method;
6a488035 129
04124b30 130 $dao = new CRM_Mailing_DAO_MailingGroup();
6a488035
TO
131
132 $mailingGroups = array(
35f7561f 133 'civicrm_group' => array(),
21dfd5f5 134 'civicrm_mailing' => array(),
6a488035
TO
135 );
136 $dao->mailing_id = $this->_mailingID;
137 $dao->find();
138 while ($dao->fetch()) {
139 // account for multi-lingual
140 // CRM-11431
141 $entityTable = 'civicrm_group';
142 if (substr($dao->entity_table, 0, 15) == 'civicrm_mailing') {
143 $entityTable = 'civicrm_mailing';
144 }
145 $mailingGroups[$entityTable][$dao->group_type][] = $dao->entity_id;
146 }
147
92d6bfcf 148 $defaults['includeGroups'] = CRM_Utils_Array::value('Include', $mailingGroups['civicrm_group']);
149 $defaults['excludeGroups'] = CRM_Utils_Array::value('Exclude', $mailingGroups['civicrm_group']);
6a488035
TO
150
151 if (!empty($mailingGroups['civicrm_mailing'])) {
92d6bfcf 152 $defaults['includeMailings'] = CRM_Utils_Array::value('Include', $mailingGroups['civicrm_mailing']);
153 $defaults['excludeMailings'] = CRM_Utils_Array::value('Exclude', $mailingGroups['civicrm_mailing']);
6a488035
TO
154 }
155 }
156
157 //when the context is search hide the mailing recipients.
158 $showHide = new CRM_Core_ShowHideBlocks();
159 $showGroupSelector = TRUE;
160 if ($this->_searchBasedMailing) {
161 $showGroupSelector = FALSE;
353ffa53
TO
162 $formElements = array('includeGroups', 'excludeGroups', 'includeMailings', 'excludeMailings');
163 $formValues = $this->controller->exportValues($this->_name);
6a488035
TO
164 foreach ($formElements as $element) {
165 if (!empty($formValues[$element])) {
166 $showGroupSelector = TRUE;
167 break;
168 }
169 }
170 }
171
172 if ($showGroupSelector) {
173 $showHide->addShow("id-additional");
174 $showHide->addHide("id-additional-show");
175 }
176 else {
177 $showHide->addShow("id-additional-show");
178 $showHide->addHide("id-additional");
179 }
180 $showHide->addToTemplate();
181
182 return $defaults;
183 }
184
185 /**
fe482240 186 * Build the form object.
6a488035 187 *
355ba699 188 * @return void
6a488035
TO
189 */
190 public function buildQuickForm() {
191
192 //get the context
193 $context = $this->get('context');
194 if ($this->_searchBasedMailing) {
195 $context = 'search';
196 }
197 $this->assign('context', $context);
198
199 $this->add('text', 'name', ts('Name Your Mailing'),
200 CRM_Core_DAO::getAttribute('CRM_Mailing_DAO_Mailing', 'name'),
201 TRUE
202 );
203
204 $hiddenMailingGroup = NULL;
205 $campaignId = NULL;
206
207 //CRM-7362 --add campaigns.
208 if ($this->_mailingID) {
209 $campaignId = CRM_Core_DAO::getFieldValue('CRM_Mailing_DAO_Mailing', $this->_mailingID, 'campaign_id');
210 $hiddenMailingGroup = CRM_Mailing_BAO_Mailing::hiddenMailingGroup($this->_mailingID);
211 }
212 CRM_Campaign_BAO_Campaign::addCampaign($this, $campaignId);
213
214 //dedupe on email option
215 $this->addElement('checkbox', 'dedupe_email', ts('Remove duplicate emails?'));
216
bac4cd35 217 // location types
218 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id', array('id' => 'display_name'));
f008d1d2 219 $this->addElement('select', 'location_type_id', ts("Location Type"), array('' => ts('Automatic')) + $locationTypes);
bac4cd35 220
221 $methods = CRM_Core_SelectValues::emailSelectMethods();
222 $this->addElement('select', 'email_selection_method', ts("Email Selection Method"), $methods);
223
6a488035 224 //get the mailing groups.
24431f7b 225 $groups = CRM_Core_PseudoConstant::nestedGroup('Mailing');
6a488035 226 if ($hiddenMailingGroup) {
79d7553f 227 $groups[$hiddenMailingGroup]
228 = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $hiddenMailingGroup, 'title');
6a488035
TO
229 }
230
231 $mailings = CRM_Mailing_PseudoConstant::completed();
232 if (!$mailings) {
233 $mailings = array();
234 }
235
236 // run the groups through a hook so users can trim it if needed
237 CRM_Utils_Hook::mailingGroups($this, $groups, $mailings);
238
239 //when the context is search add base group's.
240 if ($this->_searchBasedMailing) {
954eaf87
SL
241 //CRM-16600 Include Smart Groups in Unsubscribe list as that matches
242 //all other practices in CiviMail
6a488035
TO
243 $this->add('select', 'baseGroup',
244 ts('Unsubscription Group'),
245 array(
79d7553f 246 '' => ts('- select -'),
954eaf87 247 ) + $groups,
3e8871b9
CW
248 TRUE,
249 array('class' => 'crm-select2 huge')
6a488035
TO
250 );
251 }
252
1e5616ba
CW
253 $select2style = array(
254 'multiple' => TRUE,
255 'style' => 'width: 100%; max-width: 60em;',
256 'class' => 'crm-select2',
257 'placeholder' => ts('- select -'),
6a488035
TO
258 );
259
1e5616ba
CW
260 $this->add('select', 'includeGroups',
261 ts('Include Group(s)'),
6a488035 262 $groups,
1e5616ba
CW
263 !$this->_searchBasedMailing,
264 $select2style
6a488035
TO
265 );
266
1e5616ba
CW
267 $this->add('select', 'excludeGroups',
268 ts('Exclude Group(s)'),
269 $groups,
270 FALSE,
271 $select2style
272 );
6a488035 273
1e5616ba 274 $this->add('select', 'includeMailings',
6a488035
TO
275 ts('INCLUDE Recipients of These Mailing(s)') . ' ',
276 $mailings,
1e5616ba
CW
277 FALSE,
278 $select2style
6a488035 279 );
1e5616ba 280 $this->add('select', 'excludeMailings',
6a488035
TO
281 ts('EXCLUDE Recipients of These Mailing(s)') . ' ',
282 $mailings,
1e5616ba
CW
283 FALSE,
284 $select2style
6a488035
TO
285 );
286
6a488035
TO
287 $this->addFormRule(array('CRM_Mailing_Form_Group', 'formRule'));
288
289 $buttons = array(
35f7561f 290 array(
f212d37d
CW
291 'type' => 'next',
292 'name' => ts('Next'),
6a488035
TO
293 'spacing' => '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;',
294 'isDefault' => TRUE,
295 ),
296 array(
297 'type' => 'submit',
298 'name' => ts('Save & Continue Later'),
299 ),
300 array(
301 'type' => 'cancel',
302 'name' => ts('Cancel'),
303 ),
304 );
305
306 $this->addButtons($buttons);
307
308 $this->assign('groupCount', count($groups));
309 $this->assign('mailingCount', count($mailings));
22e263ad 310 if (count($groups) == 0 && count($mailings) == 0 && !$this->_searchBasedMailing) {
f598ae72
E
311 CRM_Core_Error::statusBounce("To send a mailing, you must have a valid group of recipients - either at least one group that's a Mailing List or at least one previous mailing or start from a search");
312 }
6a488035
TO
313 }
314
315 public function postProcess() {
316 $values = $this->controller->exportValues($this->_name);
317
318 //build hidden smart group. when user want to send mailing
319 //through search contact-> more action -> send Mailing. CRM-3711
320 $groups = array();
321 if ($this->_searchBasedMailing && $this->_contactIds) {
322 $session = CRM_Core_Session::singleton();
323
324 if ($this->_resultSelectOption == 'ts_sel') {
325 // create a static grp if only a subset of result set was selected:
326
353ffa53 327 $randID = md5(time());
6a488035 328 $grpTitle = "Hidden Group {$randID}";
353ffa53 329 $grpID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $grpTitle, 'id', 'title');
6a488035
TO
330
331 if (!$grpID) {
332 $groupParams = array(
333 'title' => $grpTitle,
334 'is_active' => 1,
335 'is_hidden' => 1,
336 'group_type' => array('2' => 1),
337 );
338
339 $group = CRM_Contact_BAO_Group::create($groupParams);
340 $grpID = $group->id;
341
342 CRM_Contact_BAO_GroupContact::addContactsToGroup($this->_contactIds, $group->id);
343
344 $newGroupTitle = "Hidden Group {$grpID}";
345 $groupParams = array(
353ffa53
TO
346 'id' => $grpID,
347 'name' => CRM_Utils_String::titleToVar($newGroupTitle),
6a488035
TO
348 'title' => $newGroupTitle,
349 'group_type' => array('2' => 1),
350 );
351 $group = CRM_Contact_BAO_Group::create($groupParams);
352 }
353
354 // note at this point its a static group
355 $smartGroupId = $grpID;
356 }
357 else {
358 //get the hidden smart group id.
359 $ssId = $this->get('ssID');
35f7561f 360 $hiddenSmartParams = array(
353ffa53 361 'group_type' => array('2' => 1),
6a488035
TO
362 'form_values' => $this->get('formValues'),
363 'saved_search_id' => $ssId,
364 'search_custom_id' => $this->get('customSearchID'),
365 'search_context' => $this->get('context'),
366 );
367
368 list($smartGroupId, $savedSearchId) = CRM_Contact_BAO_Group::createHiddenSmartGroup($hiddenSmartParams);
369
370 //set the saved search id.
371 if (!$ssId) {
372 if ($savedSearchId) {
373 $this->set('ssID', $savedSearchId);
374 }
375 else {
376 CRM_Core_Error::fatal();
377 }
378 }
379 }
380
381 //get the base group for this mailing, CRM-3711
382 $groups['base'] = array($values['baseGroup']);
383 $values['includeGroups'][] = $smartGroupId;
384 }
385
386 foreach (
353ffa53
TO
387 array(
388 'name',
389 'group_id',
390 'search_id',
391 'search_args',
392 'campaign_id',
393 'dedupe_email',
394 'location_type_id',
79d7553f 395 'email_selection_method',
353ffa53 396 ) as $n
6a488035 397 ) {
a7488080 398 if (!empty($values[$n])) {
6a488035
TO
399 $params[$n] = $values[$n];
400 }
401 }
402
6a488035
TO
403 $qf_Group_submit = $this->controller->exportValue($this->_name, '_qf_Group_submit');
404 $this->set('name', $params['name']);
405
353ffa53
TO
406 $inGroups = $values['includeGroups'];
407 $outGroups = $values['excludeGroups'];
408 $inMailings = $values['includeMailings'];
6a488035
TO
409 $outMailings = $values['excludeMailings'];
410
411 if (is_array($inGroups)) {
412 foreach ($inGroups as $key => $id) {
413 if ($id) {
414 $groups['include'][] = $id;
415 }
416 }
417 }
418 if (is_array($outGroups)) {
419 foreach ($outGroups as $key => $id) {
420 if ($id) {
421 $groups['exclude'][] = $id;
422 }
423 }
424 }
425
426 $mailings = array();
427 if (is_array($inMailings)) {
428 foreach ($inMailings as $key => $id) {
429 if ($id) {
430 $mailings['include'][] = $id;
431 }
432 }
433 }
434 if (is_array($outMailings)) {
435 foreach ($outMailings as $key => $id) {
436 if ($id) {
437 $mailings['exclude'][] = $id;
438 }
439 }
440 }
441
353ffa53
TO
442 $session = CRM_Core_Session::singleton();
443 $params['groups'] = $groups;
6a488035
TO
444 $params['mailings'] = $mailings;
445 $ids = array();
446 if ($this->get('mailing_id')) {
447
448 // don't create a new mailing if already exists
449 $ids['mailing_id'] = $this->get('mailing_id');
450
451 $groupTableName = CRM_Contact_BAO_Group::getTableName();
452 $mailingTableName = CRM_Mailing_BAO_Mailing::getTableName();
453
454 // delete previous includes/excludes, if mailing already existed
455 foreach (array('groups', 'mailings') as $entity) {
353ffa53
TO
456 $mg = new CRM_Mailing_DAO_MailingGroup();
457 $mg->mailing_id = $ids['mailing_id'];
6a488035
TO
458 $mg->entity_table = ($entity == 'groups') ? $groupTableName : $mailingTableName;
459 $mg->find();
460 while ($mg->fetch()) {
461 $mg->delete();
462 }
463 }
464 }
465 else {
466 // new mailing, so lets set the created_id
467 $session = CRM_Core_Session::singleton();
468 $params['created_id'] = $session->get('userID');
469 $params['created_date'] = date('YmdHis');
470 }
6a488035
TO
471 $mailing = CRM_Mailing_BAO_Mailing::create($params, $ids);
472 $this->set('mailing_id', $mailing->id);
473
474 $dedupeEmail = FALSE;
475 if (isset($params['dedupe_email'])) {
476 $dedupeEmail = $params['dedupe_email'];
477 }
478
1365ea2f
BS
479 // mailing id should be added to the form object
480 $this->_mailingID = $mailing->id;
481
6a488035
TO
482 // also compute the recipients and store them in the mailing recipients table
483 CRM_Mailing_BAO_Mailing::getRecipients(
484 $mailing->id,
485 $mailing->id,
6a488035
TO
486 TRUE,
487 $dedupeEmail
488 );
489
490 $count = CRM_Mailing_BAO_Recipients::mailingSize($mailing->id);
491 $this->set('count', $count);
492 $this->assign('count', $count);
493 $this->set('groups', $groups);
494 $this->set('mailings', $mailings);
495
496 if ($qf_Group_submit) {
497 //when user perform mailing from search context
498 //redirect it to search result CRM-3711.
499 $ssID = $this->get('ssID');
500 $context = $this->get('context');
501 if ($ssID && $this->_searchBasedMailing) {
502 if ($this->_action == CRM_Core_Action::BASIC) {
503 $fragment = 'search';
504 }
505 elseif ($this->_action == CRM_Core_Action::PROFILE) {
506 $fragment = 'search/builder';
507 }
508 elseif ($this->_action == CRM_Core_Action::ADVANCED) {
509 $fragment = 'search/advanced';
510 }
511 else {
512 $fragment = 'search/custom';
513 }
514
515 $context = $this->get('context');
516 if (!CRM_Contact_Form_Search::isSearchContext($context)) {
517 $context = 'search';
518 }
519 $urlParams = "force=1&reset=1&ssID={$ssID}&context={$context}";
520
521 $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
522 if (CRM_Utils_Rule::qfKey($qfKey)) {
523 $urlParams .= "&qfKey=$qfKey";
524 }
525
526 $draftURL = CRM_Utils_System::url('civicrm/mailing/browse/unscheduled', 'scheduled=false&reset=1');
527 $status = ts("You can continue later by clicking the 'Continue' action to resume working on it.<br />From <a href='%1'>Draft and Unscheduled Mailings</a>.", array(1 => $draftURL));
528
529 // Redirect user to search.
530 $url = CRM_Utils_System::url('civicrm/contact/' . $fragment, $urlParams);
531 }
532 else {
533 $status = ts("Click the 'Continue' action to resume working on it.");
534 $url = CRM_Utils_System::url('civicrm/mailing/browse/unscheduled', 'scheduled=false&reset=1');
535 }
536 CRM_Core_Session::setStatus($status, ts('Mailing Saved'), 'success');
537 return $this->controller->setDestination($url);
538 }
539 }
540
541 /**
fe482240 542 * Display Name of the form.
6a488035 543 *
6a488035
TO
544 *
545 * @return string
546 */
547 public function getTitle() {
548 return ts('Select Recipients');
549 }
550
551 /**
fe482240 552 * Global validation rules for the form.
6a488035 553 *
90c8230e
TO
554 * @param array $fields
555 * Posted values of the form.
6a488035 556 *
a6c01b45
CW
557 * @return array
558 * list of errors to be posted back to the form
6a488035 559 */
00be9182 560 public static function formRule($fields) {
6a488035
TO
561 $errors = array();
562 if (isset($fields['includeGroups']) &&
563 is_array($fields['includeGroups']) &&
564 isset($fields['excludeGroups']) &&
565 is_array($fields['excludeGroups'])
566 ) {
567 $checkGroups = array();
568 $checkGroups = array_intersect($fields['includeGroups'], $fields['excludeGroups']);
569 if (!empty($checkGroups)) {
570 $errors['excludeGroups'] = ts('Cannot have same groups in Include Group(s) and Exclude Group(s).');
571 }
572 }
573
574 if (isset($fields['includeMailings']) &&
575 is_array($fields['includeMailings']) &&
576 isset($fields['excludeMailings']) &&
577 is_array($fields['excludeMailings'])
578 ) {
579 $checkMailings = array();
580 $checkMailings = array_intersect($fields['includeMailings'], $fields['excludeMailings']);
581 if (!empty($checkMailings)) {
582 $errors['excludeMailings'] = ts('Cannot have same mail in Include mailing(s) and Exclude mailing(s).');
583 }
584 }
585
586 if (!empty($fields['search_id']) &&
587 empty($fields['group_id'])
588 ) {
589 $errors['group_id'] = ts('You must select a group to filter on');
590 }
591
592 if (empty($fields['search_id']) &&
593 !empty($fields['group_id'])
594 ) {
595 $errors['search_id'] = ts('You must select a search to filter');
596 }
597
bac4cd35 598 if (!empty($fields['location_type_id'])) {
599 if ($fields['email_selection_method'] == 'automatic') {
600 $errors['location_type_id'] = ts("If 'Email Selection Method' is automatic, you are not allowed to choose any 'Location Type'");
601 }
602 }
603 elseif ($fields['email_selection_method'] != 'automatic') {
604 $errors['email_selection_method'] = ts("If 'Location Type' is not selected, you must set the 'Email Selection Method' to automatic as well.");
605 }
606
6a488035
TO
607 return empty($errors) ? TRUE : $errors;
608 }
96025800 609
6a488035 610}