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 ( 46f6a0...4503bb )
by Ronald
02:31
created

EventItemizer::itemizeEvent()   C

Complexity

Conditions 11
Paths 12

Size

Total Lines 68
Code Lines 31

Duplication

Lines 9
Ratio 13.24 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 9
loc 68
rs 5.8371
cc 11
eloc 31
nc 12
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @file
5
 * Class EventItemizer
6
 */
7
8
namespace Roomify\Bat\Event;
9
10
use Roomify\Bat\Event\EventInterface;
11
use Roomify\Bat\Unit\Unit;
12
13
/**
14
 * The EventItemizer class does the hard work of splitting an event into discrete time
15
 * units in the following structure
16
 * [BAT_DAY][year][month][day][value]
17
 * [BAT_HOUR][year][month][day][hour][value]
18
 * [BAT_MINUTE][year][month][hour][minute][value]
19
 *
20
 * This data structure allows to quickly retrieve the state of a unit for a provided time
21
 * period. The value is either the default value of the unit or the value that the event
22
 * introduced. If the value in either BAT_DAY or BAT_HOUR is -1 it means that that specific
23
 * day or that specific hour are non-determinant. This means that in order to determine the
24
 * value of the event for that point in time we need to look at a lower level of granularity.
25
 *
26
 * Example - consider breaking up the following event
27
 *
28
 * start-date: 2016-01-01 1210
29
 * end-date: 2016-01-03 1210
30
 * value: 10
31
 *
32
 * [BAT_DAY][2016][01][d1][-1] - The first day starts at 1210 so the DAY array is not enough
33
 * [BAT_DAY][2016][01][d2][10] - The second day is a full day at the same value of 10
34
 * [BAT_DAY][2016][01][d3][-1] - The last day is no a full day so the day array in non-determinant
35
36
 * [BAT_HOUR][2016][01][d1][h12][-1] - The first hour of the event starts at 10 minutes so the hour is non-determinant
37
 * [BAT_HOUR][2016][01][d1][h13][10]
38
 * [BAT_HOUR][2016][01][d1][h14][10]
39
 * [BAT_HOUR][2016][01][d1][h15][10]
40
 * [BAT_HOUR][2016][01][d1][h16][10]
41
 * [BAT_HOUR][2016][01][d1][h17][10]
42
 * [BAT_HOUR][2016][01][d1][h18][10]
43
 * [BAT_HOUR][2016][01][d1][h19][10]
44
 * [BAT_HOUR][2016][01][d1][h20][10]
45
 * [BAT_HOUR][2016][01][d1][h21][10]
46
 * [BAT_HOUR][2016][01][d1][h22][10]
47
 * [BAT_HOUR][2016][01][d1][h23][10]
48
 *                                    - we don't need to state anything about hours on the 2nd of Jan since the day array is determinant
49
 * [BAT_HOUR][2016][01][d3][h01][10]
50
 * [BAT_HOUR][2016][01][d3][h02][10]
51
 * [BAT_HOUR][2016][01][d3][h03][10]
52
 * [BAT_HOUR][2016][01][d3][h04][10]
53
 * [BAT_HOUR][2016][01][d3][h05][10]
54
 * [BAT_HOUR][2016][01][d3][h06][10]
55
 * [BAT_HOUR][2016][01][d3][h07][10]
56
 * [BAT_HOUR][2016][01][d3][h08][10]
57
 * [BAT_HOUR][2016][01][d3][h09][10]
58
 * [BAT_HOUR][2016][01][d3][h10][10]
59
 * [BAT_HOUR][2016][01][d3][h11][10]
60
 * [BAT_HOUR][2016][01][d3][h12][-1] - The last hour of the event ends at the 10th minute so will need to minute array
61
 *
62
 * [BAT_MINUTE][2016][01][d1][h12][m00][10] - Minutes, which is the maximum granularity, are always determinant
63
 * [BAT_MINUTE][2016][01][d1][h12][m01][10]
64
 * [BAT_MINUTE][2016][01][d1][h12][m02][10]
65
 * [BAT_MINUTE][2016][01][d1][h12][m03][10]
66
 * [BAT_MINUTE][2016][01][d1][h12][m04][10]
67
 * [BAT_MINUTE][2016][01][d1][h12][m05][10]
68
 * [BAT_MINUTE][2016][01][d1][h12][m06][10]
69
 * [BAT_MINUTE][2016][01][d1][h12][m07][10]
70
 * [BAT_MINUTE][2016][01][d1][h12][m08][10]
71
 * [BAT_MINUTE][2016][01][d1][h12][m09][10]
72
 * [BAT_MINUTE][2016][01][d1][h12][m10][10]
73
 *
74
 * [BAT_MINUTE][2016][01][d3][h12][m00][10]
75
 * [BAT_MINUTE][2016][01][d3][h12][m01][10]
76
 * [BAT_MINUTE][2016][01][d3][h12][m02][10]
77
 * [BAT_MINUTE][2016][01][d3][h12][m03][10]
78
 * [BAT_MINUTE][2016][01][d3][h12][m04][10]
79
 * [BAT_MINUTE][2016][01][d3][h12][m05][10]
80
 * [BAT_MINUTE][2016][01][d3][h12][m06][10]
81
 * [BAT_MINUTE][2016][01][d3][h12][m07][10]
82
 * [BAT_MINUTE][2016][01][d3][h12][m08][10]
83
 * [BAT_MINUTE][2016][01][d3][h12][m09][10]
84
 * [BAT_MINUTE][2016][01][d3][h12][m10][10]
85
 *
86
 * Class EventItemizer
87
 * @package Roomify\Bat\Event
88
 */
