BookingService::getUserBookingsForMonth()   C
last analyzed

Complexity

Conditions 10
Paths 162

Size

Total Lines 78
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 78
rs 5.3146
cc 10
eloc 46
nc 162
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace JhFlexiTime\Service;
4
5
use JhFlexiTime\DateTime\DateTime;
6
use JhFlexiTime\Entity\Booking;
7
use JhFlexiTime\Repository\BookingRepositoryInterface;
8
use Symfony\Component\Config\Definition\Exception\Exception;
9
use ZfcUser\Entity\UserInterface;
10
use Doctrine\Common\Persistence\ObjectManager;
11
use Zend\EventManager\EventManagerInterface;
12
use Zend\EventManager\EventManager;
13
use JhFlexiTime\Options\ModuleOptions;
14
use Zend\Stdlib\Hydrator\HydratorInterface;
15
use Zend\InputFilter\InputFilterInterface;
16
17
/**
18
 * Class BookingService
19
 * @package JhFlexiTime\Service
20
 * @author Aydin Hassan <[email protected]>
21
 */
22
class BookingService
23
{
24
25
    /**
26
     * @var \JhFlexiTime\Repository\BookingRepositoryInterface
27
     */
28
    protected $bookingRepository;
29
30
    /**
31
     * @var \Doctrine\Common\Persistence\ObjectManager
32
     */
33
    protected $objectManager;
34
35
    /**
36
     * @var EventManagerInterface
37
     */
38
    protected $eventManager;
39
40
    /**
41
     * @var \JhFlexiTime\Options\ModuleOptions
42
     */
43
    protected $options;
44
45
    /**
46
     * @var \JhFlexiTime\Service\PeriodService
47
     */
48
    protected $periodService;
49
50
    /**
51
     * @var \DoctrineModule\Stdlib\Hydrator\DoctrineObject
52
     */
53
    protected $hydrator;
54
55
    /**
56
     * @var InputFilterInterface
57
     */
58
    protected $inputFilter;
59
60
    /**
61
     * @param ModuleOptions $options
62
     * @param BookingRepositoryInterface $bookingRepository
63
     * @param ObjectManager $objectManager
64
     * @param PeriodServiceInterface $periodService
65
     * @param HydratorInterface $doctrineHydrator
66
     * @param InputFilterInterface $bookingInputFilter
67
     */
68
    public function __construct(
69
        ModuleOptions $options,
70
        BookingRepositoryInterface $bookingRepository,
71
        ObjectManager $objectManager,
72
        PeriodServiceInterface $periodService,
73
        HydratorInterface $doctrineHydrator,
74
        InputFilterInterface $bookingInputFilter
75
    ) {
76
        $this->options              = $options;
77
        $this->bookingRepository    = $bookingRepository;
78
        $this->objectManager        = $objectManager;
79
        $this->periodService        = $periodService;
0 ignored issues
show
Documentation Bug introduced by
$periodService is of type object<JhFlexiTime\Servi...PeriodServiceInterface>, but the property $periodService was declared to be of type object<JhFlexiTime\Service\PeriodService>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof 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 given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
80
        $this->hydrator             = $doctrineHydrator;
0 ignored issues
show
Documentation Bug introduced by
$doctrineHydrator is of type object<Zend\Stdlib\Hydrator\HydratorInterface>, but the property $hydrator was declared to be of type object<DoctrineModule\St...ydrator\DoctrineObject>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof 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 given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
81
        $this->inputFilter          = $bookingInputFilter;
82
    }
83
84
    /**
85
     * @param array $data
86
     * @return array
87
     */
88
    public function create(array $data)
89
    {
90
        $this->inputFilter->setData($data);
91
92
        if (!$this->inputFilter->isValid()) {
93
            return [
94
                'messages'  => $this->inputFilter->getMessages(),
95
            ];
96
        }
97
98
        $booking = new Booking;
99
        $booking->setBalance(0 - $this->options->getHoursInDay());
100
        $booking = $this->hydrateBooking($booking);
101
102
        $this->getEventManager()->trigger(__FUNCTION__ . '.pre', null, ['booking' => $booking]);
103
104
        try {
105
            $this->objectManager->persist($booking);
106
            $this->objectManager->flush();
107
        } catch (\Exception $e) {
108
           //log
109
        }
110
111
        $this->getEventManager()->trigger(__FUNCTION__ . '.post', null, ['booking' => $booking]);
112
113
        return $booking;
114
    }
115
116
    /**
117
     * @param $userId
118
     * @param DateTime $date
119
     * @param array $data
120
     * @return Booking|array
121
     */
122
    public function update($userId, DateTime $date, array $data)
123
    {
124
125
        $booking = $this->getBookingByUserAndDate($userId, $date);
126
        if (null === $booking) {
127
            return [
128
                'messages' => ['Booking Does Not Exist']
129
            ];
130
        }
131
132
        $this->inputFilter->setData($data);
133
        if (!$this->inputFilter->isValid()) {
134
            return [
135
                'messages' => $this->inputFilter->getMessages(),
136
            ];
137
        }
138
139
        $booking = $this->hydrateBooking($booking);
140
141
        $this->getEventManager()->trigger(__FUNCTION__ . '.pre', null, ['booking' => $booking]);
142
        $this->objectManager->flush();
143
        $this->getEventManager()->trigger(__FUNCTION__ . '.post', null, ['booking' => $booking]);
144
145
        return $booking;
146
    }
147
148
    /**
149
     * @param int $userId
150
     * @param DateTime $date
151
     * @return array|Booking
152
     */
153
    public function delete($userId, DateTime $date)
154
    {
155
        $booking = $this->getBookingByUserAndDate($userId, $date);
156
        if (null === $booking) {
157
            return [
158
                'messages' => ['Booking Does Not Exist']
159
            ];
160
        }
161
162
        $this->getEventManager()->trigger(__FUNCTION__ . '.pre', null, ['booking' => $booking]);
163
        $this->objectManager->remove($booking);
164
        $this->objectManager->flush();
165
        $this->getEventManager()->trigger(__FUNCTION__ . '.post', null, ['booking' => $booking]);
166
167
        return $booking;
168
    }
169
170
    /**
171
     * @param $userId
172
     * @param DateTime|string $date
173
     * @throws \Exception
174
     * @return object
175
     */
176
    public function getBookingByUserAndDate($userId, DateTime $date)
177
    {
178
        return $this->bookingRepository->findOneBy(['date' => $date, 'user' => $userId]);
179
    }
180
181
    /**
182
     * @param UserInterface $user
183
     * @param DateTime $date
184
     * @return array
185
     */
186
    public function getUserBookingsForMonth(UserInterface $user, DateTime $date)
187
    {
188
        $period = new \DatePeriod(
189
            new \DateTime(sprintf('first day of %s', $date->format('F Y'))),
190
            new \DateInterval('P1D'),
191
            new \DateTime(sprintf('last day of %s 23:59:59', $date->format('F Y')))
192
        );
193
194
        $bookedDays = $this->bookingRepository->findByUserAndMonth($user, $date);
195
196
        $dates = [];
197
        foreach ($period as $day) {
198
            $dayNum = $day->format('N');
199
200
            /* Excluding days 6 & 7 (Saturday & Sunday). */
201
            if ($dayNum < 6) {
202
                $dates[$day->format('d-m-y')] = [
203
                    'date'      => $day,
204
                    'day_num'   => $dayNum
205
                ];
206
            }
207
        }
208
209
        foreach ($bookedDays as $booking) {
210
            //only add booking is it is on an allowed day
211
            //eg do not process any weekend bookings
212
            if (isset($dates[$booking->getDate()->format('d-m-y')])) {
213
                $dates[$booking->getDate()->format('d-m-y')]['booking'] = $booking;
214
            }
215
216
        }
217
218
        $weeks = [];
219
        $weekCounter = 0;
220
        $monthWorked = 0;
221
        foreach ($dates as $date) {
222
            if (!isset($weeks[$weekCounter])) {
223
                $weeks[$weekCounter] = [
224
                    'dates'  => [$date],
225
                    'workedHours'  => 0,
226
                ];
227
228
            } else {
229
                $weeks[$weekCounter]['dates'][] = $date;
230
            }
231
232
            if (isset($date['booking'])) {
233
                $weeks[$weekCounter]['workedHours'] += $date['booking']->getTotal();
234
                $monthWorked += $date['booking']->getTotal();
235
            }
236
237
            /* Reset day counter. Start new week after day 5 (Friday).
238
               Day 5 is used as we are already excluding 6 & 7. */
239
            if ($date['day_num'] == 5) {
240
                $weekCounter++;
241
            }
242
        }
243
244
        $monthAvailable = 0;
245
        $monthBalance = 0;
246
        foreach ($weeks as $key => $week) {
247
            $numDays    = count($week['dates']);
248
            $totalHours = $numDays *  $this->options->getHoursInDay();
249
            $monthAvailable += $totalHours;
250
            $weeks[$key]['totalHours']  = $totalHours;
251
            $weeks[$key]['balance']     =  $weeks[$key]['workedHours'] - $totalHours;
252
            $monthBalance += ($weeks[$key]['workedHours'] - $totalHours);
253
        }
254
255
        return [
256
            'weeks'             => $weeks,
257
            'workedMonth'       => [
258
                'availableHours'    => $monthAvailable,
259
                'monthBalance'      => $monthBalance,
260
                'hoursWorked'       => $monthWorked
261
            ],
262
        ];
263
    }
264
265
    /**
266
     * Get next/prev month/year info
267
     *
268
     * @param \DateTime $date
269
     * @return array
270
     */
271
    public function getPagination(\DateTime $date)
272
    {
273
        $date->setTime(0, 0);
274
275
        $prev = clone $date;
276
        $next = clone $date;
277
278
        $prev->modify('first day of last month');
279
        $next->modify('first day of next month');
280
281
        return [
282
            'current'   => ['m' => $date->format('M'), 'y' => $date->format('Y')],
283
            'next'      => ['m' => $next->format('M'), 'y' => $next->format('Y')],
284
            'prev'      => ['m' => $prev->format('M'), 'y' => $prev->format('Y')],
285
        ];
286
    }
287
288
    /**
289
     * @param  EventManagerInterface $eventManager
290
     */
291
    public function setEventManager(EventManagerInterface $eventManager)
292
    {
293
        $eventManager->addIdentifiers([
294
            get_called_class()
295
        ]);
296
297
        $this->eventManager = $eventManager;
298
    }
299
300
    /**
301
     * @return EventManagerInterface
302
     */
303
    public function getEventManager()
304
    {
305
        if (null === $this->eventManager) {
306
            $this->setEventManager(new EventManager());
307
        }
308
309
        return $this->eventManager;
310
    }
311
312
    /**
313
     * @param Booking $booking
314
     * @return Booking
315
     */
316
    protected function hydrateBooking(Booking $booking)
317
    {
318
        $this->hydrator->hydrate($this->inputFilter->getValues(), $booking);
319
        $totalHours = $this->periodService->calculateHourDiff($booking->getStartTime(), $booking->getEndTime());
320
        $newBalance = $totalHours - $this->options->getHoursInDay();
321
322
        $booking->setBalance($newBalance);
323
        $booking->setTotal($totalHours);
324
325
        return $booking;
326
    }
327
}
328