Merge pull request #4607 from samuelsov/CRM-15637
[civicrm-core.git] / CRM / Campaign / BAO / Campaign.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 Class CRM_Campaign_BAO_Campaign extends CRM_Campaign_DAO_Campaign {
36
37 /**
38 * Takes an associative array and creates a campaign object
39 *
40 * the function extract all the params it needs to initialize the create a
41 * contact object. the params array could contain additional unused name/value
42 * pairs
43 *
44 * @param array $params (reference ) an assoc array of name/value pairs
45 *
46 * @return CRM_Campaign_DAO_Campaign object
47 * @static
48 */
49 public static function create(&$params) {
50 if (empty($params)) {
51 return;
52 }
53
54 if (!(CRM_Utils_Array::value('id', $params))) {
55
56 if (!(CRM_Utils_Array::value('created_id', $params))) {
57 $session = CRM_Core_Session::singleton();
58 $params['created_id'] = $session->get('userID');
59 }
60
61 if (!(CRM_Utils_Array::value('created_date', $params))) {
62 $params['created_date'] = date('YmdHis');
63 }
64
65 if (!(CRM_Utils_Array::value('name', $params))) {
66 $params['name'] = CRM_Utils_String::titleToVar($params['title'], 64);
67 }
68 }
69
70 $campaign = new CRM_Campaign_DAO_Campaign();
71 $campaign->copyValues($params);
72 $campaign->save();
73
74 /* Create the campaign group record */
75
76 $groupTableName = CRM_Contact_BAO_Group::getTableName();
77
78 if (isset($params['groups']) && !empty($params['groups']['include']) && is_array($params['groups']['include'])) {
79 foreach ($params['groups']['include'] as $entityId) {
80 $dao = new CRM_Campaign_DAO_CampaignGroup();
81 $dao->campaign_id = $campaign->id;
82 $dao->entity_table = $groupTableName;
83 $dao->entity_id = $entityId;
84 $dao->group_type = 'Include';
85 $dao->save();
86 $dao->free();
87 }
88 }
89
90 //store custom data
91 if (!empty($params['custom']) &&
92 is_array($params['custom'])
93 ) {
94 CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_campaign', $campaign->id);
95 }
96
97 return $campaign;
98 }
99
100 /**
101 * Delete the campaign
102 *
103 * @param int $id id of the campaign
104 *
105 * @return bool|mixed
106 */
107 public static function del($id) {
108 if (!$id) {
109 return FALSE;
110 }
111 $dao = new CRM_Campaign_DAO_Campaign();
112 $dao->id = $id;
113 return $dao->delete();
114 }
115
116 /**
117 * Takes a bunch of params that are needed to match certain criteria and
118 * retrieves the relevant objects. Typically the valid params are only
119 * campaign_id.
120 *
121 * @param array $params (reference ) an assoc array of name/value pairs
122 * @param array $defaults (reference ) an assoc array to hold the flattened values
123 *
124 * @return \CRM_Campaign_DAO_Campaign|null
125 */
126 public function retrieve(&$params, &$defaults) {
127 $campaign = new CRM_Campaign_DAO_Campaign();
128
129 $campaign->copyValues($params);
130
131 if ($campaign->find(TRUE)) {
132 CRM_Core_DAO::storeValues($campaign, $defaults);
133 return $campaign;
134 }
135 return NULL;
136 }
137
138 /**
139 * Return the all eligible campaigns w/ cache.
140 *
141 * @param int $includeId lets inlcude this campaign by force.
142 * @param int $excludeId do not include this campaign.
143 * @param boolean $onlyActive consider only active campaigns.
144 *
145 * @param bool $onlyCurrent
146 * @param bool $appendDatesToTitle
147 * @param bool $forceAll
148 *
149 * @return mixed $campaigns a set of campaigns.@access public
150 */
151 public static function getCampaigns(
152 $includeId = NULL,
153 $excludeId = NULL,
154 $onlyActive = TRUE,
155 $onlyCurrent = TRUE,
156 $appendDatesToTitle = FALSE,
157 $forceAll = FALSE
158 ) {
159 static $campaigns;
160 $cacheKey = 0;
161 $cacheKeyParams = array(
162 'includeId', 'excludeId', 'onlyActive',
163 'onlyCurrent', 'appendDatesToTitle', 'forceAll',
164 );
165 foreach ($cacheKeyParams as $param) {
166 $cacheParam = $$param;
167 if (!$cacheParam) {
168 $cacheParam = 0;
169 }
170 $cacheKey .= '_' . $cacheParam;
171 }
172
173 if (!isset($campaigns[$cacheKey])) {
174 $where = array('( camp.title IS NOT NULL )');
175 if ($excludeId) {
176 $where[] = "( camp.id != $excludeId )";
177 }
178 if ($onlyActive) {
179 $where[] = '( camp.is_active = 1 )';
180 }
181 if ($onlyCurrent) {
182 $where[] = '( camp.end_date IS NULL OR camp.end_date >= NOW() )';
183 }
184 $whereClause = implode(' AND ', $where);
185 if ($includeId) {
186 $whereClause .= " OR ( camp.id = $includeId )";
187 }
188
189 //lets force all.
190 if ($forceAll) {
191 $whereClause = '( 1 )';
192 }
193
194 $query = "
195 SELECT camp.id,
196 camp.title,
197 camp.start_date,
198 camp.end_date
199 FROM civicrm_campaign camp
200 WHERE {$whereClause}
201 Order By camp.title";
202
203 $campaign = CRM_Core_DAO::executeQuery($query);
204 $campaigns[$cacheKey] = array();
205 $config = CRM_Core_Config::singleton();
206
207 while ($campaign->fetch()) {
208 $title = $campaign->title;
209 if ($appendDatesToTitle) {
210 $dates = array();
211 foreach (array('start_date', 'end_date') as $date) {
212 if ($campaign->$date) {
213 $dates[] = CRM_Utils_Date::customFormat($campaign->$date, $config->dateformatFull);
214 }
215 }
216 if (!empty($dates)) {
217 $title .= ' (' . implode('-', $dates) . ')';
218 }
219 }
220 $campaigns[$cacheKey][$campaign->id] = $title;
221 }
222 }
223
224 return $campaigns[$cacheKey];
225 }
226
227 /**
228 * Wrapper to self::getCampaigns( )
229 * w/ permissions and component check.
230 *
231 */
232 public static function getPermissionedCampaigns($includeId = NULL,
233 $excludeId = NULL,
234 $onlyActive = TRUE,
235 $onlyCurrent = TRUE,
236 $appendDatesToTitle = FALSE,
237 $forceAll = FALSE,
238 $doCheckForComponent = TRUE,
239 $doCheckForPermissions = TRUE
240 ) {
241 $cacheKey = 0;
242 $cachekeyParams = array(
243 'includeId', 'excludeId', 'onlyActive', 'onlyCurrent',
244 'appendDatesToTitle', 'doCheckForComponent', 'doCheckForPermissions', 'forceAll',
245 );
246 foreach ($cachekeyParams as $param) {
247 $cacheKeyParam = $$param;
248 if (!$cacheKeyParam) {
249 $cacheKeyParam = 0;
250 }
251 $cacheKey .= '_' . $cacheKeyParam;
252 }
253
254 static $validCampaigns;
255 if (!isset($validCampaigns[$cacheKey])) {
256 $isValid = TRUE;
257 $campaigns = array('campaigns' => array(),
258 'hasAccessCampaign' => FALSE,
259 'isCampaignEnabled' => FALSE,
260 );
261
262 //do check for component.
263 if ($doCheckForComponent) {
264 $campaigns['isCampaignEnabled'] = $isValid = self::isCampaignEnable();
265 }
266
267 //do check for permissions.
268 if ($doCheckForPermissions) {
269 $campaigns['hasAccessCampaign'] = $isValid = self::accessCampaign();
270 }
271
272 //finally retrieve campaigns from db.
273 if ($isValid) {
274 $campaigns['campaigns'] = self::getCampaigns($includeId,
275 $excludeId,
276 $onlyActive,
277 $onlyCurrent,
278 $appendDatesToTitle,
279 $forceAll
280 );
281 }
282
283 //store in cache.
284 $validCampaigns[$cacheKey] = $campaigns;
285 }
286
287 return $validCampaigns[$cacheKey];
288 }
289
290 /**
291 * Is CiviCampaign enabled.
292 * @return bool
293 */
294 public static function isCampaignEnable() {
295 static $isEnable = NULL;
296
297 if (!isset($isEnable)) {
298 $isEnable = FALSE;
299 $config = CRM_Core_Config::singleton();
300 if (in_array('CiviCampaign', $config->enableComponents)) {
301 $isEnable = TRUE;
302 }
303 }
304
305 return $isEnable;
306 }
307
308 /**
309 * Retrieve campaigns for dashboard.
310 *
311 * @static
312 */
313 public static function getCampaignSummary($params = array(), $onlyCount = FALSE) {
314 $campaigns = array();
315
316 //build the limit and order clause.
317 $limitClause = $orderByClause = $lookupTableJoins = NULL;
318 if (!$onlyCount) {
319 $sortParams = array(
320 'sort' => 'start_date',
321 'offset' => 0,
322 'rowCount' => 10,
323 'sortOrder' => 'desc',
324 );
325 foreach ($sortParams as $name => $default) {
326 if (!empty($params[$name])) {
327 $sortParams[$name] = $params[$name];
328 }
329 }
330
331
332 //need to lookup tables.
333 $orderOnCampaignTable = TRUE;
334 if ($sortParams['sort'] == 'status') {
335 $orderOnCampaignTable = FALSE;
336 $lookupTableJoins = "
337 LEFT JOIN civicrm_option_value status ON ( status.value = campaign.status_id OR campaign.status_id IS NULL )
338 INNER JOIN civicrm_option_group grp ON ( status.option_group_id = grp.id AND grp.name = 'campaign_status' )";
339 $orderByClause = "ORDER BY status.label {$sortParams['sortOrder']}";
340 }
341 elseif ($sortParams['sort'] == 'campaign_type') {
342 $orderOnCampaignTable = FALSE;
343 $lookupTableJoins = "
344 LEFT JOIN civicrm_option_value campaign_type ON ( campaign_type.value = campaign.campaign_type_id
345 OR campaign.campaign_type_id IS NULL )
346 INNER JOIN civicrm_option_group grp ON ( campaign_type.option_group_id = grp.id AND grp.name = 'campaign_type' )";
347 $orderByClause = "ORDER BY campaign_type.label {$sortParams['sortOrder']}";
348 }
349 elseif ($sortParams['sort'] == 'isActive') {
350 $sortParams['sort'] = 'is_active';
351 }
352 if ($orderOnCampaignTable) {
353 $orderByClause = "ORDER BY campaign.{$sortParams['sort']} {$sortParams['sortOrder']}";
354 }
355 $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}";
356 }
357
358 //build the where clause.
359 $queryParams = $where = array();
360 if (!empty($params['id'])) {
361 $where[] = "( campaign.id = %1 )";
362 $queryParams[1] = array($params['id'], 'Positive');
363 }
364 if (!empty($params['name'])) {
365 $where[] = "( campaign.name LIKE %2 )";
366 $queryParams[2] = array('%' . trim($params['name']) . '%', 'String');
367 }
368 if (!empty($params['title'])) {
369 $where[] = "( campaign.title LIKE %3 )";
370 $queryParams[3] = array('%' . trim($params['title']) . '%', 'String');
371 }
372 if (!empty($params['start_date'])) {
373 $startDate = CRM_Utils_Date::processDate($params['start_date']);
374 $where[] = "( campaign.start_date >= %4 OR campaign.start_date IS NULL )";
375 $queryParams[4] = array($startDate, 'String');
376 }
377 if (!empty($params['end_date'])) {
378 $endDate = CRM_Utils_Date::processDate($params['end_date'], '235959');
379 $where[] = "( campaign.end_date <= %5 OR campaign.end_date IS NULL )";
380 $queryParams[5] = array($endDate, 'String');
381 }
382 if (!empty($params['description'])) {
383 $where[] = "( campaign.description LIKE %6 )";
384 $queryParams[6] = array('%' . trim($params['description']) . '%', 'String');
385 }
386 if (!empty($params['campaign_type_id'])) {
387 $typeId = $params['campaign_type_id'];
388 if (is_array($params['campaign_type_id'])) {
389 $typeId = implode(' , ', $params['campaign_type_id']);
390 }
391 $where[] = "( campaign.campaign_type_id IN ( {$typeId} ) )";
392 }
393 if (!empty($params['status_id'])) {
394 $statusId = $params['status_id'];
395 if (is_array($params['status_id'])) {
396 $statusId = implode(' , ', $params['status_id']);
397 }
398 $where[] = "( campaign.status_id IN ( {$statusId} ) )";
399 }
400 if (array_key_exists('is_active', $params)) {
401 $active = "( campaign.is_active = 1 )";
402 if (!empty($params['is_active'])) {
403 $active = "( campaign.is_active = 0 OR campaign.is_active IS NULL )";
404 }
405 $where[] = $active;
406 }
407 $whereClause = NULL;
408 if (!empty($where)) {
409 $whereClause = ' WHERE ' . implode(" \nAND ", $where);
410 }
411
412 $properties = array(
413 'id',
414 'name',
415 'title',
416 'start_date',
417 'end_date',
418 'status_id',
419 'is_active',
420 'description',
421 'campaign_type_id',
422 );
423
424 $selectClause = '
425 SELECT campaign.id as id,
426 campaign.name as name,
427 campaign.title as title,
428 campaign.is_active as is_active,
429 campaign.status_id as status_id,
430 campaign.end_date as end_date,
431 campaign.start_date as start_date,
432 campaign.description as description,
433 campaign.campaign_type_id as campaign_type_id';
434 if ($onlyCount) {
435 $selectClause = 'SELECT COUNT(*)';
436 }
437 $fromClause = 'FROM civicrm_campaign campaign';
438
439 $query = "{$selectClause} {$fromClause} {$lookupTableJoins} {$whereClause} {$orderByClause} {$limitClause}";
440
441 //in case of only count.
442 if ($onlyCount) {
443 return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams);
444 }
445
446 $campaign = CRM_Core_DAO::executeQuery($query, $queryParams);
447 while ($campaign->fetch()) {
448 foreach ($properties as $property) {
449 $campaigns[$campaign->id][$property] = $campaign->$property;
450 }
451 }
452
453 return $campaigns;
454 }
455
456 /**
457 * Get the campaign count.
458 *
459 * @static
460 */
461 public static function getCampaignCount() {
462 return (int)CRM_Core_DAO::singleValueQuery('SELECT COUNT(*) FROM civicrm_campaign');
463 }
464
465 /**
466 * Get Campaigns groups
467 *
468 * @param int $campaignId campaign id
469 *
470 * @return array
471 * @static
472 */
473 public static function getCampaignGroups($campaignId) {
474 static $campaignGroups;
475 if (!$campaignId) {
476 return array();
477 }
478
479 if (!isset($campaignGroups[$campaignId])) {
480 $campaignGroups[$campaignId] = array();
481
482 $query = "
483 SELECT grp.title, grp.id
484 FROM civicrm_campaign_group campgrp
485 INNER JOIN civicrm_group grp ON ( grp.id = campgrp.entity_id )
486 WHERE campgrp.group_type = 'Include'
487 AND campgrp.entity_table = 'civicrm_group'
488 AND campgrp.campaign_id = %1";
489
490 $groups = CRM_Core_DAO::executeQuery($query, array(1 => array($campaignId, 'Positive')));
491 while ($groups->fetch()) {
492 $campaignGroups[$campaignId][$groups->id] = $groups->title;
493 }
494 }
495
496 return $campaignGroups[$campaignId];
497 }
498
499 /**
500 * Update the is_active flag in the db
501 *
502 * @param int $id id of the database record
503 * @param boolean $is_active value we want to set the is_active field
504 *
505 * @return Object DAO object on sucess, null otherwise
506 * @static
507 */
508 public static function setIsActive($id, $is_active) {
509 return CRM_Core_DAO::setFieldValue('CRM_Campaign_DAO_Campaign', $id, 'is_active', $is_active);
510 }
511
512 /**
513 * @return bool
514 */
515 public static function accessCampaign() {
516 static $allow = NULL;
517
518 if (!isset($allow)) {
519 $allow = FALSE;
520 if (CRM_Core_Permission::check('manage campaign') ||
521 CRM_Core_Permission::check('administer CiviCampaign')
522 ) {
523 $allow = TRUE;
524 }
525 }
526
527 return $allow;
528 }
529
530 /*
531 * Add select element for campaign
532 * and assign needful info to templates.
533 *
534 */
535 /**
536 * @param CRM_Core_Form $form
537 * @param int $connectedCampaignId
538 */
539 public static function addCampaign(&$form, $connectedCampaignId = NULL) {
540 //some forms do set default and freeze.
541 $appendDates = TRUE;
542 if ($form->get('action') & CRM_Core_Action::VIEW) {
543 $appendDates = FALSE;
544 }
545
546 $campaignDetails = self::getPermissionedCampaigns($connectedCampaignId, NULL, TRUE, TRUE, $appendDates);
547 $fields = array('campaigns', 'hasAccessCampaign', 'isCampaignEnabled');
548 foreach ($fields as $fld)$$fld = CRM_Utils_Array::value($fld, $campaignDetails);
549
550 //lets see do we have past campaigns.
551 $hasPastCampaigns = FALSE;
552 $allActiveCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, TRUE, FALSE);
553 if (count($allActiveCampaigns) > count($campaigns)) {
554 $hasPastCampaigns = TRUE;
555 }
556 $hasCampaigns = FALSE;
557 if (!empty($campaigns)) {
558 $hasCampaigns = TRUE;
559 }
560 if ($hasPastCampaigns) {
561 $hasCampaigns = TRUE;
562 $form->add('hidden', 'included_past_campaigns');
563 }
564
565 $showAddCampaign = FALSE;
566 $alreadyIncludedPastCampaigns = FALSE;
567 if ($connectedCampaignId || ($isCampaignEnabled && $hasAccessCampaign)) {
568 $showAddCampaign = TRUE;
569 //lets add past campaigns as options to quick-form element.
570 if ($hasPastCampaigns && $form->getElementValue('included_past_campaigns')) {
571 $campaigns = $allActiveCampaigns;
572 $alreadyIncludedPastCampaigns = TRUE;
573 }
574 $campaign = &$form->add('select',
575 'campaign_id',
576 ts('Campaign'),
577 array('' => ts('- select -')) + $campaigns,
578 FALSE,
579 array('class' => 'crm-select2')
580 );
581 //lets freeze when user does not has access or campaign is disabled.
582 if (!$isCampaignEnabled || !$hasAccessCampaign) {
583 $campaign->freeze();
584 }
585 }
586
587 $addCampaignURL = NULL;
588 if (empty($campaigns) && $hasAccessCampaign && $isCampaignEnabled) {
589 $addCampaignURL = CRM_Utils_System::url('civicrm/campaign/add', 'reset=1');
590 }
591
592 $includePastCampaignURL = NULL;
593 if ($hasPastCampaigns && $isCampaignEnabled && $hasAccessCampaign) {
594 $includePastCampaignURL = CRM_Utils_System::url('civicrm/ajax/rest',
595 'className=CRM_Campaign_Page_AJAX&fnName=allActiveCampaigns',
596 FALSE, NULL, FALSE
597 );
598 }
599
600 //carry this info to templates.
601 $infoFields = array(
602 'hasCampaigns',
603 'addCampaignURL',
604 'showAddCampaign',
605 'hasPastCampaigns',
606 'hasAccessCampaign',
607 'isCampaignEnabled',
608 'includePastCampaignURL',
609 'alreadyIncludedPastCampaigns',
610 );
611 foreach ($infoFields as $fld) $campaignInfo[$fld] = $$fld;
612 $form->assign('campaignInfo', $campaignInfo);
613 }
614
615 /**
616 * Add campaign in compoent search.
617 * and assign needful info to templates.
618 *
619 * @param CRM_Core_Form $form
620 * @param string $elementName
621 */
622 public static function addCampaignInComponentSearch(&$form, $elementName = 'campaign_id') {
623 $campaignInfo = array();
624 $campaignDetails = self::getPermissionedCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
625 $fields = array('campaigns', 'hasAccessCampaign', 'isCampaignEnabled');
626 foreach ($fields as $fld)$$fld = CRM_Utils_Array::value($fld, $campaignDetails);
627 $showCampaignInSearch = FALSE;
628 if ($isCampaignEnabled && $hasAccessCampaign && !empty($campaigns)) {
629 //get the current campaign only.
630 $currentCampaigns = self::getCampaigns(NULL, NULL, FALSE);
631 $pastCampaigns = array_diff($campaigns, $currentCampaigns);
632 $allCampaigns = array();
633 if (!empty($currentCampaigns)) {
634 $allCampaigns = array('crm_optgroup_current_campaign' => ts('Current Campaigns')) + $currentCampaigns;
635 }
636 if (!empty($pastCampaigns)) {
637 $allCampaigns += array('crm_optgroup_past_campaign' => ts('Past Campaigns')) + $pastCampaigns;
638 }
639
640 $showCampaignInSearch = TRUE;
641 $form->add('select', $elementName, ts('Campaigns'), $allCampaigns, FALSE,
642 array('id' => 'campaigns', 'multiple' => 'multiple', 'class' => 'crm-select2')
643 );
644 }
645 $infoFields = array(
646 'elementName',
647 'hasAccessCampaign',
648 'isCampaignEnabled',
649 'showCampaignInSearch',
650 );
651 foreach ($infoFields as $fld) $campaignInfo[$fld] = $$fld;
652 $form->assign('campaignInfo', $campaignInfo);
653 }
654 }