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 ( fd9624...a479a0 )
by Ronald
02:53
created

AbstractCalendar::itemizeHours()   C

Complexity

Conditions 13
Paths 14

Size

Total Lines 36
Code Lines 18

Duplication

Lines 14
Ratio 38.89 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 14
loc 36
rs 5.1234
cc 13
eloc 18
nc 14
nop 4

How to fix   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
/**
4
 * @file
5
 * Class AbstractCalendar
6
 */
7
8
namespace Roomify\Bat\Calendar;
9
10
use Roomify\Bat\Event\Event;
11
use Roomify\Bat\Unit\Unit;
12
use Roomify\Bat\Calendar\CalendarInterface;
13
use Roomify\Bat\Calendar\CalendarResponse;
14
15
/**
16
 * Handles querying and updating state stores
17
 */
18
abstract class AbstractCalendar implements CalendarInterface {
19
20
  /**
21
   * The units we are dealing with. If no unit ids set the calendar will return
22
   * results for date range and all units within that range.
23
   *
24
   * @var array
25
   */
26
  protected $units;
27
28
29
  /**
30
   * The class that will access the actual event store where event data is held.
31
   *
32
   * @var
33
   */
34
  protected $store;
35
36
  /**
37
   * The default value for events. In the event store this is represented by 0 which is then
38
   * replaced by the default value provided in the constructor.
39
   *
40
   * @var
41
   */
42
  protected $default_value;
43
44
45
  /**
46
   * {@inheritdoc}
47
   */
48
  public function addEvents($events, $granularity) {
49
50
    $added = TRUE;
51
52
    foreach ($events as $event) {
53
      // Events save themselves so here we cycle through each and return true if all events
54
      // were saved
55
56
      $check = $event->saveEvent($this->store, $granularity);
57
58
      if ($check == FALSE) {
59
        $added = FALSE;
60
        break;
61
      }
62
    }
63
64
    return $added;
65
  }
66
67
  /**
68
   * Given a start and end time will retrieve events from the defined store.
69
   *
70
   * If unit_ids where defined it will filter for those unit ids.
71
   *
72
   * @param \DateTime $start_date
73
   * @param \DateTime $end_date
74
   * @return array
75
   */
76
  public function getEvents(\DateTime $start_date, \DateTime $end_date) {
77
    // We first get events in the itemized format
78
    $itemized_events = $this->getEventsItemized($start_date, $end_date);
79
80
    // We then normalize those events to create Events that get added to an array
81
    $events = $this->getEventsNormalized($start_date, $end_date, $itemized_events);
82
83
    return $events;
84
  }
85
86
  /**
87
   * Given a start and end time this will return the states units find themselves in for that range.
88
   *
89
   * @param \DateTime $start_date
90
   * @param \DateTime $end_date
91
   * @return array
92
   *  An array of states keyed by unit
93
   */
94
  public function getStates(\DateTime $start_date, \DateTime $end_date) {
95
    $events = $this->getEvents($start_date, $end_date);
96
    $states = array();
97
    foreach ($events as $unit => $unit_events) {
98
      foreach ($unit_events as $event) {
99
        $states[$unit][$event->getValue()] = $event->getValue();
100
      }
101
    }
102
103
    return $states;
104
  }
105
106
  /**
107
   * Given a date range and a set of valid states it will return then units that are withing that
108
   * set of valid states.
109
   *
110
   * @param \DateTime $start_date
111
   * @param \DateTime $end_date
112
   * @param $valid_states
113
   *
114
   * @return CalendarResponse
115
   */
116
  public function getMatchingUnits(\DateTime $start_date, \DateTime $end_date, $valid_states, $constraints) {
117
    $units = array();
118
    $response = new CalendarResponse($start_date, $end_date, $valid_states);
119
    $keyed_units = $this->keyUnitsById();
120
121
    $states = $this->getStates($start_date, $end_date);
122
    foreach ($states as $unit => $unit_states) {
123
      // Create an array with just the states
124
      $current_states = array_keys($unit_states);
125
      // Compare the current states with the set of valid states
126
      $remaining_states = array_diff($current_states, $valid_states);
127
      if (count($remaining_states) == 0 ) {
128
        // Unit is in a state that is within the set of valid states so add to result set
129
        $units[$unit] = $unit;
130
        $response->addMatch($keyed_units[$unit], CalendarResponse::VALID_STATE);
131
      }
132
      else {
133
        $response->addMiss($keyed_units[$unit], CalendarResponse::INVALID_STATE);
134
      }
135
136
      $unit_constraints = $keyed_units[$unit]->getConstraints();
137
      $response->applyConstraints($unit_constraints);
138
    }
139
140
    $response->applyConstraints($constraints);
141
142
    return $response;
143
  }
144
145
  /**
146
   * Provides an itemized array of events keyed by the unit_id and divided by day,
147
   * hour and minute.
148
   *
149
   * @param \DateTime $start_date
150
   * @param \DateTime $end_date
151
   * @param $store
152
   *
153
   * @return array
154
   */
155
  public function getEventsItemized(\DateTime $start_date, \DateTime $end_date) {
156
    // The final events we will return
157
    $events = array();
158
159
    $keyed_units = $this->keyUnitsById();
160
161
    $db_events = $this->store->getEventData($start_date, $end_date, array_keys($keyed_units));
162
163
    // Create a mock itemized event for the period in question - since event data is either
164
    // in the database or the default value we first create a mock event and then fill it in
165
    // accordingly
166
    $mock_event = new Event($start_date, $end_date, new Unit(0,0,null), $this->default_value);
167
    $itemized = $mock_event->itemizeEvent();
168
169
    // Cycle through each unit retrieved and provide it with a fully configured itemized mock event
170
    foreach ($db_events as $unit => $event) {
171
      // Add the mock event
172
      $events[$unit] = $itemized;
173
174
      $events[$unit][Event::BAT_DAY] = $this->itemizeDays($db_events, $itemized, $unit, $keyed_units);
175
176
      // Handle hours
177 View Code Duplication
      if (isset($itemized[Event::BAT_HOUR])) {
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...
178
        $events[$unit][Event::BAT_HOUR] = $this->itemizeHours($db_events, $itemized, $unit, $keyed_units);
179
      } else {
180
        // No hours - set an empty array
181
        $events[$unit][Event::BAT_HOUR] = array();
182
      }
183
184
      // Handle minutes
185 View Code Duplication
      if (isset($itemized[Event::BAT_MINUTE])) {
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...
186
        $events[$unit][Event::BAT_MINUTE] = $this->itemizeMinutes($db_events, $itemized, $unit, $keyed_units);
187
      } else {
188
        // No minutes - set an empty array
189
        $events[$unit][Event::BAT_MINUTE] = array();
190
      }
191
192
    }
193
194
    // Check to see if any events came back from the db
195
    if (count($events) == 0) {
196
      // If we don't have any db events add mock events (itemized)
197
      foreach ($keyed_units as $id => $unit) {
198
        $empty_event = new Event($start_date, $end_date, $unit, $unit->getDefaultValue());
199
        $events[$id] = $empty_event->itemizeEvent();
200
      }
201
    }
202
203
    return $events;
204
  }
205
206
  /**
207
   * Helper function that cycles through db results and setups the BAT_DAY itemized array
208
   *
209
   * @param $db_events
210
   * @param $itemized
211
   * @param $unit
212
   * @param $keyed_units
213
   *
214
   * @return array
215
   */
216
  private function itemizeDays($db_events, $itemized, $unit, $keyed_units) {
217
    $result = array();
218
219
    foreach ($itemized[Event::BAT_DAY] as $year => $months) {
220
      foreach ($months as $month => $days) {
221
        // Check if month is defined in DB otherwise set to default value
222
        if (isset($db_events[$unit][Event::BAT_DAY][$year][$month])) {
223
          foreach ($days as $day => $value) {
224
            $result[$year][$month][$day] = ((int)$db_events[$unit][Event::BAT_DAY][$year][$month][$day] == 0 ? $keyed_units[$unit]->getDefaultValue() : (int)$db_events[$unit][Event::BAT_DAY][$year][$month][$day]);
225
          }
226
        }
227 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...
228
          foreach ($days as $day => $value) {
229
            $result[$year][$month][$day] = $keyed_units[$unit]->getDefaultValue();
230
          }
231
        }
232
      }
233
    }
234
235
    return $result;
236
  }
