Completed
Push — master ( 7e7f44...80924f )
by Paul
04:16
created

absences_Entry   F

Complexity

Total Complexity 282

Size/Duplication

Total Lines 2394
Duplicated Lines 12.95 %

Coupling/Cohesion

Components 1
Dependencies 19

Test Coverage

Coverage 37.65%

Importance

Changes 8
Bugs 4 Features 2
Metric Value
dl 310
loc 2394
ccs 366
cts 972
cp 0.3765
rs 0.6314
c 8
b 4
f 2
wmc 282
lcom 1
cbo 19

84 Methods

Rating   Name   Duplication   Size   Complexity  
C getElement() 0 48 7
F loadDefaultValues() 0 40 10
B save() 37 82 4
C setElementsDates() 0 45 7
A getElementEndGap() 0 15 3
D getFutureDate_Days() 0 109 14
A checkAvailable() 0 10 3
A getTitle() 0 8 3
A getById() 0 7 1
A getRow() 0 16 3
A getRequestType() 0 15 3
A getApprobationId() 0 9 2
A getElementsIterator() 0 7 1
A getPlannedPeriodsIterator() 0 7 1
A getFolderEntriesIterator() 12 12 2
A addElementsMovements() 0 8 2
A loadElements() 0 15 3
A getElements() 0 4 1
A addPeriod() 0 4 1
A loadPlannedPeriods() 0 21 4
A getPlannedPeriods() 0 4 1
A getPlannedDurationHours() 14 14 3
A sortElements() 0 4 1
A sortElem() 0 18 3
B checkElementsDates() 0 14 6
B getNextValidDate() 0 23 5
A getFutureDate() 0 8 2
B getWorkingPeriodsFromDate() 0 23 5
B getFutureDate_Seconds() 0 30 4
A getFutureDate_Hours() 0 6 1
C getWorkingTimeByDay() 6 51 10
B getSecondsToAdd() 0 30 5
B getFutureDate_Days_Old() 0 45 6
A createPlannedPeriods() 0 17 2
B getPeriodQuantity() 0 27 6
A getDayDurationInHours() 0 18 3
B getPeriodType() 0 19 7
B saveElements() 0 26 3
A savePlannedPeriods() 0 21 3
A applyDynamicRight() 0 13 2
A addElement() 0 4 1
A removeElement() 0 13 3
A setWorkingPeriodIndex() 0 5 1
B getWorkingPeriodIndex() 0 25 4
B loadDurations() 0 27 4
A getWorkingPeriods() 0 8 2
A getDayWorkingPeriods() 0 11 3
A getDayPlannedPeriods() 0 11 3
A getDurationDays() 0 9 2
A getDurationHours() 0 9 2
A daysToHours() 12 12 2
A hoursToDays() 10 10 2
B loadedElementsTotal() 0 32 5
A addQUantityInCache() 0 15 3
A getTotalDays() 17 17 4
A getTotalHours() 17 17 4
B getPlannedDaysBetween() 30 30 6
B getPlannedHoursBetween() 30 30 6
A containsHours() 0 12 3
A requireApproval() 0 17 4
A checkElementsValidity() 0 16 3
A checkOtherEntriesValidity() 6 21 3
C checkValidity() 14 105 8
A modifiedOn() 0 4 1
A isFixed() 0 5 1
A isPrevisonal() 0 4 1
A isFolderPrevisonal() 0 13 2
A getFolderFirst() 17 17 3
A onReject() 0 4 1
A onConfirm() 0 4 1
B updateCalendar() 0 29 2
A getNotifyFields() 8 8 1
A getYear() 11 11 2
A getArchiveYear() 20 20 3
A archive() 11 11 1
A setNotified() 16 16 2
A getManagerEditUrl() 0 6 1
A getManagerDeleteUrl() 0 9 1
A getManagerFrame() 0 15 2
C getCardFrame() 4 74 9
A getEditUrl() 0 17 3
B delete() 0 57 8
A getPlannedDurationDays() 18 18 3
A notifyOwner() 0 20 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like absences_Entry often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use absences_Entry, and based on these observations, apply Extract Interface, too.

1
<?php
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 37
	public function getRow()
