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.

AbstractCalendar::getEventsItemized()   B
last analyzed

Complexity

Conditions 10
Paths 15

Size

Total Lines 50

Duplication

Lines 12
Ratio 24 %

Importance

Changes 0
Metric Value
dl 12
loc 50
rs 7.2242
c 0
b 0
f 0
cc 10
nc 15
nop 3

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