237
238
  /**
239
   * Helper function that cycles through db results and setups the BAT_HOUR itemized array
240
   * @param $db_events
241
   * @param $itemized
242
   * @param $unit
243
   * @param $keyed_units
244
   *
245
   * @return array
246
   */
247
  private function itemizeHours($db_events, $itemized, $unit, $keyed_units) {
248
249
    $result = array();
250
251
    foreach ($itemized[Event::BAT_HOUR] as $year => $months) {
252
      foreach ($months as $month => $days) {
253
        foreach ($days as $day => $hours) {
254
          foreach ($hours as $hour => $value) {
255
            if (isset($db_events[$unit][Event::BAT_HOUR][$year][$month][$day][$hour])) {
256
              $result[$year][$month][$day][$hour] = ((int) $db_events[$unit][Event::BAT_HOUR][$year][$month][$day][$hour] == 0 ? $keyed_units[$unit]->getDefaultValue() : (int) $db_events[$unit][Event::BAT_HOUR][$year][$month][$day][$hour]);
257
            }
258 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...
259
              // If nothing from db - then revert to the defaults
260
              $result[$year][$month][$day][$hour] = (int) $keyed_units[$unit]->getDefaultValue();
261
            }
262
          }
263
        }
264
      }
265
    }
266
267
    // Now fill in hour data coming from the database which the mock event did *not* cater for in the data structure
