Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

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.

CalendarController::getDayLinksText()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 10
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 18
rs 9.9332
1
<?php
2
3
/**
4
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
5
 *
6
 * This file is part of the Kitodo and TYPO3 projects.
7
 *
8
 * @license GNU General Public License version 3 or later.
9
 * For the full copyright and license information, please read the
10
 * LICENSE.txt file that was distributed with this source code.
11
 */
12
13
namespace Kitodo\Dlf\Controller;
14
15
use Generator;
16
use Kitodo\Dlf\Domain\Model\Document;
17
use Kitodo\Dlf\Domain\Repository\StructureRepository;
18
use Psr\Http\Message\ResponseInterface;
19
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
20
21
/**
22
 * Controller class for the plugin 'Calendar'.
23
 *
24
 * @package TYPO3
25
 * @subpackage dlf
26
 *
27
 * @access public
28
 */
29
class CalendarController extends AbstractController
30
{
31
    /**
32
     * @access protected
33
     * @var StructureRepository
34
     */
35
    protected StructureRepository $structureRepository;
36
37
    /**
38
     * @access public
39
     *
40
     * @param StructureRepository $structureRepository
41
     *
42
     * @return void
43
     */
44
    public function injectStructureRepository(StructureRepository $structureRepository): void
45
    {
46
        $this->structureRepository = $structureRepository;
47
    }
48
49
    /**
50
     * @access protected
51
     * @var array This holds all issues for the list view.
52
     */
53
    protected array $allIssues = [];
54
55
    /**
56
     * The main method of the plugin
57
     *
58
     * @access public
59
     *
60
     * @return ResponseInterface the response
61
     */
62
    public function mainAction(): ResponseInterface
63
    {
64
        // Set initial document (anchor or year file) if configured.
65
        if (empty($this->requestData['id']) && !empty($this->settings['initialDocument'])) {
66
            $this->requestData['id'] = $this->settings['initialDocument'];
67
        }
68
69
        // Load current document.
70
        $this->loadDocument();
71
        if ($this->isDocMissing()) {
72
            // Quit without doing anything if required variables are not set.
73
            return $this->htmlResponse();
74
        }
75
76
        $metadata = $this->document->getCurrentDocument()->getToplevelMetadata();
77
        if (!empty($metadata['type'][0])) {
78
            $type = $metadata['type'][0];
79
        } else {
80
            return $this->htmlResponse();
81
        }
82
83
        switch ($type) {
84
            case 'newspaper':
85
            case 'ephemera':
86
                return $this->redirect('years', null, null, $this->requestData);
87
            case 'year':
88
                return $this->redirect('calendar', null, null, $this->requestData);
89
            case 'issue':
90
            default:
91
                break;
92
        }
93
94
        return $this->htmlResponse();
95
    }
96
97
    /**
98
     * The Calendar Method
99
     *
100
     * @access public
101
     *
102
     * @return ResponseInterface the response
103
     */
104
    public function calendarAction(): ResponseInterface
105
    {
106
        // access arguments passed by the mainAction()
107
        $mainRequestData = $this->request->getArguments();
108
109
        // merge both arguments together --> passing id by GET parameter tx_dlf[id] should win
110
        $this->requestData = array_merge($this->requestData, $mainRequestData);
111
112
        // Load current document.
113
        $this->loadDocument();
114
        if ($this->isDocMissing()) {
115
            // Quit without doing anything if required variables are not set.
116
            return $this->htmlResponse();
117
        }
118
119
        $calendarData = $this->buildCalendar();
120
121
        // Prepare list as alternative view.
122
        $issueData = [];
123
        foreach ($this->allIssues as $dayTimestamp => $issues) {
124
            $issueData[$dayTimestamp]['dateString'] = strftime('%A, %x', $dayTimestamp);
125
            $issueData[$dayTimestamp]['items'] = [];
126
            foreach ($issues as $issue) {
127
                $issueData[$dayTimestamp]['items'][] = $issue;
128
            }
129
        }
130
        $this->view->assign('issueData', $issueData);
131
132
        // Link to current year.
133
        $linkTitleData = $this->document->getCurrentDocument()->getToplevelMetadata();
134
        $yearLinkTitle = !empty($linkTitleData['mets_orderlabel'][0]) ? $linkTitleData['mets_orderlabel'][0] : $linkTitleData['mets_label'][0];
135
136
        $this->view->assign('calendarData', $calendarData);
137
        $this->view->assign('documentId', $this->document->getUid());
138
        $this->view->assign('yearLinkTitle', $yearLinkTitle);
139
        $this->view->assign('parentDocumentId', $this->document->getPartof() ?: $this->document->getCurrentDocument()->tableOfContents[0]['points']);
140
        $this->view->assign('allYearDocTitle', $this->document->getCurrentDocument()->getTitle($this->document->getPartof()) ?: $this->document->getCurrentDocument()->tableOfContents[0]['label']);
141
142
        return $this->htmlResponse();
143
    }
144
145
    /**
146
     * The Years Method
147
     *
148
     * @access public
149
     *
150
     * @return ResponseInterface the response
151
     */
152
    public function yearsAction(): ResponseInterface
153
    {
154
        // access arguments passed by the mainAction()
155
        $mainRequestData = $this->request->getArguments();
156
157
        // merge both arguments together --> passing id by GET parameter tx_dlf[id] should win
158
        $this->requestData = array_merge($this->requestData, $mainRequestData);
159
160
        // Load current document.
161
        $this->loadDocument();
162
        if ($this->isDocMissing()) {
163
            // Quit without doing anything if required variables are not set.
164
            return $this->htmlResponse();
165
        }
166
167
        // Get all children of anchor. This should be the year anchor documents
168
        $documents = $this->documentRepository->getChildrenOfYearAnchor($this->document->getUid(), $this->structureRepository->findOneByIndexName('year'));
0 ignored issues
show
Bug introduced by
The method findOneByIndexName() does not exist on Kitodo\Dlf\Domain\Repository\StructureRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

168
        $documents = $this->documentRepository->getChildrenOfYearAnchor($this->document->getUid(), $this->structureRepository->/** @scrutinizer ignore-call */ findOneByIndexName('year'));
Loading history...
169
170
        $years = [];
171
        // Process results.
172
        if (count($documents) === 0) {
173
            foreach ($this->document->getCurrentDocument()->tableOfContents[0]['children'] as $id => $year) {
174
                $yearLabel = empty($year['label']) ? $year['orderlabel'] : $year['label'];
175
176
                if (empty($yearLabel)) {
177
                    // if neither order nor orderlabel is set, use the id...
178
                    $yearLabel = (string) $id;
179
                }
180
181
                $years[] = [
182
                    'title' => $yearLabel,
183
                    'uid' => $year['points'],
184
                ];
185
            }
186
        } else {
187
            /** @var Document $document */
188
            foreach ($documents as $document) {
189
                $years[] = [
190
                    'title' => !empty($document->getMetsLabel()) ? $document->getMetsLabel() : (!empty($document->getMetsOrderlabel()) ? $document->getMetsOrderlabel() : $document->getTitle()),
191
                    'uid' => $document->getUid()
192
                ];
193
            }
194
        }
195
196
        $yearArray = [];
197
        if (count($years) > 0) {
198
            foreach ($years as $year) {
199
                $yearArray[] = [
200
                    'documentId' => $year['uid'],
201
                    'title' => $year['title']
202
                ];
203
            }
204
            // create an array that includes years without issues
205
            if (!empty($this->settings['showEmptyYears'])) {
206
                $yearFilled = [];
207
                $min = $yearArray[0]['title'];
208
                // round the starting decade down to zero for equal rows
209
                $min = (int) substr_replace($min, "0", -1);
210
                $max = (int) $yearArray[count($yearArray) - 1]['title'];
211
                // if we have an actual documentId it should be used, otherwise leave empty
212
                for ($i = 0; $i < $max - $min + 1; $i++) {
213
                    $key = array_search($min + $i, array_column($yearArray, 'title'));
214
                    if (is_int($key)) {
215
                        $yearFilled[] = $yearArray[$key];
216
                    } else {
217
                        $yearFilled[] = ['title' => $min + $i, 'documentId' => ''];
218
                    }
219
                }
220
                $yearArray = $yearFilled;
221
            }
222
223
            $this->view->assign('yearName', $yearArray);
224
        }
225
226
        $this->view->assign('documentId', $this->document->getUid());
227
        $this->view->assign('allYearDocTitle', $this->document->getCurrentDocument()->getTitle((int) $this->document->getUid()) ?: $this->document->getCurrentDocument()->tableOfContents[0]['label']);
228
229
        return $this->htmlResponse();
230
    }
231
232
    /**
233
     * Build calendar for a certain year
234
     *
235
     * @access protected
236
     *
237
     * @param array $calendarData Output array containing the result calendar data that is passed to Fluid template
238
     * @param array $calendarIssuesByMonth All issues sorted by month => day
239
     * @param int $year Gregorian year
240
     * @param int $firstMonth 1 for January, 2 for February, ... 12 for December
241
     * @param int $lastMonth 1 for January, 2 for February, ... 12 for December
242
     *
243
     * @return void
244
     */
245
    protected function getCalendarYear(array &$calendarData, array $calendarIssuesByMonth, int $year, int $firstMonth = 1, int $lastMonth = 12): void
246
    {
247
        for ($i = $firstMonth; $i <= $lastMonth; $i++) {
248
            $key = $year . '-' . $i;
249
250
            $calendarData[$key] = [
251
                'DAYMON_NAME' => strftime('%a', strtotime('last Monday')),
252
                'DAYTUE_NAME' => strftime('%a', strtotime('last Tuesday')),
253
                'DAYWED_NAME' => strftime('%a', strtotime('last Wednesday')),
254
                'DAYTHU_NAME' => strftime('%a', strtotime('last Thursday')),
255
                'DAYFRI_NAME' => strftime('%a', strtotime('last Friday')),
256
                'DAYSAT_NAME' => strftime('%a', strtotime('last Saturday')),
257
                'DAYSUN_NAME' => strftime('%a', strtotime('last Sunday')),
258
                'MONTHNAME'  => strftime('%B', strtotime($year . '-' . $i . '-1')) . ' ' . $year,
259
                'CALYEAR' => ($i == $firstMonth) ? $year : ''
260
            ];
261
262
            $firstOfMonth = strtotime($year . '-' . $i . '-1');
263
            $lastOfMonth = strtotime('last day of', ($firstOfMonth));
264
            $firstOfMonthStart = strtotime('last Monday', $firstOfMonth);
265
            // There are never more than 6 weeks in a month.
266
            for ($j = 0; $j <= 5; $j++) {
267
                $firstDayOfWeek = strtotime('+ ' . $j . ' Week', $firstOfMonthStart);
268
269
                $calendarData[$key]['week'][$j] = [
270
                    'DAYMON' => ['dayValue' => '&nbsp;'],
271
                    'DAYTUE' => ['dayValue' => '&nbsp;'],
272
                    'DAYWED' => ['dayValue' => '&nbsp;'],
273
                    'DAYTHU' => ['dayValue' => '&nbsp;'],
274
                    'DAYFRI' => ['dayValue' => '&nbsp;'],
275
                    'DAYSAT' => ['dayValue' => '&nbsp;'],
276
                    'DAYSUN' => ['dayValue' => '&nbsp;'],
277
                ];
278
                // Every week has seven days. ;-)
279
                for ($k = 0; $k <= 6; $k++) {
280
                    $currentDayTime = strtotime('+ ' . $k . ' Day', $firstDayOfWeek);
281
                    if (
282
                        $currentDayTime >= $firstOfMonth
283
                        && $currentDayTime <= $lastOfMonth
284
                    ) {
285
                        $dayLinks = '';
286
                        $dayLinksText = [];
287
                        $dayLinkDiv = [];
288
                        $currentMonth = date('n', $currentDayTime);
289
                        if (is_array($calendarIssuesByMonth[$currentMonth])) {
290
                            foreach ($calendarIssuesByMonth[$currentMonth] as $id => $day) {
291
                                if ($id == date('j', $currentDayTime)) {
292
                                    $dayLinks = $id;
293
                                    $dayLinksText = array_merge($dayLinksText, $this->getDayLinksText($day, $currentDayTime));
294
                                }
295
                            }
296
                            $dayLinkDiv = $dayLinksText;
297
                        }
298
                        $this->fillCalendar($calendarData[$key]['week'][$j], $currentDayTime, $dayLinks, $dayLinkDiv, $firstDayOfWeek, $k);
299
                    }
300
                }
301
            }
302
        }
303
    }
304
305
    /**
306
     * Get text links for given day.
307
     *
308
     * @access private
309
     *
310
     * @param array $day all issues for given day
311
     * @param int $currentDayTime
312
     *
313
     * @return array all issues for given day as text links
314
     */
315
    private function getDayLinksText(array $day, int $currentDayTime): array
316
    {
317
        $dayLinksText = [];
318
        foreach ($day as $issue) {
319
            $dayLinkLabel = empty($issue['title']) ? strftime('%x', $currentDayTime) : $issue['title'];
320
321
            $dayLinksText[] = [
322
                'documentId' => $issue['uid'],
323
                'text' => $dayLinkLabel
324
            ];
325
326
            // Save issue for list view.
327
            $this->allIssues[$currentDayTime][] = [
328
                'documentId' => $issue['uid'],
329
                'text' => $dayLinkLabel
330
            ];
331
        }
332
        return $dayLinksText;
333
    }
334
335
    /**
336
     * Fill calendar.
337
     *
338
     * @access private
339
     *
340
     * @param array &$calendarData calendar passed by reference
341
     * @param int $currentDayTime
342
     * @param string $dayLinks
343
     * @param array $dayLinkDiv
344
     * @param int $firstDayOfWeek
345
     * @param int $k
346
     *
347
     * @return void
348
     */
349
    private function fillCalendar(array &$calendarData, int $currentDayTime, string $dayLinks, array $dayLinkDiv, int $firstDayOfWeek, int $k): void
350
    {
351
        switch (strftime('%w', strtotime('+ ' . $k . ' Day', $firstDayOfWeek))) {
352
            case '0':
353
                $this->fillDay($calendarData, $currentDayTime, 'DAYSUN', $dayLinks, $dayLinkDiv);
354
                break;
355
            case '1':
356
                $this->fillDay($calendarData, $currentDayTime, 'DAYMON', $dayLinks, $dayLinkDiv);
357
                break;
358
            case '2':
359
                $this->fillDay($calendarData, $currentDayTime, 'DAYTUE', $dayLinks, $dayLinkDiv);
360
                break;
361
            case '3':
362
                $this->fillDay($calendarData, $currentDayTime, 'DAYWED', $dayLinks, $dayLinkDiv);
363
                break;
364
            case '4':
365
                $this->fillDay($calendarData, $currentDayTime, 'DAYTHU', $dayLinks, $dayLinkDiv);
366
                break;
367
            case '5':
368
                $this->fillDay($calendarData, $currentDayTime, 'DAYFRI', $dayLinks, $dayLinkDiv);
369
                break;
370
            case '6':
371
                $this->fillDay($calendarData, $currentDayTime, 'DAYSAT', $dayLinks, $dayLinkDiv);
372
                break;
373
        }
374
    }
375
376
    /**
377
     * Fill day.
378
     *
379
     * @access private
380
     *
381
     * @param array &$calendarData calendar passed by reference
382
     * @param int $currentDayTime
383
     * @param string $day
384
     * @param string $dayLinks
385
     * @param array $dayLinkDiv
386
     *
387
     * @return void
388
     */
389
    private function fillDay(array &$calendarData, int $currentDayTime, string $day, string $dayLinks, array $dayLinkDiv): void
390
    {
391
        $calendarData[$day]['dayValue'] = strftime('%d', $currentDayTime);
392
        if ((int) $dayLinks === (int) date('j', $currentDayTime)) {
393
            $calendarData[$day]['issues'] = $dayLinkDiv;
394
        }
395
    }
396
397
    /**
398
     * Build calendar for year (default) or season.
399
     *
400
     * @access private
401
     *
402
     * @return array
403
     */
404
    private function buildCalendar(): array
405
    {
406
        $issuesByYear = $this->getIssuesByYear();
407
408
        $calendarData = [];
409
        $iteration = 1;
410
        foreach ($issuesByYear as $year => $issuesByMonth) {
411
            // Sort by months.
412
            ksort($issuesByMonth);
413
            // Default: First month is January, last month is December.
414
            $firstMonth = 1;
415
            $lastMonth = 12;
416
            // Show calendar from first issue up to end of season if applicable.
417
            if (
418
                empty($this->settings['showEmptyMonths'])
419
                && count($issuesByYear) > 1
420
            ) {
421
                if ($iteration == 1) {
422
                    $firstMonth = (int) key($issuesByMonth);
423
                } elseif ($iteration == count($issuesByYear)) {
424
                    end($issuesByMonth);
425
                    $lastMonth = (int) key($issuesByMonth);
426
                }
427
            }
428
            $this->getCalendarYear($calendarData, $issuesByMonth, $year, $firstMonth, $lastMonth);
429
            $iteration++;
430
        }
431
432
        return $calendarData;
433
    }
434
435
    /**
436
     * Get issues by year
437
     *
438
     * @access private
439
     *
440
     * @return array
441
     */
442
    private function getIssuesByYear(): array
443
    {
444
        //  We need an array of issues with year => month => day number as key.
445
        $issuesByYear = [];
446
447
        foreach ($this->getIssues() as $issue) {
448
            $dateTimestamp = strtotime($issue['year']);
449
            if ($dateTimestamp !== false) {
450
                $_year = date('Y', $dateTimestamp);
451
                $_month = date('n', $dateTimestamp);
452
                $_day = date('j', $dateTimestamp);
453
                $issuesByYear[$_year][$_month][$_day][] = $issue;
454
            } else {
455
                $this->logger->warning('Document with UID ' . $issue['uid'] . 'has no valid date of publication');
456
            }
457
        }
458
        // Sort by years.
459
        ksort($issuesByYear);
460
461
        return $issuesByYear;
462
    }
463
464
    /**
465
     * Gets issues from table of contents or documents.
466
     *
467
     * @access private
468
     *
469
     * @return Generator
470
     */
471
    private function getIssues(): Generator
472
    {
473
        $documents = $this->documentRepository->getChildrenOfYearAnchor($this->document->getUid(), $this->structureRepository->findOneByIndexName('issue'));
0 ignored issues
show
Bug introduced by
The method getUid() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

473
        $documents = $this->documentRepository->getChildrenOfYearAnchor($this->document->/** @scrutinizer ignore-call */ getUid(), $this->structureRepository->findOneByIndexName('issue'));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
474
475
        // Process results.
476
        if ($documents->count() === 0) {
477
            return $this->getIssuesFromTableOfContents();
478
        }
479
480
        return $this->getIssuesFromDocuments($documents);
481
    }
482
483
    /**
484
     * Gets issues from table of contents.
485
     *
486
     * @access private
487
     *
488
     * @return Generator
489
     */
490
    private function getIssuesFromTableOfContents(): Generator
491
    {
492
        $toc = $this->document->getCurrentDocument()->tableOfContents;
493
494
        foreach ($toc[0]['children'] as $year) {
495
            foreach ($year['children'] as $month) {
496
                foreach ($month['children'] as $day) {
497
                    foreach ($day['children'] as $issue) {
498
                        $title = $issue['label'] ?: $issue['orderlabel'];
499
                        if (strtotime($title) !== false) {
500
                            $title = strftime('%x', strtotime($title));
501
                        }
502
503
                        yield [
504
                            'uid' => $issue['points'],
505
                            'title' => $title,
506
                            'year' => $day['orderlabel'],
507
                        ];
508
                    }
509
                }
510
            }
511
        }
512
    }
513
514
    /**
515
     * Gets issues from documents.
516
     *
517
     * @access private
518
     *
519
     * @param array|QueryResultInterface $documents to create issues
520
     *
521
     * @return Generator
522
     */
523
    private function getIssuesFromDocuments($documents): Generator
524
    {
525
        /** @var Document $document */
526
        foreach ($documents as $document) {
527
            // Set title for display in calendar view.
528
            if (!empty($document->getTitle())) {
529
                $title = $document->getTitle();
530
            } else {
531
                $title = !empty($document->getMetsLabel()) ? $document->getMetsLabel() : $document->getMetsOrderlabel();
532
                if (strtotime($title) !== false) {
533
                    $title = strftime('%x', strtotime($title));
534
                }
535
            }
536
            yield [
537
                'uid' => $document->getUid(),
538
                'title' => $title,
539
                'year' => $document->getYear()
540
            ];
541
        }
542
    }
543
}
544