GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( f45546...37cb53 )
by
unknown
30:04 queued 14:41
created

AbstractCalendar   C

Complexity

Total Complexity 78

Size/Duplication

Total Lines 456
Duplicated Lines 10.75 %

Coupling/Cohesion

Components 1
Dependencies 2
Metric Value
wmc 78
lcom 1
cbo 2
dl 49
loc 456
rs 5.4564

9 Methods

Rating   Name   Duplication   Size   Complexity  
A addEvents() 0 22 3
A getEvents() 0 11 1
A getStates() 0 11 3
B getMatchingUnits() 0 28 3
F getEventsItemized() 31 113 34
D getEventsNormalized() 18 127 26
B groupData() 0 24 4
A getUnitIds() 0 8 2
A keyUnitsById() 0 8 2

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

1
<?php
2
3
/**
4
 * @file
5
 * Class AbstractCalendar
6
 */
7
8
namespace Roomify\Bat\Calendar;
9
10
use Roomify\Bat\Event\Event;
11
use Roomify\Bat\Calendar\CalendarInterface;
12
use Roomify\Bat\Calendar\CalendarResponse;
13
14
/**
15
 * Handles querying and updating state stores
16
 */
17
abstract class AbstractCalendar implements CalendarInterface {
18
19
  /**
20
   * The units we are dealing with. If no unit ids set the calendar will return
21
   * results for date range and all units within that range.
22
   *
23
   * @var array
24
   */
25
  public $units;
26
27
28
  /**
29
   * The class that will access the actual event store where event data is held.
30
   *
31
   * @var
32
   */
33
  public $store;
34
35
  /**
36
   * The default value for events. In the event store this is represented by 0 which is then
37
   * replaced by the default value provided in the constructor.
38
   *
39
   * @var
40
   */
41
  public $default_value;
42
43
44
  /**
45
   * {@inheritdoc}
46
   */
47
  public function addEvents($events, $granularity) {
48
49
    $added = TRUE;
50
51
    foreach ($events as $event) {
52
      // Events save themselves so here we cycle through each and return true if all events
53
      // were saved
54
55
      $check = $event->saveEvent($this->store, $granularity);
56
57
      if ($check == FALSE) {
58
        $added = FALSE;
59
        watchdog('BAT', t('Event with @id, start date @start_date and end date @end_date was not added.', array('@id' => $event->value, '@start_date' => $event->startDateToString(), '@end_date' => $event->endDateToString())));
60
        break;
61
      }
62
      else {
63
        watchdog('BAT', t('Event with @id, start date @start_date and end date @end_date added.', array('@id' => $event->value, '@start_date' => $event->startDateToString(), '@end_date' => $event->endDateToString())));
64
      }
65
    }
66
67
    return $added;
68
  }
69
70
  /**
71
   * Given a start and end time will retrieve events from the defined store.
72
   *
73
   * If unit_ids where defined it will filter for those unit ids.
74
   *
75
   * @param \DateTime $start_date
76
   * @param \DateTime $end_date
77
   * @return array
78
   */
79
  public function getEvents(\DateTime $start_date, \DateTime $end_date) {
80
    $events = array();
0 ignored issues
show
Unused Code introduced by
$events is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
81
82
    // We first get events in the itemized format
83
    $itemized_events = $this->getEventsItemized($start_date, $end_date);
84
85
    // We then normalize those events to create Events that get added to an array
86
    $events = $this->getEventsNormalized($start_date, $end_date, $itemized_events);
87
88
    return $events;
89
  }
90
91
  /**
92
   * Given a start and end time this will return the states units find themselves in for that range.
93
   *
94
   * @param \DateTime $start_date
95
   * @param \DateTime $end_date
96
   * @return array
97
   *  An array of states keyed by unit
98
   */
99
  public function getStates(\DateTime $start_date, \DateTime $end_date) {
100
    $events = $this->getEvents($start_date, $end_date);
101
    $states = array();
102
    foreach ($events as $unit => $unit_events) {
103
      foreach ($unit_events as $event) {
104
        $states[$unit][$event->getValue()] = $event->getValue();
105
      }
106
    }
107
108
    return $states;
109
  }
110
111
  /**
112
   * Given a date range and a set of valid states it will return then units that are withing that
113
   * set of valid states.
114
   *
115
   * @param \DateTime $start_date
116
   * @param \DateTime $end_date
117
   * @param $valid_states
118
   *
119
   * @return CalendarResponse
120
   */
121
  public function getMatchingUnits(\DateTime $start_date, \DateTime $end_date, $valid_states, $constraints) {
122
    $units = array();
123
    $response = new CalendarResponse($start_date, $end_date, $valid_states);
124
    $keyed_units = $this->keyUnitsById();
125
126
    $states = $this->getStates($start_date, $end_date);
127
    foreach ($states as $unit => $unit_states) {
128
      // Create an array with just the states
129
      $current_states = array_keys($unit_states);
130
      // Compare the current states with the set of valid states
131
      $remaining_states = array_diff($current_states, $valid_states);
132
      if (count($remaining_states) == 0 ) {
133
        // Unit is in a state that is within the set of valid states so add to result set
134
        $units[$unit] = $unit;
135
        $response->addMatch($keyed_units[$unit], CalendarResponse::VALID_STATE);
136
      }
137
      else {
138
        $response->addMiss($keyed_units[$unit], CalendarResponse::INVALID_STATE);
139
      }
140
141
      $unit_constraints = $keyed_units[$unit]->getConstraints();
142
      $response->applyConstraints($unit_constraints);
143
    }
144
145
    $response->applyConstraints($constraints);
146
147
    return $response;
148
  }
149
150
  /**
151
   * Provides an itemized array of events keyed by the unit_id and divided by day,
152
   * hour and minute.
153
   *
154
   * @param \DateTime $start_date
155
   * @param \DateTime $end_date
156
   * @param $store
157
   *
158
   * @return array
159
   */
160
  public function getEventsItemized(\DateTime $start_date, \DateTime $end_date) {
161
    // The final events we will return
162
    $events = array();
163
164
    $keyed_units = $this->keyUnitsById();
165
166
    $db_events = $this->store->getEventData($start_date, $end_date, array_keys($keyed_units));
167
168
    // Create a mock itemized event for the period in question - since event data is either
169
    // in the database or the default value we first create a mock event and then fill it in
170
    // accordingly
171
    $mock_event = new Event($start_date, $end_date, NULL, $this->default_value);
172
    $itemized = $mock_event->itemizeEvent();
173
174
    // Cycle through each unit retrieved and provide it with a fully configured itemized mock event
175
    foreach ($db_events as $unit => $event) {
176
      // Add the mock event
177
      $events[$unit] = $itemized;
178
179
      // Fill in month data coming from the database for our event
180
      foreach ($itemized[BAT_DAY] as $year => $months) {
181
        foreach ($months as $month => $days) {
182
          // Check if month is defined in DB otherwise set to default value
183
          if (isset($db_events[$unit][BAT_DAY][$year][$month])) {
184
            foreach ($days as $day => $value) {
185
              $events[$unit][BAT_DAY][$year][$month][$day] = ((int)$db_events[$unit][BAT_DAY][$year][$month][$day] == 0 ? $keyed_units[$unit]->getDefaultValue() : (int)$db_events[$unit][BAT_DAY][$year][$month][$day]);
186
            }
187
          }
188 View Code Duplication
          else {
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...
189
            foreach ($days as $day => $value) {
190
              $events[$unit][BAT_DAY][$year][$month][$day] = $keyed_units[$unit]->getDefaultValue();
191
            }
192
          }
193
194
        }
195
      }
196
197
      // Fill in hour data coming from the database for our event that is represented
198
      // in the mock event
199
      foreach ($itemized[BAT_HOUR] as $year => $months) {
200
        foreach ($months as $month => $days) {
201
          foreach ($days as $day => $hours) {
202
            foreach ($hours as $hour => $value) {
203
              if (isset($db_events[$unit][BAT_HOUR][$year][$month][$day][$hour])) {
204
                $events[$unit][BAT_HOUR][$year][$month]['d' . $day][$hour] = ((int)$db_events[$unit][BAT_DAY][$year][$month][$day][$hour] == 0 ? $keyed_units[$unit]->getDefaultValue() : (int)$db_events[$unit][BAT_DAY][$year][$month][$day][$hour]);
205
              }
206 View Code Duplication
              else {
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...
207
                // If nothing from db - then revert to the defaults
208
                $events[$unit][BAT_HOUR][$year][$month][$day][$hour] = (int)$keyed_units[$unit]->getDefaultValue();
209
              }
210
            }
211
          }
212
        }
213
      }
214
215
      // Now fill in hour data coming from the database which the mock event did *not* cater for
216
      // but the mock event
217 View Code Duplication
      foreach ($db_events[$unit][BAT_HOUR] as $year => $months) {
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...
218
        foreach ($months as $month => $days) {
219
          foreach ($days as $day => $hours) {
220
            foreach ($hours as $hour => $value) {
221
              $events[$unit][BAT_HOUR][$year][$month]['d'.$day][$hour] = ((int)$value == 0 ? $keyed_units[$unit]->getDefaultValue() : (int)$value);
222
            }
223
          }
224
        }
225
      }
226
227
      // Fill in minute data coming from the database for our event that is represented
228
      // in the mock event
229
      foreach ($itemized[BAT_MINUTE] as $year => $months) {
230
        foreach ($months as $month => $days) {
231
          foreach ($days as $day => $hours) {
232
            foreach ($hours as $hour => $minutes) {
233
              foreach ($minutes as $minute => $value) {
234
                if (isset($db_events[$unit][BAT_MINUTE][$year][$month][$day][$hour][$minute])) {
235
                  $events[$unit][BAT_MINUTE][$year][$month]['d' .$day]['h'.$hour][$minute] = ((int)$db_events[$unit][BAT_DAY][$year][$month][$day][$hour][$minute] == 0 ? $keyed_units[$unit]->getDefaultValue() : (int)$db_events[$unit][BAT_DAY][$year][$month][$day][$hour][$minute]);
236
                }
237 View Code Duplication
                else {
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...
238
                  // If nothing from db - then revert to the defaults
239
                  $events[$unit][BAT_MINUTE][$year][$month][$day][$hour][$minute] = (int)$keyed_units[$unit]->getDefaultValue();
240
                }
241
              }
242
            }
243
          }
244
        }
245
      }
246
247
      // Now fill in minute data coming from the database which the mock event did *not* cater for
248
      foreach ($db_events[$unit][BAT_MINUTE] as $year => $months) {
249 View Code Duplication
        foreach ($months as $month => $days) {
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...
250
          foreach ($days as $day => $hours) {
251
            foreach ($hours as $hour => $minutes) {
252
              foreach ($minutes as $minute => $value) {
253
                $events[$unit][BAT_MINUTE][$year][$month]['d'.$day]['h'.$hour][$minute] = ((int)$value == 0 ? $keyed_units[$unit]->getDefaultValue() : (int)$value);
254
              }
255
            }
256
          }
257
        }
258
      }
259
260
    }
261
262
    // Check to see if any events came back from the db
263
    if (count($events) == 0) {
264
      // If we don't have any db events add mock events (itemized)
265
      foreach ($keyed_units as $id => $unit) {
266
        $empty_event = new Event($start_date, $end_date, $id, $unit->getDefaultValue());
267
        $events[$id] = $empty_event->itemizeEvent();
268
      }
269
    }
270
271
    return $events;
272
  }
273
274
  /**
275
   * Given an itemized set of event data it will return an array of Events
276
   *
277
   * @param \DateTime $start_date
278
   * @param \DateTime $end_date
279
   * @param $events
280
   *
281
   * @return array
282
   */
283
  public function getEventsNormalized(\DateTime $start_date, \DateTime $end_date, $events) {
284
285
    $normalized_events = array();
286
287
    $events_copy = $events;
288
289
    foreach ($events_copy as $unit => $data) {
290
291
      // Make sure years are sorted
292
      ksort($data[Event::BAT_DAY]);
293
      ksort($data[Event::BAT_HOUR]);
294
      ksort($data[Event::BAT_MINUTE]);
295
296
      // Set up variables to keep track of stuff
297
      $current_value = NULL;
298
      $start_event = NULL;
299
      $end_event = NULL;
300
      $event_value = NULL;
0 ignored issues
show
Unused Code introduced by
$event_value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
301
      $last_day = NULL;
0 ignored issues
show
Unused Code introduced by
$last_day is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
302
      $last_hour = NULL;
0 ignored issues
show
Unused Code introduced by
$last_hour is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
303
      $last_minute = NULL;
0 ignored issues
show
Unused Code introduced by
$last_minute is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
304
305
      foreach ($data[Event::BAT_DAY] as $year => $months) {
306
        // Make sure months are in right order
307
        ksort($months);
308
        foreach ($months as $month => $days) {
309
          foreach ($days as $day => $value) {
310
            if ($value == -1) {
311
              // Retrieve hour data
312
              $hour_data = $events[$unit][Event::BAT_HOUR][$year][$month][$day];
313
              ksort($hour_data, SORT_NATURAL);
314
              foreach ($hour_data as $hour => $hour_value) {
315
                if ($hour_value == -1) {
316
                  // We are going to need minute values
317
                  $minute_data = $events[$unit][Event::BAT_MINUTE][$year][$month][$day][$hour];
318
                  ksort($minute_data, SORT_NATURAL);
319
                  foreach ($minute_data as $minute => $minute_value) {
320
                    if ($current_value === $minute_value) {
321
                      // We are still in minutes and going through so add a minute
322
                      $end_event->add(new \DateInterval('PT1M'));
323
                    }
324
                    elseif (($current_value != $minute_value) && ($current_value !== NULL)) {
325
                      // Value just switched - let us wrap up with current event and start a new one
326
                      $normalized_events[$unit][] = new Event($start_event, $end_event, $unit, $current_value);
0 ignored issues
show
Documentation introduced by
$start_event is of type object|null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $end_event defined by NULL on line 299 can be null; however, Roomify\Bat\Event\Event::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
327
                      $start_event = clone($end_event->add(new \DateInterval('PT1M')));
328
                      $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':' . substr($minute,1));
329
                      $current_value = $minute_value;
330
                    }
331
                    if ($current_value === NULL) {
332
                      // We are down to minutes and haven't created and event yet - do one now
333
                      $start_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':' . substr($minute,1));
334
                      $end_event = clone($start_event);
335
                    }
336
                    $current_value = $minute_value;
337
                  }
338
                }
339
                elseif ($current_value === $hour_value) {
340
                  // We are in hours and can add something
341
                  $end_event->add(new \DateInterval('PT1H'));
342
                }
343 View Code Duplication
                elseif (($current_value != $hour_value) && ($current_value !== NULL)) {
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...
344
                  // Value just switched - let us wrap up with current event and start a new one
345
                  $normalized_events[$unit][] = new Event($start_event, $end_event, $unit, $current_value);
0 ignored issues
show
Documentation introduced by
$start_event is of type object|null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $end_event defined by NULL on line 299 can be null; however, Roomify\Bat\Event\Event::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
346
                  // Start event becomes the end event with a minute added
347
                  $start_event = clone($end_event->add(new \DateInterval('PT1M')));
348
                  // End event comes the current point in time
349
                  $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':00');
350
                  $current_value = $hour_value;
351
                }
352
                if ($current_value === NULL) {
353
                  // Got into hours and still haven't created an event so
354
                  $start_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':00');
355
                  // We will be occupying at least this hour so might as well mark it
356
                  $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':59');
357
                  $current_value = $hour_value;
358
                }
359
              }
360
            }
361
            elseif ($current_value === $value) {
362
              // We are adding a whole day so the end event gets moved to the end of the day we are adding
363
              $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '23:59');
364
            }