268
    if (isset($db_events[$unit][Event::BAT_HOUR])) {
269 View Code Duplication
      foreach ($db_events[$unit][Event::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...
270
        foreach ($months as $month => $days) {
271
          foreach ($days as $day => $hours) {
272
            foreach ($hours as $hour => $value) {
273
              $result[$year][$month][$day][$hour] = ((int) $value == 0 ? $keyed_units[$unit]->getDefaultValue() : (int) $value);
274
            }
275
            ksort($result[$year][$month][$day], SORT_NATURAL);
276
          }
277
        }
278
      }
279
    }
280
281
    return $result;
282
  }
283
284
  /**
285
   * Helper function that cycles through db results and setups the BAT_MINUTE itemized array
286
   *
287
   * @param $db_events
288
   * @param $itemized
289
   * @param $unit
290
   * @param $keyed_units
291
   *
292
   * @return array
293
   */
294
  private function itemizeMinutes($db_events, $itemized, $unit, $keyed_units) {
295
    $result = array();
296
297
    foreach ($itemized[Event::BAT_MINUTE] as $year => $months) {
298
      foreach ($months as $month => $days) {
299
        foreach ($days as $day => $hours) {
300
          foreach ($hours as $hour => $minutes) {
301
            foreach ($minutes as $minute => $value) {
302
              if (isset($db_events[$unit][Event::BAT_MINUTE][$year][$month][$day][$hour][$minute])) {
303
                $result[$year][$month][$day][$hour][$minute] = ((int) $db_events[$unit][Event::BAT_MINUTE][$year][$month][$day][$hour][$minute] == 0 ? $keyed_units[$unit]->getDefaultValue() : (int) $db_events[$unit][Event::BAT_MINUTE][$year][$month][$day][$hour][$minute]);
304
              }
305 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...
306
                // If nothing from db - then revert to the defaults
307
                $result[$year][$month][$day][$hour][$minute] = (int) $keyed_units[$unit]->getDefaultValue();
308
              }
309
            }
310
          }
311
        }
312
      }
313
    }
314
315
    // Now fill in minute data coming from the database which the mock event did *not* cater for
