Completed
Push — master ( 6d7662...44ae7a )
by Paul
06:04
created

absences_EntryIterator   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 69.47%

Importance

Changes 0
Metric Value
dl 0
loc 256
ccs 66
cts 95
cp 0.6947
rs 10
c 0
b 0
f 0
wmc 27
lcom 1
cbo 2

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getObject() 0 8 1
A getBaseQuery() 0 8 1
F getWhere() 0 93 20
B executeQuery() 0 23 5
1
<?php
2
/************************************************************************
3
 * OVIDENTIA http://www.ovidentia.org                                   *
4
 ************************************************************************
5
 * Copyright (c) 2003 by CANTICO ( http://www.cantico.fr )              *
6
 *                                                                      *
7
 * This file is part of Ovidentia.                                      *
8
 *                                                                      *
9
 * Ovidentia is free software; you can redistribute it and/or modify    *
10
 * it under the terms of the GNU General Public License as published by *
11
 * the Free Software Foundation; either version 2, or (at your option)  *
12
 * any later version.													*
13
 *																		*
14
 * This program 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 General Public License for more details.				*
18
 *																		*
19
 * You should have received a copy of the GNU General Public License	*
20
 * along with this program; if not, write to the Free Software			*
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,*
22
 * USA.																	*
23
************************************************************************/
24
25
26
require_once dirname(__FILE__).'/vacincl.php';
27
require_once dirname(__FILE__).'/request.class.php';
28
require_once $GLOBALS['babInstallPath'].'utilit/urlincl.php';
29
30
31
/**
32
 * Vacation request
33
 *
34
 *
35
 * @property int	$id_user
36
 * @property string $createdOn
37
 * @property int	$createdBy
38
 * @property string	$date_begin
39
 * @property string	$date_end
40
 * @property int	$idfai
41
 * @property string	$comment
42
 * @property string	$date			Last modification date or approbation date (last action)
43
 * @property string	$status			'' : unconfirmed ; 'Y' : confirmed ; 'P' : previsional
44
 * @property string	$comment2		Commentaire approbateur
45
 * @property int	$id_approver
46
 * @property int	$folder
47
 * @property int	$creation_type
48
 * @property int	$archived
49
 * 
50
 *
51
 */
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)
139
	{
140
		$request = new absences_Entry();
141
		$request->id = $id;
142
143
		return $request;
144
	}
145
146
147
	/**
148
	 * (non-PHPdoc)
149
	 * @see absences_Record::getRow()
150
	 */
151 41
	public function getRow()
152
	{
153 41
		if (null === $this->row)
154 41
		{
155 11
			if (!isset($this->id))
156 11
			{
157
				throw new Exception('Failed to load entry, missing entry id');
158
			}
159
160 11
			global $babDB;
161 11
			$res = $babDB->db_query('SELECT * FROM absences_entries WHERE id='.$babDB->quote($this->id));
162 11
			$this->setRow($babDB->db_fetch_assoc($res));
163 11
		}
164
165 41
		return $this->row;
166
	}
167
168
169
	/**
170
	 * (non-PHPdoc)
171
	 * @see absences_Request::getRequestType()
172
	 *
173
	 * @return string
174
	 */
175
	public function getRequestType()
176
	{
177
		switch($this->creation_type)
178
		{
179
			case '1':
180
				return absences_translate('Fixed vacation');
181
182
			default:
183
			case '0':
0 ignored issues
show
Unused Code introduced by
case '0': return abs...('Requested vacation'); does not seem to be reachable.

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 or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

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.

Loading history...
184
				return absences_translate('Requested vacation');
185
		}
186
187
188
189
	}
190
191
192
193
194
	public function getApprobationId()
195
	{
196
		if ($agent = $this->getAgent())
197
		{
198
			return $agent->getApprobationId();
199
		}
200
201
		return null;
202
	}
203
204
205
206
207
208
	/**
209
	 * Get elements stored in database
210
	 * @return absences_EntryElemIterator
211
	 */
212
	public function getElementsIterator()
213
	{
214
		$I = new absences_EntryElemIterator;
215
		$I->entry = $this;
216
217
		return $I;
218
	}
219
220
221 28
	public function getPlannedPeriodsIterator()
222
	{
223 28
	    $I = new absences_EntryPeriodIterator;
224 28
	    $I->entry = $this;
225
226 28
	    return $I;
227
	}
228
229
230
231
	/**
232
	 * Get entries within the same folder
233
	 * @return absences_EntryIterator
234
	 */
235 View Code Duplication
	public function getFolderEntriesIterator()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
236
	{
237
		if (!$this->folder)
238
		{
239
			return null;
240
		}
241
242
		$I = new absences_EntryIterator;
243
		$I->folder = $this->folder;
0 ignored issues
show
Documentation Bug introduced by
The property $folder was declared of type string, but $this->folder is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
244
245
		return $I;
246
	}
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 = '')
260
	{
261
		foreach($this->elements as $elem)
262
		{
263
			/*@var $elem absences_EntryElem */
264
			$elem->addMovement($message, $comment);
265
		}
266
	}
267
268
269
270
271
	/**
272
	 * Load elements from database
273
	 * @throws Exception
274
	 */
275
	public function loadElements()
276
	{
277
		if (!isset($this->id))
278
		{
279
			throw new Exception('Failed to load entry elements, id missing');
280
		}
281
282
		$this->elements = array();
283
284
		foreach($this->getElementsIterator() as $entryElem)
285
		{
286
			/*@var $entryElem absences_EntryElem */
287
			$this->addElement($entryElem);
288
		}
289
	}
290
291
	/**
292
	 * Get the loaded elements
293
	 * @return array
294
	 */
295 15
	public function getElements()
296
	{
297 15
		return $this->elements;
298
	}
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)
361
	{
362
	    $this->plannedPeriods[] = $plannedPeriod;
363
	}
364
365
366
367
368
	/**
369
	 * Load the planned working periods from database
370
	 * @throws Exception
371
	 */
372 29
	public function loadPlannedPeriods()
373
	{
374 29
	    if (!isset($this->id))
375 29
	    {
376
	        throw new Exception('Failed to load entry periods, id missing');
377
	    }
378
379 28
	    $this->plannedPeriods = array();
380
381 28
	    $res = $this->getPlannedPeriodsIterator();
382
383 28
	    if (0 === $res->count()) {
384 28
	        return $this->createPlannedPeriods();
385
	    }
386
387
	    foreach($res as $plannedPeriod)
388
	    {
389
	        /*@var $plannedPeriod absences_EntryPeriod */
390
	        $this->addPeriod($plannedPeriod);
391
	    }
392
	}
393
394
	/**
395
	 * Get the loaded planned working periods
396
	 * @return absences_EntryPeriod[]
397
	 */
398 33
	public function getPlannedPeriods()
399
	{
400 33
	    return $this->plannedPeriods;
401
	}
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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()
592
	{
593 27
	    usort($this->elements, array('absences_Entry', 'sortElem'));
594 27
	}
595
596 27
	private static function sortElem(absences_EntryElem $elem1, absences_EntryElem $elem2)