89
class EventItemizer {
90
91
  const BAT_DAY = 'bat_day';
92
  const BAT_HOUR = 'bat_hour';
93
  const BAT_MINUTE = 'bat_minute';
94
  const BAT_HOURLY = 'bat_hourly';
95
  const BAT_DAILY = 'bat_daily';
96
97
  /**
98
   * @var \Roomify\Bat\Event\EventInterface
99
   */
100
  protected $event;
101
102
  /**
103
   * @var string
104
   */
105
  protected $granularity;
106
107
  public function __construct(EventInterface $event, $granularity = EventItemizer::BAT_HOURLY) {
108
    $this->event = $event;
109
    $this->granularity = $granularity;
110
  }
111
112
  /**
113
   * Transforms the event in a breakdown of days, hours and minutes with associated states.
114
   *
115
   * @param $granularity - string
116
   * @return array
117
   */
118
  public function itemizeEvent($granularity = EventItemizer::BAT_HOURLY) {
119
    // In order to itemize the event we cycle through each day of the event and determine
120
    // what should go in the DAY array to start with. While we could use P1M this created
121
    // problems with months like February (because the period is 30 days) so stepping through
122
    // each day is safer.
123
    $interval = new \DateInterval('P1D');
124
125
    // Set the end date to the last day of the month so that we are sure to get that last month
126
    $adjusted_end_day = new \DateTime($this->event->getEndDate()->format('Y-n-t'));
127
128
    $daterange = new \DatePeriod($this->event->getStartDate(), $interval, $adjusted_end_day);
129
130
    $itemized = array();
131
132
    $old_month = $this->event->getStartDate()->format('Y-n');
133
134
    $start = TRUE;
135
136
    // Cycle through each month
137
    foreach($daterange as $date) {
138
139
      // Check if we have
140
      if  (($date->format('Y-n') != $old_month) || ($start)) {
141
142
        $year = $date->format("Y");
143
        $dayinterval = new \DateInterval('P1D');
144
145
        // Handle the first month
146
        if ($this->event->isFirstMonth($date)) {
147
          // If we are in the same month the end date is the end date of the event
148
          if ($this->event->isSameMonth()) {
149
            $dayrange = new \DatePeriod($this->event->getStartDate(), $dayinterval, new \DateTime($this->event->getEndDate()->format("Y-n-j 23:59:59")));
150
          }
151
          else { // alternatively it is the last day of the start month
152
            $dayrange = new \DatePeriod($this->event->getStartDate(), $dayinterval, $this->event->endMonthDate($this->event->getStartDate()));
153
          }
154 View Code Duplication
          foreach ($dayrange as $day) {
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...
155
            $itemized[EventItemizer::BAT_DAY][$year][$day->format('n')]['d' . $day->format('j')] = $this->event->getValue();
156
          }
157
        }
158
159
        // Handle the last month (will be skipped if event is same month)
160
        elseif ($this->event->isLastMonth($date)) {
161
          $dayrange = new \DatePeriod(new \DateTime($date->format("Y-n-1")), $dayinterval, $this->event->getEndDate());
162 View Code Duplication
          foreach ($dayrange as $day) {
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...
163
            $itemized[EventItemizer::BAT_DAY][$year][$day->format('n')]['d' . $day->format('j')] = $this->event->getValue();
164
          }
165
        }
166
167
        // We are in an in-between month - just cycle through and set dates (time on end date set to ensure it is included)
168
        else {
169
          $dayrange = new \DatePeriod(new \DateTime($date->format("Y-n-1")), $dayinterval, new \DateTime($date->format("Y-n-t 23:59:59")));
170 View Code Duplication
          foreach ($dayrange as $day) {
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...
171
            $itemized[EventItemizer::BAT_DAY][$year][$day->format('n')]['d' . $day->format('j')] = $this->event->getValue();
172
          }
173
        }
174
      }
175
      $start = FALSE;
176
      $old_month = $date->format('Y-n');
177
    }
178
179
    if ($granularity == EventItemizer::BAT_HOURLY) {
180
      // Add granural info in
181
      $itemized = $this->createDayGranural($itemized);
182
    }
183
184
    return $itemized;
185
  }
186
187
  /**
188
   * Based on the start and end dates of the event it creates the appropriate granular events
189
   * and adds them to an array suitable for manipulating easily or storing in the database.
190
   *
191
   * @param array $itemized
192
   * @return array
193
   */
194
  private function createDayGranural($itemized = array()) {
195
    $interval = new \DateInterval('PT1M');
196
197
    $sy = $this->event->getStartDate()->format('Y');
198
    $sm = $this->event->getStartDate()->format('n');
199
    $sd = $this->event->getStartDate()->format('j');
200
201
    $ey = $this->event->getEndDate()->format('Y');
202
    $em = $this->event->getEndDate()->format('n');
203
    $ed = $this->event->getEndDate()->format('j');
204
205
    // Clone the dates otherwise changes will change the event dates themselves
206
    $start_date = clone($this->event->getStartDate());
207
    $end_date = clone($this->event->getEndDate());
208
209
    if ($this->event->isSameDay()) {
210
      if (!($this->event->getEndDate()->format('H:i') == '23:59')) {
211
        $period = new \DatePeriod($start_date, $interval, $end_date->add(new \DateInterval('PT1M')));
212
        $itemized_same_day = $this->createHourlyGranular($period, $start_date);
213
        $itemized[EventItemizer::BAT_DAY][$sy][$sm]['d' . $sd] = -1;
214
        $itemized[EventItemizer::BAT_HOUR][$sy][$sm]['d' . $sd] = $itemized_same_day[EventItemizer::BAT_HOUR][$sy][$sm]['d' . $sd];
215
        $itemized[EventItemizer::BAT_MINUTE][$sy][$sm]['d' . $sd] = $itemized_same_day[EventItemizer::BAT_MINUTE][$sy][$sm]['d' . $sd];
216
      }
217
    }
218
    else {
219
      // Deal with the start day unless it starts on midnight precisely at which point the whole day is booked
220
      if (!($this->event->getStartDate()->format('H:i') == '00:00')) {
221
        $start_period = new \DatePeriod($start_date, $interval, new \DateTime($start_date->format("Y-n-j 23:59:59")));
222
        $itemized_start = $this->createHourlyGranular($start_period, $start_date);
223
        $itemized[EventItemizer::BAT_DAY][$sy][$sm]['d' . $sd] = -1;
224
        $itemized[EventItemizer::BAT_HOUR][$sy][$sm]['d' . $sd] = $itemized_start[EventItemizer::BAT_HOUR][$sy][$sm]['d' . $sd];
225
        $itemized[EventItemizer::BAT_MINUTE][$sy][$sm]['d' . $sd] = $itemized_start[EventItemizer::BAT_MINUTE][$sy][$sm]['d' . $sd];
226
      }
227
      else {
228
        // Just set an empty hour and minute
229
        $itemized[EventItemizer::BAT_HOUR][$sy][$sm]['d' . $sd] = array();
230
        $itemized[EventItemizer::BAT_MINUTE][$sy][$sm]['d' . $sd] = array();
231
      }
232
233
      // Deal with the end date unless it ends just before midnight at which point we don't need to go further
234
      if ($this->event->getEndDate()->format('H:i') == '23:59' ) {
235
        $itemized[EventItemizer::BAT_HOUR][$ey][$em]['d' . $ed] = array();
236
        $itemized[EventItemizer::BAT_MINUTE][$ey][$em]['d' . $ed] = array();
237
      } else {
238
        $end_period = new \DatePeriod(new \DateTime($end_date->format("Y-n-j 00:00:00")), $interval, $end_date->add(new \DateInterval('PT1M')));
239
        $itemized_end = $this->createHourlyGranular($end_period, new \DateTime($end_date->format("Y-n-j 00:00:00")));
240
        $itemized[EventItemizer::BAT_DAY][$ey][$em]['d' . $ed] = -1;
241
        $itemized[EventItemizer::BAT_HOUR][$ey][$em]['d' . $ed] = $itemized_end[EventItemizer::BAT_HOUR][$ey][$em]['d' . $ed];
242
        $itemized[EventItemizer::BAT_MINUTE][$ey][$em]['d' . $ed] = $itemized_end[EventItemizer::BAT_MINUTE][$ey][$em]['d' . $ed];
243
      }
244
    }
245
246
    return $itemized;
247
  }
248
249
  /**
250
   * Given a DatePeriod it transforms it in hours and minutes. Used to break the first and
251
   * last days of an event into more granular events.
252
   *
253
   * @param \DatePeriod $period
254
   * @param \DateTime $period_start
255
   * @return array
256
   */
257
  public function createHourlyGranular(\DatePeriod $period, \DateTime $period_start) {
258
    $itemized = array();
259
260
    $counter = (int)$period_start->format('i');
261
    $start_minute = $counter;
262
    foreach($period as $minute) {
263
      // Doing minutes so set the values in the minute array
264
      $itemized[EventItemizer::BAT_MINUTE][$minute->format('Y')][$minute->format('n')]['d'. $minute->format('j')]['h'. $minute->format('G')]['m' .$minute->format('i')] = $this->event->getValue();
265
      // Let the hours know that it cannot determine availability
266
      $itemized[EventItemizer::BAT_HOUR][$minute->format('Y')][$minute->format('n')]['d'. $minute->format('j')]['h'. $minute->format('G')] = -1;
267
      $counter++;
268
269
      if ($counter == 60 && $start_minute!==0) {
270
        // Not a real hour - leave as is and move on
271
        $counter = 0;
272
        $start_minute = 0;
273
      }
274
      elseif ($counter == 60 && $start_minute == 0) {
275
        // Did a real whole hour so initialize the hour
276
        $itemized[EventItemizer::BAT_HOUR][$minute->format('Y')][$minute->format('n')]['d' . $minute->format('j')]['h' . $minute->format('G')] = $this->event->getValue();
277
        // We have a whole hour so get rid of the minute info
278
        unset($itemized[EventItemizer::BAT_MINUTE][$minute->format('Y')][$minute->format('n')]['d'. $minute->format('j')]['h'. $minute->format('G')]);
279
        $counter = 0;
280
        $start_minute = 0;
281
      }
282
    }
283
284
    return $itemized;
285
  }
286
287
}