Completed
Push — master ( e0890d...51a04a )
by Tim
03:12
created

RecurrenceService::getRecurrenceForCurrentMonth()   D

Complexity

Conditions 9
Paths 9

Size

Total Lines 31
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
c 0
b 0
f 0
rs 4.909
cc 9
eloc 24
nc 9
nop 4
1
<?php
2
/**
3
 * Recurrence service
4
 *
5
 * @author  Tim Lochmüller
6
 */
7
8
namespace HDNET\Calendarize\Service;
9
10
use HDNET\Calendarize\Domain\Model\ConfigurationInterface;
11
12
/**
13
 * Recurrence service
14
 *
15
 * @author Tim Lochmüller
16
 */
17
class RecurrenceService extends AbstractService
18
{
19
20
    /**
21
     * direction up
22
     */
23
    const DIRECTION_UP = 'up';
24
25
    /**
26
     * direction down
27
     */
28
    const DIRECTION_DOWN = 'down';
29
30
    /**
31
     * Get the date if the configuration of the next month
32
     *
33
     * @param \DateTime $date
34
     * @param string    $recurrence
35
     * @param string    $day
36
     *
37
     * @return \DateTime
38
     */
39
    public function getRecurrenceForNextMonth(\DateTime $date, $recurrence, $day)
40
    {
41
        return $this->getRecurrenceForCurrentMonth($date, $recurrence, $day, '+1 month');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression $this->getRecurrenceForC...nce, $day, '+1 month'); of type DateTime|false adds false to the return on line 41 which is incompatible with the return type documented by HDNET\Calendarize\Servic...tRecurrenceForNextMonth of type DateTime. It seems like you forgot to handle an error condition.
Loading history...
42
    }
43
44
    /**
45
     * Get the date if the configuration of the next year
46
     *
47
     * @param \DateTime $date
48
     * @param string    $recurrence
49
     * @param string    $day
50
     *
51
     * @return \DateTime
52
     */
53
    public function getRecurrenceForNextYear(\DateTime $date, $recurrence, $day)
54
    {
55
        return $this->getRecurrenceForCurrentMonth($date, $recurrence, $day, '+1 year');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression $this->getRecurrenceForC...ence, $day, '+1 year'); of type DateTime|false adds false to the return on line 55 which is incompatible with the return type documented by HDNET\Calendarize\Servic...etRecurrenceForNextYear of type DateTime. It seems like you forgot to handle an error condition.
Loading history...
56
    }
57
58
    /**
59
     * Get the date if the configuration of the current month
60
     *
61
     * @param \DateTime $date
62
     * @param string    $recurrence
63
     * @param string    $day
64
     * @param string    $modify
65
     *
66
     * @return \DateTime|FALSE
67
     */
68
    protected function getRecurrenceForCurrentMonth(\DateTime $date, $recurrence, $day, $modify)
69
    {
70
        // clone and reset and move to next month
71
        $dateTime = clone $date;
72
        $dateTime->setDate($dateTime->format('Y'), $dateTime->format('m'), 1);
73
        $dateTime->modify($modify);
74
75
        $days = $this->getValidDays($day);
76
        if (!$days) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $days 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...
77
            return false;
78
        }
79
80
        switch ($recurrence) {
81
            case ConfigurationInterface::RECURRENCE_THIRD_LAST:
82
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_DOWN, $days, 3);
83
            case ConfigurationInterface::RECURRENCE_NEXT_TO_LAST:
84
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_DOWN, $days, 2);
85
            case ConfigurationInterface::RECURRENCE_LAST:
86
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_DOWN, $days);
87
            case ConfigurationInterface::RECURRENCE_FIRST:
88
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_UP, $days);
89
            case ConfigurationInterface::RECURRENCE_SECOND:
90
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_UP, $days, 2);
91
            case ConfigurationInterface::RECURRENCE_THIRD:
92
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_UP, $days, 3);
93
            case ConfigurationInterface::RECURRENCE_FOURTH:
94
                return $this->findDayInCurrentMonth($dateTime, self::DIRECTION_UP, $days, 4);
95
            default:
96
                return false;
97
        }
98
    }
99
100
    /**
101
     * Numbers are match against the date format 'N' 1 => mon till 7 => sun
102
     *
103
     * @param string $day
104
     *
105
     * @return array
106
     */
107
    protected function getValidDays($day)
108
    {
109
        $days = [];
110
        switch ($day) {
111
            case ConfigurationInterface::DAY_MONDAY:
112
                $days[] = 1;
113
                break;
114
            case ConfigurationInterface::DAY_TUESDAY:
115
                $days[] = 2;
116
                break;
117
            case ConfigurationInterface::DAY_WEDNESDAY:
118
                $days[] = 3;
119
                break;
120
            case ConfigurationInterface::DAY_THURSDAY:
121
                $days[] = 4;
122
                break;
123
            case ConfigurationInterface::DAY_FRIDAY:
124
                $days[] = 5;
125
                break;
126
            case ConfigurationInterface::DAY_SATURDAY:
127
                $days[] = 6;
128
                break;
129
            case ConfigurationInterface::DAY_SUNDAY:
130
                $days[] = 7;
131
                break;
132
            case ConfigurationInterface::DAY_SPECIAL_WEEKEND:
133
                $days[] = 7;
134
                $days[] = 6;
135
                break;
136
            case ConfigurationInterface::DAY_SPECIAL_WEEKDAY:
137
                $days = range(1, 7);
138
                break;
139
            case ConfigurationInterface::DAY_SPECIAL_BUSINESS:
140
                $days = range(1, 6);
141
                break;
142
            case ConfigurationInterface::DAY_SPECIAL_WORKDAY:
143
                $days = range(1, 5);
144
                break;
145
            default:
146
                // no day
147
                break;
148
        }
149
        return $days;
150
    }
151
152
    /**
153
     * Find the modified in the current month
154
     *
155
     * @param \DateTime $dateTime
156
     * @param string    $direction
157
     * @param array     $validDays
158
     * @param int       $position
159
     *
160
     * @return \DateTime|FALSE
161
     */
162
    protected function findDayInCurrentMonth($dateTime, $direction, $validDays, $position = 1)
163
    {
164
        if ($direction === self::DIRECTION_UP) {
165
            $dateTime->setDate($dateTime->format('Y'), $dateTime->format('m'), 1);
166
            $modify = '+1 day';
167
        } else {
168
            $dateTime->setDate($dateTime->format('Y'), $dateTime->format('m'), $dateTime->format('t'));
169
            $modify = '-1 day';
170
        }
171
        $validMonth = $dateTime->format('Y-m');
172
        while ($dateTime->format('Y-m') == $validMonth) {
173
            if (in_array($dateTime->format('N'), $validDays)) {
174
                $position--;
175
                if ($position === 0) {
176
                    return $dateTime;
177
                }
178
            }
179
            $dateTime->modify($modify);
180
        }
181
        return false;
182
    }
183
}
184