Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
OlzTermineListParams
n/a
0 / 0
n/a
0 / 0
0
n/a
0 / 0
OlzTermineList
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 4
552
0.00% covered (danger)
0.00%
0 / 1
 getSearchTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSearchResults
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 / 114
0.00% covered (danger)
0.00%
0 / 1
380
 getMonth
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3// =============================================================================
4// Zeigt geplante und vergangene Termine an.
5// =============================================================================
6
7namespace Olz\Termine\Components\OlzTermineList;
8
9use Olz\Components\Common\OlzEditableText\OlzEditableText;
10use Olz\Components\Common\OlzRootComponent;
11use Olz\Components\Page\OlzFooter\OlzFooter;
12use Olz\Components\Page\OlzHeader\OlzHeader;
13use Olz\Entity\Termine\Termin;
14use Olz\Entity\Termine\TerminLabel;
15use Olz\Termine\Components\OlzTermineFilter\OlzTermineFilter;
16use Olz\Termine\Components\OlzTermineListItem\OlzTermineListItem;
17use Olz\Utils\HttpParams;
18
19/** @extends HttpParams<array{filter?: ?string, von?: ?string}> */
20class OlzTermineListParams extends HttpParams {
21}
22
23/** @extends OlzRootComponent<array<string, mixed>> */
24class OlzTermineList extends OlzRootComponent {
25    public function getSearchTitle(): string {
26        return 'Termin-Listen';
27    }
28
29    public function getSearchResults(array $terms): array {
30        return [];
31    }
32
33    public static string $title = "Termine";
34    public static string $description = "Orientierungslauf-Wettkämpfe, OL-Wochen, OL-Weekends, Trainings und Vereinsanlässe der OL Zimmerberg.";
35
36    public function getHtml(mixed $args): string {
37        /** @return array{filter?: ?string} */
38        $params = $this->httpUtils()->validateGetParams(OlzTermineListParams::class);
39        $db = $this->dbUtils()->getDb();
40        $code_href = $this->envUtils()->getCodeHref();
41
42        $current_filter = json_decode($params['filter'] ?? '{}', true);
43        $termine_utils = $this->termineUtils()->loadTypeOptions();
44
45        if (!$termine_utils->isValidFilter($current_filter)) {
46            $valid_filter = $termine_utils->getValidFilter($current_filter);
47            $enc_json_filter = urlencode(json_encode($valid_filter) ?: '{}');
48            $this->httpUtils()->redirect("{$code_href}termine?filter={$enc_json_filter}", 308);
49        }
50
51        $termine_list_title = $termine_utils->getTitleFromFilter($current_filter);
52        $enc_json_filter = urlencode(json_encode($current_filter) ?: '{}');
53
54        $out = OlzHeader::render([
55            'title' => $termine_list_title,
56            'description' => self::$description, // TODO: Filter-specific description?
57            'canonical_url' => "{$code_href}termine?filter={$enc_json_filter}",
58        ]);
59
60        $admin_menu_out = '';
61        $has_termine_permissions = $this->authUtils()->hasPermission('termine');
62        if ($has_termine_permissions) {
63            $admin_menu_out = <<<ZZZZZZZZZZ
64                <div class='termine-list-admin-menu'>
65                    <span class='entry'>
66                        <a href='{$code_href}termine/orte' class='linkmap'>
67                            Termin-Orte
68                        </a>
69                    </span>
70                    <span class='entry'>
71                        <a href='{$code_href}termine/vorlagen' class='linkint'>
72                            Termin-Vorlagen
73                        </a>
74                    </span>
75                </div>
76                ZZZZZZZZZZ;
77        }
78        $filter_out = OlzTermineFilter::render();
79        $downloads_links_out = OlzEditableText::render(['snippet_id' => 2]);
80        $newsletter_out = OlzEditableText::render(['snippet_id' => 3]);
81        $out .= <<<ZZZZZZZZZZ
82            <div class='content-right'>
83                {$admin_menu_out}
84                <h2 class='optional'>Filter</h2>
85                {$filter_out}
86                <div class='optional'>
87                    <h2>Downloads und Links</h2>
88                    {$downloads_links_out}
89                </div>
90                <div class='optional'>
91                    <h2>Newsletter</h2>
92                    {$newsletter_out}
93                </div>
94            </div>
95            <div class='content-middle olz-termine-list-middle'>
96            ZZZZZZZZZZ;
97
98        $has_access = $this->authUtils()->hasPermission('termine');
99        if ($has_access) {
100            $out .= <<<ZZZZZZZZZZ
101                <button
102                    id='create-termin-button'
103                    class='btn btn-secondary create-termin-container'
104                    onclick='return olz.initOlzEditTerminModal()'
105                >
106                    <img src='{$code_href}assets/icns/new_white_16.svg' class='noborder' />
107                    Neuer Termin
108                </button>
109                ZZZZZZZZZZ;
110        }
111
112        $termin_repo = $this->entityManager()->getRepository(Termin::class);
113        $termin_label_repo = $this->entityManager()->getRepository(TerminLabel::class);
114        $termin_label = $termin_label_repo->findOneBy(['ident' => $current_filter['typ']]);
115        $edit_admin = '';
116        if ($termin_label) {
117            $has_termine_permissions = $this->authUtils()->hasPermission('termine');
118            if ($has_termine_permissions) {
119                $json_id = json_encode($termin_label->getId());
120                $edit_admin = <<<ZZZZZZZZZZ
121                    <button
122                        id='edit-termin-label-button'
123                        class='btn btn-secondary-outline btn-sm'
124                        onclick='return olz.termineListEditTerminLabel({$json_id})'
125                    >
126                        <img src='{$code_href}assets/icns/edit_16.svg' class='noborder' />
127                    </button>
128                    ZZZZZZZZZZ;
129            }
130        }
131        $out .= "<h1>{$termine_list_title}{$edit_admin}</h1>";
132        $details = $termin_label?->getDetails();
133        if ($details) {
134            $details_html = $this->htmlUtils()->renderMarkdown($details);
135            $details_html = $termin_label->replaceImagePaths($details_html);
136            $details_html = $termin_label->replaceFilePaths($details_html);
137            $out .= $details_html;
138        }
139
140        // -------------------------------------------------------------
141        //  VORSCHAU - LISTE
142        $inner_date_filter = $termine_utils->getSqlDateRangeFilter($current_filter, 't');
143        $inner_sql_where = <<<ZZZZZZZZZZ
144            (t.on_off = '1')
145            AND ({$inner_date_filter})
146            ZZZZZZZZZZ;
147        $type_filter = $termine_utils->getSqlTypeFilter($current_filter, 'c');
148        $outer_date_filter = $termine_utils->getSqlDateRangeFilter($current_filter, 'c');
149        $outer_sql_where = "({$type_filter}) AND ({$outer_date_filter})";
150
151        $sql = <<<ZZZZZZZZZZ
152            SELECT * FROM ((
153                SELECT
154                    'termin' as item_type,
155                    t.owner_user_id as owner_user_id,
156                    t.start_date as start_date,
157                    t.start_time as start_time,
158                    t.end_date as end_date,
159                    t.end_time as end_time,
160                    t.title as title,
161                    t.text as text,
162                    t.id as id,
163                    (
164                        SELECT GROUP_CONCAT(l.ident ORDER BY l.position ASC SEPARATOR ' ')
165                        FROM
166                            termin_label_map tl
167                            JOIN termin_labels l ON (l.id = tl.label_id)
168                        WHERE tl.termin_id = t.id
169                        GROUP BY t.id
170                    ) as typ,
171                    t.on_off as on_off,
172                    t.newsletter as newsletter,
173                    t.xkoord as xkoord,
174                    t.ykoord as ykoord,
175                    t.go2ol as go2ol,
176                    t.solv_uid as solv_uid,
177                    t.last_modified_by_user_id as last_modified_by_user_id,
178                    t.image_ids as image_ids,
179                    t.location_id as location_id
180                FROM termine t
181                WHERE ({$inner_sql_where})
182            ) UNION ALL (
183                SELECT
184                    'deadline' as item_type,
185                    t.owner_user_id as owner_user_id,
186                    DATE(t.deadline) as start_date,
187                    TIME(t.deadline) as start_time,
188                    NULL as end_date,
189                    NULL as end_time,
190                    CONCAT('Meldeschluss für ', t.title) as title,
191                    '' as text,
192                    t.id as id,
193                    'meldeschluss' as typ,
194                    t.on_off as on_off,
195                    NULL as newsletter,
196                    NULL as xkoord,
197                    NULL as ykoord,
198                    t.go2ol as go2ol,
199                    t.solv_uid as solv_uid,
200                    t.last_modified_by_user_id as last_modified_by_user_id,
201                    t.image_ids as image_ids,
202                    NULL as location_id
203                FROM termine t
204                WHERE (t.deadline IS NOT NULL) AND ({$inner_sql_where})
205            )) AS c
206            WHERE ({$outer_sql_where})
207            ORDER BY c.start_date ASC
208            ZZZZZZZZZZ;
209
210        $result = $db->query($sql);
211        $today = $this->dateUtils()->getCurrentDateInFormat('Y-m-d');
212        $meldeschluss_label = new TerminLabel();
213        $meldeschluss_label->setIdent('meldeschluss');
214        $meldeschluss_label->setIcon(null);
215        $last_date = null;
216        // @phpstan-ignore-next-line
217        while ($row = $result->fetch_assoc()) {
218            $this_date = $row['start_date'];
219            // @phpstan-ignore-next-line
220            $this_month_start = $this->getMonth($this_date).'-01';
221
222            if ($today < $this_month_start && $today > $last_date) {
223                $out .= "<div class='bar today'>Heute</div>";
224            }
225            // @phpstan-ignore-next-line
226            if ($this->getMonth($this_date) !== $this->getMonth($last_date)) {
227                // @phpstan-ignore-next-line
228                $pretty_month = $this->dateUtils()->olzDate("MM jjjj", $this_date);
229                $out .= "<h3 class='bar green'>{$pretty_month}</h3>";
230            }
231            if ($today <= $this_date && $today > $last_date && $today >= $this_month_start) {
232                $out .= "<div class='bar today'>Heute</div>";
233            }
234            $labels = [$meldeschluss_label];
235            if ($row['item_type'] === 'termin') {
236                $termin = $termin_repo->findOneBy(['id' => $row['id']]);
237                $labels = [...($termin?->getLabels() ?? [])];
238            }
239
240            $out .= OlzTermineListItem::render([
241                'id' => $row['id'],
242                'owner_user_id' => $row['owner_user_id'],
243                'start_date' => $row['start_date'],
244                'start_time' => $row['start_time'],
245                'end_date' => $row['end_date'],
246                'end_time' => $row['end_time'],
247                'title' => $row['title'],
248                'text' => $row['text'],
249                'solv_uid' => $row['solv_uid'],
250                'labels' => $labels,
251                // @phpstan-ignore-next-line
252                'image_ids' => $row['image_ids'] ? json_decode($row['image_ids'], true) : null,
253                'location_id' => $row['location_id'],
254            ]);
255
256            $last_date = $this_date;
257        }
258        if ($last_date === null) {
259            $out .= "<div class='no-entries'>Keine Einträge. Bitte Filter anpassen.</div>";
260        }
261        $out .= "</div>";
262
263        $out .= OlzFooter::render();
264
265        return $out;
266    }
267
268    protected function getMonth(?string $date): ?string {
269        if ($date === null) {
270            return null;
271        }
272        return substr($date, 0, 7);
273    }
274}