Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 137
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
OlzTermineUpcomingTile
0.00% covered (danger)
0.00%
0 / 137
0.00% covered (danger)
0.00%
0 / 7
210
0.00% covered (danger)
0.00%
0 / 1
 getRelevance
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHtml
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
30
 renderProgramList
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
20
 renderWeekendsList
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 renderTrophyList
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 renderUpcomingTrainingsList
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 getNumberOfEntries
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3// =============================================================================
4// Zeigt eine Startseiten-Kachel mit den nächsten Terminen an.
5// =============================================================================
6
7namespace Olz\Startseite\Components\OlzTermineUpcomingTile;
8
9use Olz\Entity\Termine\TerminLabel;
10use Olz\Entity\Users\User;
11use Olz\Startseite\Components\AbstractOlzTile\AbstractOlzTile;
12
13class OlzTermineUpcomingTile extends AbstractOlzTile {
14    private ?\mysqli $db = null;
15    private ?int $this_year = null;
16
17    public function getRelevance(?User $user): float {
18        return 0.7;
19    }
20
21    public function getHtml(mixed $args): string {
22        $this->termineUtils()->loadTypeOptions();
23        $this->db = $this->dbUtils()->getDb();
24        $this->this_year = intval($this->dateUtils()->getCurrentDateInFormat('Y'));
25        $code_href = $this->envUtils()->getCodeHref();
26        $code_path = $this->envUtils()->getCodePath();
27        $today = $this->dateUtils()->getIsoToday();
28        $termin_label_repo = $this->entityManager()->getRepository(TerminLabel::class);
29
30        $termine_url = $this->termineUtils()->getUrl(['typ' => 'alle', 'datum' => 'bevorstehend']);
31
32        $out = <<<ZZZZZZZZZZ
33            <h3>
34                <a href='{$termine_url}&von=st-tr' class='header-link'>
35                    <img
36                        src='{$code_href}assets/icns/termine_type_all_20.svg'
37                        alt='Termine'
38                        class='header-link-icon text-icon'
39                    >
40                    Termine
41                </a>
42            </h3>
43            ZZZZZZZZZZ;
44
45        $out .= "<div class='filters'>".implode(' ', [
46            $this->renderProgramList(),
47            $this->renderWeekendsList(),
48            $this->renderTrophyList(),
49            $this->renderUpcomingTrainingsList(),
50        ])."</div>";
51
52        $out .= "<ul class='links'>";
53        $res = $this->db->query(<<<ZZZZZZZZZZ
54            SELECT
55                t.id,
56                t.start_date as date,
57                t.title as title,
58                (
59                    SELECT l.id
60                    FROM 
61                        termin_label_map tl
62                        JOIN termin_labels l ON (l.id = tl.label_id)
63                    WHERE tl.termin_id = t.id
64                    ORDER BY l.position ASC
65                    LIMIT 1
66                ) as label_id
67            FROM termine t
68            WHERE t.on_off = '1' AND t.start_date >= '{$today}'
69            ORDER BY t.start_date ASC
70            LIMIT 7
71            ZZZZZZZZZZ);
72        $index = 0;
73        // @phpstan-ignore-next-line
74        while ($row = $res->fetch_assoc()) {
75            $id = $row['id'];
76            // @phpstan-ignore-next-line
77            $date = $this->dateUtils()->compactDate($row['date']);
78            $title = $row['title'];
79            $label_id = $row['label_id'];
80            $label = $termin_label_repo->findOneBy(['id' => $label_id]);
81            $label_ident = $label?->getIdent();
82            $fallback_path = "{$code_path}assets/icns/termine_type_{$label_ident}_20.svg";
83            $fallback_href = is_file($fallback_path)
84                ? "{$code_href}assets/icns/termine_type_{$label_ident}_20.svg" : null;
85            $icon_href = $label?->getIcon() ? $label->getFileHref($label->getIcon()) : $fallback_href;
86            $icon_img = $icon_href ? "<img src='{$icon_href}' alt='' class='link-icon text-icon'>" : '';
87            $out .= <<<ZZZZZZZZZZ
88                    <li class='flex'>
89                        <a href='{$code_href}termine/{$id}?von=st-tr-{$index}'>
90                            {$icon_img}
91                            <b>{$date}</b>: {$title}
92                        </a>
93                    </li>
94                ZZZZZZZZZZ;
95            $index++;
96        }
97        $out .= "</ul>";
98
99        return $out;
100    }
101
102    protected function renderProgramList(): string {
103        $code_href = $this->envUtils()->getCodeHref();
104        $icon = "{$code_href}assets/icns/termine_type_programm_20.svg";
105        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
106        $this_year = $this->this_year;
107        $next_year = $this->this_year + 1;
108        $imminent_filter = [
109            ...$this->termineUtils()->getDefaultFilter(),
110            'typ' => 'programm',
111            'datum' => 'bevorstehend',
112        ];
113        $this_year_filter = [
114            ...$this->termineUtils()->getDefaultFilter(),
115            'typ' => 'programm',
116            'datum' => strval($this_year),
117        ];
118        $num_imminent = $this->getNumberOfEntries($imminent_filter);
119        $out = '';
120        if ($num_imminent > 0) {
121            $num_this_year = $this->getNumberOfEntries($this_year_filter);
122            $serialized_filter = $this->termineUtils()->serialize($this_year_filter);
123            $out .= <<<ZZZZZZZZZZ
124                <a href='{$code_href}termine?filter={$serialized_filter}&von=st-tr' class='filter'>
125                    {$icon_img} Programm {$this_year}<span class='secondary'>({$num_this_year})</span>
126                </a>
127                ZZZZZZZZZZ;
128        }
129        $current_month = intval($this->dateUtils()->getCurrentDateInFormat('m'));
130        if ($current_month > 8) {
131            $next_year_filter = [
132                ...$this->termineUtils()->getDefaultFilter(),
133                'typ' => 'programm',
134                'datum' => strval($next_year),
135            ];
136            $num_next_year = $this->getNumberOfEntries($next_year_filter);
137
138            if ($num_next_year > 0) {
139                $serialized_filter = $this->termineUtils()->serialize($next_year_filter);
140                $out .= <<<ZZZZZZZZZZ
141                    <a href='{$code_href}termine?filter={$serialized_filter}&von=st-tr' class='filter'>
142                        {$icon_img} Programm {$next_year}<span class='secondary'>({$num_next_year})</span>
143                    </a>
144                    ZZZZZZZZZZ;
145            }
146        }
147        return $out;
148    }
149
150    protected function renderWeekendsList(): string {
151        $code_href = $this->envUtils()->getCodeHref();
152        $icon = "{$code_href}assets/icns/termine_type_weekend_20.svg";
153        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
154        $imminent_filter = [
155            ...$this->termineUtils()->getDefaultFilter(),
156            'typ' => 'weekend',
157            'datum' => 'bevorstehend',
158        ];
159        $num_imminent = $this->getNumberOfEntries($imminent_filter);
160        $serialized_filter = $this->termineUtils()->serialize($imminent_filter);
161        return <<<ZZZZZZZZZZ
162            <a href='{$code_href}termine?filter={$serialized_filter}&von=st-tr' class='filter'>
163                {$icon_img} Weekends<span class='secondary'>({$num_imminent})</span>
164            </a>
165            ZZZZZZZZZZ;
166    }
167
168    protected function renderTrophyList(): string {
169        $code_href = $this->envUtils()->getCodeHref();
170        $icon = "{$code_href}assets/icns/termine_type_trophy_20.svg";
171        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
172        $this_year = $this->this_year;
173        $this_year_filter = [
174            ...$this->termineUtils()->getDefaultFilter(),
175            'typ' => 'trophy',
176            'datum' => strval($this_year),
177        ];
178        $num_this_year = $this->getNumberOfEntries($this_year_filter);
179        $serialized_filter = $this->termineUtils()->serialize($this_year_filter);
180        return <<<ZZZZZZZZZZ
181            <a href='{$code_href}termine?filter={$serialized_filter}&von=st-tr' class='filter'>
182                {$icon_img} OLZ Trophy<span class='secondary'>({$num_this_year})</span>
183            </a>
184            ZZZZZZZZZZ;
185    }
186
187    protected function renderUpcomingTrainingsList(): string {
188        $code_href = $this->envUtils()->getCodeHref();
189        $icon = "{$code_href}assets/icns/termine_type_training_20.svg";
190        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
191        $imminent_filter = [
192            ...$this->termineUtils()->getDefaultFilter(),
193            'typ' => 'training',
194            'datum' => 'bevorstehend',
195        ];
196        $serialized_filter = $this->termineUtils()->serialize($imminent_filter);
197        return <<<ZZZZZZZZZZ
198            <a href='{$code_href}termine?filter={$serialized_filter}&von=st-tr' class='filter'>
199                {$icon_img} Trainings
200            </a>
201            ZZZZZZZZZZ;
202    }
203
204    /** @param array{typ?: string, datum?: string, archiv?: string} $filter */
205    protected function getNumberOfEntries(array $filter): int {
206        $date_filter = $this->termineUtils()->getSqlDateRangeFilter($filter, 'c');
207        $type_filter = $this->termineUtils()->getSqlTypeFilter($filter, 'c');
208        $filter_sql = "({$date_filter}) AND ({$type_filter})";
209        $sql = <<<ZZZZZZZZZZ
210            SELECT * 
211            FROM (
212                SELECT
213                    t.id AS id,
214                    t.start_date AS start_date,
215                    t.end_date AS end_date,
216                    (
217                        SELECT GROUP_CONCAT(l.ident ORDER BY l.position ASC SEPARATOR ' ')
218                        FROM
219                            termin_label_map tl
220                            JOIN termin_labels l ON (l.id = tl.label_id)
221                        WHERE tl.termin_id = t.id
222                        GROUP BY t.id
223                    ) as typ
224                FROM termine t
225            ) AS c
226            WHERE {$filter_sql}
227            ZZZZZZZZZZ;
228        $res = $this->db?->query($sql);
229        // @phpstan-ignore-next-line
230        return $res->num_rows;
231    }
232}