597
	{
598 27
	    $right1 = $elem1->getRight();
599 27
	    $right2 = $elem2->getRight();
600
601 27
	    if ($right1->sortkey > $right2->sortkey) {
602 26
	        return 1;
603
	    }
604
605 2
	    if ($right1->sortkey < $right2->sortkey) {
606 2
	        return -1;
607
	    }
608
609 1
	    $type1 = $right1->getType();
610 1
	    $type2 = $right2->getType();
611
612 1
	    return bab_compare(mb_strtolower($type1->name), mb_strtolower($type2->name));
613
	}
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()
622
	{
623 33
	    foreach($this->elements as $elem) {
624 33
	        if (!isset($elem->date_begin) || '0000-00-00 00:00:00' === $elem->date_begin) {
625 33
	            return false;
626
	        }
627
	        
628 10
	        if (!isset($elem->date_end) || '0000-00-00 00:00:00' === $elem->date_end) {
629
	            return false;
630
	        }
631 10
	    }
632
	    
633 10
	    return true;
634
	}
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) {
0 ignored issues
show
Bug introduced by
The expression $this->getWorkingPeriods() of type null|array<integer,object<bab_CalendarPeriod>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
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) {
0 ignored issues
show
Bug introduced by
The expression $this->getWorkingPeriods() of type null|array<integer,object<bab_CalendarPeriod>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
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
0 ignored issues
show
Documentation introduced by
There is no parameter named $startdate. Did you maybe mean $startDate?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
869
	 * @param float $quantity  days
870
	 *
871
	 * @return BAB_DateTime
872
	 */
873 24
	protected function getFutureDate_Days(BAB_DateTime $startDate, $quantity)
874
	{
875 24
	    $total_seconds = $this->getTotalHours() * 3600;
876 24
	    $total_days = $this->getTotalDays();
877 24
	    $seconds_to_add = $quantity * $total_seconds / $total_days;
878
	    
879 24
	    return $this->getFutureDate_Seconds($startDate, $seconds_to_add);
880
	}
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) {
0 ignored issues
show
Bug introduced by
The expression $this->getWorkingPeriods() of type null|array<integer,object<bab_CalendarPeriod>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
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) {
0 ignored issues
show
Bug introduced by
The expression $this->getWorkingPeriods() of type null|array<integer,object<bab_CalendarPeriod>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
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()
1173
	{
1174
		if (!isset($this->duration_hours))
1175
		{
1176
			$this->loadDurations();
1177
		}
1178
1179
		return $this->duration_hours;
1180
	}
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1206
	{
1207 1
	    $plannedHours = $this->getPlannedDurationHours();
1208
	    
1209 1
	    if (!$plannedHours) {
1210
	        return 0;
1211
	    }
1212
	    
1213 1
		$ratio = $this->getPlannedDurationDays() / $plannedHours;
1214 1
		return round(($ratio * $hours), 2);
1215
	}
1216
1217
1218
1219
	/**
1220
	 * Compute totals for loaded elements
1221
	 */
1222 24
	private function loadedElementsTotal()
1223
	{
1224 24
		if (empty($this->elements))
1225 24
		{
1226
			$this->loadElements();
1227
		}
1228
1229 24
		$this->total_days = 0.0;
1230 24
		$this->total_hours = 0.0;
1231 24
		$this->total_type_days = array();
1232 24
		$this->total_type_hours = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type double of property $total_type_hours.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1233
1234 24
		foreach($this->elements as $elem)
1235
		{
1236
			/*@var $elem absences_EntryElem */
1237 24
			$right = $elem->getRight();
1238
1239 24
			$quantity = (float) $elem->quantity;
1240
1241 24
			switch($right->quantity_unit)
1242
			{
1243 24
				case 'D':
1244 24
					$hours = $this->daysToHours($quantity);
1245 24
					$this->addQUantityInCache($right, $quantity, $hours);
1246 24
					break;
1247 1
				case 'H':
1248 1
				    $days = $this->hoursToDays($quantity);
1249 1
				    $this->addQUantityInCache($right, $days, $quantity);
1250 1
					break;
1251 24
			}
1252 24
		}
1253 24
	}
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)
1264
	{
1265 24
	    if (!isset($this->total_type_days[$right->id_type])) {
1266 24
	        $this->total_type_days[$right->id_type] = 0.0;
1267 24
	    }
1268
1269 24
	    if (!isset($this->total_type_hours[$right->id_type])) {
1270 24
	        $this->total_type_hours[$right->id_type] = 0.0;
1271 24
	    }
1272
1273 24
	    $this->total_days += $days;
1274 24
	    $this->total_hours += $hours;
1275 24
	    $this->total_type_days[$right->id_type] += $days;
1276 24
	    $this->total_type_hours[$right->id_type] += $hours;
1277 24
	}
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1291
	{
1292 24
		if (!isset($this->total_days)) {
1293
			$this->loadedElementsTotal();
1294
		}
1295
1296 24
		if (isset($id_type)) {
1297
1298
		    if (!isset($this->total_type_days[$id_type])) {
1299
		        return 0.0;
1300
		    }
1301
1302
		    return $this->total_type_days[$id_type];
1303
		}
1304
1305 24
		return $this->total_days;
1306
	}
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1316
	{
1317 24
		if (!isset($this->total_hours)) {
1318 24
			$this->loadedElementsTotal();
1319 24
		}
1320
1321 24
		if (isset($id_type)) {
1322
1323
		    if (!isset($this->total_type_hours[$id_type])) {
1324
		        return 0.0;
1325
		    }
1326
1327
		    return $this->total_type_hours[$id_type];
1328
		}
1329
1330 24
		return $this->total_hours;
1331
	}
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1349
	{
1350 1
	    if (empty($this->elements))
1351 1
	    {
1352
	        $this->loadElements();
1353
	    }
1354
1355 1
	    $total = 0.0;
1356 1
	    foreach($this->elements as $elem)
1357
	    {
1358
	        /*@var $elem absences_EntryElem */
1359 1
	        $right = $elem->getRight();
1360
1361 1
	        if (isset($id_type) && (int) $id_type !== (int) $right->id_type) {
1362
	            continue;
1363
	        }
1364
1365 1
	        $quantity = $elem->getPlannedQuantityBetween($begin, $end);
1366
1367 1
	        if ('H' === $right->quantity_unit) {
1368
	            $days = $this->hoursToDays($quantity);
1369
	        } else {
1370 1
	            $days = $quantity;
1371
	        }
1372
1373 1
	        $total += $days;
1374 1
	    }
1375
1376 1
	    return $total;
1377
	}
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1395
	{
1396
	    if (empty($this->elements))
1397
	    {
1398
	        $this->loadElements();
1399
	    }
1400
1401
	    $total = 0.0;
1402
	    foreach($this->elements as $elem)
1403
	    {
1404
	        /*@var $elem absences_EntryElem */
1405
	        $right = $elem->getRight();
1406
1407
	        if (isset($id_type) && (int) $id_type !== (int) $right->id_type) {
1408
	            continue;
1409
	        }
1410
1411
	        $quantity = $elem->getPlannedQuantityBetween($begin, $end);
1412
1413
	        if ('D' === $right->quantity_unit) {
1414
	            $hours = $this->daysToHours($quantity);
1415
	        } else {
1416
	            $hours = $quantity;
1417
	        }
1418
1419
	        $total += $hours;
1420
	    }
1421
1422
	    return $total;
1423
	}
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()
1437
	{
1438
		foreach($this->elements as $elem)
1439
		{
1440
			if ('H' === $elem->getRight()->quantity_unit)
1441
			{
1442
				return true;
1443
			}
1444
		}
1445
1446
		return false;
1447
	}
