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