Completed
Pull Request — master (#296)
by Luc
05:01
created

CalendarFactory::createFromCdbCalendar()   F

Complexity

Conditions 23
Paths 15360

Size

Total Lines 132
Code Lines 70

Duplication

Lines 15
Ratio 11.36 %

Importance

Changes 0
Metric Value
dl 15
loc 132
rs 2
c 0
b 0
f 0
cc 23
eloc 70
nc 15360
nop 1

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 CultuurNet\UDB3;
4
5
use CultuurNet\UDB3\Calendar\DayOfWeek;
6
use CultuurNet\UDB3\Calendar\OpeningHour;
7
use CultuurNet\UDB3\Calendar\OpeningTime;
8
use CultuurNet\UDB3\Cdb\DateTimeFactory;
9
10
class CalendarFactory implements CalendarFactoryInterface
11
{
12
    /**
13
     * @inheritdoc
14
     */
15
    public function createFromCdbCalendar(\CultureFeed_Cdb_Data_Calendar $cdbCalendar)
16
    {
17
        //
18
        // Get the calendar type.
19
        //
20
        $calendarType = '';
21
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_Permanent) {
22
            $calendarType = 'permanent';
23
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
24
            $calendarType = 'periodic';
25
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
26
            $calendarType = 'single';
27
            if (iterator_count($cdbCalendar) > 1) {
28
                $calendarType = 'multiple';
29
            }
30
        }
31
32
        //
33
        // Get the start day.
34
        //
35
        $cdbCalendar->rewind();
36
        $startDateString = '';
37
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
38
            /** @var \CultureFeed_Cdb_Data_Calendar_Period $period */
39
            $period = $cdbCalendar->current();
40
            $startDateString = $period->getDateFrom() . 'T00:00:00';
41 View Code Duplication
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
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...
42
            /** @var \CultureFeed_Cdb_Data_Calendar_Timestamp $timestamp */
43
            $timestamp = $cdbCalendar->current();
44
            if ($timestamp->getStartTime()) {
45
                $startDateString = $timestamp->getDate() . 'T' . $timestamp->getStartTime();
46
            } else {
47
                $startDateString = $timestamp->getDate() . 'T00:00:00';
48
            }
49
        }
50
        $startDate = !empty($startDateString) ? DateTimeFactory::dateTimeFromDateString($startDateString) : null;
51
52
        //
53
        // Get the end day.
54
        //
55
        $cdbCalendar->rewind();
56
        $endDateString = '';
57
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
58
            /** @var \CultureFeed_Cdb_Data_Calendar_Period $period */
59
            $period = $cdbCalendar->current();
60
            $endDateString = $period->getDateTo() . 'T00:00:00';
61
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
62
            $firstTimestamp = $cdbCalendar->current();
63
            /** @var \CultureFeed_Cdb_Data_Calendar_Timestamp $timestamp */
64
            $cdbCalendarAsArray = iterator_to_array($cdbCalendar);
65
            $timestamp = iterator_count($cdbCalendar) > 1 ? end($cdbCalendarAsArray) : $firstTimestamp;
66 View Code Duplication
            if ($timestamp->getEndTime()) {
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...
67
                $endDateString = $timestamp->getDate() . 'T' . $timestamp->getEndTime();
68
            } else {
69
                $endTime = $timestamp->getStartTime() ? $timestamp->getStartTime() : '00:00:00';
70
                $endDateString = $timestamp->getDate() . 'T' . $endTime;
71
            }
72
        }
73
        $endDate = !empty($endDateString) ? DateTimeFactory::dateTimeFromDateString($endDateString) : null;
74
75
        //
76
        // Get the time stamps.
77
        //
78
        $cdbCalendar->rewind();
79
        $timestamps = [];
80
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
81
            while ($cdbCalendar->valid()) {
82
                /** @var \CultureFeed_Cdb_Data_Calendar_Timestamp $timestamp */
83
                $timestamp = $cdbCalendar->current();
84
                $cdbCalendar->next();
85
86
                $startTime = $timestamp->getStartTime() ? $timestamp->getStartTime() : '00:00:00';
87
                $startDateString = $timestamp->getDate() . 'T' . $startTime;
88
89
                if ($timestamp->getEndTime()) {
90
                    $endDateString = $timestamp->getDate() . 'T' . $timestamp->getEndTime();
91
                } else {
92
                    $endDateString = $timestamp->getDate() . 'T' . $startTime;
93
                }
94
95
                $timestamps[] = $this->createTimestamp(
96
                    $startDateString,
97
                    $endDateString
98
                );
99
            }
100
        }
101
102
        //
103
        // Get the opening hours.
104
        //
105
        $cdbCalendar->rewind();
106
        $openingHours = [];
107
108
        $weekSchema = null;
109
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
110
            $period = $cdbCalendar->current();
111
            $weekSchema = $period->getWeekScheme();
112
        } else if ($cdbCalendar instanceof  \CultureFeed_Cdb_Data_Calendar_Permanent) {
113
            $weekSchema = $cdbCalendar->getWeekScheme();
114
        }
115
116
        if ($weekSchema) {
117
            $openingHours = $this->createOpeningHoursFromWeekScheme($weekSchema);
118
        }
119
120
        // End date might be before start date in cdbxml when event takes place
121
        // between e.g. 9 PM and 3 AM (the next day). UDB3 does not support this
122
        // and gracefully ignores the end time.
123
        //
124
        // Example cdbxml:
125
        //
126
        // <timestamp>
127
        //   <date>2016-12-16</date>
128
        //   <timestart>21:00:00</timestart>
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
129
        //   <timeend>05:00:00</timeend>
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
130
        // </timestamp>