1448
1449
1450
	/**
1451
	 * Test if loaded elements in entry require approval
1452
	 *
1453
	 * @return bool
1454
	 */
1455
	public function requireApproval()
1456
	{
1457
		if (empty($this->elements))
1458
		{
1459
			$this->loadElements();
1460
		}
1461
1462
		foreach($this->elements as $elem)
1463
		{
1464
			if (1 === (int) $elem->getRight()->require_approval)
1465
			{
1466
				return true;
1467
			}
1468
		}
1469
1470
		return false;
1471
	}
1472
	
1473
	
1474
	public function checkAvailable()
1475
	{
1476
	    $res = $this->getElementsIterator();
1477
	    foreach ($res as $element) {
1478
	        /*@var $element absences_EntryElem */
1479
	        if (!$element->isQuantityAvailable()) {
1480
	            throw new Exception(sprintf(absences_translate('Failed to submit this request, the quantity for right %s s not available'), $element->getRight()->description));
1481
	        }
1482
	    }
1483
	}
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()
1493
	{
1494
	    $count = 0;
1495
	    foreach($this->elements as $elem)
1496
	    {
1497
	        $quantity = (int) round(100 * $elem->quantity);
1498
	        if ($quantity > 0)
1499
	        {
1500
	            $count++;
1501
	        }
1502
	    
1503
	        $elem->checkValidity();
1504
	    }
1505
	    
1506
	    return $count;
1507
	}
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()
1515
	{
1516
	    $otherEntries = new absences_EntryIterator();
1517
	    $otherEntries->from = $this->date_begin;
1518
	    $otherEntries->to = $this->date_end;
1519
	    $otherEntries->users = array($this->id_user);
1520
	    
1521
	    
1522
	    foreach ($otherEntries as $otherEntry) {
1523
	    
1524
	        /* @var $otherEntry absences_Entry */
1525
	    
1526 View Code Duplication
	        if ($this->id != $otherEntry->id) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1527
	            $e = new absences_EntryException(absences_translate('There is allready an absence request in the period'));
1528
	            $e->entry = $this;
1529
	            $e->blocking = true;
1530
	            throw $e;
1531
	        }
1532
	    }
1533
	    
1534
	}
1535
1536
1537
	/**
1538
	 * Check request validity
1539
	 *
1540
	 * @throws absences_EntryException
1541
	 * @throws UnexpectedValueException
1542
	 * 
1543
	 * @return bool
1544
	 */
1545
	public function checkValidity()
1546
	{
1547
		// verify mandatory data
1548
1549
		if (!isset($this->id_user) || $this->id_user <= 0)
1550
		{
1551
			throw new UnexpectedValueException('Unexpected id_user');
1552
		}
1553
1554
1555
		$count = $this->checkElementsValidity();
1556
1557
1558 View Code Duplication
		if (0 === $count)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1559
		{
1560
			$e = new absences_EntryException(absences_translate('At least one vacation right must be used'));
1561
			$e->entry = $this;
1562
			$e->blocking = true;
1563
			throw $e;
1564
		}
1565
1566
1567
1568
		// test user validity
1569
1570
		require_once $GLOBALS['babInstallPath'].'utilit/userinfosincl.php';
1571
1572
		$creationdate = bab_userInfos::getCreationDate($this->id_user);
1573
1574
		if ($creationdate >= $this->date_end) {
1575
			$e = new absences_EntryException(sprintf(absences_translate('The vacation request end before user creation date : %s'), bab_shortDate(bab_mktime($creationdate))));
1576
			$e->entry = $this;
1577
			$e->blocking = true;
1578
			throw $e;
1579
		}
1580
1581
		// T8359 : si l'utilisateur est reactive la demande ne sera pas presente, il faudra reenregistrer le droit
1582
		// avant la correction de ce ticket, on creeais les demandes pour eviter ce probleme
1583
1584
		if (!bab_userInfos::isValid($this->id_user)) {
1585
1586
		    /*
1587
		    $e = new absences_EntryException(absences_translate('This user account is disabled'));
1588
		    $e->entry = $this;
1589
		    $e->blocking = true;
1590
		    throw $e;
1591
		    */
1592
1593
		    return false;
1594
		}
1595
1596
1597
		// test quantity / period duration in days
1598
1599
		$total = (int) round(100 * $this->getTotalDays());
1600
		$duration = (int) round(100 * $this->getDurationDays());
1601
1602
1603 View Code Duplication
		if (0 === $duration)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1604
		{
1605
			$e = new absences_EntryException(absences_translate('The selected period is not available'));
1606
			$e->entry = $this;
1607
			$e->blocking = true;
1608
			throw $e;
1609
		}
1610
1611
1612
1613
		if ($total !== $duration)
1614
		{
1615
			$e = new absences_EntryException(sprintf(absences_translate('The total quantity (%s) does not match the period duration (%s)'), absences_quantity($this->getTotalDays(), 'D'), absences_quantity($this->getDurationDays(), 'D')));
1616
			$e->entry = $this;
1617
			$e->blocking = !((bool) absences_getVacationOption('allow_mismatch'));
1618
			throw $e;
1619
		}
1620
1621
		// test quantity / period duration in hours only if there is one right in hours
1622
		/*
1623
		 *
1624
		 * Pas de verification du nombre d'heure pour le moment, la precision de la verification du nombre de jours devrais suffire a verifier aussi les heures
1625
		 * c'est ce qui a ete fait sur la partie en HTML lorsque les les tests etait fait uniquement cote client (vacuser.html template newvacation)
1626
		 *
1627
		if ($this->containsHours())
1628
		{
1629
			$total = (int) round(100 * $this->getTotalHours());
1630
			$duration = (int) round(100 * $this->getDurationHours());
1631
1632
			if ($total !== $duration)
1633
			{
1634
				$e = new absences_EntryException(absences_translate('The total quantity does not match the period duration in hours'));
1635
				$e->blocking = !((bool) absences_getVacationOption('allow_mismatch'));
1636
				throw $e;
1637
			}
1638
		}
1639
1640
		*/
1641
1642
1643
1644
		// verifier si la periode demandee n'est pas deja occuppe par une autre demande
1645
        $this->checkOtherEntriesValidity();
1646
		
1647
1648
		return true;
1649
	}
1650
1651
1652
	/**
1653
	 * (non-PHPdoc)
1654
	 * @see absences_Request::modifiedOn()
1655
	 *
1656
	 * @return string
1657
	 */
1658 1
	public function modifiedOn()
1659
	{
1660 1
		return $this->date;
1661
	}
1662
1663
	/**
1664
	 * Test if the entry is a fixed vacation
1665
	 * @return bool
1666
	 */
1667
	public function isFixed()
1668
	{
1669
		return (1 === (int) $this->creation_type);
1670
1671
	}
1672
1673
1674
1675
1676
1677
	/**
1678
	 * Test if entry is previsonal
1679
	 * @return bool
1680
	 */
1681
	public function isPrevisonal()
1682
	{
1683
		return ($this->status === 'P');
1684
	}
1685
1686
	/**
1687
	 * Test if at least one entry in folder is previsonal
1688
	 * @return boolean
1689
	 */