316
    if (isset($db_events[$unit][Event::BAT_MINUTE])) {
317
      foreach ($db_events[$unit][Event::BAT_MINUTE] as $year => $months) {
318 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...
319
          foreach ($days as $day => $hours) {
320
            foreach ($hours as $hour => $minutes) {
321
              foreach ($minutes as $minute => $value) {
322
                $result[$year][$month][$day][$hour][$minute] = ((int) $value == 0 ? $keyed_units[$unit]->getDefaultValue() : (int) $value);
323
              }
324
              ksort($result[$year][$month][$day][$hour], SORT_NATURAL);
325
            }
326
          }
327
        }
328
      }
329
    }
330
331
    return $result;
332
  }
333
334
  /**
335
   * Given an itemized set of event data it will return an array of Events
336
   *
337
   * @param \DateTime $start_date
338
   * @param \DateTime $end_date
339
   * @param $events
340
   *
341
   * @return array
342
   */
343
  public function getEventsNormalized(\DateTime $start_date, \DateTime $end_date, $events) {
344
345
    $normalized_events = array();
346
347
    $events_copy = $events;
348
349
    foreach ($events_copy as $unit_id => $data) {
350
351
      // Make sure years are sorted
352
      ksort($data[Event::BAT_DAY]);
353
      ksort($data[Event::BAT_HOUR]);
354
      ksort($data[Event::BAT_MINUTE]);
355
356
      // Set up variables to keep track of stuff
357
      $current_value = NULL;
358
      $start_event = NULL;
359
      $end_event = NULL;
360
      $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...
361
362
      foreach ($data[Event::BAT_DAY] as $year => $months) {
363
        // Make sure months are in right order
364
        ksort($months);
365
        foreach ($months as $month => $days) {
366
          foreach ($days as $day => $value) {
367
            if ($value == -1) {
368
              // Retrieve hour data
369
              $hour_data = $events[$unit_id][Event::BAT_HOUR][$year][$month][$day];
370
              ksort($hour_data, SORT_NATURAL);
371
              foreach ($hour_data as $hour => $hour_value) {
372
                if ($hour_value == -1) {
373
                  // We are going to need minute values
374
                  $minute_data = $events[$unit_id][Event::BAT_MINUTE][$year][$month][$day][$hour];
375
                  ksort($minute_data, SORT_NATURAL);
376
                  foreach ($minute_data as $minute => $minute_value) {
377
                    if ($current_value === $minute_value) {
378
                      // We are still in minutes and going through so add a minute
379
                      $end_event->add(new \DateInterval('PT1M'));
380
                    }
381
                    elseif (($current_value != $minute_value) && ($current_value !== NULL)) {
382
                      // Value just switched - let us wrap up with current event and start a new one
383
                      $normalized_events[$unit_id][] = new Event($start_event, $end_event, $this->getUnit($unit_id), $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 359 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...
384
                      $start_event = clone($end_event->add(new \DateInterval('PT1M')));
385
                      $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':' . substr($minute,1));
386
                      $current_value = $minute_value;
387
                    }
388
                    if ($current_value === NULL) {
389
                      // We are down to minutes and haven't created and event yet - do one now
390
                      $start_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':' . substr($minute,1));
391
                      $end_event = clone($start_event);
392
                    }
393
                    $current_value = $minute_value;
394
                  }
395
                }
396
                elseif ($current_value === $hour_value) {
397
                  // We are in hours and can add something
398
                  $end_event->add(new \DateInterval('PT1H'));
399
                }
400 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...
401
                  // Value just switched - let us wrap up with current event and start a new one
402
                  $normalized_events[$unit_id][] = new Event($start_event, $end_event, $this->getUnit($unit_id), $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 359 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...
403
                  // Start event becomes the end event with a minute added
404
                  $start_event = clone($end_event->add(new \DateInterval('PT1M')));
405
                  // End event comes the current point in time
406
                  $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':00');
407
                  $current_value = $hour_value;
408
                }
409
                if ($current_value === NULL) {
410
                  // Got into hours and still haven't created an event so
411
                  $start_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':00');
412
                  // We will be occupying at least this hour so might as well mark it
413
                  $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . substr($hour, 1) . ':59');
414
                  $current_value = $hour_value;
415
                }
416
              }
417
            }
418
            elseif ($current_value === $value) {
419
              // We are adding a whole day so the end event gets moved to the end of the day we are adding
420
              $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '23:59');
421
            }
