Completed
Pull Request — master (#296)
by Luc
08:35 queued 03:51
created

CalendarFactory   C

Complexity

Total Complexity 36

Size/Duplication

Total Lines 260
Duplicated Lines 5.77 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 17
dl 15
loc 260
rs 6.9142
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
F createFromCdbCalendar() 15 132 23
A createFromWeekScheme() 0 17 2
B createOpeningHoursFromWeekScheme() 0 42 6
A addToOpeningHours() 0 16 3
B createTimestamp() 0 25 2

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace CultuurNet\UDB3;
4
5
use CultuurNet\UDB3\Calendar\DayOfWeek;
6
use CultuurNet\UDB3\Calendar\DayOfWeekCollection;
7
use CultuurNet\UDB3\Calendar\OpeningHour;
8
use CultuurNet\UDB3\Calendar\OpeningTime;
9
use CultuurNet\UDB3\Cdb\DateTimeFactory;
10
11
class CalendarFactory implements CalendarFactoryInterface
12
{
13
    /**
14
     * @inheritdoc
15
     */
16
    public function createFromCdbCalendar(\CultureFeed_Cdb_Data_Calendar $cdbCalendar)
17
    {
18
        //
19
        // Get the calendar type.
20
        //
21
        $calendarType = '';
22
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_Permanent) {
23
            $calendarType = 'permanent';
24
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
25
            $calendarType = 'periodic';
26
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
27
            $calendarType = 'single';
28
            if (iterator_count($cdbCalendar) > 1) {
29
                $calendarType = 'multiple';
30
            }
31
        }
32
33
        //
34
        // Get the start day.
35
        //
36
        $cdbCalendar->rewind();
37
        $startDateString = '';
38
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
39
            /** @var \CultureFeed_Cdb_Data_Calendar_Period $period */
40
            $period = $cdbCalendar->current();
41
            $startDateString = $period->getDateFrom() . 'T00:00:00';
42 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...
43
            /** @var \CultureFeed_Cdb_Data_Calendar_Timestamp $timestamp */
44
            $timestamp = $cdbCalendar->current();
45
            if ($timestamp->getStartTime()) {
46
                $startDateString = $timestamp->getDate() . 'T' . $timestamp->getStartTime();
47
            } else {
48
                $startDateString = $timestamp->getDate() . 'T00:00:00';
49
            }
50
        }
51
        $startDate = !empty($startDateString) ? DateTimeFactory::dateTimeFromDateString($startDateString) : null;
52
53
        //
54
        // Get the end day.
55
        //
56
        $cdbCalendar->rewind();
57
        $endDateString = '';
58
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
59
            /** @var \CultureFeed_Cdb_Data_Calendar_Period $period */
60
            $period = $cdbCalendar->current();
61
            $endDateString = $period->getDateTo() . 'T00:00:00';
62
        } else if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
63
            $firstTimestamp = $cdbCalendar->current();
64
            /** @var \CultureFeed_Cdb_Data_Calendar_Timestamp $timestamp */
65
            $cdbCalendarAsArray = iterator_to_array($cdbCalendar);
66
            $timestamp = iterator_count($cdbCalendar) > 1 ? end($cdbCalendarAsArray) : $firstTimestamp;
67 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...
68
                $endDateString = $timestamp->getDate() . 'T' . $timestamp->getEndTime();
69
            } else {
70
                $endTime = $timestamp->getStartTime() ? $timestamp->getStartTime() : '00:00:00';
71
                $endDateString = $timestamp->getDate() . 'T' . $endTime;
72
            }
73
        }
74
        $endDate = !empty($endDateString) ? DateTimeFactory::dateTimeFromDateString($endDateString) : null;
75
76
        //
77
        // Get the time stamps.
78
        //
79
        $cdbCalendar->rewind();
80
        $timestamps = [];
81
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_TimestampList) {
82
            while ($cdbCalendar->valid()) {
83
                /** @var \CultureFeed_Cdb_Data_Calendar_Timestamp $timestamp */
84
                $timestamp = $cdbCalendar->current();
85
                $cdbCalendar->next();
86
87
                $startTime = $timestamp->getStartTime() ? $timestamp->getStartTime() : '00:00:00';
88
                $startDateString = $timestamp->getDate() . 'T' . $startTime;
89
90
                if ($timestamp->getEndTime()) {
91
                    $endDateString = $timestamp->getDate() . 'T' . $timestamp->getEndTime();
92
                } else {
93
                    $endDateString = $timestamp->getDate() . 'T' . $startTime;
94
                }
95
96
                $timestamps[] = $this->createTimestamp(
97
                    $startDateString,
98
                    $endDateString
99
                );
100
            }
101
        }
102
103
        //
104
        // Get the opening hours.
105
        //
106
        $cdbCalendar->rewind();
107
        $openingHours = [];
108
109
        $weekSchema = null;
110
        if ($cdbCalendar instanceof \CultureFeed_Cdb_Data_Calendar_PeriodList) {
111
            $period = $cdbCalendar->current();
112
            $weekSchema = $period->getWeekScheme();
113
        } else if ($cdbCalendar instanceof  \CultureFeed_Cdb_Data_Calendar_Permanent) {
114
            $weekSchema = $cdbCalendar->getWeekScheme();
115
        }
