Completed
Push — master ( 5db245...cdc2ed )
by Markus
11s
created

RecurrenceRule   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 433
Duplicated Lines 13.86 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 56
lcom 1
cbo 1
dl 60
loc 433
ccs 93
cts 93
cp 1
rs 6.5957
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getEscapedValue() 0 4 1
F buildParameterBag() 0 56 13
A setCount() 0 6 1
A getCount() 0 4 1
A setUntil() 0 6 1
A getUntil() 0 4 1
A setFreq() 0 10 2
A getFreq() 0 4 1
A setInterval() 0 6 1
A getInterval() 0 4 1
A setWkst() 0 6 1
A setByMonth() 0 10 4
B setByWeekNo() 10 10 5
B setByYearDay() 10 10 5
B setByMonthDay() 10 10 5
A setByDay() 0 6 1
A setByHour() 10 10 4
A setByMinute() 10 10 4
A setBySecond() 10 10 4

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 RecurrenceRule 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 RecurrenceRule, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the eluceo/iCal package.
5
 *
6
 * (c) Markus Poerschke <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Eluceo\iCal\Property\Event;
13
14
use Eluceo\iCal\ParameterBag;
15
use Eluceo\iCal\Property\ValueInterface;
16
use InvalidArgumentException;
17
18
/**
19
 * Implementation of Recurrence Rule.
20
 *
21
 * @see https://tools.ietf.org/html/rfc5545#section-3.8.5.3
22
 */
