repetition start date on the basis of parent event start date
[civicrm-core.git] / CRM / Core / BAO / RecurringEntity.php
CommitLineData
62933949 1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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-2013
32 * $Id$
33 *
34 */
35
36require_once 'packages/When/When.php';
37
38class CRM_Core_BAO_RecurringEntity extends CRM_Core_DAO_RecurringEntity {
39
40 static $_tableDAOMapper =
41 array(
42 'civicrm_event' => 'CRM_Event_DAO_Event',
43 'civicrm_price_set_entity' => 'CRM_Price_DAO_PriceSetEntity',
44 'civicrm_uf_join' => 'CRM_Core_DAO_UFJoin',
45 'civicrm_tell_friend' => 'CRM_Friend_DAO_Friend',
46 'civicrm_pcp_block' => 'CRM_PCP_DAO_PCPBlock',
47 );
48
49 static function add(&$params) {
50 if (CRM_Utils_Array::value('id', $params)) {
51 CRM_Utils_Hook::pre('edit', 'RecurringEntity', $params['id'], $params);
52 }
53 else {
54 CRM_Utils_Hook::pre('create', 'RecurringEntity', NULL, $params);
55 }
56
57 $daoRecurringEntity = new CRM_Core_DAO_RecurringEntity();
58 $daoRecurringEntity->copyValues($params);
59 $result = $daoRecurringEntity->save();
60
61 if (CRM_Utils_Array::value('id', $params)) {
62 CRM_Utils_Hook::post('edit', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity);
63 }
64 else {
65 CRM_Utils_Hook::post('create', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity);
66 }
67 return $result;
68 }
69
70 static function quickAdd($parentId, $entityId, $entityTable) {
71 $params =
72 array(
73 'parent_id' => $parentId,
74 'entity_id' => $entityId,
75 'entity_table' => $entityTable
76 );
77 return self::add($params);
78 }
79
36b8b5f3 80 // MODE = 3 (ALL)
81 static public function getEntitiesForParent($parentId, $entityTable, $includeParent = TRUE, $mode = 3, $initiatorId = NULL) {
62933949 82 $entities = array();
83
36b8b5f3 84 if (!$initiatorId) {
85 $initiatorId = $parentId;
86 }
87
88 $queryParams = array(
89 1 => array($parentId, 'Integer'),
90 2 => array($entityTable, 'String'),
91 3 => array($initiatorId, 'Integer'),
92 );
93
94 if (!$mode) {
60b36f60 95 $mode = CRM_Core_DAO::singleValueQuery("SELECT mode FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams);
36b8b5f3 96 }
97
62933949 98 $query = "SELECT *
99 FROM civicrm_recurring_entity
100 WHERE parent_id = %1 AND entity_table = %2";
101 if (!$includeParent) {
36b8b5f3 102 $query .= " AND entity_id != " . ($initiatorId ? "%3" : "%1");
103 }
104
105 if ($mode == '1') { // MODE = SINGLE
106 $query .= " AND entity_id = %3";
107 } else if ($mode == '2') { // MODE = FUTURE
108 $recurringEntityID = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams);
109 if ($recurringEntityID) {
110 $query .= $includeParent ? " AND id >= %4" : " AND id > %4";
111 $query .= " ORDER BY id ASC"; // FIXME: change to order by dates
112 $queryParams[4] = array($recurringEntityID, 'Integer');
113 } else {
114 // something wrong, return empty
115 return array();
116 }
62933949 117 }
62933949 118
36b8b5f3 119 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
62933949 120 while ($dao->fetch()) {
121 $entities["{$dao->entity_table}_{$dao->entity_id}"]['table'] = $dao->entity_table;
122 $entities["{$dao->entity_table}_{$dao->entity_id}"]['id'] = $dao->entity_id;
123 }
124 return $entities;
125 }
126
36b8b5f3 127 static public function getEntitiesFor($entityId, $entityTable, $includeParent = TRUE, $mode = 3) {
62933949 128 $parentId = self::getParentFor($entityId, $entityTable);
129 if ($parentId) {
36b8b5f3 130 return self::getEntitiesForParent($parentId, $entityTable, $includeParent, $mode, $entityId);
62933949 131 }
132 return array();
133 }
134
135 static public function getParentFor($entityId, $entityTable, $includeParent = TRUE) {
136 $query = "
137 SELECT parent_id
138 FROM civicrm_recurring_entity
139 WHERE entity_id = %1 AND entity_table = %2";
140 if (!$includeParent) {
141 $query .= " AND parent_id != %1";
142 }
143 $parentId =
144 CRM_Core_DAO::singleValueQuery($query,
145 array(
146 1 => array($entityId, 'Integer'),
147 2 => array($entityTable, 'String'),
148 )
149 );
150 return $parentId;
151 }
152
153 //static public function copyCreateEntity('civicrm_event', array('id' => $params['parent_event_id'], $newParams) {
154 static public function copyCreateEntity($entityTable, $fromCriteria, $newParams, $createRecurringEntity = TRUE) {
155 $daoName = self::$_tableDAOMapper[$entityTable];
156 $newObject = CRM_Core_DAO::copyGeneric($daoName, $fromCriteria, $newParams);
157
158 if ($newObject->id && $createRecurringEntity) {
159 $object = new $daoName( );
160 foreach ($fromCriteria as $key => $value) {
161 $object->$key = $value;
162 }
163 $object->find(TRUE);
164
165 CRM_Core_BAO_RecurringEntity::quickAdd($object->id, $newObject->id, $entityTable);
166 }
167 return $newObject;
168 }
169
170 static public function triggerUpdate($obj) {
60b36f60 171 // if DB version is earlier than 4.6 skip any processing
172 static $currentVer = NULL;
173 if (!$currentVer) {
174 $currentVer = CRM_Core_BAO_Domain::version();
175 }
176 if (version_compare($currentVer, '4.6.alpha1') < 0) {
177 return;
178 }
179
62933949 180 static $processedEntities = array();
181 if (empty($obj->id) || empty($obj->__table)) {
182 return FALSE;
183 }
184 $key = "{$obj->__table}_{$obj->id}";
185
186 if (array_key_exists($key, $processedEntities)) {
187 // already processed
188 return NULL;
189 }
190
191 // get related entities
36b8b5f3 192 $repeatingEntities = self::getEntitiesFor($obj->id, $obj->__table, FALSE, NULL);
62933949 193 if (empty($repeatingEntities)) {
194 // return if its not a recurring entity parent
195 return NULL;
196 }
36b8b5f3 197 // mark being processed
62933949 198 $processedEntities[$key] = 1;
199
36b8b5f3 200 // to make sure we not copying to source itself
201 unset($repeatingEntities[$key]);
202
203 foreach($repeatingEntities as $key => $val) {
62933949 204 $entityID = $val['id'];
205 $entityTable = $val['table'];
206
207 $processedEntities[$key] = 1;
208
209 if (array_key_exists($entityTable, self::$_tableDAOMapper)) {
210 $daoName = self::$_tableDAOMapper[$entityTable];
211
62933949 212 // FIXME: generalize me
213 $skipData = array('start_date' => NULL,
214 'end_date' => NULL,
215 );
216
36b8b5f3 217 $updateDAO = CRM_Core_DAO::cascadeUpdate($daoName, $obj->id, $entityID, $skipData);
218 CRM_Core_DAO::freeResult();
62933949 219 }
220 }
221 // done with processing. lets unset static var.
222 unset($processedEntities);
223 }
224
225 static function mapFormValuesToDB($formParams = array()){
226 $dbParams = array();
227 if(CRM_Utils_Array::value('used_for', $formParams)){
228 $dbParams['used_for'] = $formParams['used_for'];
229 }
230
231 if(CRM_Utils_Array::value('parent_event_id', $formParams)){
232 $dbParams['entity_value'] = $formParams['parent_event_id'];
b1d1479a 233 }
234
235 if(CRM_Utils_Array::value('repetition_start_date', $formParams)){
236 $repetition_start_date = new DateTime($formParams['repetition_start_date']);
237 $repetition_start_date->modify('+1 day');
238 $dbParams['entity_status'] = CRM_Utils_Date::processDate($repetition_start_date->format('Y-m-d H:i:s'));
239 }
62933949 240
241 if(CRM_Utils_Array::value('repetition_frequency_unit', $formParams)){
b1d1479a 242 $dbParams['repetition_frequency_unit'] = $formParams['repetition_frequency_unit'];
243 }
62933949 244
245 if(CRM_Utils_Array::value('repetition_frequency_interval', $formParams)){
b1d1479a 246 $dbParams['repetition_frequency_interval'] = $formParams['repetition_frequency_interval'];
247 }
62933949 248
249 //For Repeats on:(weekly case)
b1d1479a 250 if($formParams['repetition_frequency_unit'] == 'week'){
251 if(CRM_Utils_Array::value('start_action_condition', $formParams)){
252 $repeats_on = CRM_Utils_Array::value('start_action_condition', $formParams);
253 $dbParams['start_action_condition'] = implode(",", array_keys($repeats_on));
62933949 254 }
b1d1479a 255 }
62933949 256
257 //For Repeats By:(monthly case)
b1d1479a 258 if($formParams['repetition_frequency_unit'] == 'month'){
259 if($formParams['repeats_by'] == 1){
260 if(CRM_Utils_Array::value('limit_to', $formParams)){
261 $dbParams['limit_to'] = $formParams['limit_to'];
62933949 262 }
b1d1479a 263 }
264 if($formParams['repeats_by'] == 2){
265 if(CRM_Utils_Array::value('start_action_date_1', $formParams) && CRM_Utils_Array::value('start_action_date_2', $formParams)){
266 $dbParams['start_action_date'] = $formParams['start_action_date_1']." ".$formParams['start_action_date_2'];
62933949 267 }
268 }
b1d1479a 269 }
62933949 270
271 //For "Ends" - After:
b1d1479a 272 if($formParams['ends'] == 1){
273 if(CRM_Utils_Array::value('start_action_offset', $formParams)){
274 $dbParams['start_action_offset'] = $formParams['start_action_offset'];
62933949 275 }
b1d1479a 276 }
62933949 277
b1d1479a 278 //For "Ends" - On:
279 if($formParams['ends'] == 2){
280 if(CRM_Utils_Array::value('repeat_absolute_date', $formParams)){
281 $dbParams['absolute_date'] = CRM_Utils_Date::processDate($formParams['repeat_absolute_date']);
62933949 282 }
62933949 283 }
b1d1479a 284 return $dbParams;
285 }
62933949 286
b1d1479a 287 static public function getScheduleReminderDetailsById($scheduleReminderId){
288 $query = "SELECT *
289 FROM civicrm_action_schedule WHERE 1";
290 if($scheduleReminderId){
291 $query .= "
292 AND id = %1";
62933949 293 }
b1d1479a 294 $dao = CRM_Core_DAO::executeQuery($query,
295 array(
296 1 => array($scheduleReminderId, 'Integer')
297 )
298 );
299 $dao->fetch();
300 return $dao;
301 }
62933949 302
b1d1479a 303 static function getRecursionFromReminder($scheduleReminderId){
304 if($scheduleReminderId){
305 //Get all the details from schedule reminder table
306 $scheduleReminderDetails = self::getScheduleReminderDetailsById($scheduleReminderId);
307 $scheduleReminderDetails = (array) $scheduleReminderDetails;
308 $recursionDetails = self::getRecursionFromReminderByDBParams($scheduleReminderDetails);
62933949 309 }
b1d1479a 310 return $recursionDetails;
311 }
62933949 312
b1d1479a 313 static function getRecursionFromReminderByDBParams($scheduleReminderDetails = array()){
314 $r = new When();
315 //If there is some data for this id
316 if($scheduleReminderDetails['repetition_frequency_unit']){
317 if($scheduleReminderDetails['entity_status']){
318 $currDate = date('Y-m-d H:i:s', strtotime($scheduleReminderDetails['entity_status']));
319 }else{
62933949 320 $currDate = date("Y-m-d H:i:s");
b1d1479a 321 }
322 $start = new DateTime($currDate);
323 if($scheduleReminderDetails['repetition_frequency_unit']){
324 $repetition_frequency_unit = $scheduleReminderDetails['repetition_frequency_unit'];
325 if($repetition_frequency_unit == "day"){
326 $repetition_frequency_unit = "dai";
62933949 327 }
b1d1479a 328 $repetition_frequency_unit = $repetition_frequency_unit.'ly';
329 $r->recur($start, $repetition_frequency_unit);
330 }
62933949 331
b1d1479a 332 if($scheduleReminderDetails['repetition_frequency_interval']){
333 $r->interval($scheduleReminderDetails['repetition_frequency_interval']);
334 }else{
335 $r->errors[] = 'Repeats every: is a required field';
336 }
62933949 337
b1d1479a 338 //week
339 if($scheduleReminderDetails['repetition_frequency_unit'] == 'week'){
340 if($scheduleReminderDetails['start_action_condition']){
341 $startActionCondition = $scheduleReminderDetails['start_action_condition'];
342 $explodeStartActionCondition = explode(',', $startActionCondition);
343 $buildRuleArray = array();
344 foreach($explodeStartActionCondition as $key => $val){
345 $buildRuleArray[] = strtoupper(substr($val, 0, 2));
62933949 346 }
b1d1479a 347 $r->wkst('MO')->byday($buildRuleArray);
62933949 348 }
b1d1479a 349 }
62933949 350
b1d1479a 351 //month
352 if($scheduleReminderDetails['repetition_frequency_unit'] == 'month'){
353 if($scheduleReminderDetails['limit_to']){
354 $r->bymonthday(array($scheduleReminderDetails['limit_to']));
62933949 355 }
b1d1479a 356 if($scheduleReminderDetails['start_action_date']){
357 $startActionDate = explode(" ", $scheduleReminderDetails['start_action_date']);
358 switch ($startActionDate[0]) {
359 case 'first':
360 $startActionDate1 = 1;
361 break;
362 case 'second':
363 $startActionDate1 = 2;
364 break;
365 case 'third':
366 $startActionDate1 = 3;
367 break;
368 case 'fourth':
369 $startActionDate1 = 4;
370 break;
371 case 'last':
372 $startActionDate1 = -1;
373 break;
c828f12a 374 }
b1d1479a 375 $concatStartActionDateBits = $startActionDate1.strtoupper(substr($startActionDate[1], 0, 2));
376 $r->byday(array($concatStartActionDateBits));
62933949 377 }
b1d1479a 378 }
62933949 379
b1d1479a 380 //Ends
381 if($scheduleReminderDetails['start_action_offset']){
382 if($scheduleReminderDetails['start_action_offset'] > 30){
383 $r->errors[] = 'Occurrences should be less than or equal to 30';
62933949 384 }
b1d1479a 385 $r->count($scheduleReminderDetails['start_action_offset']);
386 }
62933949 387
b1d1479a 388 if($scheduleReminderDetails['absolute_date']){
389 $absoluteDate = CRM_Utils_Date::setDateDefaults($scheduleReminderDetails['absolute_date']);
390 $endDate = new DateTime($absoluteDate[0].' '.$absoluteDate[1]);
391 $r->until($endDate);
392 }
393
394 if(!$scheduleReminderDetails['start_action_offset'] && !$scheduleReminderDetails['absolute_date']){
395 $r->errors[] = 'Ends: is a required field';
396 }
397 }else{
398 $r->errors[] = 'Repeats: is a required field';
399 }
400 return $r;
401 }
62933949 402
fd1abec4 403 /*
404 * Get Reminder id based on event id
405 */
406 static public function getReminderDetailsByEventId($eventId, $used_for){
407 if($eventId){
408 $query = "
409 SELECT *
410 FROM civicrm_action_schedule
411 WHERE entity_value = %1";
412 if($used_for){
413 $query .= " AND used_for = %2";
414 }
415 $params = array(
416 1 => array($eventId, 'Integer'),
417 2 => array($used_for, 'String')
418 );
419 $dao = CRM_Core_DAO::executeQuery($query, $params);
420 $dao->fetch();
421 }
422 return $dao;
2eeee284 423 }
424
ad82cae1 425 static public function generateRecursions($recursionObj, $params = array(), $excludeDates = array()) {
2eeee284 426 $newParams = $recursionResult = array();
ad82cae1 427 if ($recursionObj && !empty($params)) {
428 $initialCount = CRM_Utils_Array::value('start_action_offset', $params);
2eeee284 429 if(CRM_Utils_Array::value('parent_event_start_date', $params) && CRM_Utils_Array::value('parent_event_id', $params)){
430 $count = 1;
ad82cae1 431 while ($result = $recursionObj->next()) {
2eeee284 432 $newParams['start_date'] = CRM_Utils_Date::processDate($result->format('Y-m-d H:i:s'));
433 $parentStartDate = new DateTime($params['parent_event_start_date']);
ad82cae1 434
2eeee284 435 //If events with end date
436 if(CRM_Utils_Array::value('parent_event_end_date', $params)){
437 $parentEndDate = new DateTime($params['parent_event_end_date']);
438 $interval = $parentStartDate->diff($parentEndDate);
439 $end_date = new DateTime($newParams['start_date']);
440 $end_date->add($interval);
441 $newParams['end_date'] = CRM_Utils_Date::processDate($end_date->format('Y-m-d H:i:s'));
442 $recursionResult[$count]['end_date'] = $newParams['end_date'];
443 }
444 $recursionResult[$count]['start_date'] = $newParams['start_date'];
ad82cae1 445
446 $skip = FALSE;
447 foreach ($excludeDates as $date) {
448 $date = CRM_Utils_Date::processDate($date, NULL, FALSE, 'Ymd');
449 if (($date == $result->format('Ymd')) ||
450 ($end_date && ($date > $result->format('Ymd')) && ($date <= $end_date->format('Ymd')))
451 ) {
452 $skip = TRUE;
453 break;
454 }
455 }
456
457 if ($skip) {
458 unset($recursionResult[$count]);
459 if ($initialCount && ($initialCount > 0)) {
460 // lets increase the counter, so we get correct number of occurrences
461 $initialCount++;
462 $recursionObj->count($initialCount);
463 }
464 continue;
465 }
2eeee284 466 $count++;
467 }
468 }
469 }
470 return $recursionResult;
471 }
472
473 static public function addEntityThroughRecursion($recursionResult = array(), $currEntityID){
474 if(!empty($recursionResult) && $currEntityID){
475 $parent_event_id = CRM_Core_BAO_RecurringEntity::getParentFor($currEntityID, 'civicrm_event');
476 if(!$parent_event_id){
477 $parent_event_id = $currEntityID;
478 }
479
480 // add first entry just for parent
481 CRM_Core_BAO_RecurringEntity::quickAdd($parent_event_id, $parent_event_id, 'civicrm_event');
482
483 foreach ($recursionResult as $key => $value) {
484 $newEventObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity('civicrm_event',
485 array('id' => $parent_event_id),
486 $value);
487
488 CRM_Core_BAO_RecurringEntity::copyCreateEntity('civicrm_price_set_entity',
489 array(
490 'entity_id' => $parent_event_id,
491 'entity_table' => 'civicrm_event'
492 ),
493 array(
494 'entity_id' => $newEventObj->id
495 ),
496 FALSE
497 );
498
499 CRM_Core_BAO_RecurringEntity::copyCreateEntity('civicrm_uf_join',
500 array(
501 'entity_id' => $parent_event_id,
502 'entity_table' => 'civicrm_event'
503 ),
504 array(
505 'entity_id' => $newEventObj->id
506 ),
507 FALSE
508 );
509
510 CRM_Core_BAO_RecurringEntity::copyCreateEntity('civicrm_tell_friend',
511 array(
512 'entity_id' => $parent_event_id,
513 'entity_table' => 'civicrm_event'
514 ),
515 array(
516 'entity_id' => $newEventObj->id
517 )
518 );
519
520 CRM_Core_BAO_RecurringEntity::copyCreateEntity('civicrm_pcp_block',
521 array(
522 'entity_id' => $parent_event_id,
523 'entity_table' => 'civicrm_event'
524 ),
525 array(
526 'entity_id' => $newEventObj->id
527 )
528 );
529 }
530 }
531 }
8dc6e78a 532
533 static public function delEntityRelations($entityId, $entityTable){
534 if(!$entityId && !$entityTable){
535 return FALSE;
536 }
537 $parentID = self::getParentFor($entityId, $entityTable);
538 if($parentID){
539 $dao = new CRM_Core_DAO_RecurringEntity();
540 $dao->parent_id = $parentID;
541 return $dao->delete();
542 }
543 }
62933949 544
fd1abec4 545}