Completed
Push — FVSv2 ( 1cad04...78f5f9 )
by Patrick
01:35
created

DepartmentAPI::generateSimplePDFSchedule()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
use PhpOffice\PhpSpreadsheet\Spreadsheet;
4
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
5
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
6
7
class DepartmentAPI extends Http\Rest\DataTableAPI
8
{
9
    use Processor;
10
11
    protected $isAdmin = null;
12
    protected $isLead = null;
13
14
    public function __construct()
15
    {
16
        parent::__construct('fvs', 'departments', 'departmentID');
0 ignored issues
show
Documentation introduced by
'departmentID' is of type string, but the function expects a boolean.

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...
17
    }
18
19
    public function setup($app)
20
    {
21
        parent::setup($app);
22
        $app->get('/{dept}/roles[/]', array($this, 'getRolesForDepartment'));
23
        $app->post('/{dept}/roles[/]', array($this, 'createRoleForDepartment'));
24
        $app->patch('/{dept}/roles/{roleName}[/]', array($this, 'updateRoleForDepartment'));
25
        $app->get('/{dept}/shifts[/]', array($this, 'getShiftsForDepartment'));
26
        $app->post('/{dept}/shifts[/]', array($this, 'createShiftForDepartment'));
27
        $app->get('/{dept}/shifts/Actions/GenerateShiftSchedule', array($this, 'generateShiftSchedule'));
28
    }
29
30
    protected function isVolunteerAdmin($request)
31
    {
32
        $this->validateLoggedIn($request);
33
        if($this->isAdmin === null)
34
        {
35
            $this->isAdmin = $this->user->isInGroupNamed('VolunteerAdmins');
1 ignored issue
show
Bug introduced by
The property user does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
36
        }
37
        return $this->isAdmin;
38
    }
39
40
    protected function canCreate($request)
41
    {
42
        return $this->isVolunteerAdmin($request);
43
    }
44
45
    protected function canEditDept($request, $deptId, $dept = null)
46
    {
47
        if($this->isVolunteerAdmin($request))
48
        {
49
            return true;
50
        }
51
        if($dept !== null)
52
        {
53
            return $this->isUserDepartmentLead2($dept, $this->user);
54
        }
55
        return $this->isUserDepartmentLead($deptId, $this->user);
56
    }
57
58
    protected function canUpdate($request, $entity)
59
    {
60
        return $this->canEditDept($request, false);
61
    }
62
63
    protected function canDelete($request, $entity)
64
    {
65
        if($this->isVolunteerAdmin($request))
66
        {
67
            return true;
68
        }
69
        return false;
70
    }
71
72
    protected function processEntry($entry, $request)
73
    {
74
        $entry['available'] = true;
75
        $entry['isAdmin'] = $this->canEditDept($request, null, $entry);
76
        if(isset($entry['public']) && $entry['public'] === false)
77
        {
78
            if(!$this->isUserDepartmentLead2($entry, $this->user))
79
            {
80
                $entry['available'] = false;
81
                $entry['why'] = 'Not lead of department';
82
            }
83
            if(!$entry['available'] && !$entry['isAdmin'])
84
            {
85
                return null;
86
            }
87
        }
88
        return $entry;
89
    }
90
91
    public function getRolesForDepartment($request, $response, $args)
92
    {
93
        $deptId = $args['dept'];
94
        if($this->canEditDept($request, $deptId) === false)
95
        {
96
            return $response->withStatus(401);
97
        }
98
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'roles');
99
        $filter = new \Data\Filter("departmentID eq '$deptId'");
100
        $odata = $request->getAttribute('odata', new \ODataParams(array()));
101
        $roles = $dataTable->read($filter, $odata->select, $odata->top,
102
                                  $odata->skip, $odata->orderby);
103
        if($roles === false)
104
        {
105
            $roles = array();
106
        }
107
        $count = count($roles);
108
        for($i = 0; $i < $count; $i++)
109
        {
110
            $roles[$i] = $this->processRole($roles[$i], $request);
111
        }
112
        return $response->withJson($roles);
113
    }
114
115
    public function getShiftsForDepartment($request, $response, $args)
116
    {
117
        $deptId = $args['dept'];
118
        if($this->canEditDept($request, $deptId) === false)
119
        {
120
            return $response->withStatus(401);
121
        }
122
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'shifts');
123
        $filter = new \Data\Filter("departmentID eq '$deptId'");
124
        $odata = $request->getAttribute('odata', new \ODataParams(array()));
125
        $shifts = $dataTable->read($filter, $odata->select, $odata->top,
126
                                  $odata->skip, $odata->orderby);
127
        if($shifts === false)
128
        {
129
            $shifts = array();
130
        }
131
        return $response->withJson($shifts);
132
    }
133
134 View Code Duplication
    public function createRoleForDepartment($request, $response, $args)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in 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...
