| Total Complexity | 55 |
| Total Lines | 389 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like TaskRecurrence often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use TaskRecurrence, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 4 | class TaskRecurrence extends BaseRecurrence |
||
| 5 | { |
||
| 6 | /** |
||
| 7 | * Timezone info which is always false for task |
||
| 8 | */ |
||
| 9 | var $tz = false; |
||
| 10 | |||
| 11 | function __construct($store, $message) |
||
| 12 | { |
||
| 13 | $this->store = $store; |
||
| 14 | $this->message = $message; |
||
| 15 | |||
| 16 | $properties = array(); |
||
| 17 | $properties["entryid"] = PR_ENTRYID; |
||
| 18 | $properties["parent_entryid"] = PR_PARENT_ENTRYID; |
||
| 19 | $properties["icon_index"] = PR_ICON_INDEX; |
||
| 20 | $properties["message_class"] = PR_MESSAGE_CLASS; |
||
| 21 | $properties["message_flags"] = PR_MESSAGE_FLAGS; |
||
| 22 | $properties["subject"] = PR_SUBJECT; |
||
| 23 | $properties["importance"] = PR_IMPORTANCE; |
||
| 24 | $properties["sensitivity"] = PR_SENSITIVITY; |
||
| 25 | $properties["last_modification_time"] = PR_LAST_MODIFICATION_TIME; |
||
| 26 | $properties["status"] = "PT_LONG:PSETID_Task:0x8101"; |
||
| 27 | $properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102"; |
||
| 28 | $properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104"; |
||
| 29 | $properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105"; |
||
| 30 | $properties["reset_reminder"] = "PT_BOOLEAN:PSETID_Task:0x8107"; |
||
| 31 | $properties["dead_occurrence"] = "PT_BOOLEAN:PSETID_Task:0x8109"; |
||
| 32 | $properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f"; |
||
| 33 | $properties["recurring_data"] = "PT_BINARY:PSETID_Task:0x8116"; |
||
| 34 | $properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110"; |
||
| 35 | $properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111"; |
||
| 36 | $properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c"; |
||
| 37 | $properties["task_f_creator"] = "PT_BOOLEAN:PSETID_Task:0x811e"; |
||
| 38 | $properties["owner"] = "PT_STRING8:PSETID_Task:0x811f"; |
||
| 39 | $properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126"; |
||
| 40 | |||
| 41 | $properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501"; |
||
| 42 | $properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502"; |
||
| 43 | $properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503"; |
||
| 44 | |||
| 45 | $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506"; |
||
| 46 | $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a"; |
||
| 47 | $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586"; |
||
| 48 | $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords"; |
||
| 49 | |||
| 50 | $properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516"; |
||
| 51 | $properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517"; |
||
| 52 | $properties["commonassign"] = "PT_LONG:PSETID_Common:0x8518"; |
||
| 53 | $properties["flagdueby"] = "PT_SYSTIME:PSETID_Common:0x8560"; |
||
| 54 | $properties["side_effects"] = "PT_LONG:PSETID_Common:0x8510"; |
||
| 55 | |||
| 56 | $this->proptags = getPropIdsFromStrings($store, $properties); |
||
| 57 | |||
| 58 | parent::__construct($store, $message, $properties); |
||
|
|
|||
| 59 | } |
||
| 60 | |||
| 61 | /** |
||
| 62 | * Function which saves recurrence and also regenerates task if necessary. |
||
| 63 | *@param array $recur new recurrence properties |
||
| 64 | *@return array of properties of regenerated task else false |
||
| 65 | */ |
||
| 66 | function setRecurrence(&$recur) |
||
| 67 | { |
||
| 68 | $this->recur = $recur; |
||
| 69 | $this->action =& $recur; |
||
| 70 | |||
| 71 | if(!isset($this->recur["changed_occurrences"])) |
||
| 72 | $this->recur["changed_occurrences"] = Array(); |
||
| 73 | |||
| 74 | if(!isset($this->recur["deleted_occurrences"])) |
||
| 75 | $this->recur["deleted_occurrences"] = Array(); |
||
| 76 | |||
| 77 | if (!isset($this->recur['startocc'])) $this->recur['startocc'] = 0; |
||
| 78 | if (!isset($this->recur['endocc'])) $this->recur['endocc'] = 0; |
||
| 79 | |||
| 80 | // Save recurrence because we need proper startrecurrdate and endrecurrdate |
||
| 81 | $this->saveRecurrence(); |
||
| 82 | |||
| 83 | // Update $this->recur with proper startrecurrdate and endrecurrdate updated after saving recurrence |
||
| 84 | $msgProps = mapi_getprops($this->message, array($this->proptags['recurring_data'])); |
||
| 85 | $recurring_data = $this->parseRecurrence($msgProps[$this->proptags['recurring_data']]); |
||
| 86 | foreach($recurring_data as $key => $value) { |
||
| 87 | $this->recur[$key] = $value; |
||
| 88 | } |
||
| 89 | |||
| 90 | $this->setFirstOccurrence(); |
||
| 91 | |||
| 92 | // Let's see if next occurrence has to be generated |
||
| 93 | return $this->moveToNextOccurrence(); |
||
| 94 | } |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Sets task object to first occurrence if startdate/duedate of task object is different from first occurrence |
||
| 98 | */ |
||
| 99 | function setFirstOccurrence() |
||
| 100 | { |
||
| 101 | // Check if it is already the first occurrence |
||
| 102 | if($this->action['start'] == $this->recur["start"]){ |
||
| 103 | return; |
||
| 104 | } else { |
||
| 105 | $items = $this->getNextOccurrence(); |
||
| 106 | |||
| 107 | $props = array(); |
||
| 108 | $props[$this->proptags['startdate']] = $items[$this->proptags['startdate']]; |
||
| 109 | $props[$this->proptags['commonstart']] = $items[$this->proptags['startdate']]; |
||
| 110 | |||
| 111 | $props[$this->proptags['duedate']] = $items[$this->proptags['duedate']]; |
||
| 112 | $props[$this->proptags['commonend']] = $items[$this->proptags['duedate']]; |
||
| 113 | |||
| 114 | mapi_setprops($this->message, $props); |
||
| 115 | } |
||
| 116 | } |
||
| 117 | |||
| 118 | /** |
||
| 119 | * Function which creates new task as current occurrence and moves the |
||
| 120 | * existing task to next occurrence. |
||
| 121 | * |
||
| 122 | *@param array $recur $action from client |
||
| 123 | *@return boolean if moving to next occurrence succeed then it returns |
||
| 124 | * properties of either newly created task or existing task ELSE |
||
| 125 | * false because that was last occurrence |
||
| 126 | */ |
||
| 127 | function moveToNextOccurrence() |
||
| 128 | { |
||
| 129 | $result = false; |
||
| 130 | /** |
||
| 131 | * Every recurring task should have a 'duedate'. If a recurring task is created with no start/end date |
||
| 132 | * then we create first two occurrence separately and for first occurrence recurrence has ended. |
||
| 133 | */ |
||
| 134 | if ((empty($this->action['startdate']) && empty($this->action['duedate'])) |
||
| 135 | || ($this->action['complete'] == 1) || (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence'])){ |
||
| 136 | |||
| 137 | $nextOccurrence = $this->getNextOccurrence(); |
||
| 138 | $result = mapi_getprops($this->message, array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID)); |
||
| 139 | |||
| 140 | $props = array(); |
||
| 141 | if ($nextOccurrence) { |
||
| 142 | if (!isset($this->action['deleteOccurrence'])) { |
||
| 143 | // Create current occurrence as separate task |
||
| 144 | $result = $this->regenerateTask($this->action['complete']); |
||
| 145 | } |
||
| 146 | |||
| 147 | // Set reminder for next occurrence |
||
| 148 | $this->setReminder($nextOccurrence); |
||
| 149 | |||
| 150 | // Update properties for next occurrence |
||
| 151 | $this->action['duedate'] = $props[$this->proptags['duedate']] = $nextOccurrence[$this->proptags['duedate']]; |
||
| 152 | $this->action['commonend'] = $props[$this->proptags['commonend']] = $nextOccurrence[$this->proptags['duedate']]; |
||
| 153 | |||
| 154 | $this->action['startdate'] = $props[$this->proptags['startdate']] = $nextOccurrence[$this->proptags['startdate']]; |
||
| 155 | $this->action['commonstart'] = $props[$this->proptags['commonstart']] = $nextOccurrence[$this->proptags['startdate']]; |
||
| 156 | |||
| 157 | // If current task as been mark as 'Complete' then next occurrence should be incomplete. |
||
| 158 | if (isset($this->action['complete']) && $this->action['complete'] == 1) { |
||
| 159 | $this->action['status'] = $props[$this->proptags["status"]] = olTaskNotStarted; |
||
| 160 | $this->action['complete'] = $props[$this->proptags["complete"]] = false; |
||
| 161 | $this->action['percent_complete'] = $props[$this->proptags["percent_complete"]] = 0; |
||
| 162 | } |
||
| 163 | |||
| 164 | $props[$this->proptags["dead_occurrence"]] = false; |
||
| 165 | } else { |
||
| 166 | if (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence']) |
||
| 167 | return false; |
||
| 168 | |||
| 169 | // Didn't get next occurrence, probably this is the last one, so recurrence ends here |
||
| 170 | $props[$this->proptags["dead_occurrence"]] = true; |
||
| 171 | $props[$this->proptags["datecompleted"]] = $this->action['datecompleted']; |
||
| 172 | $props[$this->proptags["task_f_creator"]] = true; |
||
| 173 | |||
| 174 | //OL props |
||
| 175 | $props[$this->proptags["side_effects"]] = 1296; |
||
| 176 | $props[$this->proptags["icon_index"]] = 1280; |
||
| 177 | } |
||
| 178 | |||
| 179 | mapi_setprops($this->message, $props); |
||
| 180 | } |
||
| 181 | |||
| 182 | return $result; |
||
| 183 | } |
||
| 184 | |||
| 185 | /** |
||
| 186 | * Function which return properties of next occurrence |
||
| 187 | *@return array startdate/enddate of next occurrence |
||
| 188 | */ |
||
| 189 | function getNextOccurrence() |
||
| 190 | { |
||
| 191 | if ($this->recur) { |
||
| 192 | $items = array(); |
||
| 193 | |||
| 194 | //@TODO: fix start of range |
||
| 195 | $start = isset($this->messageprops[$this->proptags["duedate"]]) ? $this->messageprops[$this->proptags["duedate"]] : $this->action['start']; |
||
| 196 | $dayend = ($this->recur['term'] == 0x23) ? 0x7fffffff : $this->dayStartOf($this->recur["end"]); |
||
| 197 | |||
| 198 | // Fix recur object |
||
| 199 | $this->recur['startocc'] = 0; |
||
| 200 | $this->recur['endocc'] = 0; |
||
| 201 | |||
| 202 | // Retrieve next occurrence |
||
| 203 | $items = $this->getItems($start, $dayend, 1); |
||
| 204 | |||
| 205 | return !empty($items) ? $items[0] : false; |
||
| 206 | } |
||
| 207 | } |
||
| 208 | |||
| 209 | /** |
||
| 210 | * Function which clones current occurrence and sets appropriate properties. |
||
| 211 | * The original recurring item is moved to next occurrence. |
||
| 212 | *@param boolean $markComplete true if existing occurrence has to be mark complete else false. |
||
| 213 | */ |
||
| 214 | function regenerateTask($markComplete) |
||
| 297 | } |
||
| 298 | |||
| 299 | /** |
||
| 300 | * processOccurrenceItem, adds an item to a list of occurrences, but only if the |
||
| 301 | * resulting occurrence starts or ends in the interval <$start, $end> |
||
| 302 | * @param array $items reference to the array to be added to |
||
| 303 | * @param date $start start of timeframe in GMT TIME |
||
| 304 | * @param date $end end of timeframe in GMT TIME |
||
| 305 | * @param date $basedate (hour/sec/min assumed to be 00:00:00) in LOCAL TIME OF THE OCCURRENCE |
||
| 306 | */ |
||
| 307 | function processOccurrenceItem(&$items, $start, $end, $now) |
||
| 308 | { |
||
| 309 | if ($now > $start) { |
||
| 310 | $newItem = array(); |
||
| 311 | $newItem[$this->proptags['startdate']] = $now; |
||
| 312 | |||
| 313 | // If startdate and enddate are set on task, then slide enddate according to duration |
||
| 314 | if (isset($this->messageprops[$this->proptags["startdate"]]) && isset($this->messageprops[$this->proptags["duedate"]])) { |
||
| 315 | $newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']] + ($this->messageprops[$this->proptags["duedate"]] - $this->messageprops[$this->proptags["startdate"]]); |
||
| 316 | } else { |
||
| 317 | $newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']]; |
||
| 318 | } |
||
| 319 | |||
| 320 | $items[] = $newItem; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | |||
| 324 | /** |
||
| 325 | * Function which marks existing occurrence to 'Complete' |
||
| 326 | *@param array $recur array action from client |
||
| 327 | *@return array of properties of regenerated task else false |
||
| 328 | */ |
||
| 329 | function markOccurrenceComplete(&$recur) |
||
| 330 | { |
||
| 331 | // Fix timezone object |
||
| 332 | $this->tz = false; |
||
| 333 | $this->action =& $recur; |
||
| 334 | $dead_occurrence = isset($this->messageprops[$this->proptags['dead_occurrence']]) ? $this->messageprops[$this->proptags['dead_occurrence']] : false; |
||
| 335 | |||
| 336 | if (!$dead_occurrence) { |
||
| 337 | return $this->moveToNextOccurrence(); |
||
| 338 | } |
||
| 339 | |||
| 340 | return false; |
||
| 341 | } |
||
| 342 | |||
| 343 | /** |
||
| 344 | * Function which sets reminder on recurring task after existing occurrence has been deleted or marked complete. |
||
| 345 | *@param array $nextOccurrence properties of next occurrence |
||
| 346 | */ |
||
| 347 | function setReminder($nextOccurrence) |
||
| 348 | { |
||
| 349 | $props = array(); |
||
| 350 | if ($nextOccurrence) { |
||
| 351 | // Check if reminder is reset. Default is 'false' |
||
| 352 | $reset_reminder = isset($this->messageprops[$this->proptags['reset_reminder']]) ? $this->messageprops[$this->proptags['reset_reminder']] : false; |
||
| 353 | $reminder = $this->messageprops[$this->proptags['reminder']]; |
||
| 354 | |||
| 355 | // Either reminder was already set OR reminder was set but was dismissed bty user |
||
| 356 | if ($reminder || $reset_reminder) { |
||
| 357 | // Reminder can be set at any time either before or after the duedate, so get duration between the reminder time and duedate |
||
| 358 | $reminder_time = isset($this->messageprops[$this->proptags['reminder_time']]) ? $this->messageprops[$this->proptags['reminder_time']] : 0; |
||
| 359 | $reminder_difference = isset($this->messageprops[$this->proptags['duedate']]) ? $this->messageprops[$this->proptags['duedate']] : 0; |
||
| 360 | $reminder_difference = $reminder_difference - $reminder_time; |
||
| 361 | |||
| 362 | // Apply duration to next calculated duedate |
||
| 363 | $next_reminder_time = $nextOccurrence[$this->proptags['duedate']] - $reminder_difference; |
||
| 364 | |||
| 365 | $props[$this->proptags['reminder_time']] = $next_reminder_time; |
||
| 366 | $props[$this->proptags['flagdueby']] = $next_reminder_time; |
||
| 367 | $this->action['reminder'] = $props[$this->proptags['reminder']] = true; |
||
| 368 | } |
||
| 369 | } else { |
||
| 370 | // Didn't get next occurrence, probably this is the last occurrence |
||
| 371 | $props[$this->proptags['reminder']] = false; |
||
| 372 | $props[$this->proptags['reset_reminder']] = false; |
||
| 373 | } |
||
| 374 | |||
| 375 | if (!empty($props)) |
||
| 376 | mapi_setprops($this->message, $props); |
||
| 377 | } |
||
| 378 | |||
| 379 | /** |
||
| 380 | * Function which recurring task to next occurrence. |
||
| 381 | * It simply doesn't regenerate task |
||
| 382 | @param array $action |
||
| 383 | */ |
||
| 384 | function deleteOccurrence($action) |
||
| 393 | } |
||
| 394 | } |
||
| 395 | ?> |
||
| 396 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.