152
	{
153 37
		if (null === $this->row)
154 37
		{
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 37
		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 11
	public function getPlannedPeriodsIterator()
222
	{
223 11
	    $I = new absences_EntryPeriodIterator;
224 11
	    $I->entry = $this;
225
226 11
	    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 14
	public function getElements()
296
	{
297 14
		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 12
	public function loadPlannedPeriods()
373
	{
374 12
	    if (!isset($this->id))
375 12
	    {
376
	        throw new Exception('Failed to load entry periods, id missing');
377
	    }
378
379 11
	    $this->plannedPeriods = array();
380
381 11
	    $res = $this->getPlannedPeriodsIterator();
382
383 11
	    if (0 === $res->count()) {
384 11
	        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 13
	public function getPlannedPeriods()
399
	{
400 13
	    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 4 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 4
	    if (empty($this->plannedPeriods)) {
415
	        $this->loadPlannedPeriods();
416
	    }
417
418 4
	    $total = 0.0;
419
420 4
	    foreach ($this->getPlannedPeriods() as $entryPeriod) {
421 4
	        $total += $entryPeriod->getDurationDays($begin, $end);
422 4
	    }
423
	    
424
425
	    
426
	     
427
428 4
	    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 3 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 3
	    if (empty($this->plannedPeriods)) {
443
	        $this->loadPlannedPeriods();
444
	    }
445
446 3
	    $total = 0.0;
447
448 3
	    foreach ($this->getPlannedPeriods() as $entryPeriod) {
449 3
	        $total += $entryPeriod->getDurationHours($begin, $end);
450 3
	    }
451
452 3
	    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 23
	public function sortElements()
592
	{
593 23
	    usort($this->elements, array('absences_Entry', 'sortElem'));
594 23
	}
595
596 23
	private static function sortElem(absences_EntryElem $elem1, absences_EntryElem $elem2)
597
	{
598 23
	    $right1 = $elem1->getRight();
599 23
	    $right2 = $elem2->getRight();
600
601 23
	    if ($right1->sortkey > $right2->sortkey) {
602 22
	        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 29
	public function checkElementsDates()
622
	{
623 29
	    foreach($this->elements as $elem) {
624 29
	        if (!isset($elem->date_begin) || '0000-00-00 00:00:00' === $elem->date_begin) {
625 29
	            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
	 * Add dates to loaded elements using the user calendar
639
	 */
640 29
	public function setElementsDates()
641
	{
642 29
	    include_once $GLOBALS['babInstallPath']."utilit/dateTime.php";
643
644 29
	    if (0 === count($this->elements)) {
645
	        throw new absences_EntryException('No elements to set dates on, id_entry='.$this->id.', owner='.$this->getUserName());
646
	    }
647
	    
648 29
	    if ($this->checkElementsDates()) {
649
	        // dates allready set
650
	        // calling getFutureDate twice does not work
651 10
	        return;
652
	    }
653
654 29
	    if (1 === count($this->elements)) {
655 6
	        $element = reset($this->elements);
656
	        /*@var $element absences_EntryElem */
657 6
	        $element->date_begin = $this->date_begin;
658 6
	        $element->date_end = $this->date_end;
659 6
	        return;
660
	    }
661
	    
662 23
	    $this->sortElements();
663
        
664 23
	    $loop = BAB_DateTime::fromIsoDateTime($this->date_begin);
665
666 23
	    foreach($this->elements as $element) {
667
	        /*@var $element absences_EntryElem */
668 23
	        $element->date_begin = $loop->getIsoDateTime();
669
	        
670 23
	        $loop = $this->getFutureDate($loop, (float) $element->quantity, $element->getRight()->quantity_unit);
671 23
	        $element->date_end = $loop->getIsoDateTime();
672
	        
673 23
	        if ($element->date_end > $this->date_end) {
674 2
	            $element->date_end = $this->date_end;
675 2
	        }
676
	        
677 23
	        $loop = $this->getNextValidDate($loop);
678 23
	    }
679
	    
680
	    // round the last half day to the request period end
681 23
	    if ($this->getElementEndGap() <= 3600) {
682 21
	        $this->elements[count($this->elements)-1]->date_end = $this->date_end;
683 21
	    }
684 23
	}
685
	
686
	/**
687
	 * Get the gap beetween the last element end date and the period end date
688
	 * @return int
689
	 */
690 23
	protected function getElementEndGap()
691
	{
692 23
	    $computedLastDate = bab_mktime($this->elements[count($this->elements)-1]->date_end);
693 23
	    $periodEnd = bab_mktime($this->date_end);
694
	     
695 23
	    if ($periodEnd > $computedLastDate) {
696 3
	         return ($periodEnd - $computedLastDate);
697
	    }
698
	    
699 20
	    if ($computedLastDate > $periodEnd) {
700
	        return ($computedLastDate - $periodEnd);
701
	    }
702
	    
703 20
	    return 0;
704
	}
705
706
707
	/**
708
	 * set the date to the next valid date
709
	 * @param BAB_DateTime $date
710
	 * @return BAB_DateTime
711
	 */
712 23
	protected function getNextValidDate(BAB_DateTime $date)
713
	{
714 23
	    $moment = $date->getTimeStamp();
715
716 23
	    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...
717
718 23
	        if ($moment >= $period->ts_end) {
719 23
	            continue;
720
	        }
721
722
	        // if the future date (end date of the element) is in a worked period
723
	        // the future date is valid as a next date
724 23
	        if ($moment < $period->ts_end && $moment > $period->ts_begin) {
725 10
	            return $date;
726
	        }
727
728
729 13
	        return BAB_DateTime::fromTimeStamp($period->ts_begin);
730 21
	    }
731
732
733 21
	    return $date;
734
	}
735
736
737
738
	/**
739
	 * Add quantity to startdate only on working periods
740
	 *
741
	 * @param BAB_DateTime $startdate
742
	 * @param float $quantity
743
	 * @param string $quantity_unit D|H
744
	 *
745
	 * @return BAB_DateTime
746
	 */
747 23
	protected function getFutureDate(BAB_DateTime $startdate, $quantity, $quantity_unit)
748
	{
749 23
	    if ('H' === $quantity_unit) {
750 4
	        return $this->getFutureDate_Hours($startdate, $quantity);
751
	    }
752
753 20
	    return $this->getFutureDate_Days($startdate, $quantity);
754
	}
755
756
757
	/**
758
	 * Split working periods
759
	 * @return array
760
	 */
761 18
	protected function getWorkingPeriodsFromDate(BAB_DateTime $startdate)
762
	{
763 18
	    $periods = array();
764 18
	    $start = $startdate->getTimeStamp();
765
766 18
	    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...
767
768 18
	        if ($start >= $period->ts_end) {
769
	            // continue to the next worked period
770 15
	            continue;
771
	        }
772
773 18
	        if ($start > $period->ts_begin && $start < $period->ts_end) {
774 10
	            $period->setBeginDate($startdate);
775 10
	            $periods[] = $period;
776 10
	            continue;
777
	        }
778
779 18
	        $periods[] = $period;
780 18
	    }
781
782 18
	    return $periods;
783
	}
784
785
786
787
	/**
788
	 * Add quantity to startdate only on working periods
789
	 *
790
	 * @param BAB_DateTime $startdate
791
	 * @param float $seconds_to_add
792
	 *
793
	 * @return BAB_DateTime
794
	 */
795 18
	protected function getFutureDate_Seconds(BAB_DateTime $startdate, $seconds_to_add)
796
	{
797 18
	    $worked_total = 0; //seconds
798
799
800 18
	    foreach ($this->getWorkingPeriodsFromDate($startdate) as $period) {
801
802 18
	        $add_in_period = ($seconds_to_add - $worked_total);
803 18
	        $worked_total += $period->getDuration();
804
805 18
	        if ((int) $worked_total === (int) $seconds_to_add) {
806
	            // la duree de la periode de travail est egale a duree demandee
807
	            // en tenant compte des periodes de travail precedentes
808
809 17
	            return BAB_DateTime::fromTimeStamp($period->ts_end);
810
	        }
811
812
813 15
            if ($worked_total > $seconds_to_add) {
814
                // la date future se trouve a l'interieur d'une periode travaillee
815 10
                $futureDate = $period->ts_begin + $add_in_period;
816 10
                return BAB_DateTime::fromTimeStamp($futureDate);
817
            }
818
819
            // continue to the next worked period
820
821 15
	    }
822
823 2
	    return BAB_DateTime::fromIsoDateTime($this->date_end);
824
	}
825
826
827
828
829
830
831
	/**
832
	 * Add quantity to startdate only on working periods
833
	 *
834
	 * @param BAB_DateTime $startdate
835
	 * @param float $quantity  hours
836
	 *
837
	 * @return BAB_DateTime
838
	 */
839 4
	protected function getFutureDate_Hours(BAB_DateTime $startdate, $quantity)
840
	{
841 4
	    $seconds_to_add = $quantity * 3600;
842
843 4
	    return $this->getFutureDate_Seconds($startdate, $seconds_to_add);
844
	}
845
	
846
	
847
	/**
848
	 * periodes travailles, durees et types a partir d'une date
849
	 * 
850
	 * duration: seconds
851
	 * type: AMPM | AM | PM
852
	 * dayend: timestamp
853
	 * 
854
	 * @param BAB_DateTime $startdate
855
	 * @return array
856
	 */
857 20
	protected function getWorkingTimeByDay(BAB_DateTime $startdate)
858
	{
859 20
	    $start = $startdate->getTimeStamp();
860 20
	    $days = array();
861 20
	    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...
862
	        
863
	        
864 20
	        if ($start >= $period->ts_end) {
865 15
	            continue;
866
	        }
867
	        
868
	        
869
	        
870 20
	        $d = date('Y-m-d', $period->ts_begin);
871
	        
872 20
	        if (!isset($days[$d])) {
873
	            
874 20
	            $days[$d] = array(
875 20
	                'duration' => 0,
876 20
	                'type' => null,
877
	                'dayend' => null
878 20
	            );
879 20
	        }
880
	        
881
	            
882 20
	        $days[$d]['duration'] += $period->getDuration();
883
	        
884 20
	        if ($period->ts_end > $days[$d]['dayend']) {
885 20
	            $days[$d]['dayend'] = $period->ts_end;
886 20
	        }
887
	        
888
	        
889 20
	        $type = $this->getPeriodType($period);
890
	        
891 20 View Code Duplication
	        if ('AM' === $days[$d]['type'] && 'PM' === $type) {
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...
892 19
	            $days[$d]['type'] = 'AMPM';
893 19
	        }
894
	        
895 20 View Code Duplication
	        if ('PM' === $days[$d]['type'] && 'AM' === $type) {
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...
896
	            $days[$d]['type'] = 'AMPM';
897
	        }
898
	        
899 20
	        if (!isset($days[$d]['type'])) {
900 20
	            $days[$d]['type'] = $type;
901 20
	        }
902 20
	    }
903
	    
904
	    
905
	    
906 20
	    return $days;
907
	}
908
	
909
	
910
	
911
912
	
913
	
914
	
915
	
916
	/**
917
	 * Add quantity to startdate only on working periods
918
	 *
919
	 * @param BAB_DateTime $startdate
920
	 * @param float $quantity  days
921
	 *
922
	 * @return BAB_DateTime
923
	 */
924 20
	protected function getFutureDate_Days(BAB_DateTime $startdate, $quantity)
925
	{
926
	    
927 20
	    $return = clone $startdate;
928
	    
929 20
	    $morning = clone $startdate;
930 20
	    $morning->setIsoTime('00:00:00');
931
	    
932 20
	    $days = $this->getWorkingTimeByDay($morning);
933
	    
934
	    
935 20
	    $seconds_to_add = 0;
936
937
	    
938
	    // traiter les jours entiers
939
	    
940 20
	    $fulldays = $lastfulldays = (float) floor($quantity);
941 20
	    $lastquantity = $quantity;
942 20
	    $lastdays = $days;
943 20
	    $day = key($days);
0 ignored issues
show
Unused Code introduced by
$day is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
944
	    
945 20
	    $pos = 0;
946 20
	    if (0 < $fulldays) {
947
948 15
	        foreach($days as $keyday => $arr) {
949
950 15
	            $dayquantity = 'AMPM' === $arr['type'] ? 1.0 : 0.5;
951
952 15
	            $lastfulldays -= $dayquantity;
953
954 15
	            if ($lastfulldays <= 0) {
955 15
	                $lastquantity = $quantity - $fulldays - $lastfulldays;
956
957 15
	                if ($pos > 0) {
958 9
	                    $lastdays = array_slice($days, $pos, null, true);
959
	                    
960 9
	                } else {
961 12
	                    $lastdays = $days;
962
	                }
963
964 15
	                $day = $keyday;
0 ignored issues
show
Unused Code introduced by
$day is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
965
	                
966 15
	                break;
967
	            }
968
969 9
	            $pos++;
970 15
	        }
971
	        
972
	        
973
	        
974
975
	        
976 15
	        if ($fulldays > 0 && $lastquantity <= 0) {
977
	            
978
	            
979
	            
980
	            // il ne reste pas de temps a appliquer sur la date
981
	            // on se place donc a la fin d'une periode travaillee
982
983 7
	            reset($days);
984 7
	            for($i=0; $i<$fulldays-1; $i++) {
985 6
	                next($days);
986 6
	            }
987
	            
988 7
	            $newstart = current($days);
989 7
	            $return = BAB_DateTime::fromTimeStamp($newstart['dayend']);
990
	            
991
	            //echo $fulldays.' '.$startdate->getIsoDateTime().' -> '.$return->getIsoDateTime()."\n";
992
	            
993 7
	        } else {
994
	            
995
	            // il reste du temps a ajouter sur la date
996
	            // on ajoute juste le nombre de jours complets
997
	            
998 8
	            $return->add($fulldays, BAB_DATETIME_DAY);
999
	        }
1000
	        
1001
	        
1002
	        
1003
	        // si la date de debut est supperieur a la date d'ouverture de la premiere periode travaillee
1004
	        // on considere que la date de debut est sur la prochaine periode travaillee, par exemple commence l'apres-midi
1005 15
	        $start = reset($days);
1006 15
	        $fromstart = $this->getWorkingTimeByDay($startdate);
1007 15
	        $firstday = reset($fromstart);
1008 15
	        $missing_duration = $start['duration'] - $firstday['duration'];
1009 15
	        if ($missing_duration > 0) {
1010
	            // var_dump($startdate->getIsoDateTime().' '.($missing_duration/3600).'H');
1011 3
	            $seconds_to_add = $missing_duration;
1012 3
	        }
1013 15
	    }
1014
	    
1015
	    
1016
	    
1017 20
	    if ($seconds_to_add === 0 && ($lastquantity <= 0 || !isset($lastdays))) {
1018 6
	        return $return;
1019
	    }
1020
	    
1021 15
	    $seconds_to_add += $this->getSecondsToAdd($lastdays, $lastquantity);
1022
	    
1023
	    
1024 15
	    if (0 === $seconds_to_add) {
1025
	        return $return;
1026
	    }
1027
1028
	    
1029 15
	    $return = $this->getFutureDate_Seconds($return, $seconds_to_add);
1030
	    
1031 15
	    return $return;
1032
	}
1033
	
1034
	
1035
	/**
1036
	 * Trouver le nombre de secondes a ajouter a une date pour une quantite 
1037
	 * @param array $lastdays      Jours restants sur la periode
1038
	 * @param float $lastquantity  Nombre de jours a ajouter, uniquement les jours incomplets de la fin de periode, les jours complets ont ete traites avant
1039
	 * 
1040
	 */
1041 15
	protected function getSecondsToAdd(Array $lastdays, $lastquantity)
1042
	{
1043 15
	    $seconds_to_add = 0;
1044
	    
1045
	    //var_dump('lastquantity: '.$lastquantity);
1046
	    
1047
	    // trouver les heures a partir de la quantite restante
1048
	    
1049 15
	    foreach($lastdays as $keyday => $arr) {
1050
	        
1051 15
	        $q = 'AMPM' === $arr['type'] ? 1.0 : 0.5;
1052
	    
1053 15
	        if ($lastquantity > $q) {
1054
	            $lastquantity -= $q;
1055
	            continue;
1056
	        }
1057
	    
1058
	        //var_dump(($arr['duration']/3600).' '.$lastquantity.' '.$arr['type'].' '.$q);
1059
	        
1060 15
	        if ($lastquantity == $q) {
1061 1
	            $seconds_to_add = $arr['duration'];
1062 1
	            break;
1063
	        }
1064
	    
1065 14
	        $seconds_to_add = $arr['duration'] * $lastquantity;
1066 14
	        break;
1067 15
	    }
1068
	    
1069 15
	    return $seconds_to_add;
1070
	}
1071
	
1072
	
1073
1074
	/**
1075
	 * Add quantity to startdate only on working periods
1076
	 * 
1077
	 * @deprecated probleme avec les periodes a cheval sur 12:00 conbinne aux quantites inferieurs a 1 jour
1078
	 *
1079
	 * @param BAB_DateTime $startdate
1080
	 * @param float $quantity  days
1081
	 *
1082
	 * @return BAB_DateTime
1083
	 */
1084
	protected function getFutureDate_Days_Old(BAB_DateTime $startdate, $quantity)
1085
	{
1086
	    
1087
	    $start = $startdate->getTimeStamp();
1088
1089
	    $periods_quantity = 0; // days
1090
1091
        // get the number of worked hours from startdate to the end of the day
1092
 
1093
	    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...
1094
1095
	        if ($start >= $period->ts_end) {
1096
	            // continue to the next worked period
1097
	            //var_dump('working period ignored, start='.bab_shortDate($start, true).' >= '.bab_shortDate($period->ts_end, true));
1098
	            continue;
1099
	        }
1100
1101
	        $periods_quantity += $this->getPeriodQuantity($startdate, $period);
1102
	        
1103
1104
	        if ($periods_quantity >= $quantity) {
1105
1106
	            $overhead = $periods_quantity - $quantity;
1107
1108
	            $futureDate = BAB_DateTime::fromTimeStamp($period->ts_end);
1109
1110
	            // var_dump($futureDate->getIsoDateTime().' overhead='.$overhead.' ('.$periods_quantity.' - '.$quantity.')');
1111
1112
	            if ($overhead) {
1113
	                $futureDate->less(
1114
	                    3600 * $this->getDayDurationInHours($futureDate->getIsoDate(), $overhead),
1115
	                    BAB_DATETIME_SECOND
1116
	                );
1117
	            }
1118
1119
	            if ($futureDate->getIsoDateTime() > $this->date_end) {
1120
	                $futureDate = BAB_DateTime::fromIsoDateTime($this->date_end);
1121
	            }
1122
1123
	            return $futureDate;
1124
	        }
1125
	    }
1126
1127
	    return BAB_DateTime::fromIsoDateTime($this->date_end);
1128
	}
1129
1130
1131
	/**
1132
	 * Create the planned periods in the entry boundaries
1133
	 * from the calendar working periods
1134
	 */
1135 23
	public function createPlannedPeriods()
1136
	{
1137 23
	    require_once dirname(__FILE__).'/entry_period.class.php';
1138 23
	    $this->plannedPeriods = array();
1139
1140 23
	    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...
1141
1142
	        /*@var $workingPeriod bab_CalendarPeriod */
1143
1144 23
	        $plannedPeriod = new absences_EntryPeriod();
1145 23
	        $plannedPeriod->setEntry($this);
1146 23
	        $plannedPeriod->date_begin = date('Y-m-d H:i:s', $workingPeriod->ts_begin);
1147 23
	        $plannedPeriod->date_end = date('Y-m-d H:i:s', $workingPeriod->ts_end);
1148
1149 23
	        $this->plannedPeriods[] = $plannedPeriod;
1150 23
	    }
1151 23
	}
1152
1153
1154
	/**
1155
	 * Get period quantity in days from a datetime
1156
	 *
1157
	 * @param BAB_DateTime         $startdate
1158
	 * @param bab_CalendarPeriod   $p
1159
	 *
1160
	 * @return float
1161
	 */
1162
	protected function getPeriodQuantity(BAB_DateTime $startdate, bab_CalendarPeriod $p)
1163
	{
1164
	    $type = $this->getPeriodType($p);
1165
1166
	    if ('AMPM' === $type) {
1167
	        $period_days = 1.0;
1168
	    }
1169
1170
	    if ('AM' === $type || 'PM' === $type) {
1171
	        $period_days = 0.5;
1172
	    }
1173
1174
	    $moment = $startdate->getTimeStamp();
1175
	    
1176
	    
1177
	    if ($moment > $p->ts_begin && $moment < $p->ts_end) {
1178
	        $period_seconds = $p->getDuration();
1179
	        $new_period = clone $p;
1180
	        $new_period->setBeginDate($startdate);
1181
1182
	        $new_seconds = $new_period->getDuration();
1183
1184
	        $period_days = ($new_seconds * $period_days) / $period_seconds;
0 ignored issues
show
Bug introduced by
The variable $period_days does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1185
	    }
1186
1187
	    return $period_days;
1188
	}
1189
1190
1191
1192
1193
	/**
1194
	 * Convert days to hours
1195
	 * using the number of hours in a specified day
1196
	 * the number of days given as parameter should be less than 1
1197
	 *
1198
	 * @param string $date     Must be a date in the entry period
1199
	 * @param float $days
1200
	 *
1201
	 * @return float   Hours
1202
	 */
1203
	protected function getDayDurationInHours($date, $days)
1204
	{
1205
	    $hours_in_day = 0;
1206
1207
        foreach ($this->getWorkingPeriods() as $p) {
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...
1208
            $pdate = date('Y-m-d', $p->ts_begin);
1209
1210
            if ($pdate !== $date) {
1211
                continue;
1212
            }
1213
1214
            $hours_in_day += ($p->getDuration()/3600);
1215
        }
1216
1217
        $hours = ($days * $hours_in_day);
1218
1219
        return $hours;
1220
	}
1221
1222
1223
1224
1225
	/**
1226
	 *
1227
	 *
1228
	 * @param bab_CalendarPeriod $period
1229
	 *
1230
	 * @return AM | PM | AMPM
1231
	 */
1232 20
	protected function getPeriodType(bab_CalendarPeriod $period)
1233
	{
1234 20
	    $endtype = date('A', $period->ts_end);
1235 20
	    $begintype = date('A', $period->ts_begin);
1236
1237 20
	    if ('AM' === $endtype || '12:00:00' === date('H:i:s', $period->ts_end)) { //  || 'AM' === $begintype  && '14:00:00' >= date('H:i:s', $period->ts_end)
1238 14
	        return 'AM';
1239
	    }
1240
	    
1241 20
	    if ('AM' === $begintype && '14:00:00' >= date('H:i:s', $period->ts_end)) {
1242 6
	        return 'AM';
1243
	    }
1244
1245 20
	    if ('PM' === $begintype || '12:00:00' === date('H:i:s', $period->ts_begin)) {
1246 20
	        return 'PM';
1247
	    }
1248
	    
1249
	    return 'AMPM';
1250
	}
1251
1252
1253
1254
1255
	/**
1256
	 * Save elements of entry to database
1257
	 *
1258
	 */
1259
	public function saveElements()
1260
	{
1261
		$processed_ids = array();
1262
1263
		foreach ($this->elements as $elem)
1264
		{
1265
			/*@var $elem absences_EntryElem */
1266
		    
1267
		    try {
1268
		    
1269
    			$elem->save();
1270
    			$processed_ids[] = $elem->id;
1271
    			
1272
		    } catch(Exception $e) {
1273
		        // fail to save one element, it will be deleted or not created
1274
		        bab_debug($e->getMessage());
1275
		    }
1276
		}
1277
1278
		// delete removed elements
1279
1280
		global $babDB;
1281
1282
		$babDB->db_query('DELETE FROM absences_entries_elem WHERE id_entry='.$babDB->quote($this->id).' AND id NOT IN('.$babDB->quote($processed_ids).')');
1283
1284
	}
1285
1286
1287
1288
1289
	public function savePlannedPeriods()
1290
	{
1291
	    if (empty($this->plannedPeriods)) {
1292
	        throw new Exception('Planned periods where not loaded or set');
1293
	    }
1294
1295
	    $processed_ids = array();
1296
1297
	    foreach ($this->plannedPeriods as $period)
1298
	    {
1299
	        /*@var $elem absences_EntryPeriod */
1300
	        $period->save();
1301
1302
	        $processed_ids[] = $period->id;
1303
	    }
1304
1305
	    global $babDB;
1306
1307
	    $babDB->db_query('DELETE FROM absences_entries_periods WHERE id_entry='.$babDB->quote($this->id).' AND id NOT IN('.$babDB->quote($processed_ids).')');
1308
1309
	}
1310
1311
1312
1313
	/**
1314
	 * Apply dynamic rights for all right involved in the entry
1315
	 */
1316
	public function applyDynamicRight()
1317
	{
1318
		require_once dirname(__FILE__).'/agent_right.class.php';
1319
1320
		$I = new absences_AgentRightManagerIterator();
1321
		$I->setAgent($this->getAgent());
1322
1323
		foreach ($I as $agentRight)
1324
		{
1325
			/*@var $agentRight absences_AgentRight */
1326
			$agentRight->applyDynamicRight();
1327
		}
1328
	}
1329
1330
1331
1332
1333
	/**
1334
	 * Add element to list
1335
	 * @param absences_EntryElem $elem
1336
	 */
1337 39
	public function addElement(absences_EntryElem $elem)
1338
	{
1339 39
		$this->elements[] = $elem;
1340 39
	}
1341
1342
	/**
1343
	 * Remove an element in the list
1344
	 * @param int $id_right
1345
	 *
1346
	 * @return bool
1347
	 */
1348
	public function removeElement($id_right)
1349
	{
1350
		foreach ($this->elements as $key => $elem)
1351
		{
1352
			if ($elem->id_right == $id_right)
1353
			{
1354
				unset($this->elements[$key]);
1355
				return true;
1356
			}
1357
		}
1358
1359
		return false;
1360
	}
1361
1362
1363
	/**
1364
	 * Set the working period index for the entry
1365
	 * Used in unit tests to set differents working periods
1366
	 * if not used, the workingPeriodIndex will be generated from the calendar API
1367
	 *
1368
	 */
1369 38
	public function setWorkingPeriodIndex(Array $index_working)
1370
	{
1371 38
	    $this->workingPeriodIndex = $index_working;
1372 38
	    return $this;
1373
	}
1374
1375
	/**
1376
	 * Get working period index for the user and for the period
1377
	 * @return array
1378
	 */
1379 35
	private function getWorkingPeriodIndex()
1380
	{
1381 35
	    if (!isset($this->workingPeriodIndex)) {
1382
1383
	        include_once $GLOBALS['babInstallPath']."utilit/dateTime.php";
1384
1385
	        list($index_working,, $is_free) = absences_getHalfDaysIndex(
1386
	            $this->id_user,
1387
	            BAB_DateTime::fromIsoDateTime($this->date_begin),
1388
	            BAB_DateTime::fromIsoDateTime($this->date_end),
1389
	            true
1390
	        );
1391
1392
1393
	        foreach ($index_working as $key => $period_list) {
1394
	            if (!isset($is_free[$key])) {
1395
	                unset($index_working[$key]);
1396
	            }
1397
	        }
1398
1399
	        $this->workingPeriodIndex = $index_working;
1400
	    }
1401
1402 35
	    return $this->workingPeriodIndex;
1403
	}
1404
1405
1406
1407
	/**
1408
	 * Number of free days and hours between two dates
1409
	 *
1410
	 */
1411 35
	private function loadDurations() {
1412
1413 35
		$this->duration_days 	= 0.0;
1414 35
		$this->duration_hours 	= 0.0;
1415 35
		$this->working_periods = array();
1416
1417
1418
1419 35
		$index_working = $this->getWorkingPeriodIndex();
1420
1421
1422 35
		foreach ($index_working as $key => $period_list) {
1423
1424 35
			$this->duration_days += 0.5;
1425
1426 35
			foreach($period_list as $p)
1427
			{
1428
				/*@var $p bab_CalendarPeriod */
1429
1430 35
				if ($p->getCollection() instanceof bab_WorkingPeriodCollection)
1431 35
				{
1432 35
				    $this->working_periods[] = $p;
1433 35
					$this->duration_hours 	+= ($p->getDuration() / 3600);
1434 35
				}
1435 35
			}
1436 35
		}
1437 35
	}
1438
1439
1440
	/**
1441
	 * Get list of working periods of the entry
1442
	 * @return bab_CalendarPeriod[]
1443
	 */
1444 35
	protected function getWorkingPeriods()
1445
	{
1446 35
	    if (!isset($this->working_periods)) {
1447 35
	        $this->loadDurations();
1448 35
	    }
1449
1450 35
	    return $this->working_periods;
1451
	}
1452
1453
1454
	/**
1455
	 * List of working periods for one day
1456
	 * @param string $date 10 chars
1457
	 *
1458
	 * @return bab_CalendarPeriod[]
1459
	 */
1460
	public function getDayWorkingPeriods($date)
1461
	{
1462
	    $return = array();
1463
	    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...
1464
	        if ($date === date('Y-m-d', $period->ts_begin)) {
1465
	            $return[] = $period;
1466
	        }
1467
	    }
1468
1469
	    return $return;
1470
	}
1471
1472
1473
	/**
1474
	 * List of working periods for one day
1475
	 * @param string $date 10 chars
1476
	 *
1477
	 * @return absences_EntryPeriod[]
1478
	 */
1479
	public function getDayPlannedPeriods($date)
1480
	{
1481
	    $return = array();
1482
	    foreach ($this->getPlannedPeriodsIterator() as $period) {
1483
	        if ($date === substr($period->date_begin, 0, 10)) {
1484
	            $return[] = $period;
1485
	        }
1486
	    }
1487
1488
	    return $return;
1489
	}
1490
1491
1492
1493
1494
	/**
1495
	 * Get period duration in days
1496
	 * @return float
1497
	 */
1498
	public function getDurationDays()
1499
	{
1500
		if (!isset($this->duration_days))
1501
		{
1502
			$this->loadDurations();
1503
		}
1504
1505
		return $this->duration_days;
1506
	}
1507
1508
	/**
1509
	 * Get period duration in hours
1510
	 * @return float
1511
	 */
1512
	public function getDurationHours()
1513
	{
1514
		if (!isset($this->duration_hours))
1515
		{
1516
			$this->loadDurations();
1517
		}
1518
1519
		return $this->duration_hours;
1520
	}
1521
1522
1523
	/**
1524
	 * Convert a number of days to hours
1525
	 * @param float $days
1526
	 * @return float
1527
	 */
1528 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...
1529
	{
1530
	    
1531
	    
1532
		if (0 === (int) round(100 * $this->getTotalDays()))
1533
		{
1534
			return 0;
1535
		}
1536
1537
		$ratio = $this->getPlannedDurationHours() / $this->getPlannedDurationDays();
1538
		return round(($ratio * $days), 2);
1539
	}
1540
1541
	/**
1542
	 * Convert a number of hours to days
1543
	 * @param float $hours
1544
	 * @return float
1545
	 */
1546 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...
1547
	{
1548
		if (0 == $this->getTotalHours())
1549
		{
1550
			return 0;
1551
		}
1552
1553
		$ratio = $this->getPlannedDurationDays() / $this->getPlannedDurationHours();
1554
		return round(($ratio * $hours), 2);
1555
	}
1556
1557
1558
1559
	/**
1560
	 * Compute totals for loaded elements
1561
	 */
1562
	private function loadedElementsTotal()
1563
	{
1564
		if (empty($this->elements))
1565
		{
1566
			$this->loadElements();
1567
		}
1568
1569
		$this->total_days = 0.0;
1570
		$this->total_hours = 0.0;
1571
		$this->total_type_days = array();
1572
		$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...
1573
1574
		foreach($this->elements as $elem)
1575
		{
1576
			/*@var $elem absences_EntryElem */
1577
			$right = $elem->getRight();
1578
1579
			$quantity = (float) $elem->quantity;
1580
1581
			switch($right->quantity_unit)
1582
			{
1583
				case 'D':
1584
					$hours = $this->daysToHours($quantity);
1585
					$this->addQUantityInCache($right, $quantity, $hours);
1586
					break;
1587
				case 'H':
1588
				    $days = $this->hoursToDays($quantity);
1589
				    $this->addQUantityInCache($right, $days, $quantity);
1590
					break;
1591
			}
1592
		}
1593
	}
1594
1595
1596
	/**
1597
	 * Populate the cache variables for one element
1598
	 *
1599
	 * @param absences_Right $right
1600
	 * @param float $days
1601
	 * @param float $hours
1602
	 */
1603
	private function addQUantityInCache(absences_Right $right, $days, $hours)
1604
	{
1605
	    if (!isset($this->total_type_days[$right->id_type])) {
1606
	        $this->total_type_days[$right->id_type] = 0.0;
1607
	    }
1608
1609
	    if (!isset($this->total_type_hours[$right->id_type])) {
1610
	        $this->total_type_hours[$right->id_type] = 0.0;
1611
	    }
1612
1613
	    $this->total_days += $days;
1614
	    $this->total_hours += $hours;
1615
	    $this->total_type_days[$right->id_type] += $days;
1616
	    $this->total_type_hours[$right->id_type] += $hours;
1617
	}
1618
1619
1620
1621
1622
1623
	/**
1624
	 * Get sum of elements quantity, converted in days
1625
	 *
1626
	 * @param int $id_type Optional filter by type
1627
	 *
1628
	 * @return float
1629
	 */
1630 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...
1631
	{
1632
		if (!isset($this->total_days)) {
1633
			$this->loadedElementsTotal();
1634
		}
1635
1636
		if (isset($id_type)) {
1637
1638
		    if (!isset($this->total_type_days[$id_type])) {
1639
		        return 0.0;
1640
		    }
1641
1642
		    return $this->total_type_days[$id_type];
1643
		}
1644
1645
		return $this->total_days;
1646
	}
1647
1648
	/**
1649
	 * Get sum of elements quantity, converted in hours
1650
	 *
1651
	 * @param int $id_type Optional filter by type
1652
	 *
1653
	 * @return float
1654
	 */
1655 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...
1656
	{
1657
		if (!isset($this->total_hours)) {
1658
			$this->loadedElementsTotal();
1659
		}
1660
1661
		if (isset($id_type)) {
1662
1663
		    if (!isset($this->total_type_hours[$id_type])) {
1664
		        return 0.0;
1665
		    }
1666
1667
		    return $this->total_type_hours[$id_type];
1668
		}
1669
1670
		return $this->total_hours;
1671
	}
1672
1673
1674
1675
1676
	/**
1677
	 * Number of days on entry between two dates
1678
	 * si les dates de l'element sont a cheval sur la periode demandee
1679
	 * on utlise les heures travailles qui etait en vigeur au moment de la creation
1680
	 * de la demande
1681
	 *
1682
	 * @param string   $begin	Datetime
1683
	 * @param string   $end		Datetime
1684
	 * @param int      $id_type Optional filter by type
1685
	 *
1686
	 * @return float (days)
1687
	 */
1688 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...
1689
	{
1690 1
	    if (empty($this->elements))
1691 1
	    {
1692
	        $this->loadElements();
1693
	    }
1694
1695 1
	    $total = 0.0;
1696 1
	    foreach($this->elements as $elem)
1697
	    {
1698
	        /*@var $elem absences_EntryElem */
1699 1
	        $right = $elem->getRight();
1700
1701 1
	        if (isset($id_type) && (int) $id_type !== (int) $right->id_type) {
1702
	            continue;
1703
	        }
1704
1705 1
	        $quantity = $elem->getPlannedQuantityBetween($begin, $end);
1706
1707 1
	        if ('H' === $right->quantity_unit) {
1708
	            $days = $this->hoursToDays($quantity);
1709
	        } else {
1710 1
	            $days = $quantity;
1711
	        }
1712
1713 1
	        $total += $days;
1714 1
	    }
1715
1716 1
	    return $total;
1717
	}
1718
1719
1720
1721
1722
	/**
1723
	 * Number of hours on entry between two dates
1724
	 * si les dates de l'element sont a cheval sur la periode demandee
1725
	 * on utlise les heures travailles qui etait en vigeur au moment de la creation
1726
	 * de la demande
1727
	 *
1728
	 * @param string   $begin	Datetime
1729
	 * @param string   $end		Datetime
1730
	 * @param int      $id_type Optional filter by type
1731
	 *
1732
	 * @return float (hours)
1733
	 */
1734 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...
1735
	{
1736
	    if (empty($this->elements))
1737
	    {
1738
	        $this->loadElements();
1739
	    }
1740
1741
	    $total = 0.0;
1742
	    foreach($this->elements as $elem)
1743
	    {
1744
	        /*@var $elem absences_EntryElem */
1745
	        $right = $elem->getRight();
1746
1747
	        if (isset($id_type) && (int) $id_type !== (int) $right->id_type) {
1748
	            continue;
1749
	        }
1750
1751
	        $quantity = $elem->getPlannedQuantityBetween($begin, $end);
1752
1753
	        if ('D' === $right->quantity_unit) {
1754
	            $hours = $this->daysToHours($quantity);
1755
	        } else {
1756
	            $hours = $quantity;
1757
	        }
1758
1759
	        $total += $hours;
1760
	    }
1761
1762
	    return $total;
1763
	}
1764
1765
1766
1767
1768
1769
1770
1771
1772
	/**
1773
	 * Test if the loaded elements in entry contains rights in hours
1774
	 * @return bool
1775
	 */
1776
	public function containsHours()
1777
	{
1778
		foreach($this->elements as $elem)
1779
		{
1780
			if ('H' === $elem->getRight()->quantity_unit)
1781
			{
1782
				return true;
1783
			}
1784
		}
1785
1786
		return false;
1787
	}
1788
1789
1790
	/**
1791
	 * Test if loaded elements in entry require approval
1792
	 *
1793
	 * @return bool
1794
	 */
1795
	public function requireApproval()
1796
	{
1797
		if (empty($this->elements))
1798
		{
1799
			$this->loadElements();
1800
		}
1801
1802
		foreach($this->elements as $elem)
1803
		{
1804
			if (1 === (int) $elem->getRight()->require_approval)
1805
			{
1806
				return true;
1807
			}
1808
		}
1809
1810
		return false;
1811
	}
1812
	
1813
	
1814
	public function checkAvailable()
1815
	{
1816
	    $res = $this->getElementsIterator();
1817
	    foreach ($res as $element) {
1818
	        /*@var $element absences_EntryElem */
1819
	        if (!$element->isQuantityAvailable()) {
1820
	            throw new Exception(sprintf(absences_translate('Failed to submit this request, the quantity for right %s s not available'), $element->getRight()->description));
1821
	        }
1822
	    }
1823
	}
1824
1825
	
1826
	/**
1827
	 * Check elements validity
1828
	 * @throws UnexpectedValueException
1829
	 * 
1830
	 * @return int number of elements with quantity > 0
1831
	 */
1832
	protected function checkElementsValidity()
1833
	{
1834
	    $count = 0;
1835
	    foreach($this->elements as $elem)
1836
	    {
1837
	        $quantity = (int) round(100 * $elem->quantity);
1838
	        if ($quantity > 0)
1839
	        {
1840
	            $count++;
1841
	        }
1842
	    
1843
	        $elem->checkValidity();
1844
	    }
1845
	    
1846
	    return $count;
1847
	}
1848
	
1849
	
1850
	/**
1851
	 * throw an exception if there is another entry in the same period
1852
	 * @throws absences_EntryException
1853
	 */
1854
	protected function checkOtherEntriesValidity()
1855
	{
1856
	    $otherEntries = new absences_EntryIterator();
1857
	    $otherEntries->from = $this->date_begin;
1858
	    $otherEntries->to = $this->date_end;
1859
	    $otherEntries->users = array($this->id_user);
1860
	    
1861
	    
1862
	    foreach ($otherEntries as $otherEntry) {
1863
	    
1864
	        /* @var $otherEntry absences_Entry */
1865
	    
1866 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...
1867
	            $e = new absences_EntryException(absences_translate('There is allready an absence request in the period'));
1868
	            $e->entry = $this;
1869
	            $e->blocking = true;
1870
	            throw $e;
1871
	        }
1872
	    }
1873
	    
1874
	}
1875
1876
1877
	/**
1878
	 * Check request validity
1879
	 *
1880
	 * @throws absences_EntryException
1881
	 * @throws UnexpectedValueException
1882
	 * 
1883
	 * @return bool
1884
	 */
1885
	public function checkValidity()
1886
	{
1887
		// verify mandatory data
1888
1889
		if (!isset($this->id_user) || $this->id_user <= 0)
1890
		{
1891
			throw new UnexpectedValueException('Unexpected id_user');
1892
		}
1893
1894
1895
		$count = $this->checkElementsValidity();
1896
1897
1898 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...
1899
		{
1900
			$e = new absences_EntryException(absences_translate('At least one vacation right must be used'));
1901
			$e->entry = $this;
1902
			$e->blocking = true;
1903
			throw $e;
1904
		}
1905
1906
1907
1908
		// test user validity
1909
1910
		require_once $GLOBALS['babInstallPath'].'utilit/userinfosincl.php';
1911
1912
		$creationdate = bab_userInfos::getCreationDate($this->id_user);
1913
1914
		if ($creationdate >= $this->date_end) {
1915
			$e = new absences_EntryException(sprintf(absences_translate('The vacation request end before user creation date : %s'), bab_shortDate(bab_mktime($creationdate))));
1916
			$e->entry = $this;
1917
			$e->blocking = true;
1918
			throw $e;
1919
		}
1920
1921
		// T8359 : si l'utilisateur est reactive la demande ne sera pas presente, il faudra reenregistrer le droit
1922
		// avant la correction de ce ticket, on creeais les demandes pour eviter ce probleme
1923
1924
		if (!bab_userInfos::isValid($this->id_user)) {
1925
1926
		    /*
1927
		    $e = new absences_EntryException(absences_translate('This user account is disabled'));
1928
		    $e->entry = $this;
1929
		    $e->blocking = true;
1930
		    throw $e;
1931
		    */
1932
1933
		    return false;
1934
		}
1935
1936
1937
		// test quantity / period duration in days
1938
1939
		$total = (int) round(100 * $this->getTotalDays());
1940
		$duration = (int) round(100 * $this->getDurationDays());
1941
1942
1943 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...
1944
		{
1945
			$e = new absences_EntryException(absences_translate('The selected period is not available'));
1946
			$e->entry = $this;
1947
			$e->blocking = true;
1948
			throw $e;
1949
		}
1950
1951
1952
1953
		if ($total !== $duration)
1954
		{
1955
			$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')));
1956
			$e->entry = $this;
1957
			$e->blocking = !((bool) absences_getVacationOption('allow_mismatch'));
1958
			throw $e;
1959
		}
1960
1961
		// test quantity / period duration in hours only if there is one right in hours
1962
		/*
1963
		 *
1964
		 * 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
1965
		 * 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)
1966
		 *
1967
		if ($this->containsHours())
1968
		{
1969
			$total = (int) round(100 * $this->getTotalHours());
1970
			$duration = (int) round(100 * $this->getDurationHours());
1971
1972
			if ($total !== $duration)
1973
			{
1974
				$e = new absences_EntryException(absences_translate('The total quantity does not match the period duration in hours'));
1975
				$e->blocking = !((bool) absences_getVacationOption('allow_mismatch'));
1976
				throw $e;
1977
			}
1978
		}
1979
1980
		*/
1981
1982
1983
1984
		// verifier si la periode demandee n'est pas deja occuppe par une autre demande
1985
        $this->checkOtherEntriesValidity();
1986
		
1987
1988
		return true;
1989
	}
1990
1991
1992
	/**
1993
	 * (non-PHPdoc)
1994
	 * @see absences_Request::modifiedOn()
1995
	 *
1996
	 * @return string
1997
	 */
1998 1
	public function modifiedOn()
1999
	{
2000 1
		return $this->date;
2001
	}
2002
2003
	/**
2004
	 * Test if the entry is a fixed vacation
2005
	 * @return bool
2006
	 */
2007
	public function isFixed()
2008
	{
2009
		return (1 === (int) $this->creation_type);
2010
2011
	}
2012
2013
2014
2015
2016
2017
	/**
2018
	 * Test if entry is previsonal
2019
	 * @return bool
2020
	 */
2021
	public function isPrevisonal()
2022
	{
2023
		return ($this->status === 'P');
2024
	}
2025
2026
	/**
2027
	 * Test if at least one entry in folder is previsonal
2028
	 * @return boolean
2029
	 */
2030
	public function isFolderPrevisonal()
2031
	{
2032
		if (!$this->folder)
2033
		{
2034
			return false;
2035
		}
2036
2037
		$I = new absences_EntryIterator;
2038
		$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...
2039
		$I->status = 'P';
2040
2041
		return ($I->count() > 0);
2042
	}
2043
2044
	/**
2045
	 * Get the first entry in folder
2046
	 * @return absences_Entry
2047
	 */
2048 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...
2049
	{
2050
		if (!$this->folder)
2051
		{
2052
			return null;
2053
		}
2054
2055
		$I = new absences_EntryIterator;
2056
		$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...
2057
2058
		foreach($I as $first)
2059
		{
2060
			return $first;
2061
		}
2062
2063
		return null;
2064
	}
2065
2066
2067
	/**
2068
	 * Process specific code when the request is rejected
2069
	 *
2070
	 */
2071
	protected function onReject()
2072
	{
2073
		$this->updateCalendar();
2074
	}
2075
2076
2077
	/**
2078
	 * Process specific code when the request is confirmed
2079
	 *
2080
	 */
2081
	public function onConfirm()
2082
	{
2083
		$this->updateCalendar();
2084
	}
2085
2086
2087
2088
	/**
2089
	 * Call the user calendar backend to update the event
2090
	 * call the event to notify about calendar event modification
2091
	 */
2092
	public function updateCalendar()
2093
	{
2094
		require_once $GLOBALS['babInstallPath'].'utilit/dateTime.php';
2095
2096
		// try to update event copy in other backend (caldav)
2097
2098
		$begin = BAB_DateTime::fromIsoDateTime($this->date_begin);
2099
		$end = BAB_DateTime::fromIsoDateTime($this->date_end);
2100
		$period = absences_getPeriod($this->id, $this->id_user,  $begin, $end);
2101
		if ($period) {
2102
2103
			// probably set a new description if the event has been approved or rejected
2104
			absences_setPeriodProperties($period, $this);
2105
2106
			// save copy of event to calendar backend (if caldav)
2107
			$period->save();
2108
		}
2109
2110
2111
		// Update calendar data overlapped with event
2112
2113
		$date_begin = bab_mktime($this->date_begin);
2114
		$date_end	= bab_mktime($this->date_end);
2115
2116
		include_once $GLOBALS['babInstallPath']."utilit/eventperiod.php";
2117
		$event = new bab_eventPeriodModified($date_begin, $date_end, $this->id_user);
2118
		$event->types = BAB_PERIOD_VACATION;
0 ignored issues
show
Bug introduced by
The property types cannot be accessed from this context as it is declared private in class bab_eventPeriodModified.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2119
		bab_fireEvent($event);
2120
	}
2121
2122
2123
	public function getTitle()
2124
	{
2125
	    if (isset($this->todelete) && $this->todelete) {
2126
	        return absences_translate('vacation request to delete');
2127
	    }
2128
	    
2129
		return absences_translate('vacation request');
2130
	}
2131
2132
2133 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...
2134
	{
2135
		return array(
2136
			absences_translate('From') 		=> bab_shortDate(bab_mktime($this->date_begin)),
2137
			absences_translate('Until')		=> bab_shortDate(bab_mktime($this->date_end)),
2138
			absences_translate('Quantity') 	=> absences_quantity($this->getTotalDays(), 'D')
2139
		);
2140
	}
2141
2142
2143 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...
2144
	{
2145
		$year = (int) substr($this->date_begin, 0, 4);
2146
2147
		if (0 === $year)
2148
		{
2149
			return null;
2150
		}
2151
2152
		return $year;
2153
	}
2154
2155
2156 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...
2157
	{
2158
		require_once $GLOBALS['babInstallPath'].'utilit/dateTime.php';
2159
		$year = (int) substr($this->date_begin, 0, 4);
2160
2161
		if (0 === $year)
2162
		{
2163
			return null;
2164
		}
2165
2166
		$day = absences_getVacationOption('archivage_day');
2167
		$month = absences_getVacationOption('archivage_month');
2168
2169
		$currentYear = new BAB_DateTime($year, $month, $day);
2170
		if($this->date_begin < $currentYear->getIsoDate()){
2171
			$year = $year-1;
2172
		}
2173
2174
		return $year;
2175
	}
2176
2177 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...
2178
	{
2179
		global $babDB;
2180
2181
		$babDB->db_query("
2182
			UPDATE absences_entries
2183
			SET archived=".$babDB->quote(1)."
2184
			WHERE
2185
				id=".$babDB->quote($this->id)."
2186
		");
2187
	}
2188
2189
2190 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...
2191
	{
2192
		global $babDB;
2193
2194
		if (!$this->id)
2195
		{
2196
			throw new Exception('Missing ID');
2197
		}
2198
2199
		$babDB->db_query("
2200
			UPDATE absences_entries
2201
				SET appr_notified=".$babDB->quote(1)."
2202
			WHERE
2203
				id=".$babDB->quote($this->id)."
2204
		");
2205
	}
2206
2207
2208
	public function getManagerEditUrl()
2209
	{
2210
		$addon = bab_getAddonInfosInstance('absences');
2211
		$ts = bab_mktime($this->date_begin);
2212
		return $addon->getUrl().'vacuser&idx=period&id='.$this->id.'&year='.date('Y', $ts).'&month='.date('n', $ts).'&rfrom=1';
2213
	}
2214
2215
2216
	public function getManagerDeleteUrl()
2217
	{
2218
		$addon = bab_getAddonInfosInstance('absences');
2219
		$url = new bab_url($addon->getUrl().'vacadmb');
2220
		$url->idx = 'delete';
2221
		$url->id_entry = $this->id;
2222
		$url->from = $_SERVER['REQUEST_URI'];
2223
		return $url->toString();
2224
	}
2225
2226
2227
	public function getManagerFrame()
2228
	{
2229
		$W = bab_Widgets();
2230
		$vbox = $W->VBoxLayout();
2231
2232
		if ($this->isFixed())
2233
		{
2234
			$vbox->addItem($W->Icon(absences_translate('Fixed vacation period'), Func_Icons::ACTIONS_VIEW_CALENDAR_DAY));
2235
		} else {
2236
			$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));
2237
		}
2238
		$vbox->addItem($W->Label(absences_DateTimePeriod($this->date_begin, $this->date_end)));
2239
2240
		return $vbox;
2241
	}
2242
2243
2244
	/**
2245
	 *
2246
	 * @param bool 			$display_username	Affiche le nom du demandeur dans la card frame ou non, utile pour les listes contenant plusieurs demandeurs possibles
2247
	 * @param int			$rfrom				si les demandes de la liste sont modifiee par un gestionnaire ou gestionnaire delegue
2248
 	 * @param int			$ide				id entite de l'organigramme >0 si gestionnaire delegue seulement
2249
	 */
2250
	public function getCardFrame($display_username, $rfrom, $ide)
2251
	{
2252
		bab_functionality::includeOriginal('Icons');
2253
2254
		$W = bab_Widgets();
2255
		$layout = $W->HBoxLayout()->setHorizontalSpacing(2,'em')->addClass('widget-full-width');
2256
		$frame = $W->Frame(null, $layout);
2257
2258
		$frame->addClass(Func_Icons::ICON_LEFT_16);
2259
		$frame->addClass('absences-entry-cardframe');
2260
		$layout->addItem($col1 = $W->VBoxLayout()->setVerticalSpacing(.5,'em'));
2261
		$layout->addItem($col2 = $W->VBoxLayout()->setVerticalSpacing(.3,'em'));
2262
2263
		if ($this->isPrevisonal())
2264
		{
2265
			$btn = $W->Link($W->Button()->addItem($W->Label(absences_translate('Submit for approval'))), absences_addon()->getUrl()."vacuser&idx=subprev&id_entry=".$this->id);
2266
			$btn->setSizePolicy('display-opened');
2267
			$layout->addItem($btn);
2268
		}
2269
2270
		if ($this->isFolderPrevisonal())
2271
		{
2272
			$first = $this->getFolderFirst();
2273
			if ($first && $first->id === $this->id)
2274
			{
2275
				$btn = $W->Link($W->Button()->addItem($W->Label(absences_translate('Submit requests for approval'))), absences_addon()->getUrl()."vacuser&idx=subprev&id_entry=".$this->id);
2276
				$btn->setSizePolicy('display-closed');
2277
				$layout->addItem($btn);
2278
			}
2279
		}
2280
2281
2282
		$layout->addItem($col3 = $W->VBoxLayout()->setVerticalSpacing(.5,'em'));
2283
2284
		if ($this->isFixed())
2285
		{
2286
			$col1->addItem($W->Icon(absences_translate('Fixed vacation period'), Func_Icons::ACTIONS_VIEW_CALENDAR_DAY));
2287
			$col1->setCanvasOptions($col1->Options()->width(25,'em'));
2288
		} else {
2289
			$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));
2290
			$col1->setCanvasOptions($col1->Options()->width(25,'em'));
2291
2292
			$col1->addItem($this->getStatusIcon());
2293
		}
2294
2295
		$col2->setSizePolicy(Widget_SizePolicy::MAXIMUM);
2296
2297
		$col2->addItem($W->Title(absences_DateTimePeriod($this->date_begin, $this->date_end), 5));
2298
2299
		if ($display_username)
2300
		{
2301
			$col2->addItem($this->labelledValue(absences_translate('Owner'), $this->getUserName()));
2302
		}
2303
2304
		$col2->addItem($this->labelledValue(absences_translate('Quantity'), absences_vacEntryQuantity($this->id)));
2305
2306
2307
2308
2309 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...
2310
		{
2311
			$col3->addItem($W->Link($W->Icon(absences_translate('Modify'), Func_Icons::ACTIONS_DOCUMENT_EDIT), $this->getEditUrl($rfrom, $ide)));
2312
		}
2313
2314
		if ($this->canDelete())
2315
		{
2316
			$urldelete = absences_addon()->getUrl()."vacuser&idx=delete&id_entry=".$this->id;
2317
			$col3->addItem($W->Link($W->Icon(absences_translate('Delete'), Func_Icons::ACTIONS_EDIT_DELETE), $urldelete));
2318
		}
2319
2320
		$frame->setTitle(sprintf(absences_translate('Created the %s'), bab_shortDate(bab_mktime($this->createdOn()))));
2321
2322
		return $frame;
2323
	}
2324
2325
2326
2327
2328
2329
	/**
2330
	 * @return string
2331
	 */
2332
	public function getEditUrl($rfrom, $ide = null)
2333
	{
2334
		$begin_ts = bab_mktime($this->date_begin);
2335
		$url = absences_addon()->getUrl()."vacuser&idx=period&id=".$this->id."&year=".date('Y',$begin_ts)."&month=".date('n',$begin_ts);
2336
2337
		if (isset($rfrom))
2338
		{
2339
			$url .= '&rfrom='.$rfrom;
2340
		}
2341
2342
		if (isset($ide))
2343
		{
2344
			$url .= '&ide='.$ide;
2345
		}
2346
2347
		return $url;
2348
	}
2349
2350
2351
2352
	/**
2353
	 * Delete the vacation request
2354
	 * @return bool
2355
	 */
2356
	public function delete()
2357
	{
2358
2359
2360
2361
		global $babDB;
2362
2363
		if (!$this->getRow())
2364
		{
2365
			return false;
2366
		}
2367
2368
		parent::delete();
2369
		
2370
		if ('0000-00-00 00:00:00' !== $this->date_begin && '0000-00-00 00:00:00' !== $this->date_end) {
2371
    		include_once $GLOBALS['babInstallPath']."utilit/dateTime.php";
2372
    		$date_begin = BAB_DateTime::fromIsoDateTime($this->date_begin);
2373
    		$date_end	= BAB_DateTime::fromIsoDateTime($this->date_end);
2374
    
2375
    		$period = absences_getPeriod($this->id, $this->id_user, $date_begin, $date_end);
2376
    		if (null !== $period)
2377
    		{
2378
    			$period->delete();
2379
    		}
2380
		}
2381
		$babDB->db_query("DELETE FROM absences_dynamic_rights WHERE id_entry=".$babDB->quote($this->id));
2382
		$babDB->db_query("DELETE FROM ".ABSENCES_ENTRIES_ELEM_TBL." WHERE id_entry=".$babDB->quote($this->id)."");
2383
		$babDB->db_query("DELETE FROM ".ABSENCES_ENTRIES_TBL." WHERE id=".$babDB->quote($this->id));
2384
2385
		$this->applyDynamicRight();
2386
		
2387
		if (isset($date_begin) && isset($date_end)) {
2388
    		$cal_begin = clone $date_begin;
2389
    		$cal_end = clone $date_end;
2390
    
2391
    		$cal_end->add(1, BAB_DATETIME_MONTH);
2392
    
2393
    		while ($cal_begin->getTimeStamp() <= $cal_end->getTimeStamp()) {
2394
    			$month	= $cal_begin->getMonth();
2395
    			$year	= $cal_begin->getYear();
2396
    			absences_updateCalendar($this->id_user, $year, $month);
2397
    			$cal_begin->add(1, BAB_DATETIME_MONTH);
2398
    		}
2399
    		
2400
    		$this->addMovement(
2401
    		        sprintf(
2402
    		                absences_translate('The vacation entry from %s to %s has been deleted'),
2403
    		                $date_begin->shortFormat(true),
2404
    		                $date_end->shortFormat(true)
2405
    		        )
2406
    		);
2407
		}
2408
2409
		
2410
2411
		return true;
2412
	}
2413
2414
2415
2416
2417
2418
2419
2420
	/**
2421
	 * (non-PHPdoc)
2422
	 * @see absences_Request::notifyOwner()
2423
	 */
2424
	public function notifyOwner()
2425
	{
2426
		parent::notifyOwner();
2427
2428
		if ('Y' != $this->status)
2429
		{
2430
			return;
2431
		}
2432
2433
		$agent = $this->getAgent();
2434
		$emails = $agent->getEmails();
2435
2436
		if (empty($emails))
2437
		{
2438
			return;
2439
		}
2440
2441
		require_once dirname(__FILE__).'/request.notify.php';
2442
		absences_notifyEntryOwnerEmails(array($this), $emails);
2443
	}
2444
2445
}
2446
2447
2448
2449
2450
class absences_EntryException extends Exception
2451
{
2452
	/**
2453
	 * Optional entry associated to error (unsaved entry object)
2454
	 * @var absences_Entry
2455
	 */
2456
	public $entry;
2457
2458
2459
	/**
2460
	 * Define if the exception if blocking a save
2461
	 * @var bool
2462
	 */
2463
	public $blocking = true;
2464
}
2465
2466
2467
2468
/**
2469
 * Vacation requests
2470
 * Sorted by creation date
2471
 */
2472
class absences_EntryIterator extends absences_Iterator
2473
{
2474
2475
	/**
2476
	 *
2477
	 * @var string
2478
	 */
2479
	public $orderby = 'createdOn ASC';
2480
2481
2482
	/**
2483
	 *
2484
	 * @var string
2485
	 */
2486
	public $folder;
2487
2488
	/**
2489
	 *
2490
	 * @var array
2491
	 */
2492
	public $users;
2493
2494
2495
	/**
2496
	 *
2497
	 * @var mixed (array|string)
2498
	 */
2499
	public $status;
2500
2501
2502
	/**
2503
	 * Entry to ignore in the folder
2504
	 * @var int
2505
	 */
2506
	public $id_entry_folder;
2507
2508
2509
	/**
2510
	 * Filtrer les demandes necessitant ou pas un email aux approbateurs
2511
	 * @var int
2512
	 */
2513
	public $appr_notified;
2514
2515
	/**
2516
	 * Filtrer les demandes avec unes instance d'approbation
2517
	 * @var bool
2518
	 */
2519
	public $idfai_set;
2520
2521
2522
	/**
2523
	 * Filtrer les demandes avec une liste d'instances d'approbation
2524
	 * @var array
2525
	 */
2526
	public $appr_idfai;
2527
2528
2529
	/**
2530
	 * Search all request created before this date time
2531
	 * @var string
2532
	 */
2533
	public $createdOn;
2534
2535
	/**
2536
	 * Search all request modified before this date
2537
	 * @var string
2538
	 */
2539
	public $modifiedOn;
2540
2541
2542
	/**
2543
	 * Datetime
2544
	 * @var string
2545
	 */
2546
	public $from;
2547
2548
2549
	/**
2550
	 * Datetime
2551
	 * @var string
2552
	 */
2553
	public $to;
2554
2555
2556
	/**
2557
	 * Filtrer les demandes par annee
2558
	 * @var int
2559
	 */
2560
	public $year;
2561
2562
2563
	/**
2564
	 * Filtrer les demandes par organisation
2565
	 * @var int
2566
	 */
2567
	public $organization;
2568
2569
2570
	/**
2571
	 * Filtrer les demandes par statut d'archivage
2572
	 * @var int
2573
	 */
2574
	public $archived = 0;
2575
	
2576
	/**
2577
	 * with at least one element with this right
2578
	 */
2579
	public $id_right;
2580
2581
2582
2583 6
	public function getObject($data)
2584
	{
2585
2586 6
		$entry = new absences_Entry;
2587 6
		$entry->setRow($data);
2588 6
		return $entry;
2589
2590
	}
2591
2592
2593
2594 21
	public function executeQuery()
2595
	{
2596 21
		if(is_null($this->_oResult))
2597 21
		{
2598 21
			global $babDB;
2599
			$req = 'SELECT e.* 
2600
				FROM
2601
					absences_entries e 
2602 21
				';
2603
2604
2605 21
			$where = array();
2606 21
			if (isset($this->folder))
2607 21
			{
2608
				$where[] = 'e.folder='.$babDB->quote($this->folder);
2609
2610
				if (isset($this->id_entry_folder))
2611
				{
2612
					$where[] = 'e.id<>'.$babDB->quote($this->id_entry_folder);
2613
				}
2614
			}
2615
2616 21
			if (!empty($this->users))
2617 21
			{
2618 21
				$where[] = 'e.id_user IN('.$babDB->quote($this->users).')';
2619 21
			}
2620
2621 21
			if (isset($this->status))
2622 21
			{
2623 7
				$where[] = 'e.status IN('.$babDB->quote($this->status).')';
2624 7
			}
2625
2626 21
			if (isset($this->createdOn))
2627 21
			{
2628 15
				$where[] = 'e.createdOn<='.$babDB->quote($this->createdOn);
2629 15
			}
2630
2631 21
			if (isset($this->modifiedOn))
2632 21
			{
2633
				$where[] = 'e.`date`<='.$babDB->quote($this->modifiedOn);
2634
			}
2635
2636 21
			if (isset($this->appr_notified))
2637 21
			{
2638
				$where[] = 'e.appr_notified='.$babDB->quote($this->appr_notified);
2639
			}
2640
2641 21
			if (isset($this->idfai_set) && $this->idfai_set)
2642 21
			{
2643
				$where[] = 'e.idfai>'.$babDB->quote(0);
2644
			}
2645
2646 21
			if (isset($this->appr_idfai))
2647 21
			{
2648
				$where[] = 'e.idfai IN('.$babDB->quote($this->appr_idfai).')';
2649
			}
2650
2651 21
			if (isset($this->from))
2652 21
			{
2653
				$where[] = 'e.date_end >'.$babDB->quote($this->from);
2654
			}
2655
2656 21
			if (isset($this->to))
2657 21
			{
2658
				$where[] = 'e.date_begin <'.$babDB->quote($this->to);
2659
			}
2660
2661 21
			if (isset($this->startTo))
2662 21
			{
2663
				$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...
2664
			}
2665
2666 21
			if (isset($this->startFrom))
2667 21
			{
2668
				$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...
2669
			}
2670
2671 21
			if (isset($this->year))
2672 21
			{
2673
				$where[] = 'YEAR(e.date_begin)='.$babDB->quote($this->year);
2674
			}
2675
2676 21 View Code Duplication
			if (isset($this->organization) && $this->organization)
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...
2677 21
			{
2678
				$req .= ', absences_personnel p';
2679
				$where[] = 'e.id_user=p.id_user';
2680
				$where[] = 'p.id_organization='.$babDB->quote($this->organization);
2681
			}
2682
2683 21
			if (isset($this->archived))
2684 21
			{
2685 21
				$where[] = 'e.archived='.$babDB->quote($this->archived);
2686 21
			}
2687
			
2688 21
			if (isset($this->id_right))
2689 21
			{
2690 21
			    $where[] = 'e.id IN(SELECT id_entry FROM absences_entries_elem WHERE id_right='.$babDB->quote($this->id_right).')';
2691 21
			}
2692
2693
			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...
2694 21
			{
2695 21
				$req .= ' WHERE '.implode(' AND ', $where);
2696 21
			}
2697
2698 21
			$req .= ' ORDER BY '.$this->orderby;
2699
			
2700 21
			$this->setMySqlResult($this->getDataBaseAdapter()->db_query($req));
2701 21
		}
2702 21
	}
2703
}
2704
2705
2706
/**
2707
 * Entry elements iterator
2708
 */
2709
class absences_EntryElemIterator extends absences_Iterator
2710
{
2711
	/**
2712
	 *
2713
	 * @var absences_Entry
2714
	 */
2715
	public $entry;
2716
2717
	/**
2718
	 * Filter by a list of id vaction types
2719
	 * @var int[]
2720
	 */
2721
	public $types;
2722
2723
2724
	public function getObject($data)
2725
	{
2726
		require_once dirname(__FILE__).'/type.class.php';
2727
		require_once dirname(__FILE__).'/right.class.php';
2728
		require_once dirname(__FILE__).'/entry_elem.class.php';
2729
2730
		$type_row = $this->getRowByPrefix($data, 'type');
2731
		$type = new absences_Type($type_row['id']);
2732
		$type->setRow($type_row);
2733
2734
		$right_row = $this->getRowByPrefix($data, 'right');
2735
		$right = new absences_Right($right_row['id']);
2736
		$right->setRow($right_row);
2737
		$right->setType($type);
2738
2739
		$elem_row = $this->getRowByPrefix($data, 'elem');
2740
		$elem = new absences_EntryElem();
2741
		$elem->setRow($elem_row);
2742
		$elem->setRight($right);
2743
		$elem->setEntry($this->entry);
2744
2745
		return $elem;
2746
	}
2747
2748
2749
2750
	public function executeQuery()
2751
	{
2752
		if(is_null($this->_oResult))
2753
		{
2754
			global $babDB;
2755
			$req = 'SELECT
2756
2757
				ee.id 					elem__id,
2758
				ee.id_entry 			elem__id_entry,
2759
				ee.id_right				elem__id_right,
2760
				ee.quantity				elem__quantity,
2761
			    ee.date_begin           elem__date_begin,
2762
			    ee.date_end             elem__date_end,
2763
2764
				r.id					right__id,
2765
				r.id_creditor			right__id_creditor,
2766
				r.kind					right__kind,
2767
			    r.createdOn			    right__createdOn,
2768
				r.date_entry			right__date_entry,
2769
				r.date_begin			right__date_begin,
2770
				r.date_end				right__date_end,
2771
				r.quantity				right__quantity,
2772
				r.quantity_unit			right__quantity_unit,
2773
				r.quantity_inc_month 	right__quantity_inc_month,
2774
				r.quantity_inc_max 		right__quantity_inc_max,
2775
				r.quantity_inc_last		right__quantity_inc_last,
2776
				r.id_type				right__id_type,
2777
				r.description			right__description,
2778
				r.active				right__active,
2779
				r.cbalance	 			right__cbalance,
2780
				r.date_begin_valid		right__date_begin_valid,
2781
				r.date_end_valid		right__date_end_valid,
2782
				r.date_end_fixed		right__date_end_fixed,
2783
				r.date_begin_fixed		right__date_begin_fixed,
2784
				r.no_distribution 		right__no_distribution,
2785
				r.use_in_cet			right__use_in_cet,
2786
				r.id_rgroup				right__id_rgroup,
2787
				r.earlier				right__earlier,
2788
				r.earlier_begin_valid 	right__earlier_begin_valid,
2789
				r.earlier_end_valid		right__earlier_end_valid,
2790
				r.later					right__later,
2791
				r.later_begin_valid		right__later_begin_valid,
2792
				r.later_end_valid		right__later_end_valid,
2793
				r.delay_before			right__delay_before,
2794
				r.id_report_type		right__id_report_type,
2795
				r.date_end_report		right__date_end_report,
2796
				r.description_report	right__description_report,
2797
				r.id_reported_from		right__id_reported_from,
2798
				r.quantity_alert_days	right__quantity_alert_days,
2799
				r.quantity_alert_types	right__quantity_alert_types,
2800
				r.quantity_alert_begin	right__quantity_alert_begin,
2801
				r.quantity_alert_end	right__quantity_alert_end,
2802
				r.dynconf_types			right__dynconf_types,
2803
				r.dynconf_begin			right__dynconf_begin,
2804
				r.dynconf_end			right__dynconf_end,
2805
				r.sync_status			right__sync_status,
2806
				r.sync_update			right__sync_update,
2807
				r.uuid					right__uuid,
2808
				r.archived				right__archived,
2809
				r.sortkey				right__sortkey,
2810
				r.require_approval		right__require_approval,
2811
2812
2813
				t.id					type__id,
2814
				t.name					type__name,
2815
				t.description			type__description,
2816
				t.color					type__color
2817
			FROM
2818
				absences_entries_elem ee,
2819
				absences_rights r,
2820
				absences_types t
2821
2822
			WHERE
2823
				ee.id_entry='.$babDB->quote($this->entry->id).'
2824
				AND ee.id_right = r.id
2825
				AND r.id_type = t.id';
2826
2827
			if (isset($this->types)) {
2828
			    $req .= ' AND t.id IN('.$babDB->quote($this->types).')';
2829
			}
2830
2831
		    $req .= ' ORDER BY ee.date_begin';
2832
2833
			$this->setMySqlResult($this->getDataBaseAdapter()->db_query($req));
2834
		}
2835
	}
2836
2837
2838
}
2839
2840
2841
2842
/**
2843
 * Entry periods iterator
2844
 */
2845
class absences_EntryPeriodIterator extends absences_Iterator
2846
{
2847
    /**
2848
     *
2849
     * @var absences_Entry
2850
     */
2851
    public $entry;
2852
2853
2854
2855
    public function getObject($data)
2856
    {
2857
        require_once dirname(__FILE__).'/entry_period.class.php';
2858
2859
2860
2861
        $elem_row = $this->getRowByPrefix($data, 'period');
2862
        $elem = new absences_EntryPeriod();
2863
        $elem->setRow($elem_row);
2864
        $elem->setEntry($this->entry);
2865
2866
        return $elem;
2867
    }
2868
2869
2870
2871 11
    public function executeQuery()
2872
    {
2873 11
        if(is_null($this->_oResult))
2874 11
        {
2875 11
            global $babDB;
2876
            $req = 'SELECT
2877
2878
				ep.id 					period__id,
2879
				ep.id_entry 			period__id_entry,
2880
			    ep.date_begin           period__date_begin,
2881
			    ep.date_end             period__date_end
2882
2883
			FROM
2884
				absences_entries_periods ep
2885
			WHERE
2886 11
				ep.id_entry='.$babDB->quote($this->entry->id).'';
2887
2888
2889 11
            $req .= ' ORDER BY ep.date_begin';
2890
2891 11
            $this->setMySqlResult($this->getDataBaseAdapter()->db_query($req));
2892 11
        }
2893 11
    }
2894
2895
2896
}
2897