135
    {
136
        $deptId = $args['dept'];
137
        if($this->canEditDept($request, $deptId) === false)
138
        {
139
            return $response->withStatus(401);
140
        }
141
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'roles');
142
        $obj = $request->getParsedBody();
143
        if($obj == NULL)
144
        {
145
            $obj = json_decode($request->getBody()->getContents(), true);
146
        }
147
        $obj['departmentID'] = $deptId;
148
        $ret = $dataTable->create($obj);
149
        return $response->withJson($ret);
150
    }
151
152 View Code Duplication
    public function createShiftForDepartment($request, $response, $args)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
153
    {
154
        $deptId = $args['dept'];
155
        if($this->canEditDept($request, $deptId) === false)
156
        {
157
            return $response->withStatus(401);
158
        }
159
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'shifts');
160
        $obj = $request->getParsedBody();
161
        if($obj == NULL)
162
        {
163
            $obj = json_decode($request->getBody()->getContents(), true);
164
        }
165
        $obj['departmentID'] = $deptId;
166
        $ret = $dataTable->create($obj);
167
        return $response->withJson($ret);
168
    }
169
170
    public function updateRoleForDepartment($request, $response, $args)
171
    {
172
        $deptId = $args['dept'];
173
        $roleId = $args['roleName'];
174
        if($this->canEditDept($request, $deptId) === false)
175
        {
176
            return $response->withStatus(401);
177
        }
178
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'roles');
179
        $filter = new \Data\Filter("departmentID eq '$deptId' and short_name eq '$roleId'");
180
        $entry = $dataTable->read($filter);
181
        if(empty($entry))
182
        {
183
            return $response->withStatus(404);
184
        }
185
        if(count($entry) === 1 && isset($entry[0]))
186
        {
187
            $entry = $entry[0];
0 ignored issues
show
Unused Code introduced by
$entry 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...
188
        }
189
        $obj = $request->getParsedBody();
190
        if($obj === null)
191
        {
192
            $request->getBody()->rewind();
193
            $obj = $request->getBody()->getContents();
194
            $tmp = json_decode($obj, true);
195
            if($tmp !== null)
196
            {
197
                $obj = $tmp;
198
            }
199
        }
200
        $ret = $dataTable->update($filter, $obj);
201
        return $response->withJson($ret);
202
    }
203
204
    public function generateShiftSchedule($request, $response, $args)
205
    {
206
        $deptId = $args['dept'];
207
        if($this->canEditDept($request, $deptId) === false)
208
        {
209
            return $response->withStatus(401);
210
        }
211
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'departments');
212
        $depts = $dataTable->read(new \Data\Filter('departmentID eq '.$deptId));
213
        if(empty($depts))
214
        {
215
            return $response->withStatus(404);
216
        }
217
        $dataTable = DataSetFactory::getDataTableByNames('fvs', 'shifts');
218
        $eventId = $request->getParam('eventID');
219
        $filter = new \Data\Filter('eventID eq '.$eventId.' and departmentID eq '.$deptId);
220
        $shifts = $dataTable->read($filter);
221
        if(empty($shifts))
222
        {
223
            return $response->withStatus(404);
224
        }
225
        switch($request->getParam('type'))
226
        {
227
            case 'simplePDF':
228
               return $this->generateSimplePDFSchedule($depts[0], $shifts, $response);
229
            case 'gridXLSX':
230
               return $this->generateGridSchedule($depts[0], $shifts, $request, $response, 'XLSX');
231
            case 'gridPDF':
232
               return $this->generateGridSchedule($depts[0], $shifts, $request, $response, 'PDF');
233
        }
234
        return $response->withJson($shifts);
235
    }
236
237 View Code Duplication
    public function getRoleNameFromID($roleID)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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
    {
239
        static $roles = null;
240
        if($roles === null)
241
        {
242
            $dataTable = DataSetFactory::getDataTableByNames('fvs', 'roles');
243
            $tmp = $dataTable->read();
244
            $roles = array();
245
            $count = count($tmp);
246
            for($i = 0; $i < $count; $i++)
247
            {
248
                if(isset($tmp[$i]['display_name']))
249
                {
250
                    $roles[$tmp[$i]['short_name']] = $tmp[$i]['display_name'];
251
                }
252
                else
253
                {
254
                    $roles[$tmp[$i]['short_name']] = $tmp[$i]['short_name'];
255
                }
256
            }
257
        }
258
        return $roles[$roleID];
259
    }
260
261
    public function generateSimplePDFSchedule($dept, $shifts, $response)
262
    {
263
        $pdf = new \Schedules\SimplePDF($dept, $shifts);
264
        $response = $response->withHeader('Content-Type', 'application/pdf');
265
        $response->getBody()->write($pdf->toPDFBuffer());
266
        return $response;
267
    }