131
        //
132
        if ($endDate < $startDate) {
133
            $endDate = $startDate;
134
        }
135
136
        //
137
        // Create the calendar value object.
138
        //
139
        return new Calendar(
140
            CalendarType::fromNative($calendarType),
141
            $startDate,
142
            $endDate,
143
            $timestamps,
144
            $openingHours
145
        );
146
    }
147
148
    /**
149
     * @param \CultureFeed_Cdb_Data_Calendar_Weekscheme|null $weekScheme
150
     * @return Calendar
151
     */
152
    public function createFromWeekScheme(
153
        \CultureFeed_Cdb_Data_Calendar_Weekscheme $weekScheme = null
154
    ) {
155
        $openingHours = [];
156
157
        if ($weekScheme) {
158
            $openingHours = $this->createOpeningHoursFromWeekScheme($weekScheme);
159
        }
160
161
        return new Calendar(
162
            CalendarType::PERMANENT(),
163
            null,
164
            null,
165
            [],
166
            $openingHours
167
        );
168
    }
169
170
    /**
171
     * @param \CultureFeed_Cdb_Data_Calendar_Weekscheme $weekScheme
172
     * @return OpeningHour[]
173
     */
174
    private function createOpeningHoursFromWeekScheme(
175
        \CultureFeed_Cdb_Data_Calendar_Weekscheme $weekScheme
176
    ) {
177
        $openingHours = [];
178
179
        foreach ($weekScheme->getDays() as $day) {
180
            if ($day->isOpen()) {
181
                /** @var \CultureFeed_Cdb_Data_Calendar_OpeningTime[] $openingTimes */
182
                $openingTimes = $day->getOpeningTimes();
183
184
                // A day could be marked as open but without any hours.
185
                // This means all day open but needs to be mapped to 00:00:00.
186
                if (count($openingTimes) === 0) {
187
                    $openingTimes[] = new \CultureFeed_Cdb_Data_Calendar_OpeningTime(
188
                        '00:00:00',
189
                        '00:00:00'
190
                    );
191
                }
192
193
                foreach ($openingTimes as $openingTime) {
194
                    $opens = \DateTime::createFromFormat(
195
                        'H:i:s',
196
                        $openingTime->getOpenFrom()
197
                    );
198
                    $closes = \DateTime::createFromFormat(
199
                        'H:i:s',
200
                        $openingTime->getOpenTill()
201
                    );
202
203
                    $openingHour = new OpeningHour(
204
                        OpeningTime::fromNativeDateTime($opens),
0 ignored issues
show
Security Bug introduced by
It seems like $opens defined by \DateTime::createFromFor...ingTime->getOpenFrom()) on line 194 can also be of type false; however, CultuurNet\UDB3\Calendar...e::fromNativeDateTime() does only seem to accept object<DateTimeInterface>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
205
                        $closes ? OpeningTime::fromNativeDateTime($closes) : OpeningTime::fromNativeDateTime($opens),
0 ignored issues
show
Security Bug introduced by
It seems like $opens defined by \DateTime::createFromFor...ingTime->getOpenFrom()) on line 194 can also be of type false; however, CultuurNet\UDB3\Calendar...e::fromNativeDateTime() does only seem to accept object<DateTimeInterface>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
206
                        DayOfWeek::fromNative($day->getDayName())
207
                    );
208
209
                    $openingHours = $this->addToOpeningHours($openingHour, ...$openingHours);
210
                }
211
            }
212
        }
213
214
        return $openingHours;
215
    }
216
217
    /**
218
     * @param OpeningHour $newOpeningHour
219
     * @param OpeningHour[] ...$openingHours
220
     * @return OpeningHour[]
221
     */
222
    private function addToOpeningHours(
223
        OpeningHour $newOpeningHour,
224
        OpeningHour ...$openingHours
225
    ) {
226
        foreach ($openingHours as $openingHour) {
227
            if ($openingHour->hasEqualHours($newOpeningHour)) {
0 ignored issues
show
Bug introduced by
The method hasEqualHours cannot be called on $openingHour (of type array<integer,object<Cul...\Calendar\OpeningHour>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
228
                $openingHour->addDaysOfWeek(...$newOpeningHour->getDaysOfWeek());
0 ignored issues
show
Bug introduced by
The method addDaysOfWeek cannot be called on $openingHour (of type array<integer,object<Cul...\Calendar\OpeningHour>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
229
                return $openingHours;
230
            }
231
        }
232
233
        $openingHours[] = $newOpeningHour;
234
        return $openingHours;
235
    }
236
237
    /**
238
     * @param string $startDateString
239
     * @param string $endDateString
240
     * @return Timestamp
241
     */
242
    private function createTimestamp(
243
        $startDateString,
244
        $endDateString
245
    ) {
246
        $startDate = DateTimeFactory::dateTimeFromDateString($startDateString);
247
        $endDate = DateTimeFactory::dateTimeFromDateString($endDateString);
248
249
        // End date might be before start date in cdbxml when event takes place
250
        // between e.g. 9 PM and 3 AM (the next day). UDB3 does not support this
251
        // and gracefully ignores the end time.
252
        //
253
        // Example cdbxml:
254
        //
255
        // <timestamp>
256
        //   <date>2016-12-16</date>
257
        //   <timestart>21:00:00</timestart>
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
258
        //   <timeend>05:00:00</timeend>
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
259
        // </timestamp>
260
        //
261
        if ($endDate < $startDate) {
262
            $endDate = $startDate;
263
        }
264
265
        return new Timestamp($startDate, $endDate);
266
    }
267
}
268