1690
	public function isFolderPrevisonal()
1691
	{
1692
		if (!$this->folder)
1693
		{
1694
			return false;
1695
		}
1696
1697
		$I = new absences_EntryIterator;
1698
		$I->folder = $this->folder;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->folder can also be of type integer. However, the property $folder is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1699
		$I->status = 'P';
1700
1701
		return ($I->count() > 0);
1702
	}
1703
1704
	/**
1705
	 * Get the first entry in folder
1706
	 * @return absences_Entry
1707
	 */
1708 View Code Duplication
	public function getFolderFirst()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1709
	{
1710
		if (!$this->folder)
1711
		{
1712
			return null;
1713
		}
1714
1715
		$I = new absences_EntryIterator;
1716
		$I->folder = $this->folder;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->folder can also be of type integer. However, the property $folder is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1717
1718
		foreach($I as $first)
1719
		{
1720
			return $first;
1721
		}
1722
1723
		return null;
1724
	}
1725
1726
1727
	/**
1728
	 * Process specific code when the request is rejected
1729
	 *
1730
	 */
1731
	protected function onReject()
1732
	{
1733
		$this->updateCalendar();
1734
	}
1735
1736
1737
	/**
1738
	 * Process specific code when the request is confirmed
1739
	 *
1740
	 */
1741
	public function onConfirm()
1742
	{
1743
		$this->updateCalendar();
1744
	}
1745
1746
1747
1748
	/**
1749
	 * Call the user calendar backend to update the event
1750
	 * call the event to notify about calendar event modification
1751
	 */
1752
	public function updateCalendar()
1753
	{
1754
		require_once $GLOBALS['babInstallPath'].'utilit/dateTime.php';
1755
1756
		// try to update event copy in other backend (caldav)
1757
1758
		$begin = BAB_DateTime::fromIsoDateTime($this->date_begin);
1759
		$end = BAB_DateTime::fromIsoDateTime($this->date_end);
1760
		$period = absences_getPeriod($this->id, $this->id_user,  $begin, $end);
1761
		if ($period) {
1762
1763
			// probably set a new description if the event has been approved or rejected
1764
			absences_setPeriodProperties($period, $this);
1765
1766
			// save copy of event to calendar backend (if caldav)
1767
			$period->save();
1768
		}
1769
1770
1771
		// Update calendar data overlapped with event
1772
1773
		$date_begin = bab_mktime($this->date_begin);
1774
		$date_end	= bab_mktime($this->date_end);
1775
1776
		include_once $GLOBALS['babInstallPath']."utilit/eventperiod.php";
1777
		$event = new bab_eventPeriodModified($date_begin, $date_end, $this->id_user);
1778
		$event->types = BAB_PERIOD_VACATION;
1779
		bab_fireEvent($event);
1780
	}
1781
1782
1783
	public function getTitle()
1784
	{
1785
	    if (isset($this->todelete) && $this->todelete) {
1786
	        return absences_translate('vacation request to delete');
1787
	    }
1788
	    
1789
		return absences_translate('vacation request');
1790
	}
1791
1792
1793 View Code Duplication
	public function getNotifyFields()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1794
	{
1795
		return array(
1796
			absences_translate('From') 		=> bab_shortDate(bab_mktime($this->date_begin)),
1797
			absences_translate('Until')		=> bab_shortDate(bab_mktime($this->date_end)),
1798
			absences_translate('Quantity') 	=> absences_quantity($this->getTotalDays(), 'D')
1799
		);
1800
	}
1801
1802
1803 View Code Duplication
	public function getYear()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1804
	{
1805
		$year = (int) substr($this->date_begin, 0, 4);
1806
1807
		if (0 === $year)
1808
		{
1809
			return null;
1810
		}
1811
1812
		return $year;
1813
	}
1814
1815
1816 View Code Duplication
	public function getArchiveYear()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1817
	{
1818
		require_once $GLOBALS['babInstallPath'].'utilit/dateTime.php';
1819
		$year = (int) substr($this->date_begin, 0, 4);
1820
1821
		if (0 === $year)
1822
		{
1823
			return null;
1824
		}
1825
1826
		$day = absences_getVacationOption('archivage_day');
1827
		$month = absences_getVacationOption('archivage_month');
1828
1829
		$currentYear = new BAB_DateTime($year, $month, $day);
1830
		if($this->date_begin < $currentYear->getIsoDate()){
1831
			$year = $year-1;
1832
		}
1833
1834
		return $year;
1835
	}