268
269
    public function generateGridSchedule($dept, $shifts, $request, $response, $type)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
270
    {
271
        $ssheat = new Spreadsheet();
272
        $sheat = $ssheat->getActiveSheet();
273
        $sheat->setCellValue('A1', $dept['departmentName']);
274
        $count = count($shifts);
275
        $days = array();
276
        $roles = array();
277
        $roles2 = array();
278
        for($i = 0; $i < $count; $i++)
279
        {
280
            $start = new DateTime($shifts[$i]['startTime']);
281
            $end = new DateTime($shifts[$i]['endTime']);
282
            $shifts[$i]['startTime'] = $start;
283
            $shifts[$i]['endTime'] = $end;
284
            $startDateStr = $start->format('l (n/j/Y)');
285
            $endDateStr = $end->format('l (n/j/Y)');
286
            $days[$startDateStr] = 1;
287
            $days[$endDateStr] = 1;
288
            $diff = $start->diff($end);
289
            $shifts[$i]['length'] = $diff->h;
290
            if(!isset($roles[$shifts[$i]['roleID']]))
291
            {
292
                 $roles[$shifts[$i]['roleID']] = $shifts[$i]['length'];
293
                 $roles2[$shifts[$i]['roleID']] = array();
294
            }
295
            else
296
            {
297
                 if($roles[$shifts[$i]['roleID']] < $shifts[$i]['length'])
298
                 {
299
                     $roles[$shifts[$i]['roleID']] = $shifts[$i]['length'];
300
                 }
301
            }
302
            array_push($roles2[$shifts[$i]['roleID']], array('start'=>$start, 'end'=>$end));
303
        }
304
        arsort($roles);
305
        usort($shifts, array($this, 'shiftTimeSort'));
306
        $originalStartTime = $shifts[0]['startTime'];
307
        $str = $shifts[0]['startTime']->format('c');
308
        $start = date_parse($str);
309
        $lastShift = $shifts[$count - 1];
310
        $interval = $lastShift['endTime']->diff($shifts[0]['startTime']);
311
        $hourCount = ($interval->d*24) + $interval->h;
312
        $simpleHours = array();
313
        $militaryHours = array();
314
        $hour = $start['hour'];
315
        for($i = 0; $i < $hourCount; $i++)
316
        {
317
            if($hour < 12)
318
            {
319
                if($hour === 0)
320
                {
321
                    array_push($simpleHours, '12a');
322
                }
323
                else
324
                {
325
                    array_push($simpleHours, $hour.'a');
326
                }
327
            }
328
            else
329
            {
330
                if($hour === 12)
331
                {
332
                    array_push($simpleHours, $hour.'p');
333
                }
334
                else
335
                {
336
                    array_push($simpleHours, ($hour - 12).'p');
337
                }
338
            }
339
            array_push($militaryHours, $hour.':00');
340
            $hour++;
341
            if($hour === 24)
342
            {
343
                $hour = 0;
344
            }
345
        }
346
        $sheat->fromArray($simpleHours, null, 'B2');
347
        $sheat->fromArray($militaryHours, null, 'B3');
348
        $mergeCount = 24 - $start['hour'];
349
        if($mergeCount > $hourCount)
350
        {
351
            $mergeCount = $hourCount;
352
        }
353
        $days = array_keys($days);
354
        $cellIndex = 2;
355
        while($mergeCount)
356
        {
357
            $sheat->mergeCellsByColumnAndRow($cellIndex, 1, $cellIndex + $mergeCount - 1, 1);
358
            $sheat->setCellValueByColumnAndRow($cellIndex, 1, array_shift($days));
359
            $cell = $sheat->getCellByColumnAndRow($cellIndex, 1);
360
            $cell->getStyle()->getAlignment()->setHorizontal('center');
361
            $cellIndex += $mergeCount;
362
            $hourCount -= $mergeCount;
363
            $mergeCount = $hourCount;
364
            if($mergeCount > 24)
365
            {
366
                $mergeCount = 24;
367
            }
368
        }
369
        $i = 0;
370
        $rows = array();
371
        foreach($roles as $role=>$hour)
372
        {
373
            $sheat->setCellValueByColumnAndRow(1, 4 + $i, $this->getRoleNameFromID($role));
374
            array_push($rows, $role);
375
            $overlaps = array();
376
            for($j = 0; $j < count($roles2[$role]) - 1; $j++)
377
            {
378
                $currRole = $roles2[$role][$j];
379
                $nextRole = $roles2[$role][$j + 1];
380
                if($currRole['end'] > $nextRole['start'])
381
                {
382
                    $str = $currRole['start']->format('c');
383
                    if(!isset($overlaps[$str]))
384
                    {
385
                        $overlaps[$str] = 0;
386
                    }
387
                    $overlaps[$str]++;
388
                }
389
            }
390
            if(!empty($overlaps))
391
            {
392
                $overlapCount = max(array_values($overlaps));
393
                for($j = 0; $j < $overlapCount + 1; $j++)
394
                {
395
                    $i++;
396
                    $sheat->setCellValueByColumnAndRow(1, 4 + $i, $this->getRoleNameFromID($role));
397
                    if($j > 0)
398
                    {
399
                        array_push($rows, $role);
400
                    }
401
                }
402
            }
403
            else
404
            {
405
                $i++;
406
            }
407
        }
408
        $shift = array_shift($shifts);
409
        while($shift)
410
        {
411
            $i = 1;
412
            $timeDiff = $originalStartTime->diff($shift['startTime']);
413
            $hoursFromStart = ($timeDiff->d*24)+$timeDiff->h;
414
            $firstRow = array_search($shift['roleID'], $rows);
415
            $cell = $sheat->getCellByColumnAndRow($hoursFromStart+2, $firstRow+4);
416
            if($cell->isInMergeRange())
417
            {
418
                while($rows[$firstRow+$i] === $shift['roleID'])
419
                {
420
                    $cell = $sheat->getCellByColumnAndRow($hoursFromStart+2, $firstRow+4+$i);
421
                    if(!$cell->isInMergeRange())
422
                    {
423
                        break;
424
                    }
425
                    $i++;
426
                }
427
                $sheat->mergeCellsByColumnAndRow($hoursFromStart+2, $firstRow+4+$i, $hoursFromStart+1+$shift['length'], $firstRow+4+$i);
428
            }
429
            else
430
            {
431
                $sheat->mergeCellsByColumnAndRow($hoursFromStart+2, $firstRow+4, $hoursFromStart+1+$shift['length'], $firstRow+4);
432
            }
433
            $shift = array_shift($shifts);
434
        }
435
        $rowCount = count($rows);
436
        $style = $sheat->getStyleByColumnAndRow(2, 4, 1+count($simpleHours), 3 + $rowCount);
437
        $style->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
438
        $hourCount = count($simpleHours);
439
        for($i = 0; $i < $hourCount; $i++)
440
        {
441
            for($j = 0; $j < $rowCount; $j++)
442
            {
443
                 $cell = $sheat->getCellByColumnAndRow($i+2, $j+4);
444
                 if($cell->isInMergeRange())
445
                 {
446
                      continue;
447
                 }
448
                 else
449
                 {
450
                     $style = $cell->getStyle();
451
                     $style->getBorders()->getAllBorders()->setBorderStyle(false);
452
                     $style->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_PATTERN_LIGHTGRAY);
453
                 }
454
            }
455
        }
