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

api/v1/class.DepartmentAPI.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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');
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');
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)
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)
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];
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
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)
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