365 View Code Duplication
            elseif (($current_value !== $value) && ($current_value !== NULL)) {
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...
366
              // Value just switched - let us wrap up with current event and start a new one
367
              $normalized_events[$unit][] = new Event($start_event, $end_event, $unit, $current_value);
0 ignored issues
show
Documentation introduced by
$start_event is of type object|null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $end_event defined by NULL on line 299 can be null; however, Roomify\Bat\Event\Event::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
368
              // Start event becomes the end event with a minute added
369
              $start_event = clone($end_event->add(new \DateInterval('PT1M')));
370
              // End event becomes the current day which we have not account for yet
371
              $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '23:59');
372
              $current_value = $value;
373
            }
374
            if ($current_value === NULL) {
375
              // We have not created an event yet so let's do it now
376
              $start_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '00:00');
377
              $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '23:59');
378
              $current_value = $value;
379
            }
380
          }
381
        }
382
      }
383
384
      // Add the last event in for which there is nothing in the loop to catch it
385
      $normalized_events[$unit][] = new Event($start_event, $end_event, $unit, $current_value);
0 ignored issues
show
Documentation introduced by
$start_event is of type object|null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $end_event defined by NULL on line 299 can be null; however, Roomify\Bat\Event\Event::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
386
    }
387
388
    // Given the database structure we may get events that are not with the date ranges we were looking for
