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