Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 135
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 / 135
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 / 44
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=startseite' 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        // @phpstan-ignore-next-line
73        while ($row = $res->fetch_assoc()) {
74            $id = $row['id'];
75            // @phpstan-ignore-next-line
76            $date = $this->dateUtils()->compactDate($row['date']);
77            $title = $row['title'];
78            $label_id = $row['label_id'];
79            $label = $termin_label_repo->findOneBy(['id' => $label_id]);
80            $label_ident = $label?->getIdent();
81            $fallback_path = "{$code_path}assets/icns/termine_type_{$label_ident}_20.svg";
82            $fallback_href = is_file($fallback_path)
83                ? "{$code_href}assets/icns/termine_type_{$label_ident}_20.svg" : null;
84            $icon_href = $label?->getIcon() ? $label->getFileHref($label->getIcon()) : $fallback_href;
85            $icon_img = $icon_href ? "<img src='{$icon_href}' alt='' class='link-icon text-icon'>" : '';
86            $out .= <<<ZZZZZZZZZZ
87                    <li class='flex'>
88                        <a href='{$code_href}termine/{$id}?von=startseite'>
89                            {$icon_img}
90                            <b>{$date}</b>: {$title}
91                        </a>
92                    </li>
93                ZZZZZZZZZZ;
94        }
95        $out .= "</ul>";
96
97        return $out;
98    }
99
100    protected function renderProgramList(): string {
101        $code_href = $this->envUtils()->getCodeHref();
102        $icon = "{$code_href}assets/icns/termine_type_programm_20.svg";
103        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
104        $this_year = $this->this_year;
105        $next_year = $this->this_year + 1;
106        $imminent_filter = [
107            ...$this->termineUtils()->getDefaultFilter(),
108            'typ' => 'programm',
109            'datum' => 'bevorstehend',
110        ];
111        $this_year_filter = [
112            ...$this->termineUtils()->getDefaultFilter(),
113            'typ' => 'programm',
114            'datum' => strval($this_year),
115        ];
116        $num_imminent = $this->getNumberOfEntries($imminent_filter);
117        $out = '';
118        if ($num_imminent > 0) {
119            $num_this_year = $this->getNumberOfEntries($this_year_filter);
120            $serialized_filter = $this->termineUtils()->serialize($this_year_filter);
121            $out .= <<<ZZZZZZZZZZ
122                <a href='{$code_href}termine?filter={$serialized_filter}&von=startseite' class='filter'>
123                    {$icon_img} Programm {$this_year}<span class='secondary'>({$num_this_year})</span>
124                </a>
125                ZZZZZZZZZZ;
126        }
127        $current_month = intval($this->dateUtils()->getCurrentDateInFormat('m'));
128        if ($current_month > 8) {
129            $next_year_filter = [
130                ...$this->termineUtils()->getDefaultFilter(),
131                'typ' => 'programm',
132                'datum' => strval($next_year),
133            ];
134            $num_next_year = $this->getNumberOfEntries($next_year_filter);
135
136            if ($num_next_year > 0) {
137                $serialized_filter = $this->termineUtils()->serialize($next_year_filter);
138                $out .= <<<ZZZZZZZZZZ
139                    <a href='{$code_href}termine?filter={$serialized_filter}&von=startseite' class='filter'>
140                        {$icon_img} Programm {$next_year}<span class='secondary'>({$num_next_year})</span>
141                    </a>
142                    ZZZZZZZZZZ;
143            }
144        }
145        return $out;
146    }
147
148    protected function renderWeekendsList(): string {
149        $code_href = $this->envUtils()->getCodeHref();
150        $icon = "{$code_href}assets/icns/termine_type_weekend_20.svg";
151        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
152        $imminent_filter = [
153            ...$this->termineUtils()->getDefaultFilter(),
154            'typ' => 'weekend',
155            'datum' => 'bevorstehend',
156        ];
157        $num_imminent = $this->getNumberOfEntries($imminent_filter);
158        $serialized_filter = $this->termineUtils()->serialize($imminent_filter);
159        return <<<ZZZZZZZZZZ
160            <a href='{$code_href}termine?filter={$serialized_filter}&von=startseite' class='filter'>
161                {$icon_img} Weekends<span class='secondary'>({$num_imminent})</span>
162            </a>
163            ZZZZZZZZZZ;
164    }
165
166    protected function renderTrophyList(): string {
167        $code_href = $this->envUtils()->getCodeHref();
168        $icon = "{$code_href}assets/icns/termine_type_trophy_20.svg";
169        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
170        $this_year = $this->this_year;
171        $this_year_filter = [
172            ...$this->termineUtils()->getDefaultFilter(),
173            'typ' => 'trophy',
174            'datum' => strval($this_year),
175        ];
176        $num_this_year = $this->getNumberOfEntries($this_year_filter);
177        $serialized_filter = $this->termineUtils()->serialize($this_year_filter);
178        return <<<ZZZZZZZZZZ
179            <a href='{$code_href}termine?filter={$serialized_filter}&von=startseite' class='filter'>
180                {$icon_img} OLZ Trophy<span class='secondary'>({$num_this_year})</span>
181            </a>
182            ZZZZZZZZZZ;
183    }
184
185    protected function renderUpcomingTrainingsList(): string {
186        $code_href = $this->envUtils()->getCodeHref();
187        $icon = "{$code_href}assets/icns/termine_type_training_20.svg";
188        $icon_img = "<img src='{$icon}' alt='' class='link-icon'>";
189        $imminent_filter = [
190            ...$this->termineUtils()->getDefaultFilter(),
191            'typ' => 'training',
192            'datum' => 'bevorstehend',
193        ];
194        $serialized_filter = $this->termineUtils()->serialize($imminent_filter);
195        return <<<ZZZZZZZZZZ
196            <a href='{$code_href}termine?filter={$serialized_filter}&von=startseite' class='filter'>
197                {$icon_img} Trainings
198            </a>
199            ZZZZZZZZZZ;
200    }
201
202    /** @param array{typ?: string, datum?: string, archiv?: string} $filter */
203    protected function getNumberOfEntries(array $filter): int {
204        $date_filter = $this->termineUtils()->getSqlDateRangeFilter($filter, 'c');
205        $type_filter = $this->termineUtils()->getSqlTypeFilter($filter, 'c');
206        $filter_sql = "({$date_filter}) AND ({$type_filter})";
207        $sql = <<<ZZZZZZZZZZ
208            SELECT * 
209            FROM (
210                SELECT
211                    t.id AS id,
212                    t.start_date AS start_date,
213                    t.end_date AS end_date,
214                    (
215                        SELECT GROUP_CONCAT(l.ident ORDER BY l.position ASC SEPARATOR ' ')
216                        FROM
217                            termin_label_map tl
218                            JOIN termin_labels l ON (l.id = tl.label_id)
219                        WHERE tl.termin_id = t.id
220                        GROUP BY t.id
221                    ) as typ
222                FROM termine t
223            ) AS c
224            WHERE {$filter_sql}
225            ZZZZZZZZZZ;
226        $res = $this->db?->query($sql);
227        // @phpstan-ignore-next-line
228        return $res->num_rows;
229    }
230}