389
    // We get rid of them here so that the user has a clean result.
390
    foreach ($normalized_events as $unit => $events) {
391
      foreach ($events as $key => $event) {
392
        if ($event->inRange($start_date, $end_date)) {
393
          // Adjust start or end dates of events so everything is within range
394
          if ($event->startsEarlier($start_date)) {
395
            $event->setStartDate($start_date);
396
          }
397
          if ($event->endsLater($end_date)) {
398
            $event->setEndDate($end_date);
399
          }
400
        }
401
        else {
402
          // Event completely not in range so unset it
403
          unset($normalized_events[$unit][$key]);
404
        }
405
      }
406
    }
407
408
    return $normalized_events;
409
  }
410
411
  /**
412
   * A simple utility funciton that given an array of datum=>value will group results based on
413
   * those that have the same value. Useful for grouping events based on state.
414
   *
415
   * @param $data
416
   * @param $length
417
   */
418
  public function groupData($data, $length) {
419
    // Given an array of the structure $date => $value we create another array
420
    // of structure $event, $length, $value
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% 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...
421
    // Cycle through day data and create events
422
    $flipped = array();
423
    $e = 0;
424
    $j = 0;
425
    $old_value = NULL;
426
427
    foreach ($data as $datum => $value) {
428
      $j++;
429
      if ($j <= $length) {
430
        // If the value has changed and we are not just starting
431
        if (($value != $old_value)) {
432
          $e++;
433
          $flipped[$e][$value][$datum] = $datum;
434
          $old_value = $value;
435
        }
436
        else {
437
          $flipped[$e][$value][$datum] = $datum;
438
        }
439
      }
440
    }
441
  }
442
443
  /**
444
   * Return an array of unit ids from the set of units
445
   * supplied to the Calendar.
446
   *
447
   * @return array
448
   */
449
  public function getUnitIds() {
450
    $unit_ids = array();
451
    foreach ($this->units as $unit) {
452
      $unit_ids[] = $unit->getUnitId();
453
    }
454
455
    return $unit_ids;
456
  }
457
458
  /**
459
   * Return an array of units keyed by unit id
460
   *
461
   * @return array
462
   */
463
  public function keyUnitsById() {
464
    $keyed_units = array();
465
    foreach ($this->units as $unit) {
466
      $keyed_units[$unit->getUnitId()] = $unit;
467
    }
468
469
    return $keyed_units;
470
  }
471
472
}
473