456
        $sheat->getColumnDimension('A')->setAutoSize(true);
457
        if($type === 'XLSX')
458
        {
459
            $writer = new Xlsx($ssheat);
460
            $content = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
461
            $extension = '.xlsx';
462
        }
463
        else if($type === 'PDF')
464
        {
465
            $sheat->getPageSetup()->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
466
            $writer = new mpdf($ssheat);
467
            $writer->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
468
            $content = 'application/pdf';
469
            $extension = '.pdf';
470
        }
471
        else
472
        {
473
            return $response->withJson(array('msg'=>'Unknown type specified: '.$type), 400);
474
        }
475
        ob_start();
476
        $writer->save('php://output');
477
        $str = ob_get_clean();
478
        $response = $response->withHeader('Content-Type', $content);
479
        $response = $response->withHeader('Content-Disposition', 'attachment; filename='.$dept['departmentName'].$extension);
480
        $response->getBody()->write($str);
481
        return $response;
482
    }
483
484
    public function shiftSort($a, $b)
485
    {
486
        return strcmp($this->getRoleNameFromID($a['roleID']), $this->getRoleNameFromID($b['roleID']));
487
    }
488
489
    public function groupSort($a, $b)
490
    {
491
        $aArr = explode(' ', $a);
492
        $bArr = explode(' ', $b);
493
        if($aArr[1] === 'PM' && $bArr[1] === 'AM')
494
        {
495
            return 1;
496
        }
497
        else if($aArr[1] === 'AM' && $bArr[1] === 'PM')
498
        {
499
            return -1;
500
        }
501
        return strcmp($a, $b);
502
    }
503
504
    public function shiftTimeSort($a, $b)
505
    {
506
        $interval = $a['startTime']->diff($b['startTime']);
507
        if($interval->invert === 0)
508
        {
509
            if($interval->h || $interval->i)
510
            {
511
                return -1;
512
            }
513
            else
514
            {
515
                return 0;
516
            }
517
        }
518
        else if($interval->invert === 1 && $interval->h)
519
        {
520
            return 1;
521
        }
522
        print_r($interval);
523
        die();
524
    }
525
}
526
527