422 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...
423
              // Value just switched - let us wrap up with current event and start a new one
424
              $normalized_events[$unit_id][] = new Event($start_event, $end_event, $this->getUnit($unit_id), $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 359 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...
425
              // Start event becomes the end event with a minute added
426
              $start_event = clone($end_event->add(new \DateInterval('PT1M')));
427
              // End event becomes the current day which we have not account for yet
428
              $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '23:59');
429
              $current_value = $value;
430
            }
431
            if ($current_value === NULL) {
432
              // We have not created an event yet so let's do it now
433
              $start_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '00:00');
434
              $end_event = new \DateTime($year . '-' . $month . '-' . substr($day, 1) . ' ' . '23:59');
435
              $current_value = $value;
436
            }
437
          }
438
        }
439
      }
440
441
      // Add the last event in for which there is nothing in the loop to catch it
442
      $normalized_events[$unit_id][] = new Event($start_event, $end_event, $this->getUnit($unit_id), $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 359 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...
443
    }
444
445
    // Given the database structure we may get events that are not with the date ranges we were looking for
446
    // We get rid of them here so that the user has a clean result.
447
    foreach ($normalized_events as $unit_id => $events) {
448
      foreach ($events as $key => $event) {
449
        if ($event->overlaps($start_date, $end_date)) {
450
          // Adjust start or end dates of events so everything is within range
451
          if ($event->startsEarlier($start_date)) {
452
            $event->setStartDate($start_date);
453
          }
454
          if ($event->endsLater($end_date)) {
455
            $event->setEndDate($end_date);
456
          }
457
        }
458
        else {
459
          // Event completely not in range so unset it
460
          unset($normalized_events[$unit_id][$key]);
461
        }
462
      }
463
    }
464
465
    return $normalized_events;
466
  }
467
468
  /**
469
   * A simple utility function that given an array of datum=>value will group results based on
470
   * those that have the same value. Useful for grouping events based on state.
471
   *
472
   * @param $data
473
   * @param $length
474
   */
475
  public function groupData($data, $length) {
476
    $flipped = array();
477
    $e = 0;
478
    $j = 0;
479
    $old_value = NULL;
480
481
    foreach ($data as $datum => $value) {
482
      $j++;
483
      if ($j <= $length) {
484
        // If the value has changed and we are not just starting
485
        if (($value != $old_value)) {
486
          $e++;
487
          $flipped[$e][$value][$datum] = $datum;
488
          $old_value = $value;
489
        }
490
        else {
491
          $flipped[$e][$value][$datum] = $datum;
492
        }
493
      }
494
    }
495
  }
496
497
  /**
498
   * Return an array of unit ids from the set of units
499
   * supplied to the Calendar.
500
   *
501
   * @return array
502
   */
503
  protected function getUnitIds() {
504
    $unit_ids = array();
505
    foreach ($this->units as $unit) {
506
      $unit_ids[] = $unit->getUnitId();
507
    }
508
509
    return $unit_ids;
510
  }
511
512
  /**
513
   * Return an array of units keyed by unit id
514
   *
515
   * @return array
516
   */
517
  protected function keyUnitsById() {
518
    $keyed_units = array();
519
    foreach ($this->units as $unit) {
520
      $keyed_units[$unit->getUnitId()] = $unit;
521
    }
522
523
    return $keyed_units;
524
  }
525
526
  /**
527
   * Returns the unit object.
528
   *
529
   * @param $unit_id
530
   * @return mixed
531
   */
532
  protected function getUnit($unit_id) {
533
    $keyed =  $this->keyUnitsById();
534
    return $keyed[$unit_id];
535
  }
536
537
538
}
539