116
117
        if ($weekSchema) {
118
            $openingHours = $this->createOpeningHoursFromWeekScheme($weekSchema);
119
        }
120
121
        // End date might be before start date in cdbxml when event takes place
122
        // between e.g. 9 PM and 3 AM (the next day). UDB3 does not support this
123
        // and gracefully ignores the end time.
124
        //
125
        // Example cdbxml:
126
        //
127
        // <timestamp>
128
        //   <date>2016-12-16</date>
129
        //   <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...
130
        //   <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...
131
        // </timestamp>
132
        //
133
        if ($endDate < $startDate) {
134
            $endDate = $startDate;
135
        }
136
137
        //
138
        // Create the calendar value object.
139
        //
140
        return new Calendar(
141
            CalendarType::fromNative($calendarType),
142
            $startDate,
143
            $endDate,
144
            $timestamps,
145
            $openingHours
146
        );
147
    }
148
149
    /**
150
     * @param \CultureFeed_Cdb_Data_Calendar_Weekscheme|null $weekScheme
151
     * @return Calendar
152
     */
153
    public function createFromWeekScheme(
154
        \CultureFeed_Cdb_Data_Calendar_Weekscheme $weekScheme = null
155
    ) {
156
        $openingHours = [];
157
158
        if ($weekScheme) {
159
            $openingHours = $this->createOpeningHoursFromWeekScheme($weekScheme);
160
        }
161
162
        return new Calendar(
163
            CalendarType::PERMANENT(),
164
            null,
165
            null,
166
            [],
167
            $openingHours
168
        );
169
    }
170
171
    /**
172
     * @param \CultureFeed_Cdb_Data_Calendar_Weekscheme $weekScheme
173
     * @return OpeningHour[]
174
     */
175
    private function createOpeningHoursFromWeekScheme(
176
        \CultureFeed_Cdb_Data_Calendar_Weekscheme $weekScheme
177
    ) {
178
        $openingHours = [];
179
180
        foreach ($weekScheme->getDays() as $day) {
181
            if ($day->isOpen()) {
182
                /** @var \CultureFeed_Cdb_Data_Calendar_OpeningTime[] $openingTimes */
183
                $openingTimes = $day->getOpeningTimes();
184
185
                // A day could be marked as open but without any hours.
186
                // This means all day open but needs to be mapped to 00:00:00.
187
                if (count($openingTimes) === 0) {
188
                    $openingTimes[] = new \CultureFeed_Cdb_Data_Calendar_OpeningTime(
189
                        '00:00:00',
190
                        '00:00:00'
191
                    );
192
                }
193
194
                foreach ($openingTimes as $openingTime) {
195
                    $opens = \DateTime::createFromFormat(
196
                        'H:i:s',
197
                        $openingTime->getOpenFrom()
198
                    );
199
                    $closes = \DateTime::createFromFormat(
200
                        'H:i:s',
201
                        $openingTime->getOpenTill()
202
                    );
203
204
                    $openingHour = new OpeningHour(
205
                        OpeningTime::fromNativeDateTime($opens),
0 ignored issues
show
Security Bug introduced by
It seems like $opens defined by \DateTime::createFromFor...ingTime->getOpenFrom()) on line 195 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
                        $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 195 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...
207
                        new DayOfWeekCollection(DayOfWeek::fromNative($day->getDayName()))
208
                    );
209
210
                    $openingHours = $this->addToOpeningHours($openingHour, ...$openingHours);
211
                }
212
            }
213
        }
214
215
        return $openingHours;
216
    }
217
218
    /**
219
     * @param OpeningHour $newOpeningHour
220
     * @param OpeningHour[] ...$openingHours
221
     * @return OpeningHour[]
222
     */
223
    private function addToOpeningHours(
224
        OpeningHour $newOpeningHour,
225
        OpeningHour ...$openingHours
226
    ) {
227
        foreach ($openingHours as $openingHour) {
228
            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...
229
                $openingHour->addDayOfWeekCollection(
0 ignored issues
show
Bug introduced by
The method addDayOfWeekCollection 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...
230
                    $newOpeningHour->getDayOfWeekCollection()
231
                );
232
                return $openingHours;
233
            }
234
        }
235
236
        $openingHours[] = $newOpeningHour;
237
        return $openingHours;
238
    }
239
240
    /**
241
     * @param string $startDateString
242
     * @param string $endDateString
243
     * @return Timestamp
244
     */
245
    private function createTimestamp(
246
        $startDateString,
247
        $endDateString
248
    ) {
249
        $startDate = DateTimeFactory::dateTimeFromDateString($startDateString);
250
        $endDate = DateTimeFactory::dateTimeFromDateString($endDateString);
251
252
        // End date might be before start date in cdbxml when event takes place
253
        // between e.g. 9 PM and 3 AM (the next day). UDB3 does not support this
254
        // and gracefully ignores the end time.
255
        //
256
        // Example cdbxml:
257
        //
258
        // <timestamp>
259
        //   <date>2016-12-16</date>
260
        //   <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...
261
        //   <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...
262
        // </timestamp>
263
        //
264
        if ($endDate < $startDate) {
265
            $endDate = $startDate;
266
        }
267
268
        return new Timestamp($startDate, $endDate);
269
    }
270
}
271