Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like absences_Entry 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 absences_Entry, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
52 | class absences_Entry extends absences_Request |
||
53 | { |
||
54 | |||
55 | const CREATION_USER = 0; |
||
56 | const CREATION_FIXED = 1; |
||
57 | |||
58 | |||
59 | |||
60 | |||
61 | /** |
||
62 | * Memory for saved or unsaved elements of a vacation request |
||
63 | * @var array |
||
64 | */ |
||
65 | private $elements = array(); |
||
66 | |||
67 | |||
68 | /** |
||
69 | * Memory for working periods of a vacation request |
||
70 | * they are the working periods saved with the entry at the creation of the request |
||
71 | * the periods will remain event after a workschedule modification for the user |
||
72 | * @var array |
||
73 | */ |
||
74 | private $plannedPeriods = array(); |
||
75 | |||
76 | /** |
||
77 | * @var float |
||
78 | */ |
||
79 | private $duration_days = null; |
||
80 | |||
81 | /** |
||
82 | * @var float |
||
83 | */ |
||
84 | private $duration_hours = null; |
||
85 | |||
86 | |||
87 | /** |
||
88 | * Cache for actual working periods from calendar |
||
89 | * @var bab_CalendarPeriod[] |
||
90 | */ |
||
91 | private $working_periods; |
||
92 | |||
93 | |||
94 | /** |
||
95 | * cache for total quantity |
||
96 | * @var float |
||
97 | */ |
||
98 | private $total_days = null; |
||
99 | |||
100 | /** |
||
101 | * cache for total quantity |
||
102 | * @var float |
||
103 | */ |
||
104 | private $total_hours = null; |
||
105 | |||
106 | |||
107 | /** |
||
108 | * cache for total quantity per type |
||
109 | * @var array |
||
110 | */ |
||
111 | private $total_type_days = null; |
||
112 | |||
113 | /** |
||
114 | * cache for total quantity per type |
||
115 | * @var float |
||
116 | */ |
||
117 | private $total_type_hours = null; |
||
118 | |||
119 | |||
120 | |||
121 | /** |
||
122 | * @var array |
||
123 | */ |
||
124 | private $workingPeriodIndex = null; |
||
125 | |||
126 | |||
127 | /** |
||
128 | * @see absences_EntryPeriod::getDurationDays |
||
129 | * @var array |
||
130 | */ |
||
131 | public $_getDurationDays_halfDays = array(); |
||
132 | |||
133 | |||
134 | |||
135 | /** |
||
136 | * @return absences_Entry |
||
137 | */ |
||
138 | public static function getById($id) |
||
145 | |||
146 | |||
147 | /** |
||
148 | * (non-PHPdoc) |
||
149 | * @see absences_Record::getRow() |
||
150 | */ |
||
151 | 41 | public function getRow() |
|
167 | |||
168 | |||
169 | /** |
||
170 | * (non-PHPdoc) |
||
171 | * @see absences_Request::getRequestType() |
||
172 | * |
||
173 | * @return string |
||
174 | */ |
||
175 | public function getRequestType() |
||
190 | |||
191 | |||
192 | |||
193 | |||
194 | public function getApprobationId() |
||
203 | |||
204 | |||
205 | |||
206 | |||
207 | |||
208 | /** |
||
209 | * Get elements stored in database |
||
210 | * @return absences_EntryElemIterator |
||
211 | */ |
||
212 | public function getElementsIterator() |
||
219 | |||
220 | |||
221 | 28 | public function getPlannedPeriodsIterator() |
|
228 | |||
229 | |||
230 | |||
231 | /** |
||
232 | * Get entries within the same folder |
||
233 | * @return absences_EntryIterator |
||
234 | */ |
||
235 | View Code Duplication | public function getFolderEntriesIterator() |
|
247 | |||
248 | |||
249 | |||
250 | |||
251 | |||
252 | |||
253 | |||
254 | /** |
||
255 | * |
||
256 | * @param string $message Generated message |
||
257 | * @param string $comment Author comment |
||
258 | */ |
||
259 | public function addElementsMovements($message, $comment = '') |
||
267 | |||
268 | |||
269 | |||
270 | |||
271 | /** |
||
272 | * Load elements from database |
||
273 | * @throws Exception |
||
274 | */ |
||
275 | public function loadElements() |
||
290 | |||
291 | /** |
||
292 | * Get the loaded elements |
||
293 | * @return array |
||
294 | */ |
||
295 | 15 | public function getElements() |
|
299 | |||
300 | /** |
||
301 | * Get element by right from the loaded elements |
||
302 | * @param int|absences_Right $right |
||
303 | * @return absences_EntryElem |
||
304 | */ |
||
305 | 19 | public function getElement($right) |
|
306 | { |
||
307 | 19 | $id_right = $right; |
|
308 | 19 | if ($right instanceof absences_Right) { |
|
309 | $id_right = $right->id; |
||
310 | } |
||
311 | |||
312 | |||
313 | 19 | if (empty($this->elements)) { |
|
314 | // not loaded |
||
315 | |||
316 | 5 | require_once dirname(__FILE__).'/entry_elem.class.php'; |
|
317 | |||
318 | 5 | global $babDB; |
|
319 | |||
320 | 5 | $res = $babDB->db_query('SELECT * |
|
321 | FROM absences_entries_elem |
||
322 | WHERE |
||
323 | 5 | id_entry='.$babDB->quote($this->id).' |
|
324 | 5 | AND id_right='.$babDB->quote($id_right)); |
|
325 | |||
326 | 5 | $row = $babDB->db_fetch_assoc($res); |
|
327 | |||
328 | 5 | if (!$row) { |
|
329 | return null; |
||
330 | } |
||
331 | |||
332 | 5 | $elem = new absences_EntryElem(); |
|
333 | 5 | $elem->setRow($row); |
|
334 | |||
335 | 5 | if ($right instanceof absences_Right) { |
|
336 | $elem->setRight($right); |
||
337 | } |
||
338 | |||
339 | 5 | return $elem; |
|
340 | } |
||
341 | |||
342 | |||
343 | // already loaded |
||
344 | |||
345 | 14 | foreach($this->elements as $element) { |
|
346 | 14 | if ($element->id_right == $id_right) { |
|
347 | 14 | return $element; |
|
348 | } |
||
349 | 11 | } |
|
350 | |||
351 | return null; |
||
352 | } |
||
353 | |||
354 | |||
355 | |||
356 | /** |
||
357 | * Add a planned period |
||
358 | * @param absences_EntryPeriod $plannedPeriod |
||
359 | */ |
||
360 | public function addPeriod(absences_EntryPeriod $plannedPeriod) |
||
364 | |||
365 | |||
366 | |||
367 | |||
368 | /** |
||
369 | * Load the planned working periods from database |
||
370 | * @throws Exception |
||
371 | */ |
||
372 | 29 | public function loadPlannedPeriods() |
|
393 | |||
394 | /** |
||
395 | * Get the loaded planned working periods |
||
396 | * @return absences_EntryPeriod[] |
||
397 | */ |
||
398 | 33 | public function getPlannedPeriods() |
|
402 | |||
403 | |||
404 | /** |
||
405 | * Get planned duration |
||
406 | * |
||
407 | * @param string $begin Optional limit to use for duration |
||
408 | * @param string $end Optional limit to use for duration |
||
409 | * |
||
410 | * @return float |
||
411 | */ |
||
412 | 28 | View Code Duplication | public function getPlannedDurationDays($begin = null, $end = null) |
413 | { |
||
414 | 28 | if (empty($this->plannedPeriods)) { |
|
415 | 16 | $this->loadPlannedPeriods(); |
|
416 | 16 | } |
|
417 | |||
418 | 28 | $total = 0.0; |
|
419 | |||
420 | 28 | foreach ($this->getPlannedPeriods() as $entryPeriod) { |
|
421 | 28 | $total += $entryPeriod->getDurationDays($begin, $end); |
|
422 | 28 | } |
|
423 | |||
424 | |||
425 | |||
426 | |||
427 | |||
428 | 28 | return $total; |
|
429 | } |
||
430 | |||
431 | |||
432 | /** |
||
433 | * Get planned duration |
||
434 | * |
||
435 | * @param string $begin Optional limit to use for duration |
||
436 | * @param string $end Optional limit to use for duration |
||
437 | * |
||
438 | * @return float |
||
439 | */ |
||
440 | 27 | View Code Duplication | public function getPlannedDurationHours($begin = null, $end = null) |
441 | { |
||
442 | 27 | if (empty($this->plannedPeriods)) { |
|
443 | 1 | $this->loadPlannedPeriods(); |
|
444 | 1 | } |
|
445 | |||
446 | 27 | $total = 0.0; |
|
447 | |||
448 | 27 | foreach ($this->getPlannedPeriods() as $entryPeriod) { |
|
449 | 27 | $total += $entryPeriod->getDurationHours($begin, $end); |
|
450 | 27 | } |
|
451 | |||
452 | 27 | return $total; |
|
453 | } |
||
454 | |||
455 | |||
456 | 7 | public function loadDefaultValues() |
|
457 | { |
||
458 | |||
459 | 7 | if (!isset($this->createdOn)) { |
|
460 | $this->createdOn = date('Y-m-d H:i:s'); |
||
461 | } |
||
462 | |||
463 | 7 | if (!isset($this->date)) { |
|
464 | $this->date = date('Y-m-d H:i:s'); |
||
465 | } |
||
466 | |||
467 | 7 | if (!isset($this->comment)) { |
|
468 | 7 | $this->comment = ''; |
|
469 | 7 | } |
|
470 | |||
471 | 7 | if (!isset($this->comment2)) { |
|
472 | 7 | $this->comment2 = ''; |
|
473 | 7 | } |
|
474 | |||
475 | 7 | if (!isset($this->idfai)) { |
|
476 | 7 | $this->idfai = '0'; |
|
477 | 7 | } |
|
478 | |||
479 | 7 | if (!isset($this->status)) { |
|
480 | $this->status = 'N'; |
||
481 | } |
||
482 | |||
483 | 7 | if (!isset($this->id_approver)) { |
|
484 | 7 | $this->id_approver = '0'; |
|
485 | 7 | } |
|
486 | |||
487 | 7 | if (!isset($this->folder)) { |
|
488 | 7 | $this->folder = '0'; |
|
489 | 7 | } |
|
490 | |||
491 | 7 | if (!isset($this->creation_type)) { |
|
492 | 7 | $this->creation_type = '0'; |
|
493 | 7 | } |
|
494 | |||
495 | 7 | } |
|
496 | |||
497 | |||
498 | /** |
||
499 | * Save entry to database |
||
500 | * without validity checking |
||
501 | * |
||
502 | * @return bool |
||
503 | */ |
||
504 | 7 | public function save() |
|
505 | { |
||
506 | // save entry |
||
507 | |||
508 | 7 | global $babDB; |
|
509 | |||
510 | 7 | $this->loadDefaultValues(); |
|
511 | |||
512 | 7 | if (isset($this->id)) |
|
513 | 7 | { |
|
514 | $req = " |
||
515 | UPDATE absences_entries |
||
516 | SET |
||
517 | 2 | `date` =".$babDB->quote($this->date).", |
|
518 | 2 | date_begin =".$babDB->quote($this->date_begin).", |
|
519 | 2 | date_end =".$babDB->quote($this->date_end).", |
|
520 | 2 | comment =".$babDB->quote($this->comment).", |
|
521 | 2 | idfai =".$babDB->quote($this->idfai).", |
|
522 | 2 | status =".$babDB->quote($this->status).", |
|
523 | 2 | comment2 =".$babDB->quote($this->comment2).", |
|
524 | 2 | id_approver =".$babDB->quote($this->id_approver).", |
|
525 | 2 | folder =".$babDB->quote($this->folder).", |
|
526 | 2 | creation_type =".$babDB->quote($this->creation_type)." |
|
527 | 2 | "; |
|
528 | |||
529 | 2 | if (isset($this->todelete)) |
|
530 | 2 | { |
|
531 | $req .= ", todelete=".$babDB->quote($this->todelete); |
||
532 | } |
||
533 | |||
534 | 2 | if (isset($this->appr_notified)) |
|
535 | 2 | { |
|
536 | $req .= ", appr_notified=".$babDB->quote($this->appr_notified); |
||
537 | } |
||
538 | |||
539 | |||
540 | $req .= " WHERE |
||
541 | 2 | id=".$babDB->quote($this->id)." "; |
|
542 | |||
543 | 2 | $babDB->db_query($req); |
|
544 | |||
545 | |||
546 | 2 | View Code Duplication | } else { |
547 | |||
548 | 7 | $babDB->db_query(" |
|
549 | INSERT INTO absences_entries |
||
550 | ( |
||
551 | id_user, |
||
552 | date_begin, |
||
553 | date_end, |
||
554 | comment, |
||
555 | `createdOn`, |
||
556 | `date`, |
||
557 | idfai, |
||
558 | status, |
||
559 | comment2, |
||
560 | id_approver, |
||
561 | folder, |
||
562 | creation_type |
||
563 | ) |
||
564 | VALUES |
||
565 | ( |
||
566 | 7 | ".$babDB->quote($this->id_user).", |
|
567 | 7 | ".$babDB->quote($this->date_begin).", |
|
568 | 7 | ".$babDB->quote($this->date_end).", |
|
569 | 7 | ".$babDB->quote($this->comment).", |
|
570 | 7 | ".$babDB->quote($this->createdOn).", |
|
571 | 7 | ".$babDB->quote($this->date).", |
|
572 | 7 | ".$babDB->quote($this->idfai).", |
|
573 | 7 | ".$babDB->quote($this->status).", |
|
574 | 7 | ".$babDB->quote($this->comment2).", |
|
575 | 7 | ".$babDB->quote($this->id_approver).", |
|
576 | 7 | ".$babDB->quote($this->folder).", |
|
577 | 7 | ".$babDB->quote($this->creation_type)." |
|
578 | ) |
||
579 | 7 | "); |
|
580 | |||
581 | 7 | $this->id = $babDB->db_insert_id(); |
|
582 | } |
||
583 | |||
584 | |||
585 | 7 | } |
|
586 | |||
587 | |||
588 | /** |
||
589 | * Sort the loaded element by right order, type name |
||
590 | */ |
||
591 | 27 | public function sortElements() |
|
595 | |||
596 | 27 | private static function sortElem(absences_EntryElem $elem1, absences_EntryElem $elem2) |
|
614 | |||
615 | |||
616 | /** |
||
617 | * Verifier si les dates des elements sont correctement parametres |
||
618 | * en cas de modificiation de la quantite, toujours mettre les dates a zero |
||
619 | * @return bool |
||
620 | */ |
||
621 | 33 | public function checkElementsDates() |
|
635 | |||
636 | |||
637 | |||
638 | |||
639 | /** |
||
640 | * Add dates to loaded elements using the user calendar |
||
641 | */ |
||
642 | 33 | public function setElementsDates() |
|
643 | { |
||
644 | 33 | include_once $GLOBALS['babInstallPath']."utilit/dateTime.php"; |
|
645 | |||
646 | 33 | if (0 === count($this->elements)) { |
|
647 | throw new absences_EntryException('No elements to set dates on, id_entry='.$this->id.', owner='.$this->getUserName()); |
||
648 | } |
||
649 | |||
650 | 33 | if ($this->checkElementsDates()) { |
|
651 | // dates allready set |
||
652 | // calling getFutureDate twice does not work |
||
653 | 10 | return; |
|
654 | } |
||
655 | |||
656 | 33 | if (1 === count($this->elements)) { |
|
657 | 6 | $element = reset($this->elements); |
|
658 | /*@var $element absences_EntryElem */ |
||
659 | 6 | $element->date_begin = $this->date_begin; |
|
660 | 6 | $element->date_end = $this->date_end; |
|
661 | 6 | return; |
|
662 | } |
||
663 | |||
664 | 27 | $this->sortElements(); |
|
665 | |||
666 | 27 | $loop = BAB_DateTime::fromIsoDateTime($this->date_begin); |
|
667 | |||
668 | |||
669 | |||
670 | 27 | foreach($this->elements as $element) { |
|
671 | /*@var $element absences_EntryElem */ |
||
672 | 27 | $element->date_begin = $loop->getIsoDateTime(); |
|
673 | |||
674 | 27 | $loop = $this->getFutureDate($loop, (float) $element->quantity, $element->getRight()->quantity_unit); |
|
675 | 27 | $element->date_end = $loop->getIsoDateTime(); |
|
676 | |||
677 | 27 | if ($element->date_end > $this->date_end) { |
|
678 | 1 | $element->date_end = $this->date_end; |
|
679 | 1 | } |
|
680 | |||
681 | 27 | $loop = $this->getNextValidDate($loop); |
|
682 | 27 | } |
|
683 | |||
684 | // round the last half day to the request period end |
||
685 | 27 | if ($this->getElementEndGap() <= 3600) { |
|
686 | 23 | $this->elements[count($this->elements)-1]->date_end = $this->date_end; |
|
687 | 23 | } |
|
688 | 27 | } |
|
689 | |||
690 | /** |
||
691 | * Get the gap beetween the last element end date and the period end date |
||
692 | * @return int |
||
693 | */ |
||
694 | 27 | protected function getElementEndGap() |
|
695 | { |
||
696 | 27 | $computedLastDate = bab_mktime($this->elements[count($this->elements)-1]->date_end); |
|
697 | 27 | $periodEnd = bab_mktime($this->date_end); |
|
698 | |||
699 | 27 | if ($periodEnd > $computedLastDate) { |
|
700 | 6 | return ($periodEnd - $computedLastDate); |
|
701 | } |
||
702 | |||
703 | 21 | if ($computedLastDate > $periodEnd) { |
|
704 | return ($computedLastDate - $periodEnd); |
||
705 | } |
||
706 | |||
707 | 21 | return 0; |
|
708 | } |
||
709 | |||
710 | |||
711 | /** |
||
712 | * set the date to the next valid date |
||
713 | * @param BAB_DateTime $date |
||
714 | * @return BAB_DateTime |
||
715 | */ |
||
716 | 27 | protected function getNextValidDate(BAB_DateTime $date) |
|
717 | { |
||
718 | 27 | $moment = $date->getTimeStamp(); |
|
719 | |||
720 | 27 | foreach ($this->getWorkingPeriods() as $period) { |
|
721 | |||
722 | 27 | if ($moment >= $period->ts_end) { |
|
723 | 27 | continue; |
|
724 | } |
||
725 | |||
726 | // if the future date (end date of the element) is in a worked period |
||
727 | // the future date is valid as a next date |
||
728 | 27 | if ($moment < $period->ts_end && $moment > $period->ts_begin) { |
|
729 | 15 | return $date; |
|
730 | } |
||
731 | |||
732 | |||
733 | 13 | return BAB_DateTime::fromTimeStamp($period->ts_begin); |
|
734 | 23 | } |
|
735 | |||
736 | |||
737 | 23 | return $date; |
|
738 | } |
||
739 | |||
740 | |||
741 | |||
742 | /** |
||
743 | * Add quantity to startdate only on working periods |
||
744 | * |
||
745 | * @param BAB_DateTime $startdate |
||
746 | * @param float $quantity |
||
747 | * @param string $quantity_unit D|H |
||
748 | * |
||
749 | * @return BAB_DateTime |
||
750 | */ |
||
751 | 27 | protected function getFutureDate(BAB_DateTime $startdate, $quantity, $quantity_unit) |
|
752 | { |
||
753 | 27 | if ('H' === $quantity_unit) { |
|
754 | 4 | return $this->getFutureDate_Hours($startdate, $quantity); |
|
755 | } |
||
756 | |||
757 | 24 | return $this->getFutureDate_Days($startdate, $quantity); |
|
758 | } |
||
759 | |||
760 | |||
761 | /** |
||
762 | * Split working periods |
||
763 | * @return array |
||
764 | */ |
||
765 | 27 | protected function getWorkingPeriodsFromDate(BAB_DateTime $startdate) |
|
766 | { |
||
767 | 27 | $periods = array(); |
|
768 | 27 | $start = $startdate->getTimeStamp(); |
|
769 | |||
770 | 27 | foreach ($this->getWorkingPeriods() as $period) { |
|
771 | |||
772 | 27 | $period = clone $period; // do not overwrite the working periods |
|
773 | // create array of new objects |
||
774 | |||
775 | 27 | if ($start >= $period->ts_end) { |
|
776 | // continue to the next worked period |
||
777 | 21 | continue; |
|
778 | } |
||
779 | |||
780 | 27 | if ($start > $period->ts_begin && $start < $period->ts_end) { |
|
781 | 15 | $period->setBeginDate($startdate); |
|
782 | 15 | $periods[] = $period; |
|
783 | 15 | continue; |
|
784 | } |
||
785 | |||
786 | 27 | $periods[] = $period; |
|
787 | 27 | } |
|
788 | |||
789 | 27 | return $periods; |
|
790 | } |
||
791 | |||
792 | |||
793 | |||
794 | /** |
||
795 | * Add quantity to startdate only on working periods |
||
796 | * |
||
797 | * @param BAB_DateTime $startdate |
||
798 | * @param float $seconds_to_add |
||
799 | * |
||
800 | * @return BAB_DateTime |
||
801 | */ |
||
802 | 27 | protected function getFutureDate_Seconds(BAB_DateTime $startdate, $seconds_to_add) |
|
803 | { |
||
804 | 27 | $worked_total = 0; //seconds |
|
805 | |||
806 | |||
807 | 27 | foreach ($this->getWorkingPeriodsFromDate($startdate) as $period) { |
|
808 | |||
809 | 27 | $add_in_period = ($seconds_to_add - $worked_total); |
|
810 | 27 | $worked_total += $period->getDuration(); |
|
811 | |||
812 | 27 | if ((int) $worked_total === (int) $seconds_to_add) { |
|
813 | // la duree de la periode de travail est egale a duree demandee |
||
814 | // en tenant compte des periodes de travail precedentes |
||
815 | |||
816 | 25 | return BAB_DateTime::fromTimeStamp($period->ts_end); |
|
817 | } |
||
818 | |||
819 | |||
820 | 27 | if ($worked_total > $seconds_to_add) { |
|
821 | // la date future se trouve a l'interieur d'une periode travaillee |
||
822 | 15 | $futureDate = $period->ts_begin + $add_in_period; |
|
823 | 15 | return BAB_DateTime::fromTimeStamp($futureDate); |
|
824 | } |
||
825 | |||
826 | // continue to the next worked period |
||
827 | |||
828 | 27 | } |
|
829 | |||
830 | return BAB_DateTime::fromIsoDateTime($this->date_end); |
||
831 | } |
||
832 | |||
833 | |||
834 | |||
835 | |||
836 | |||
837 | |||
838 | /** |
||
839 | * Add quantity to startdate only on working periods |
||
840 | * |
||
841 | * @param BAB_DateTime $startdate |
||
842 | * @param float $quantity hours |
||
843 | * |
||
844 | * @return BAB_DateTime |
||
845 | */ |
||
846 | 4 | protected function getFutureDate_Hours(BAB_DateTime $startdate, $quantity) |
|
847 | { |
||
848 | 4 | $seconds_to_add = $quantity * 3600; |
|
849 | |||
850 | 4 | return $this->getFutureDate_Seconds($startdate, $seconds_to_add); |
|
851 | } |
||
852 | |||
853 | |||
854 | |||
855 | |||
856 | |||
857 | |||
858 | |||
859 | |||
860 | |||
861 | |||
862 | |||
863 | |||
864 | |||
865 | /** |
||
866 | * Add quantity to startdate only on working periods |
||
867 | * |
||
868 | * @param BAB_DateTime $startdate |
||
869 | * @param float $quantity days |
||
870 | * |
||
871 | * @return BAB_DateTime |
||
872 | */ |
||
873 | 24 | protected function getFutureDate_Days(BAB_DateTime $startDate, $quantity) |
|
881 | |||
882 | |||
883 | |||
884 | |||
885 | |||
886 | |||
887 | |||
888 | /** |
||
889 | * Create the planned periods in the entry boundaries |
||
890 | * from the calendar working periods |
||
891 | */ |
||
892 | 36 | public function createPlannedPeriods() |
|
893 | { |
||
894 | 36 | require_once dirname(__FILE__).'/entry_period.class.php'; |
|
895 | 36 | $this->plannedPeriods = array(); |
|
896 | |||
897 | 36 | foreach ($this->getWorkingPeriods() as $workingPeriod) { |
|
898 | |||
899 | /*@var $workingPeriod bab_CalendarPeriod */ |
||
900 | |||
901 | 36 | $plannedPeriod = new absences_EntryPeriod(); |
|
902 | 36 | $plannedPeriod->setEntry($this); |
|
903 | 36 | $plannedPeriod->date_begin = date('Y-m-d H:i:s', $workingPeriod->ts_begin); |
|
904 | 36 | $plannedPeriod->date_end = date('Y-m-d H:i:s', $workingPeriod->ts_end); |
|
905 | |||
906 | 36 | $this->plannedPeriods[] = $plannedPeriod; |
|
907 | 36 | } |
|
908 | 36 | } |
|
909 | |||
910 | |||
911 | |||
912 | |||
913 | |||
914 | |||
915 | /** |
||
916 | * Save elements of entry to database |
||
917 | * |
||
918 | */ |
||
919 | public function saveElements() |
||
920 | { |
||
921 | $processed_ids = array(); |
||
922 | |||
923 | foreach ($this->elements as $elem) |
||
924 | { |
||
925 | /*@var $elem absences_EntryElem */ |
||
926 | |||
927 | try { |
||
928 | |||
929 | $elem->save(); |
||
930 | $processed_ids[] = $elem->id; |
||
931 | |||
932 | } catch(Exception $e) { |
||
933 | // fail to save one element, it will be deleted or not created |
||
934 | bab_debug($e->getMessage()); |
||
935 | } |
||
936 | } |
||
937 | |||
938 | // delete removed elements |
||
939 | |||
940 | global $babDB; |
||
941 | |||
942 | $babDB->db_query('DELETE FROM absences_entries_elem WHERE id_entry='.$babDB->quote($this->id).' AND id NOT IN('.$babDB->quote($processed_ids).')'); |
||
943 | |||
944 | } |
||
945 | |||
946 | |||
947 | |||
948 | |||
949 | public function savePlannedPeriods() |
||
950 | { |
||
951 | if (empty($this->plannedPeriods)) { |
||
952 | throw new Exception('Planned periods where not loaded or set'); |
||
953 | } |
||
954 | |||
955 | $processed_ids = array(); |
||
956 | |||
957 | foreach ($this->plannedPeriods as $period) |
||
958 | { |
||
959 | /*@var $elem absences_EntryPeriod */ |
||
960 | $period->save(); |
||
961 | |||
962 | $processed_ids[] = $period->id; |
||
963 | } |
||
964 | |||
965 | global $babDB; |
||
966 | |||
967 | $babDB->db_query('DELETE FROM absences_entries_periods WHERE id_entry='.$babDB->quote($this->id).' AND id NOT IN('.$babDB->quote($processed_ids).')'); |
||
968 | |||
969 | } |
||
970 | |||
971 | |||
972 | |||
973 | /** |
||
974 | * Apply dynamic rights for all right involved in the entry |
||
975 | */ |
||
976 | public function applyDynamicRight() |
||
977 | { |
||
978 | require_once dirname(__FILE__).'/agent_right.class.php'; |
||
979 | |||
980 | $I = new absences_AgentRightManagerIterator(); |
||
981 | $I->setAgent($this->getAgent()); |
||
982 | |||
983 | foreach ($I as $agentRight) |
||
984 | { |
||
985 | /*@var $agentRight absences_AgentRight */ |
||
986 | $agentRight->applyDynamicRight(); |
||
987 | } |
||
988 | } |
||
989 | |||
990 | |||
991 | |||
992 | |||
993 | /** |
||
994 | * Add element to list |
||
995 | * @param absences_EntryElem $elem |
||
996 | */ |
||
997 | 43 | public function addElement(absences_EntryElem $elem) |
|
998 | { |
||
999 | 43 | $this->elements[] = $elem; |
|
1000 | 43 | } |
|
1001 | |||
1002 | /** |
||
1003 | * Remove an element in the list |
||
1004 | * @param int $id_right |
||
1005 | * |
||
1006 | * @return bool |
||
1007 | */ |
||
1008 | public function removeElement($id_right) |
||
1009 | { |
||
1010 | foreach ($this->elements as $key => $elem) |
||
1011 | { |
||
1012 | if ($elem->id_right == $id_right) |
||
1013 | { |
||
1014 | unset($this->elements[$key]); |
||
1015 | return true; |
||
1016 | } |
||
1017 | } |
||
1018 | |||
1019 | return false; |
||
1020 | } |
||
1021 | |||
1022 | |||
1023 | /** |
||
1024 | * Set the working period index for the entry |
||
1025 | * Used in unit tests to set differents working periods |
||
1026 | * if not used, the workingPeriodIndex will be generated from the calendar API |
||
1027 | * |
||
1028 | */ |
||
1029 | 42 | public function setWorkingPeriodIndex(Array $index_working) |
|
1030 | { |
||
1031 | 42 | $this->workingPeriodIndex = $index_working; |
|
1032 | 42 | return $this; |
|
1033 | } |
||
1034 | |||
1035 | /** |
||
1036 | * Get working period index for the user and for the period |
||
1037 | * @return array |
||
1038 | */ |
||
1039 | 39 | private function getWorkingPeriodIndex() |
|
1040 | { |
||
1041 | 39 | if (!isset($this->workingPeriodIndex)) { |
|
1042 | |||
1043 | include_once $GLOBALS['babInstallPath']."utilit/dateTime.php"; |
||
1044 | |||
1045 | list($index_working,, $is_free) = absences_getHalfDaysIndex( |
||
1046 | $this->id_user, |
||
1047 | BAB_DateTime::fromIsoDateTime($this->date_begin), |
||
1048 | BAB_DateTime::fromIsoDateTime($this->date_end), |
||
1049 | true |
||
1050 | ); |
||
1051 | |||
1052 | |||
1053 | foreach ($index_working as $key => $period_list) { |
||
1054 | if (!isset($is_free[$key])) { |
||
1055 | unset($index_working[$key]); |
||
1056 | } |
||
1057 | } |
||
1058 | |||
1059 | $this->workingPeriodIndex = $index_working; |
||
1060 | } |
||
1061 | |||
1062 | 39 | return $this->workingPeriodIndex; |
|
1063 | } |
||
1064 | |||
1065 | |||
1066 | |||
1067 | /** |
||
1068 | * Number of free days and hours between two dates |
||
1069 | * |
||
1070 | */ |
||
1071 | 39 | private function loadDurations() { |
|
1072 | |||
1073 | 39 | $this->duration_days = 0.0; |
|
1074 | 39 | $this->duration_hours = 0.0; |
|
1075 | 39 | $this->working_periods = array(); |
|
1076 | |||
1077 | |||
1078 | |||
1079 | 39 | $index_working = $this->getWorkingPeriodIndex(); |
|
1080 | |||
1081 | |||
1082 | 39 | foreach ($index_working as $period_list) { |
|
1083 | |||
1084 | 39 | $this->duration_days += 0.5; |
|
1085 | |||
1086 | 39 | foreach($period_list as $p) |
|
1087 | { |
||
1088 | /*@var $p bab_CalendarPeriod */ |
||
1089 | |||
1090 | 39 | if ($p->getCollection() instanceof bab_WorkingPeriodCollection) |
|
1091 | 39 | { |
|
1092 | 39 | $this->working_periods[] = $p; |
|
1093 | 39 | $this->duration_hours += ($p->getDuration() / 3600); |
|
1094 | 39 | } |
|
1095 | 39 | } |
|
1096 | 39 | } |
|
1097 | 39 | } |
|
1098 | |||
1099 | |||
1100 | /** |
||
1101 | * Get list of working periods of the entry |
||
1102 | * @return bab_CalendarPeriod[] |
||
1103 | */ |
||
1104 | 39 | protected function getWorkingPeriods() |
|
1105 | { |
||
1106 | 39 | if (!isset($this->working_periods)) { |
|
1107 | 39 | $this->loadDurations(); |
|
1108 | 39 | } |
|
1109 | |||
1110 | 39 | return $this->working_periods; |
|
1111 | } |
||
1112 | |||
1113 | |||
1114 | /** |
||
1115 | * List of working periods for one day |
||
1116 | * @param string $date 10 chars |
||
1117 | * |
||
1118 | * @return bab_CalendarPeriod[] |
||
1119 | */ |
||
1120 | public function getDayWorkingPeriods($date) |
||
1121 | { |
||
1122 | $return = array(); |
||
1123 | foreach ($this->getWorkingPeriods() as $period) { |
||
1124 | if ($date === date('Y-m-d', $period->ts_begin)) { |
||
1125 | $return[] = $period; |
||
1126 | } |
||
1127 | } |
||
1128 | |||
1129 | return $return; |
||
1130 | } |
||
1131 | |||
1132 | |||
1133 | /** |
||
1134 | * List of working periods for one day |
||
1135 | * @param string $date 10 chars |
||
1136 | * |
||
1137 | * @return absences_EntryPeriod[] |
||
1138 | */ |
||
1139 | public function getDayPlannedPeriods($date) |
||
1140 | { |
||
1141 | $return = array(); |
||
1142 | foreach ($this->getPlannedPeriodsIterator() as $period) { |
||
1143 | if ($date === substr($period->date_begin, 0, 10)) { |
||
1144 | $return[] = $period; |
||
1145 | } |
||
1146 | } |
||
1147 | |||
1148 | return $return; |
||
1149 | } |
||
1150 | |||
1151 | |||
1152 | |||
1153 | |||
1154 | /** |
||
1155 | * Get period duration in days |
||
1156 | * @return float |
||
1157 | */ |
||
1158 | public function getDurationDays() |
||
1159 | { |
||
1160 | if (!isset($this->duration_days)) |
||
1161 | { |
||
1162 | $this->loadDurations(); |
||
1163 | } |
||
1164 | |||
1165 | return $this->duration_days; |
||
1166 | } |
||
1167 | |||
1168 | /** |
||
1169 | * Get period duration in hours |
||
1170 | * @return float |
||
1171 | */ |
||
1172 | public function getDurationHours() |
||
1181 | |||
1182 | |||
1183 | /** |
||
1184 | * Convert a number of days to hours |
||
1185 | * @param float $days |
||
1186 | * @return float |
||
1187 | */ |
||
1188 | 24 | View Code Duplication | private function daysToHours($days) |
1189 | { |
||
1190 | 24 | $plannedDays = $this->getPlannedDurationDays(); |
|
1191 | |||
1192 | 24 | if (!$plannedDays) { |
|
1193 | return 0; |
||
1194 | } |
||
1195 | |||
1196 | 24 | $ratio = $this->getPlannedDurationHours() / $plannedDays; |
|
1197 | 24 | return round(($ratio * $days), 2); |
|
1198 | } |
||
1199 | |||
1200 | /** |
||
1201 | * Convert a number of hours to days |
||
1202 | * @param float $hours |
||
1203 | * @return float |
||
1204 | */ |
||
1205 | 1 | View Code Duplication | private function hoursToDays($hours) |
1216 | |||
1217 | |||
1218 | |||
1219 | /** |
||
1220 | * Compute totals for loaded elements |
||
1221 | */ |
||
1222 | 24 | private function loadedElementsTotal() |
|
1254 | |||
1255 | |||
1256 | /** |
||
1257 | * Populate the cache variables for one element |
||
1258 | * |
||
1259 | * @param absences_Right $right |
||
1260 | * @param float $days |
||
1261 | * @param float $hours |
||
1262 | */ |
||
1263 | 24 | private function addQUantityInCache(absences_Right $right, $days, $hours) |
|
1278 | |||
1279 | |||
1280 | |||
1281 | |||
1282 | |||
1283 | /** |
||
1284 | * Get sum of elements quantity, converted in days |
||
1285 | * |
||
1286 | * @param int $id_type Optional filter by type |
||
1287 | * |
||
1288 | * @return float |
||
1289 | */ |
||
1290 | 24 | View Code Duplication | public function getTotalDays($id_type = null) |
1307 | |||
1308 | /** |
||
1309 | * Get sum of elements quantity, converted in hours |
||
1310 | * |
||
1311 | * @param int $id_type Optional filter by type |
||
1312 | * |
||
1313 | * @return float |
||
1314 | */ |
||
1315 | 24 | View Code Duplication | public function getTotalHours($id_type = null) |
1332 | |||
1333 | |||
1334 | |||
1335 | |||
1336 | /** |
||
1337 | * Number of days on entry between two dates |
||
1338 | * si les dates de l'element sont a cheval sur la periode demandee |
||
1339 | * on utlise les heures travailles qui etait en vigeur au moment de la creation |
||
1340 | * de la demande |
||
1341 | * |
||
1342 | * @param string $begin Datetime |
||
1343 | * @param string $end Datetime |
||
1344 | * @param int $id_type Optional filter by type |
||
1345 | * |
||
1346 | * @return float (days) |
||
1347 | */ |
||
1348 | 1 | View Code Duplication | public function getPlannedDaysBetween($begin, $end, $id_type = null) |
1378 | |||
1379 | |||
1380 | |||
1381 | |||
1382 | /** |
||
1383 | * Number of hours on entry between two dates |
||
1384 | * si les dates de l'element sont a cheval sur la periode demandee |
||
1385 | * on utlise les heures travailles qui etait en vigeur au moment de la creation |
||
1386 | * de la demande |
||
1387 | * |
||
1388 | * @param string $begin Datetime |
||
1389 | * @param string $end Datetime |
||
1390 | * @param int $id_type Optional filter by type |
||
1391 | * |
||
1392 | * @return float (hours) |
||
1393 | */ |
||
1394 | View Code Duplication | public function getPlannedHoursBetween($begin, $end, $id_type = null) |
|
1424 | |||
1425 | |||
1426 | |||
1427 | |||
1428 | |||
1429 | |||
1430 | |||
1431 | |||
1432 | /** |
||
1433 | * Test if the loaded elements in entry contains rights in hours |
||
1434 | * @return bool |
||
1435 | */ |
||
1436 | public function containsHours() |
||
1448 | |||
1449 | |||
1450 | /** |
||
1451 | * Test if loaded elements in entry require approval |
||
1452 | * |
||
1453 | * @return bool |
||
1454 | */ |
||
1455 | public function requireApproval() |
||
1472 | |||
1473 | |||
1474 | public function checkAvailable() |
||
1484 | |||
1485 | |||
1486 | /** |
||
1487 | * Check elements validity |
||
1488 | * @throws UnexpectedValueException |
||
1489 | * |
||
1490 | * @return int number of elements with quantity > 0 |
||
1491 | */ |
||
1492 | protected function checkElementsValidity() |
||
1508 | |||
1509 | |||
1510 | /** |
||
1511 | * throw an exception if there is another entry in the same period |
||
1512 | * @throws absences_EntryException |
||
1513 | */ |
||
1514 | protected function checkOtherEntriesValidity() |
||
1535 | |||
1536 | |||
1537 | /** |
||
1538 | * Check request validity |
||
1539 | * |
||
1540 | * @throws absences_EntryException |
||
1541 | * @throws UnexpectedValueException |
||
1542 | * |
||
1543 | * @param bool $checkDuration Checking duration require a saved entry |
||
1544 | * Use false if entry is checked before save |
||
1545 | * |
||
1546 | * @return bool |
||
1547 | */ |
||
1548 | public function checkValidity($checkDuration = true) |
||
1656 | |||
1657 | |||
1658 | /** |
||
1659 | * (non-PHPdoc) |
||
1660 | * @see absences_Request::modifiedOn() |
||
1661 | * |
||
1662 | * @return string |
||
1663 | */ |
||
1664 | 1 | public function modifiedOn() |
|
1668 | |||
1669 | /** |
||
1670 | * Test if the entry is a fixed vacation |
||
1671 | * @return bool |
||
1672 | */ |
||
1673 | public function isFixed() |
||
1678 | |||
1679 | |||
1680 | |||
1681 | |||
1682 | |||
1683 | /** |
||
1684 | * Test if entry is previsonal |
||
1685 | * @return bool |
||
1686 | */ |
||
1687 | public function isPrevisonal() |
||
1691 | |||
1692 | /** |
||
1693 | * Test if at least one entry in folder is previsonal |
||
1694 | * @return boolean |
||
1695 | */ |
||
1696 | public function isFolderPrevisonal() |
||
1709 | |||
1710 | /** |
||
1711 | * Get the first entry in folder |
||
1712 | * @return absences_Entry |
||
1713 | */ |
||
1714 | View Code Duplication | public function getFolderFirst() |
|
1731 | |||
1732 | |||
1733 | /** |
||
1734 | * Process specific code when the request is rejected |
||
1735 | * |
||
1736 | */ |
||
1737 | protected function onReject() |
||
1741 | |||
1742 | |||
1743 | /** |
||
1744 | * Process specific code when the request is confirmed |
||
1745 | * |
||
1746 | */ |
||
1747 | public function onConfirm() |
||
1751 | |||
1752 | |||
1753 | |||
1754 | /** |
||
1755 | * Call the user calendar backend to update the event |
||
1756 | * call the event to notify about calendar event modification |
||
1757 | */ |
||
1758 | public function updateCalendar() |
||
1787 | |||
1788 | |||
1789 | public function getTitle() |
||
1797 | |||
1798 | |||
1799 | View Code Duplication | public function getNotifyFields() |
|
1807 | |||
1808 | |||
1809 | View Code Duplication | public function getYear() |
|
1820 | |||
1821 | |||
1822 | View Code Duplication | public function getArchiveYear() |
|
1842 | |||
1843 | View Code Duplication | public function archive() |
|
1854 | |||
1855 | |||
1856 | View Code Duplication | public function setNotified() |
|
1872 | |||
1873 | |||
1874 | public function getManagerEditUrl() |
||
1880 | |||
1881 | |||
1882 | public function getManagerDeleteUrl() |
||
1891 | |||
1892 | |||
1893 | public function getManagerFrame() |
||
1908 | |||
1909 | |||
1910 | /** |
||
1911 | * |
||
1912 | * @param bool $display_username Affiche le nom du demandeur dans la card frame ou non, utile pour les listes contenant plusieurs demandeurs possibles |
||
1913 | * @param int $rfrom si les demandes de la liste sont modifiee par un gestionnaire ou gestionnaire delegue |
||
1914 | * @param int $ide id entite de l'organigramme >0 si gestionnaire delegue seulement |
||
1915 | */ |
||
1916 | public function getCardFrame($display_username, $rfrom, $ide) |
||
1990 | |||
1991 | |||
1992 | |||
1993 | |||
1994 | |||
1995 | /** |
||
1996 | * @return string |
||
1997 | */ |
||
1998 | public function getEditUrl($rfrom, $ide = null) |
||
2015 | |||
2016 | |||
2017 | |||
2018 | /** |
||
2019 | * Delete the vacation request |
||
2020 | * @return bool |
||
2021 | */ |
||
2022 | public function delete() |
||
2079 | |||
2080 | |||
2081 | |||
2082 | |||
2083 | |||
2084 | |||
2085 | |||
2086 | /** |
||
2087 | * (non-PHPdoc) |
||
2088 | * @see absences_Request::notifyOwner() |
||
2089 | */ |
||
2090 | public function notifyOwner() |
||
2110 | |||
2111 | } |
||
2112 | |||
2736 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.