Completed
Push — FVSv2 ( c17b7d...6cb237 )
by Patrick
01:37
created

GridSchedule   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 286
Duplicated Lines 2.8 %

Coupling/Cohesion

Components 2
Dependencies 9

Importance

Changes 0
Metric Value
dl 8
loc 286
rs 8.64
c 0
b 0
f 0
wmc 47
lcom 2
cbo 9

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getSimpleHour() 0 16 4
A grayOutUnused() 0 20 4
F createSpreadSheet() 8 163 22
A getBuffer() 0 25 3
A shiftSort() 0 4 1
A groupSort() 0 14 5
B shiftTimeSort() 0 21 7

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

1
<?php
2
namespace Schedules;
3
4
use PhpOffice\PhpSpreadsheet\Spreadsheet;
5
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
6
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
7
8
require_once('../../api/v1/class.Processor.php');
9
10
class GridSchedule
11
{
12
    use ShiftSchedule;
13
    use \Processor;
14
15
    protected $department;
16
    protected $shifts;
17
    protected $ssheat;
18
19
    public function __construct($department, $shifts)
20
    {
21
        $this->department = $department;
22
        $this->shifts = $shifts;
23
        $this->ssheat = $this->createSpreadSheet();
24
    }
25
26
    protected function getSimpleHour($hour)
27
    {
28
        if($hour < 12)
29
        {
30
            if($hour === 0)
31
            {
32
                return '12a';
33
            }
34
            return $hour.'a';
35
        }
36
        if($hour === 12)
37
        {
38
            return $hour.'p';
39
        }
40
        return ($hour - 12).'p';
41
    }
42
43
    protected function grayOutUnused($hourCount, $rowCount, $sheat)
44
    {
45
        for($i = 0; $i < $hourCount; $i++)
46
        {
47
            for($j = 0; $j < $rowCount; $j++)
48
            {
49
                 $cell = $sheat->getCellByColumnAndRow($i+2, $j+4);
50
                 if($cell->isInMergeRange())
51
                 {
52
                      continue;
53
                 }
54
                 else
55
                 {
56
                     $style = $cell->getStyle();
57
                     $style->getBorders()->getAllBorders()->setBorderStyle(false);
58
                     $style->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTGRAY);
59
                 }
60
            }
61
        }
62
    }
63
64
    protected function createSpreadSheet()
