Completed
Push — master ( 10986c...56896a )
by Amine
05:29
created

DayAttendance::parsePauseBlocks()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3.0175

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
ccs 7
cts 8
cp 0.875
rs 9.4285
cc 3
eloc 7
nc 3
nop 2
crap 3.0175
1
<?php
2
3
namespace AmineBenHariz\Attendance;
4
5
/**
6
 * Class DayAttendance
7
 * @package AmineBenHariz\Attendance
8
 */
9
class DayAttendance
10
{
11
    /**
12
     * example: 2015-12-12|08:30 (10:00-10:30) (12:30-13:30) (16:00-16:30) 17:30
13
     */
14
    const DAY_ATTENDANCE_LINE_REGEX =
15
        '/^\d{4}-\d{2}-\d{2}\|\d{2}:\d{2}( \(\d{2}:\d{2}-\d{2}:\d{2}\))* \d{2}:\d{2}(\|[^\|]*)?$/';
16
17
    /**
18
     * @var \DateTime
19
     */
20
    private $arrival;
21
22
    /**
23
     * @var \DateTime
24
     */
25
    private $departure;
26
27
    /**
28
     * @var Pause[]
29
     */
30
    private $pauseList = [];
31
32
    /**
33
     * @var string
34
     */
35
    private $description = "";
36
37
    /**
38
     * DayAttendance constructor.
39
     * @param \DateTime $arrival
40
     * @param \DateTime $departure
41
     * @param Pause[] $pauseList
42
     */
43 30
    public function __construct(\DateTime $arrival, \DateTime $departure, array $pauseList = [])
44
    {
45 30
        if ($arrival > $departure) {
46 3
            throw new \InvalidArgumentException;
47
        }
48
49 27
        if ($arrival->format('Y-m-d') !== $departure->format('Y-m-d')) {
50 3
            throw new \InvalidArgumentException;
51
        }
52
53 24
        $this->arrival = $arrival;
54 24
        $this->departure = $departure;
55
56 24
        if (!empty($pauseList)) {
57 24
            foreach ($pauseList as $pause) {
58 24
                $this->addPause($pause);
59 21
            }
60 15
        }
61 15
    }
62
63
    /**
64
     * @return \DateTime
65
     */
66 45
    public function getArrival()
67
    {
68 45
        return $this->arrival;
69
    }
70
71
    /**
72
     * @return \DateTime
73
     */
74 39
    public function getDeparture()
75
    {
76 39
        return $this->departure;
77
    }
78
79
    /**
80
     * @return Pause[]
81
     */
82 39
    public function getPauseList()
83
    {
84 39
        return $this->pauseList;
85
    }
86
87
    /**
88
     * @return string
89
     */
90 15
    public function getDescription()
91
    {
92 15
        return $this->description;
93
    }
94
95
    /**
96
     * @param string $description
97
     */
98 15
    public function setDescription($description)
99
    {
100 15
        $this->description = $description;
101 15
    }
102
103
    /**
104
     * @param Pause $pause
105
     */
106 24
    private function addPause(Pause $pause)
107
    {
108 24
        if ($pause->getStart() < $this->getArrival()) {
109 3
            throw new \InvalidArgumentException;
110
        }
111
112 21
        if ($pause->getEnd() > $this->getDeparture()) {
113 3
            throw new \InvalidArgumentException;
114
        }
115
116 21
        if ($this->isPauseOverlapping($pause)) {
117 3
            throw new \InvalidArgumentException;
118
        }
119
120
121 21
        $this->pauseList[] = $pause;
122 21
    }
123
124
    /**
125
     * @param Pause $pause
126
     * @return bool
127
     */
128 21
    private function isPauseOverlapping(Pause $pause)
129
    {
130 21
        $existingPauseList = $this->getPauseList();
131 21
        if (empty($existingPauseList)) {
132 21
            return false;
133
        }
134
135 15
        foreach ($existingPauseList as $existingPause) {
136 15
            if ($pause->isOverlapping($existingPause)) {
137 3
                return true;
138
            }
139 12
        }
140
141 12
        return false;
142
    }
143
144
    /**
145
     * @return \DateInterval
146
     */
147 9
    public function getDuration()
148
    {
149 9
        $cursor = clone $this->getArrival();
150
151
        // PHP 5.4 : empty() can only handle variables
152 9
        $pauseList = $this->getPauseList();
153
154 9
        if (!empty($pauseList)) {
155 9
            foreach ($pauseList as $pause) {
156 9
                $cursor->add($pause->getDuration());
157 9
            }
158 9
        }
159
160 9
        return $cursor->diff($this->getDeparture());
161
    }
162
163
    /**
164
     * @return int
165
     */
166 6
    public function getTotalMinutes()
167
    {
168 6
        $duration = $this->getDuration();
169 6
        return intval($duration->format('%H')) * 60 + intval($duration->format('%I'));
170
    }
171
172
    /**
173
     * @param $dayAttendanceLine
174
     * @return DayAttendance
175
     */
176 15
    public static function parseDayAttendanceLine($dayAttendanceLine)
177
    {
178 15
        if (!self::isValidDayAttendanceLine($dayAttendanceLine)) {
179 3
            throw new \InvalidArgumentException;
180
        }
181
182 12
        $parts = explode('|', $dayAttendanceLine);
183
184
        // if empty description
185 12
        if (!isset($parts[2])) {
186 9
            $parts[2] = '';
187 9
        }
188
189 12
        list($date, $timeLine, $description) = $parts;
190
191 12
        $times = explode(' ', $timeLine);
192
193 12
        $arrival = new \DateTime($date . ' ' . array_shift($times));
194 12
        $departure = new \DateTime($date . ' ' . array_pop($times));
195
196 12
        $pauseList = self::parsePauseBlocks($date, $times);
197
198 12
        $dayAttendance = new DayAttendance($arrival, $departure, $pauseList);
199 12
        $dayAttendance->setDescription($description);
200 12
        return $dayAttendance;
201
    }
202
203
    /**
204
     * @param string $date date in Y-m-d format, ex: 2016-03-29
205
     * @param array $pauseBlocks
206
     * @return Pause[]
207
     */
208 12
    private static function parsePauseBlocks($date, $pauseBlocks)
209
    {
210 12
        if (empty($pauseBlocks)) {
211
            return [];
212
        }
213
214 12
        $pauseList = [];
215 12
        foreach ($pauseBlocks as $pauseBlock) {
216 12
            $pauseList[] = self::parsePauseBlock($date, $pauseBlock);
217 12
        }
218
219 12
        return $pauseList;
220
    }
221
222
    /**
223
     * @param string $date date in Y-m-d format, ex: 2016-03-29
224
     * @param string $pauseBlock ex: (10:00-10:30)
225
     * @return Pause
226
     */
227 12
    private static function parsePauseBlock($date, $pauseBlock)
228
    {
229 12
        $pauseStart = new \DateTime($date . ' ' . substr($pauseBlock, 1, 5));
230 12
        $pauseEnd = new \DateTime($date . ' ' . substr($pauseBlock, 7, 5));
231 12
        return new Pause($pauseStart, $pauseEnd);
232
    }
233
234
    /**
235
     * @param $dayAttendanceLine
236
     * @return int
237
     */
238 42
    public static function isValidDayAttendanceLine($dayAttendanceLine)
239
    {
240 42
        return preg_match(self::DAY_ATTENDANCE_LINE_REGEX, $dayAttendanceLine) === 1;
241
    }
242
243
    /**
244
     * @return string
245
     */
246 6
    public function exportLine()
247
    {
248 6
        $line = $this->getDate() . '|' . $this->getTimeLine();
249
250 6
        if ($this->getDescription() !== '') {
251 3
            $line .= '|' . $this->getDescription();
252 3
        }
253
254 6
        return $line;
255
    }
256
257
    /**
258
     * @return string
259
     */
260 9
    public function getDate()
261
    {
262 9
        return $this->getArrival()->format('Y-m-d');
263
    }
264
265
    /**
266
     * @return string
267
     */
268 9
    public function getTimeLine()
269
    {
270 9
        $line = $this->getArrival()->format('H:i');
271
272 9
        foreach ($this->getPauseList() as $pause) {
273 9
            $line .= ' ' . $pause->exportBlock();
274 9
        }
275
276 9
        $line .= ' ' . $this->getDeparture()->format('H:i');
277
278 9
        return $line;
279
    }
280
}
281