23
class RecurrenceRule implements ValueInterface
24
{
25
    const FREQ_YEARLY = 'YEARLY';
26
    const FREQ_MONTHLY = 'MONTHLY';
27
    const FREQ_WEEKLY = 'WEEKLY';
28
    const FREQ_DAILY = 'DAILY';
29
    const FREQ_HOURLY = 'HOURLY';
30
    const FREQ_MINUTELY = 'MINUTELY';
31
    const FREQ_SECONDLY = 'SECONDLY';
32
33
    const WEEKDAY_SUNDAY = 'SU';
34
    const WEEKDAY_MONDAY = 'MO';
35
    const WEEKDAY_TUESDAY = 'TU';
36
    const WEEKDAY_WEDNESDAY = 'WE';
37
    const WEEKDAY_THURSDAY = 'TH';
38
    const WEEKDAY_FRIDAY = 'FR';
39
    const WEEKDAY_SATURDAY = 'SA';
40
41
    /**
42
     * The frequency of an Event.
43
     *
44
     * @var string
45
     */
46
    protected $freq = self::FREQ_YEARLY;
47
48
    /**
49
     * @var null|int
50
     */
51
    protected $interval = 1;
52
53
    /**
54
     * @var null|int
55
     */
56
    protected $count = null;
57
58
    /**
59
     * @var null|\DateTimeInterface
60
     */
61
    protected $until = null;
62
63
    /**
64
     * @var null|string
65
     */
66
    protected $wkst;
67
68
    /**
69
     * @var null|string
70
     */
71
    protected $byMonth;
72
73
    /**
74
     * @var null|string
75
     */
76
    protected $byWeekNo;
77
78
    /**
79
     * @var null|string
80
     */
81
    protected $byYearDay;
82
83
    /**
84
     * @var null|string
85
     */
86
    protected $byMonthDay;
87
88
    /**
89
     * @var null|string
90
     */
91
    protected $byDay;
92
93
    /**
94
     * @var null|string
95
     */
96
    protected $byHour;
97
98
    /**
99
     * @var null|string
100
     */
101
    protected $byMinute;
102
103
    /**
104
     * @var null|string
105
     */
106
    protected $bySecond;
107
108 11
    public function getEscapedValue(): string
109
    {
110 11
        return $this->buildParameterBag()->toString();
111
    }
112
113
    /**
114
     * @return ParameterBag
115
     */
116 11
    protected function buildParameterBag()
117
    {
118 11
        $parameterBag = new ParameterBag();
119
120 11
        $parameterBag->setParam('FREQ', $this->freq);
121
122 11
        if (null !== $this->interval) {
123 10
            $parameterBag->setParam('INTERVAL', $this->interval);
124
        }
125
126 11
        if (null !== $this->count) {
127 1
            $parameterBag->setParam('COUNT', $this->count);
128
        }
129
130 11
        if (null != $this->until) {
131 1
            $parameterBag->setParam('UNTIL', $this->until->format('Ymd\THis\Z'));
132
        }
133
134 11
        if (null !== $this->wkst) {
135 1
            $parameterBag->setParam('WKST', $this->wkst);
136
        }
137
138 11
        if (null !== $this->byMonth) {
139 1
            $parameterBag->setParam('BYMONTH', explode(',', $this->byMonth));
140
        }
141
142 11
        if (null !== $this->byWeekNo) {
143 1
            $parameterBag->setParam('BYWEEKNO', explode(',', $this->byWeekNo));
144
        }
145
146 11
        if (null !== $this->byYearDay) {
147 1
            $parameterBag->setParam('BYYEARDAY', explode(',', $this->byYearDay));
148
        }
149
150 11
        if (null !== $this->byMonthDay) {
151 1
            $parameterBag->setParam('BYMONTHDAY', explode(',', $this->byMonthDay));
152
        }
153
154 11
        if (null !== $this->byDay) {
155 1
            $parameterBag->setParam('BYDAY', explode(',', $this->byDay));
156
        }
157
158 11
        if (null !== $this->byHour) {
159 1
            $parameterBag->setParam('BYHOUR', explode(',', $this->byHour));
160
        }
161
162 11
        if (null !== $this->byMinute) {
163 1
            $parameterBag->setParam('BYMINUTE', explode(',', $this->byMinute));
164
        }
165
166 11
        if (null !== $this->bySecond) {
167 1
            $parameterBag->setParam('BYSECOND', explode(',', $this->bySecond));
168
        }
169
170 11
        return $parameterBag;
171
    }
172
173
    /**
174
     * @param int|null $count
175
     *
176
     * @return $this
177
     */
178 1
    public function setCount($count)
179
    {
180 1
        $this->count = $count;
181
182 1
        return $this;
183
    }
184
185
    /**
186
     * @return int|null
187
     */
188 2
    public function getCount()
189
    {
190 2
        return $this->count;
191
    }
192
193
    /**
194
     * @param \DateTimeInterface|null $until
195
     *
196
     * @return $this
197
     */
198 2
    public function setUntil(\DateTimeInterface $until = null)
199
    {
200 2
        $this->until = $until;
201
202 2
        return $this;
203
    }
204
205
    /**
206
     * @return \DateTimeInterface|null
207
     */
208 1
    public function getUntil()
209
    {
210 1
        return $this->until;
211
    }
212
213
    /**
214
     * The FREQ rule part identifies the type of recurrence rule.  This
215
     * rule part MUST be specified in the recurrence rule.  Valid values
216
     * include.
217
     *
218
     * SECONDLY, to specify repeating events based on an interval of a second or more;
219
     * MINUTELY, to specify repeating events based on an interval of a minute or more;
220
     * HOURLY, to specify repeating events based on an interval of an hour or more;
221
     * DAILY, to specify repeating events based on an interval of a day or more;
222
     * WEEKLY, to specify repeating events based on an interval of a week or more;
223
     * MONTHLY, to specify repeating events based on an interval of a month or more;
224
     * YEARLY, to specify repeating events based on an interval of a year or more.
225
     *
226
     * @param string $freq
227
     *
228
     * @return $this
229
     *
230
     * @throws \InvalidArgumentException
231
     */
232 4
    public function setFreq($freq)
233
    {
234 4
        if (@constant('static::FREQ_' . $freq) !== null) {
235 3
            $this->freq = $freq;
236
        } else {
237 1
            throw new \InvalidArgumentException("The Frequency {$freq} is not supported.");
238
        }
239
240 3
        return $this;
241
    }
242
243
    /**
244
     * @return string
245
     */
246 1
    public function getFreq()
247
    {
248 1
        return $this->freq;
249
    }
250
251
    /**
252
     * The INTERVAL rule part contains a positive integer representing at
253
     * which intervals the recurrence rule repeats.
254
     *
255
     * @param int|null $interval
256
     *
257
     * @return $this
258
     */
259 3
    public function setInterval($interval)
260
    {
261 3
        $this->interval = $interval;
262
263 3
        return $this;
264
    }
265
266
    /**
267
     * @return int|null
268
     */
269 1
    public function getInterval()
270
    {
271 1
        return $this->interval;
272
    }
273
274
    /**
275
     * The WKST rule part specifies the day on which the workweek starts.
276
     * Valid values are MO, TU, WE, TH, FR, SA, and SU.
277
     *
278
     * @param string $value
279
     *
280
     * @return $this
281
     */
282 1
    public function setWkst($value)
283
    {
284 1
        $this->wkst = $value;
285
286 1
        return $this;
287
    }
288
289
    /**
290
     * The BYMONTH rule part specifies a COMMA-separated list of months of the year.
291
     * Valid values are 1 to 12.
292
     *
293
     * @param int $month
294
     *
295
     * @throws \InvalidArgumentException
296
     *
297
     * @return $this
298
     */
299 6
    public function setByMonth($month)
300
    {
301 6
        if (!is_integer($month) || $month <= 0 || $month > 12) {
302 5
            throw new InvalidArgumentException('Invalid value for BYMONTH');
303
        }
304
305 1
        $this->byMonth = $month;
0 ignored issues
show
Documentation Bug introduced by
It seems like $month of type integer is incompatible with the declared type null|string of property $byMonth.

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...
306
307 1
        return $this;
308
    }
309
310
    /**
311
     * The BYWEEKNO rule part specifies a COMMA-separated list of ordinals specifying weeks of the year.
312
     * Valid values are 1 to 53 or -53 to -1.
313
     *
314
     * @param int $value
315
     *
316
     * @throws \InvalidArgumentException
317
     *
318
     * @return $this
319
     */
320 5 View Code Duplication
    public function setByWeekNo($value)
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...
321
    {
322 5
        if (!is_integer($value) || $value > 53 || $value < -53 || $value === 0) {
323 4
            throw new InvalidArgumentException('Invalid value for BYWEEKNO');
324
        }
325
326 1
        $this->byWeekNo = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type integer is incompatible with the declared type null|string of property $byWeekNo.

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...
327
328 1
        return $this;
329
    }
330
331
    /**
332
     * The BYYEARDAY rule part specifies a COMMA-separated list of days of the year.
333
     * Valid values are 1 to 366 or -366 to -1.
334
     *
335
     * @param int $day
336
     *
337
     * @throws \InvalidArgumentException
338
     *
339
     * @return $this
340
     */
341 5 View Code Duplication
    public function setByYearDay($day)
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...
342
    {
343 5
        if (!is_integer($day) || $day > 366 || $day < -366 || $day === 0) {
344 4
            throw new InvalidArgumentException('Invalid value for BYYEARDAY');
345
        }
346
347 1
        $this->byYearDay = $day;
0 ignored issues
show
Documentation Bug introduced by
It seems like $day of type integer is incompatible with the declared type null|string of property $byYearDay.

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...
348
349 1
        return $this;
350
    }
351
352
    /**
353
     * The BYMONTHDAY rule part specifies a COMMA-separated list of days of the month.
354
     * Valid values are 1 to 31 or -31 to -1.
355
     *
356
     * @param int $day
357
     *
358
     * @return $this
359
     *
360
     * @throws \InvalidArgumentException
361
     */
362 5 View Code Duplication
    public function setByMonthDay($day)
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...
363
    {
364 5
        if (!is_integer($day) || $day > 31 || $day < -31 || $day === 0) {
365 4
            throw new InvalidArgumentException('Invalid value for BYMONTHDAY');
366
        }
367
368 1
        $this->byMonthDay = $day;
0 ignored issues
show
Documentation Bug introduced by
It seems like $day of type integer is incompatible with the declared type null|string of property $byMonthDay.

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...
369
370 1
        return $this;
371
    }
372
373
    /**
374
     * The BYDAY rule part specifies a COMMA-separated list of days of the week;.
375
     *
376
     * SU indicates Sunday; MO indicates Monday; TU indicates Tuesday;
377
     * WE indicates Wednesday; TH indicates Thursday; FR indicates Friday; and SA indicates Saturday.
378
     *
379
     * Each BYDAY value can also be preceded by a positive (+n) or negative (-n) integer.
380
     * If present, this indicates the nth occurrence of a specific day within the MONTHLY or YEARLY "RRULE".
381
     *
382
     * @param string $day
383
     *
384
     * @return $this
385
     */
386 1
    public function setByDay(string $day)
387
    {
388 1
        $this->byDay = $day;
389
390 1
        return $this;
391
    }
392
393
    /**
394
     * The BYHOUR rule part specifies a COMMA-separated list of hours of the day.
395
     * Valid values are 0 to 23.
396
     *
397
     * @param int $value
398
     *
399
     * @return $this
400
     *
401
     * @throws \InvalidArgumentException
402
     */
403 4 View Code Duplication
    public function setByHour($value)
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...
404
    {
405 4
        if (!is_integer($value) || $value < 0 || $value > 23) {
406 3
            throw new \InvalidArgumentException('Invalid value for BYHOUR');
407
        }
408
409 1
        $this->byHour = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type integer is incompatible with the declared type null|string of property $byHour.

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...
410
411 1
        return $this;
412
    }
413
414
    /**
415
     * The BYMINUTE rule part specifies a COMMA-separated list of minutes within an hour.
416
     * Valid values are 0 to 59.
417
     *
418
     * @param int $value
419
     *
420
     * @return $this
421
     *
422
     * @throws \InvalidArgumentException
423
     */
424 4 View Code Duplication
    public function setByMinute($value)
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...
425
    {
426 4
        if (!is_integer($value) || $value < 0 || $value > 59) {
427 3
            throw new \InvalidArgumentException('Invalid value for BYMINUTE');
428
        }
429
430 1
        $this->byMinute = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type integer is incompatible with the declared type null|string of property $byMinute.

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...
431
432 1
        return $this;
433
    }
434
435
    /**
436
     * The BYSECOND rule part specifies a COMMA-separated list of seconds within a minute.
437
     * Valid values are 0 to 60.
438
     *
439
     * @param int $value
440
     *
441
     * @return $this
442
     *
443
     * @throws \InvalidArgumentException
444
     */
445 4 View Code Duplication
    public function setBySecond($value)
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...
446
    {
447 4
        if (!is_integer($value) || $value < 0 || $value > 60) {
448 3
            throw new \InvalidArgumentException('Invalid value for BYSECOND');
449
        }
450
451 1
        $this->bySecond = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type integer is incompatible with the declared type null|string of property $bySecond.

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...
452
453 1
        return $this;
454
    }
455
}
456