1836
1837 View Code Duplication
	public function archive()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1838
	{
1839
		global $babDB;
1840
1841
		$babDB->db_query("
1842
			UPDATE absences_entries
1843
			SET archived=".$babDB->quote(1)."
1844
			WHERE
1845
				id=".$babDB->quote($this->id)."
1846
		");
1847
	}
1848
1849
1850 View Code Duplication
	public function setNotified()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1851
	{
1852
		global $babDB;
1853
1854
		if (!$this->id)
1855
		{
1856
			throw new Exception('Missing ID');
1857
		}
1858
1859
		$babDB->db_query("
1860
			UPDATE absences_entries
1861
				SET appr_notified=".$babDB->quote(1)."
1862
			WHERE
1863
				id=".$babDB->quote($this->id)."
1864
		");
1865
	}
1866
1867
1868
	public function getManagerEditUrl()
1869
	{
1870
		$addon = bab_getAddonInfosInstance('absences');
1871
		$ts = bab_mktime($this->date_begin);
1872
		return $addon->getUrl().'vacuser&idx=period&id='.$this->id.'&year='.date('Y', $ts).'&month='.date('n', $ts).'&rfrom=1';
1873
	}
1874
1875
1876
	public function getManagerDeleteUrl()
1877
	{
1878
		$addon = bab_getAddonInfosInstance('absences');
1879
		$url = new bab_url($addon->getUrl().'vacadmb');
1880
		$url->idx = 'delete';
1881
		$url->id_entry = $this->id;
1882
		$url->from = $_SERVER['REQUEST_URI'];
1883
		return $url->toString();
1884
	}
1885
1886
1887
	public function getManagerFrame()
1888
	{
1889
		$W = bab_Widgets();
1890
		$vbox = $W->VBoxLayout();
1891
1892
		if ($this->isFixed())
1893
		{
1894
			$vbox->addItem($W->Icon(absences_translate('Fixed vacation period'), Func_Icons::ACTIONS_VIEW_CALENDAR_DAY));
1895
		} else {
1896
			$vbox->addItem($W->Link($W->Icon(absences_translate('Vacation request'), Func_Icons::ACTIONS_VIEW_LIST_DETAILS), absences_addon()->getUrl()."vacadmb&idx=morvw&id=".$this->id));
1897
		}
1898
		$vbox->addItem($W->Label(absences_DateTimePeriod($this->date_begin, $this->date_end)));
1899
1900
		return $vbox;
1901
	}
1902
1903
1904
	/**
1905
	 *
1906
	 * @param bool 			$display_username	Affiche le nom du demandeur dans la card frame ou non, utile pour les listes contenant plusieurs demandeurs possibles
1907
	 * @param int			$rfrom				si les demandes de la liste sont modifiee par un gestionnaire ou gestionnaire delegue
1908
 	 * @param int			$ide				id entite de l'organigramme >0 si gestionnaire delegue seulement
1909
	 */
1910
	public function getCardFrame($display_username, $rfrom, $ide)
1911
	{
1912
		bab_functionality::includeOriginal('Icons');
1913
1914
		$W = bab_Widgets();
1915
		$layout = $W->HBoxLayout()->setHorizontalSpacing(2,'em')->addClass('widget-full-width');
1916
		$frame = $W->Frame(null, $layout);
1917
1918
		$frame->addClass(Func_Icons::ICON_LEFT_16);
1919
		$frame->addClass('absences-entry-cardframe');
1920
		$layout->addItem($col1 = $W->VBoxLayout()->setVerticalSpacing(.5,'em'));
1921
		$layout->addItem($col2 = $W->VBoxLayout()->setVerticalSpacing(.3,'em'));
1922
1923
		if ($this->isPrevisonal())
1924
		{
1925
			$btn = $W->Link($W->Button()->addItem($W->Label(absences_translate('Submit for approval'))), absences_addon()->getUrl()."vacuser&idx=subprev&id_entry=".$this->id);
1926
			$btn->setSizePolicy('display-opened');
1927
			$layout->addItem($btn);
1928
		}
1929
1930
		if ($this->isFolderPrevisonal())
1931
		{
1932
			$first = $this->getFolderFirst();
1933
			if ($first && $first->id === $this->id)
1934
			{
1935
				$btn = $W->Link($W->Button()->addItem($W->Label(absences_translate('Submit requests for approval'))), absences_addon()->getUrl()."vacuser&idx=subprev&id_entry=".$this->id);
1936
				$btn->setSizePolicy('display-closed');
1937
				$layout->addItem($btn);
1938
			}
1939
		}
1940
1941
1942
		$layout->addItem($col3 = $W->VBoxLayout()->setVerticalSpacing(.5,'em'));
1943
1944
		if ($this->isFixed())
1945
		{
1946
			$col1->addItem($W->Icon(absences_translate('Fixed vacation period'), Func_Icons::ACTIONS_VIEW_CALENDAR_DAY));
1947
			$col1->setCanvasOptions($col1->Options()->width(25,'em'));
1948
		} else {
1949
			$col1->addItem($W->Link($W->Icon(absences_translate('Vacation request'), Func_Icons::ACTIONS_VIEW_LIST_DETAILS), absences_addon()->getUrl()."vacuser&idx=morve&id=".$this->id));
1950
			$col1->setCanvasOptions($col1->Options()->width(25,'em'));
1951
1952
			$col1->addItem($this->getStatusIcon());
1953
		}
1954
1955
		$col2->setSizePolicy(Widget_SizePolicy::MAXIMUM);
1956
1957
		$col2->addItem($W->Title(absences_DateTimePeriod($this->date_begin, $this->date_end), 5));
1958
1959
		if ($display_username)
1960
		{
1961
			$col2->addItem($this->labelledValue(absences_translate('Owner'), $this->getUserName()));
1962
		}
1963
1964
		$col2->addItem($this->labelledValue(absences_translate('Quantity'), absences_vacEntryQuantity($this->id)));
1965
1966
1967
1968
1969 View Code Duplication
		if ($this->canModify())
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1970
		{
1971
			$col3->addItem($W->Link($W->Icon(absences_translate('Modify'), Func_Icons::ACTIONS_DOCUMENT_EDIT), $this->getEditUrl($rfrom, $ide)));
1972
		}
1973
1974
		if ($this->canDelete())
1975
		{
1976
			$urldelete = absences_addon()->getUrl()."vacuser&idx=delete&id_entry=".$this->id;
1977
			$col3->addItem($W->Link($W->Icon(absences_translate('Delete'), Func_Icons::ACTIONS_EDIT_DELETE), $urldelete));
1978
		}
1979
1980
		$frame->setTitle(sprintf(absences_translate('Created the %s'), bab_shortDate(bab_mktime($this->createdOn()))));
1981
1982
		return $frame;
1983
	}
1984
1985
1986
1987
1988
1989
	/**
1990
	 * @return string
1991
	 */
1992
	public function getEditUrl($rfrom, $ide = null)
1993
	{
1994
		$begin_ts = bab_mktime($this->date_begin);
1995
		$url = absences_addon()->getUrl()."vacuser&idx=period&id=".$this->id."&year=".date('Y',$begin_ts)."&month=".date('n',$begin_ts);
1996
1997
		if (isset($rfrom))
1998
		{
1999
			$url .= '&rfrom='.$rfrom;
2000
		}
2001
2002
		if (isset($ide))
2003
		{
2004
			$url .= '&ide='.$ide;
2005
		}
2006
2007
		return $url;
2008
	}
2009
2010
2011
2012
	/**
2013
	 * Delete the vacation request
2014
	 * @return bool
2015
	 */
2016
	public function delete()
2017
	{
2018
2019
2020
2021
		global $babDB;
2022
2023
		if (!$this->getRow())
2024
		{
2025
			return false;
2026
		}
2027
2028
		parent::delete();
2029
		
2030
		if ('0000-00-00 00:00:00' !== $this->date_begin && '0000-00-00 00:00:00' !== $this->date_end) {
2031
    		include_once $GLOBALS['babInstallPath']."utilit/dateTime.php";
2032
    		$date_begin = BAB_DateTime::fromIsoDateTime($this->date_begin);
2033
    		$date_end	= BAB_DateTime::fromIsoDateTime($this->date_end);
2034
    
2035
    		$period = absences_getPeriod($this->id, $this->id_user, $date_begin, $date_end);
2036
    		if (null !== $period)
2037
    		{
2038
    			$period->delete();
2039
    		}
2040
		}
2041
		$babDB->db_query("DELETE FROM absences_dynamic_rights WHERE id_entry=".$babDB->quote($this->id));
2042
		$babDB->db_query("DELETE FROM ".ABSENCES_ENTRIES_ELEM_TBL." WHERE id_entry=".$babDB->quote($this->id)."");
2043
		$babDB->db_query("DELETE FROM ".ABSENCES_ENTRIES_TBL." WHERE id=".$babDB->quote($this->id));
2044
2045
		$this->applyDynamicRight();
2046
		
2047
		if (isset($date_begin) && isset($date_end)) {
2048
    		$cal_begin = clone $date_begin;
2049
    		$cal_end = clone $date_end;
2050
    
2051
    		$cal_end->add(1, BAB_DATETIME_MONTH);
2052
    
2053
    		while ($cal_begin->getTimeStamp() <= $cal_end->getTimeStamp()) {
2054
    			$month	= $cal_begin->getMonth();
2055
    			$year	= $cal_begin->getYear();
2056
    			absences_updateCalendar($this->id_user, $year, $month);
2057
    			$cal_begin->add(1, BAB_DATETIME_MONTH);
2058
    		}
2059
    		
2060
    		$this->addMovement(
2061
    		        sprintf(
2062
    		                absences_translate('The vacation entry from %s to %s has been deleted'),
2063
    		                $date_begin->shortFormat(true),
2064
    		                $date_end->shortFormat(true)
2065
    		        )
2066
    		);
2067
		}
2068
2069
		
2070
2071
		return true;
2072
	}
2073
2074
2075
2076
2077
2078
2079
2080
	/**
2081
	 * (non-PHPdoc)
2082
	 * @see absences_Request::notifyOwner()
2083
	 */
2084
	public function notifyOwner()
2085
	{
2086
		parent::notifyOwner();
2087
2088
		if ('Y' != $this->status)
2089
		{
2090
			return;
2091
		}
2092
2093
		$agent = $this->getAgent();
2094
		$emails = $agent->getEmails();
2095
2096
		if (empty($emails))
2097
		{
2098
			return;
2099
		}
2100
2101
		require_once dirname(__FILE__).'/request.notify.php';
2102
		absences_notifyEntryOwnerEmails(array($this), $emails);
2103
	}
2104
2105
}
2106
2107
2108
2109
2110
class absences_EntryException extends Exception
2111
{
2112
	/**
2113
	 * Optional entry associated to error (unsaved entry object)
2114
	 * @var absences_Entry
2115
	 */
2116
	public $entry;
2117
2118
2119
	/**
2120
	 * Define if the exception if blocking a save
2121
	 * @var bool
2122
	 */
2123
	public $blocking = true;
2124
}
2125
2126
2127
2128
/**
2129
 * Vacation requests
2130
 * Sorted by creation date
2131
 */
2132
class absences_EntryIterator extends absences_Iterator
2133
{
2134
2135
	/**
2136
	 *
2137
	 * @var string
2138
	 */
2139
	public $orderby = 'e.createdOn ASC';
2140
2141
2142
	/**
2143
	 *
2144
	 * @var string
2145
	 */
2146
	public $folder;
2147
2148
	/**
2149
	 *
2150
	 * @var array
2151
	 */
2152
	public $users;
2153
2154
2155
	/**
2156
	 *
2157
	 * @var mixed (array|string)
2158
	 */
2159
	public $status;
2160
2161
2162
	/**
2163
	 * Entry to ignore in the folder
2164
	 * @var int
2165
	 */
2166
	public $id_entry_folder;
2167
2168
2169
	/**
2170
	 * Filtrer les demandes necessitant ou pas un email aux approbateurs
2171
	 * @var int
2172
	 */
2173
	public $appr_notified;
2174
2175
	/**
2176
	 * Filtrer les demandes avec unes instance d'approbation
2177
	 * @var bool
2178
	 */
2179
	public $idfai_set;
2180
2181
2182
	/**
2183
	 * Filtrer les demandes avec une liste d'instances d'approbation
2184
	 * @var array
2185
	 */
2186
	public $appr_idfai;
2187
2188
2189
	/**
2190
	 * Search all request created before this date time
2191
	 * @var string
2192
	 */
2193
	public $createdOn;
2194
2195
	/**
2196
	 * Search all request modified before this date
2197
	 * @var string
2198
	 */
2199
	public $modifiedOn;
2200
2201
2202
	/**
2203
	 * Datetime
2204
	 * @var string
2205
	 */
2206
	public $from;
2207
2208
2209
	/**
2210
	 * Datetime
2211
	 * @var string
2212
	 */
2213
	public $to;
2214
2215
2216
	/**
2217
	 * Filtrer les demandes par annee
2218
	 * @var int
2219
	 */
2220
	public $year;
2221
2222
2223
	/**
2224
	 * Filtrer les demandes par organisation
2225
	 * @var int
2226
	 */
2227
	public $organization;
2228
2229
2230
	/**
2231
	 * Filtrer les demandes par statut d'archivage
2232
	 * @var int
2233
	 */
2234
	public $archived = 0;
2235
	
2236
	/**
2237
	 * with at least one element with this right
2238
	 */
2239
	public $id_right;
2240
2241
2242
2243 6
	public function getObject($data)
2244
	{
2245
2246 6
		$entry = new absences_Entry;
2247 6
		$entry->setRow($data);
2248 6
		return $entry;
2249
2250
	}
2251
	
2252
	/**
2253
	 * @return string
2254
	 */
2255 21
	protected function getBaseQuery()
2256
	{
2257
	    return 'SELECT e.* 
2258
				FROM
2259
					absences_entries e 
2260 21
				';
2261
	
2262
	}
2263
	
2264
	
2265
	/**
2266
	 * @return array
2267
	 */
2268 21
	protected function getWhere()
2269
	{
2270 21
	    global $babDB;
2271
	    
2272 21
	    $where = array();
2273 21
	    if (isset($this->folder))
2274 21
	    {
2275
	        $where[] = 'e.folder='.$babDB->quote($this->folder);
2276
	    
2277
	        if (isset($this->id_entry_folder))
2278
	        {
2279
	            $where[] = 'e.id<>'.$babDB->quote($this->id_entry_folder);
2280
	        }
2281
	    }
2282
	    
2283 21
	    if (!empty($this->users))
2284 21
	    {
2285 21
	        $where[] = 'e.id_user IN('.$babDB->quote($this->users).')';
2286 21
	    }
2287
	    
2288 21
	    if (isset($this->status))
2289 21
	    {
2290 7
	        $where[] = 'e.status IN('.$babDB->quote($this->status).')';
2291 7
	    }
2292
	    
2293 21
	    if (isset($this->createdOn))
2294 21
	    {
2295 15
	        $where[] = 'e.createdOn<='.$babDB->quote($this->createdOn);
2296 15
	    }
2297
	    
2298 21
	    if (isset($this->modifiedOn))
2299 21
	    {
2300
	        $where[] = 'e.`date`<='.$babDB->quote($this->modifiedOn);
2301
	    }
2302
	    
2303 21
	    if (isset($this->appr_notified))
2304 21
	    {
2305
	        $where[] = 'e.appr_notified='.$babDB->quote($this->appr_notified);
2306
	    }
2307
	    
2308 21
	    if (isset($this->idfai_set) && $this->idfai_set)
2309 21
	    {
2310
	        $where[] = 'e.idfai>'.$babDB->quote(0);
2311
	    }
2312
	    
2313 21
	    if (isset($this->appr_idfai))
2314 21
	    {
2315
	        $where[] = 'e.idfai IN('.$babDB->quote($this->appr_idfai).')';
2316
	    }
2317
	    
2318 21
	    if (isset($this->from))
2319 21
	    {
2320
	        $where[] = 'e.date_end >'.$babDB->quote($this->from);
2321
	    }
2322
	    
2323 21
	    if (isset($this->to))
2324 21
	    {
2325
	        $where[] = 'e.date_begin <'.$babDB->quote($this->to);
2326
	    }
2327
	    
2328 21
	    if (isset($this->startTo))
2329 21
	    {
2330
	        $where[] = 'e.date_begin <='.$babDB->quote($this->startTo);
0 ignored issues
show
Bug introduced by
The property startTo does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2331
	    }
2332
	    
2333 21
	    if (isset($this->startFrom))
2334 21
	    {
2335
	        $where[] = 'e.date_begin >='.$babDB->quote($this->startFrom);
0 ignored issues
show
Bug introduced by
The property startFrom does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2336
	    }
2337
	    
2338 21
	    if (isset($this->year))
2339 21
	    {
2340
	        $where[] = 'YEAR(e.date_begin)='.$babDB->quote($this->year);
2341
	    }
2342
	    
2343 21
	    if (isset($this->organization) && $this->organization)
2344 21
	    {
2345
	        $where[] = 'e.id_user=p.id_user';
2346
	        $where[] = 'p.id_organization='.$babDB->quote($this->organization);
2347
	    }
2348
	    
2349 21
	    if (isset($this->archived))
2350 21
	    {
2351 21
	        $where[] = 'e.archived='.$babDB->quote($this->archived);
2352 21
	    }
2353
	    	
2354 21
	    if (isset($this->id_right))
2355 21
	    {
2356 21
	        $where[] = 'e.id IN(SELECT id_entry FROM absences_entries_elem WHERE id_right='.$babDB->quote($this->id_right).')';
2357 21
	    }
2358
	    
2359 21
	    return $where;
2360
	}
2361
2362
2363
2364 21
	public function executeQuery()
2365
	{
2366 21
		if(is_null($this->_oResult))
2367 21
		{
2368 21
			$req = $this->getBaseQuery();
2369
2370 21
			$where = $this->getWhere();
2371
			
2372 21
			if (isset($this->organization) && $this->organization)
2373 21
			{
2374
			    $req .= ', absences_personnel p';
2375
			}
2376
2377
			if ($where)
0 ignored issues
show
Bug Best Practice introduced by
The expression $where of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2378 21
			{
2379 21
				$req .= ' WHERE '.implode(' AND ', $where);
2380 21
			}
2381
2382 21
			$req .= ' ORDER BY '.$this->orderby;
2383
			
2384 21
			$this->setMySqlResult($this->getDataBaseAdapter()->db_query($req));
2385 21
		}
2386 21
	}
2387
}
2388
2389
2390
/**
2391
 * Entry elements iterator joined on entries
2392
 */
2393
class absences_ElementEntryIterator extends absences_EntryIterator
2394
{
2395
    
2396
    public function getObject($data)
2397
    {
2398
        require_once dirname(__FILE__).'/type.class.php';
2399
        require_once dirname(__FILE__).'/right.class.php';
2400
        require_once dirname(__FILE__).'/entry_elem.class.php';
2401
        
2402
        $entry_row = $this->getRowByPrefix($data, 'entry');
2403
        $entry = new absences_Entry($entry_row['id']);
0 ignored issues
show
Unused Code introduced by
The call to absences_Entry::__construct() has too many arguments starting with $entry_row['id'].

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
2404
        $entry->setRow($entry_row);
2405
    
2406
        $type_row = $this->getRowByPrefix($data, 'type');
2407
        $type = new absences_Type($type_row['id']);
2408
        $type->setRow($type_row);
2409
    
2410
        $right_row = $this->getRowByPrefix($data, 'right');
2411
        $right = new absences_Right($right_row['id']);
2412
        $right->setRow($right_row);
2413
        $right->setType($type);
2414
    
2415
        $elem_row = $this->getRowByPrefix($data, 'elem');
2416
        $elem = new absences_EntryElem();
2417
        $elem->setRow($elem_row);
2418
        $elem->setRight($right);
2419
        $elem->setEntry($entry);
2420
    
2421
        return $elem;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $elem; (absences_EntryElem) is incompatible with the return type of the parent method absences_EntryIterator::getObject of type absences_Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
2422
    }
2423
    
2424
    
2425
    /**
2426
     * @return string
2427
     */
2428
    protected function getBaseQuery()
2429
    {
2430
        return 'SELECT 
2431
                
2432
                    e.id                    entry__id,
2433
                    e.id_user               entry__id_user,
2434
                    e.createdby             entry__createdby,
2435
                    e.date_begin            entry__date_begin,
2436
                    e.date_end              entry__date_end,
2437
                    e.idfai                 entry__idfai,
2438
                    e.comment               entry__comment,
2439
                    e.createdOn             entry__createdOn,
2440
                    e.date                  entry__date,
2441
                    e.status                entry__status,
2442
                    e.comment2              entry__comment2,
2443
                    e.id_approver           entry__id_approver,
2444
                    e.folder                entry__folder,
2445
                    e.creation_type         entry__creation_type,
2446
                    e.appr_notified         entry__appr_notified,
2447
                    e.archived              entry__archived,
2448
                    e.todelete              entry__todelete,
2449
                    e.firstconfirm          entry__firstconfirm,
2450
                
2451
                    ee.id 					elem__id,
2452
    				ee.id_entry 			elem__id_entry,
2453
    				ee.id_right				elem__id_right,
2454
    				ee.quantity				elem__quantity,
2455
    			    ee.date_begin           elem__date_begin,
2456
    			    ee.date_end             elem__date_end,
2457
    
2458
    				r.id					right__id,
2459
    				r.id_creditor			right__id_creditor,
2460
    				r.kind					right__kind,
2461
    			    r.createdOn			    right__createdOn,
2462
    				r.date_entry			right__date_entry,
2463
    				r.date_begin			right__date_begin,
2464
    				r.date_end				right__date_end,
2465
    				r.quantity				right__quantity,
2466
    				r.quantity_unit			right__quantity_unit,
2467
    				r.quantity_inc_month 	right__quantity_inc_month,
2468
    				r.quantity_inc_max 		right__quantity_inc_max,
2469
    				r.quantity_inc_last		right__quantity_inc_last,
2470
    				r.id_type				right__id_type,
2471
    				r.description			right__description,
2472
    				r.active				right__active,
2473
    				r.cbalance	 			right__cbalance,
2474
    				r.date_begin_valid		right__date_begin_valid,
2475
    				r.date_end_valid		right__date_end_valid,
2476
    				r.date_end_fixed		right__date_end_fixed,
2477
    				r.date_begin_fixed		right__date_begin_fixed,
2478
    				r.no_distribution 		right__no_distribution,
2479
    				r.use_in_cet			right__use_in_cet,
2480
    				r.id_rgroup				right__id_rgroup,
2481
    				r.earlier				right__earlier,
2482
    				r.earlier_begin_valid 	right__earlier_begin_valid,
2483
    				r.earlier_end_valid		right__earlier_end_valid,
2484
    				r.later					right__later,
2485
    				r.later_begin_valid		right__later_begin_valid,
2486
    				r.later_end_valid		right__later_end_valid,
2487
    				r.delay_before			right__delay_before,
2488
    				r.id_report_type		right__id_report_type,
2489
    				r.date_end_report		right__date_end_report,
2490
    				r.description_report	right__description_report,
2491
    				r.id_reported_from		right__id_reported_from,
2492
    				r.quantity_alert_days	right__quantity_alert_days,
2493
    				r.quantity_alert_types	right__quantity_alert_types,
2494
    				r.quantity_alert_begin	right__quantity_alert_begin,
2495
    				r.quantity_alert_end	right__quantity_alert_end,
2496
    				r.dynconf_types			right__dynconf_types,
2497
    				r.dynconf_begin			right__dynconf_begin,
2498
    				r.dynconf_end			right__dynconf_end,
2499
    				r.sync_status			right__sync_status,
2500
    				r.sync_update			right__sync_update,
2501
    				r.uuid					right__uuid,
2502
    				r.archived				right__archived,
2503
    				r.sortkey				right__sortkey,
2504
    				r.require_approval		right__require_approval,
2505
    
2506
    
2507
    				t.id					type__id,
2508
    				t.name					type__name,
2509
    				t.description			type__description,
2510
    				t.color					type__color
2511
				FROM
2512
					absences_entries e,
2513
                    absences_entries_elem ee,
2514
                    absences_rights r,
2515
                    absences_types t 
2516
				';
2517
    
2518
    }
2519
    
2520
    /**
2521
     * @return array
2522
     */
2523
    protected function getWhere()
2524
    {
2525
        $where = parent::getWhere();
2526
        
2527
        $where[] = 'ee.id_entry=e.id';
2528
        $where[] = 'ee.id_right=r.id';
2529
        $where[] = 'r.id_type=t.id';
2530
        
2531
        return $where;
2532
    }
2533
}
2534
2535
2536
2537
/**
2538
 * Entry elements iterator
2539
 */
2540
class absences_EntryElemIterator extends absences_Iterator
2541
{
2542
	/**
2543
	 *
2544
	 * @var absences_Entry
2545
	 */
2546
	public $entry;
2547
2548
	/**
2549
	 * Filter by a list of id vaction types
2550
	 * @var int[]
2551
	 */
2552
	public $types;
2553
2554
2555
	public function getObject($data)
2556
	{
2557
		require_once dirname(__FILE__).'/type.class.php';
2558
		require_once dirname(__FILE__).'/right.class.php';
2559
		require_once dirname(__FILE__).'/entry_elem.class.php';
2560
2561
		$type_row = $this->getRowByPrefix($data, 'type');
2562
		$type = new absences_Type($type_row['id']);
2563
		$type->setRow($type_row);
2564
2565
		$right_row = $this->getRowByPrefix($data, 'right');
2566
		$right = new absences_Right($right_row['id']);
2567
		$right->setRow($right_row);
2568
		$right->setType($type);
2569
2570
		$elem_row = $this->getRowByPrefix($data, 'elem');
2571
		$elem = new absences_EntryElem();
2572
		$elem->setRow($elem_row);
2573
		$elem->setRight($right);
2574
		$elem->setEntry($this->entry);
2575
2576
		return $elem;
2577
	}
2578
2579
2580
2581
	public function executeQuery()
2582
	{
2583
		if(is_null($this->_oResult))
2584
		{
2585
			global $babDB;
2586
			$req = 'SELECT
2587
2588
				ee.id 					elem__id,
2589
				ee.id_entry 			elem__id_entry,
2590
				ee.id_right				elem__id_right,
2591
				ee.quantity				elem__quantity,
2592
			    ee.date_begin           elem__date_begin,
2593
			    ee.date_end             elem__date_end,
2594
2595
				r.id					right__id,
2596
				r.id_creditor			right__id_creditor,
2597
				r.kind					right__kind,
2598
			    r.createdOn			    right__createdOn,
2599
				r.date_entry			right__date_entry,
2600
				r.date_begin			right__date_begin,
2601
				r.date_end				right__date_end,
2602
				r.quantity				right__quantity,
2603
				r.quantity_unit			right__quantity_unit,
2604
				r.quantity_inc_month 	right__quantity_inc_month,
2605
				r.quantity_inc_max 		right__quantity_inc_max,
2606
				r.quantity_inc_last		right__quantity_inc_last,
2607
				r.id_type				right__id_type,
2608
				r.description			right__description,
2609
				r.active				right__active,
2610
				r.cbalance	 			right__cbalance,
2611
				r.date_begin_valid		right__date_begin_valid,
2612
				r.date_end_valid		right__date_end_valid,
2613
				r.date_end_fixed		right__date_end_fixed,
2614
				r.date_begin_fixed		right__date_begin_fixed,
2615
				r.no_distribution 		right__no_distribution,
2616
				r.use_in_cet			right__use_in_cet,
2617
				r.id_rgroup				right__id_rgroup,
2618
				r.earlier				right__earlier,
2619
				r.earlier_begin_valid 	right__earlier_begin_valid,
2620
				r.earlier_end_valid		right__earlier_end_valid,
2621
				r.later					right__later,
2622
				r.later_begin_valid		right__later_begin_valid,
2623
				r.later_end_valid		right__later_end_valid,
2624
				r.delay_before			right__delay_before,
2625
				r.id_report_type		right__id_report_type,
2626
				r.date_end_report		right__date_end_report,
2627
				r.description_report	right__description_report,
2628
				r.id_reported_from		right__id_reported_from,
2629
				r.quantity_alert_days	right__quantity_alert_days,
2630
				r.quantity_alert_types	right__quantity_alert_types,
2631
				r.quantity_alert_begin	right__quantity_alert_begin,
2632
				r.quantity_alert_end	right__quantity_alert_end,
2633
				r.dynconf_types			right__dynconf_types,
2634
				r.dynconf_begin			right__dynconf_begin,
2635
				r.dynconf_end			right__dynconf_end,
2636
				r.sync_status			right__sync_status,
2637
				r.sync_update			right__sync_update,
2638
				r.uuid					right__uuid,
2639
				r.archived				right__archived,
2640
				r.sortkey				right__sortkey,
2641
				r.require_approval		right__require_approval,
2642
2643
2644
				t.id					type__id,
2645
				t.name					type__name,
2646
				t.description			type__description,
2647
				t.color					type__color
2648
			FROM
2649
				absences_entries_elem ee,
2650
				absences_rights r,
2651
				absences_types t
2652
2653
			WHERE
2654
				ee.id_entry='.$babDB->quote($this->entry->id).'
2655
				AND ee.id_right = r.id
2656
				AND r.id_type = t.id';
2657
2658
			if (isset($this->types)) {
2659
			    $req .= ' AND t.id IN('.$babDB->quote($this->types).')';
2660
			}
2661
2662
		    $req .= ' ORDER BY ee.date_begin';
2663
2664
			$this->setMySqlResult($this->getDataBaseAdapter()->db_query($req));
2665
		}
2666
	}
2667
2668
2669
}
2670
2671
2672
2673
/**
2674
 * Entry periods iterator
2675
 */
2676
class absences_EntryPeriodIterator extends absences_Iterator
2677
{
2678
    /**
2679
     *
2680
     * @var absences_Entry
2681
     */
2682
    public $entry;
2683
2684
2685
2686
    public function getObject($data)
2687
    {
2688
        require_once dirname(__FILE__).'/entry_period.class.php';
2689
2690
2691
2692
        $elem_row = $this->getRowByPrefix($data, 'period');
2693
        $elem = new absences_EntryPeriod();
2694
        $elem->setRow($elem_row);
2695
        $elem->setEntry($this->entry);
2696
2697
        return $elem;
2698
    }
2699
2700
2701
2702 28
    public function executeQuery()
2703
    {
2704 28
        if(is_null($this->_oResult))
2705 28
        {
2706 28
            global $babDB;
2707
            $req = 'SELECT
2708
2709
				ep.id 					period__id,
2710
				ep.id_entry 			period__id_entry,
2711
			    ep.date_begin           period__date_begin,
2712
			    ep.date_end             period__date_end
2713
2714
			FROM
2715
				absences_entries_periods ep
2716
			WHERE
2717 28
				ep.id_entry='.$babDB->quote($this->entry->id).'';
2718
2719
2720 28
            $req .= ' ORDER BY ep.date_begin';
2721
2722 28
            $this->setMySqlResult($this->getDataBaseAdapter()->db_query($req));
2723 28
        }
2724 28
    }
2725
2726
2727
}
2728