65
    {
66
        $shifts = $this->shifts;
67
        $dept = $this->department;
68
        $ssheat = new Spreadsheet();
69
        $sheat = $ssheat->getActiveSheet();
70
        $sheat->setCellValue('A1', $dept['departmentName']);
71
        $count = count($shifts);
72
        $days = array();
73
        $roles = array();
74
        $roles2 = array();
75
        for($i = 0; $i < $count; $i++)
76
        {
77
            $start = new \DateTime($shifts[$i]['startTime']);
78
            $end = new \DateTime($shifts[$i]['endTime']);
79
            $shifts[$i]['startTime'] = $start;
80
            $shifts[$i]['endTime'] = $end;
81
            $startDateStr = $start->format('l (n/j/Y)');
82
            $endDateStr = $end->format('l (n/j/Y)');
83
            $days[$startDateStr] = 1;
84
            $days[$endDateStr] = 1;
85
            $diff = $start->diff($end);
86
            $shifts[$i]['length'] = $diff->h;
87
            if(!isset($roles[$shifts[$i]['roleID']]))
88
            {
89
                 $roles[$shifts[$i]['roleID']] = $shifts[$i]['length'];
90
                 $roles2[$shifts[$i]['roleID']] = array();
91
            }
92
            else
93
            {
94
                 if($roles[$shifts[$i]['roleID']] < $shifts[$i]['length'])
95
                 {
96
                     $roles[$shifts[$i]['roleID']] = $shifts[$i]['length'];
97
                 }
98
            }
99
            array_push($roles2[$shifts[$i]['roleID']], array('start'=>$start, 'end'=>$end));
100
        }
101
        arsort($roles);
102
        usort($shifts, array($this, 'shiftTimeSort'));
103
        $originalStartTime = $shifts[0]['startTime'];
104
        $str = $shifts[0]['startTime']->format('c');
105
        $start = date_parse($str);
106
        $lastShift = $shifts[$count - 1];
107
        $interval = $lastShift['endTime']->diff($shifts[0]['startTime']);
108
        $hourCount = ($interval->d*24) + $interval->h;
109
        $simpleHours = array();
110
        $militaryHours = array();
111
        $hour = $start['hour'];
112
        for($i = 0; $i < $hourCount; $i++)
113
        {
114
            array_push($simpleHours, $this->getSimpleHour($hour));
115
            array_push($militaryHours, $hour.':00');
116
            $hour++;
117
            if($hour === 24)
118
            {
119
                $hour = 0;
120
            }
121
        }
122
        $sheat->fromArray($simpleHours, null, 'B2');
123
        $sheat->fromArray($militaryHours, null, 'B3');
124
        $mergeCount = 24 - $start['hour'];
125
        if($mergeCount > $hourCount)
126
        {
127
            $mergeCount = $hourCount;
128
        }
129
        $days = array_keys($days);
130
        $cellIndex = 2;
131
        while($mergeCount)
132
        {
133
            $sheat->mergeCellsByColumnAndRow($cellIndex, 1, $cellIndex + $mergeCount - 1, 1);
134
            $sheat->setCellValueByColumnAndRow($cellIndex, 1, array_shift($days));
135
            $cell = $sheat->getCellByColumnAndRow($cellIndex, 1);
136
            $cell->getStyle()->getAlignment()->setHorizontal('center');
137
            $cellIndex += $mergeCount;
138
            $hourCount -= $mergeCount;
139
            $mergeCount = $hourCount;
140
            if($mergeCount > 24)
141
            {
142
                $mergeCount = 24;
143
            }
144
        }
145
        $i = 0;
146
        $rows = array();
147
        foreach($roles as $role=>$hour)
148
        {
149
            $sheat->setCellValueByColumnAndRow(1, 4 + $i, $this->getRoleNameFromID($role));
150
            array_push($rows, $role);
151
            $overlaps = array();
152
            for($j = 0; $j < count($roles2[$role]) - 1; $j++)
153
            {
154
                $currRole = $roles2[$role][$j];
155
                $nextRole = $roles2[$role][$j + 1];
156
                if($currRole['end'] > $nextRole['start'])
157
                {
158
                    $str = $currRole['start']->format('c');
159
                    if(!isset($overlaps[$str]))
160
                    {
161
                        $overlaps[$str] = 0;
162
                    }
163
                    $overlaps[$str]++;
164
                }
165
            }
166
            if(!empty($overlaps))
167
            {
168
                $overlapCount = max(array_values($overlaps));
169
                for($j = 0; $j < $overlapCount + 1; $j++)
170
                {
171
                    $i++;
172
                    $sheat->setCellValueByColumnAndRow(1, 4 + $i, $this->getRoleNameFromID($role));
173
                    if($j > 0)
174
                    {
175
                        array_push($rows, $role);
176
                    }
177
                }
178
            }
179
            else
180
            {
181
                $i++;
182
            }
183
        }
184
        $shift = array_shift($shifts);
185
        while($shift)
186
        {
187
            $i = 1;
188
            $timeDiff = $originalStartTime->diff($shift['startTime']);
189
            $hoursFromStart = ($timeDiff->d*24)+$timeDiff->h;
190
            $firstRow = array_search($shift['roleID'], $rows);
191
            $cell = $sheat->getCellByColumnAndRow($hoursFromStart+2, $firstRow+4);
192
            if($cell->isInMergeRange())
193
            {
194
                while($rows[$firstRow+$i] === $shift['roleID'])
195
                {
196
                    $cell = $sheat->getCellByColumnAndRow($hoursFromStart+2, $firstRow+4+$i);
197
                    if(!$cell->isInMergeRange())
198
                    {
199
                        break;
200
                    }
201
                    $i++;
202
                }
203
                $sheat->mergeCellsByColumnAndRow($hoursFromStart+2, $firstRow+4+$i, $hoursFromStart+1+$shift['length'], $firstRow+4+$i);
204 View Code Duplication
                if(isset($shift['participant']))
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
                {
206
                    $sheat->setCellValueByColumnAndRow($hoursFromStart+2, $firstRow+4+$i, $this->getParticipantDiplayName($shift['participant']));
207
                }
208
            }
209
            else
210
            {
211
                $sheat->mergeCellsByColumnAndRow($hoursFromStart+2, $firstRow+4, $hoursFromStart+1+$shift['length'], $firstRow+4);
212 View Code Duplication
                if(isset($shift['participant']))
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
                {
214
                    $sheat->setCellValueByColumnAndRow($hoursFromStart+2, $firstRow+4, $this->getParticipantDiplayName($shift['participant']));
215
                }
216
            }
217
            $shift = array_shift($shifts);
218
        }
219
        $rowCount = count($rows);
220
        $style = $sheat->getStyleByColumnAndRow(2, 4, 1+count($simpleHours), 3 + $rowCount);
221
        $style->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
222
        $hourCount = count($simpleHours);
223
        $this->grayOutUnused($hourCount, $rowCount, $sheat);
224
        $sheat->getColumnDimension('A')->setAutoSize(true);
225
        return $ssheat;
226
    }
227
228
    public function getBuffer($type)
229
    {
230
        if($type === 'XLSX')
231
        {
232
            $writer = new Xlsx($this->ssheat);
233
            $content = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
234
            $extension = '.xlsx';
235
        }
236
        else if($type === 'PDF')
237
        {
238
            $this->ssheat->getActiveSheet()->getPageSetup()->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
239
            $writer = new mpdf($this->ssheat);
240
            $writer->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
241
            $content = 'application/pdf';
242
            $extension = '.pdf';
243
        }
244
        else
245
        {
246
            return array('error'=> true, 'msg'=>'Unknown type specified: '.$type);
247
        }
248
        ob_start();
249
        $writer->save('php://output');
250
        $str = ob_get_clean();
251
        return array('content-type'=>$content, 'extension'=>$extension, 'buffer'=>$str); 
252
    }
253
254
    public function shiftSort($a, $b)
255
    {
256
        return strcmp($this->getRoleNameFromID($a['roleID']), $this->getRoleNameFromID($b['roleID']));
257
    }
258
259
    public function groupSort($a, $b)
260
    {
261
        $aArr = explode(' ', $a);
262
        $bArr = explode(' ', $b);
263
        if($aArr[1] === 'PM' && $bArr[1] === 'AM')
264
        {
265
            return 1;
266
        }
267
        else if($aArr[1] === 'AM' && $bArr[1] === 'PM')
268
        {
269
            return -1;
270
        }
271
        return strcmp($a, $b);
272
    }
273
274
    public function shiftTimeSort($a, $b)
275
    {
276
        $interval = $a['startTime']->diff($b['startTime']);
277
        if($interval->invert === 0)
278
        {
279
            if($interval->h || $interval->i)
280
            {
281
                return -1;
282
            }
283
            else
284
            {
285
                return 0;
286
            }
287
        }
288
        else if($interval->invert === 1 && ($interval->h || $interval->days))
289
        {
290
            return 1;
291
        }
292
        print_r($interval);
293
        die();
294
    }
295
}
296