Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
OlzNewsListParams
n/a
0 / 0
n/a
0 / 0
0
n/a
0 / 0
OlzNewsList
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 4
650
0.00% covered (danger)
0.00%
0 / 1
 hasAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSearchTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSearchResultsWhenHasAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHtmlWhenHasAccess
0.00% covered (danger)
0.00%
0 / 118
0.00% covered (danger)
0.00%
0 / 1
506
1<?php
2
3namespace Olz\News\Components\OlzNewsList;
4
5use Olz\Apps\OlzApps;
6use Olz\Components\Common\OlzRootComponent;
7use Olz\Components\Page\OlzFooter\OlzFooter;
8use Olz\Components\Page\OlzHeader\OlzHeader;
9use Olz\Entity\News\NewsEntry;
10use Olz\Entity\Roles\Role;
11use Olz\Entity\Users\User;
12use Olz\News\Components\OlzNewsFilter\OlzNewsFilter;
13use Olz\News\Components\OlzNewsListItem\OlzNewsListItem;
14use Olz\Utils\HttpParams;
15
16/** @extends HttpParams<array{
17 *   filter?: ?string,
18 *   seite?: ?numeric-string,
19 *   von?: ?string,
20 * }> */
21class OlzNewsListParams extends HttpParams {
22}
23
24/** @extends OlzRootComponent<array<string, mixed>> */
25class OlzNewsList extends OlzRootComponent {
26    public function hasAccess(): bool {
27        return true;
28    }
29
30    public function getSearchTitle(): string {
31        return 'TODO';
32    }
33
34    public function getSearchResultsWhenHasAccess(array $terms): array {
35        return [];
36    }
37
38    public static string $title = "News";
39    public static string $description = "Aktuelle Beiträge, Berichte von Anlässen und weitere Neuigkeiten von der OL Zimmerberg.";
40
41    public static int $page_size = 25;
42
43    public function getHtmlWhenHasAccess(mixed $args): string {
44        $params = $this->httpUtils()->validateGetParams(OlzNewsListParams::class);
45        $db = $this->dbUtils()->getDb();
46        $entityManager = $this->dbUtils()->getEntityManager();
47        $code_href = $this->envUtils()->getCodeHref();
48
49        $news_utils = $this->newsUtils();
50        $current_filter = $news_utils->deserialize($params['filter'] ?? $this->session()->get('news_filter') ?? '');
51        $page_number = intval($params['seite'] ?? $this->session()->get('news_page') ?? 1);
52        $page_index = $page_number - 1;
53
54        if (!$news_utils->isValidFilter($current_filter)) {
55            $valid_filter = $news_utils->getValidFilter($current_filter);
56            $serialized_filter = $news_utils->serialize($valid_filter);
57            $this->httpUtils()->redirect("{$code_href}news?filter={$serialized_filter}", empty($params['filter']) ? 308 : 410);
58        }
59
60        $valid_filter = $news_utils->getValidFilter($current_filter);
61        $serialized_filter = $news_utils->serialize($valid_filter);
62
63        $this->session()->set('news_filter', $serialized_filter);
64        $this->session()->set('news_page', "{$page_number}");
65
66        $news_list_title = $news_utils->getTitleFromFilter($valid_filter);
67        $out = OlzHeader::render([
68            'title' => $news_list_title,
69            'description' => self::$description, // TODO: Filter-specific description?
70            'canonical_url' => "{$code_href}news?filter={$serialized_filter}&seite={$page_number}",
71        ]);
72
73        $out .= "<div class='content-right'>";
74        $out .= "<h2 class='optional'>Filter</h2>";
75        $out .= OlzNewsFilter::render(['currentFilter' => $valid_filter]);
76        $out .= "</div>";
77        $out .= "<div class='content-middle olz-news-list-middle'>";
78
79        $is_logged_in = $this->authUtils()->hasPermission('any');
80        $has_blog = $this->authUtils()->hasPermission('kaderblog');
81        $has_roles = !empty($this->authUtils()->getAuthenticatedRoles());
82        $json_mode = htmlentities(json_encode($has_roles ? ($has_blog ? 'account_with_all' : 'account_with_aktuell') : ($has_blog ? 'account_with_blog' : 'account')) ?: '');
83        $class = $is_logged_in ? ' create-news-container' : ' dropdown-toggle';
84        $properties = $is_logged_in
85            ? <<<ZZZZZZZZZZ
86                onclick='return olz.initOlzEditNewsModal({$json_mode})'
87                ZZZZZZZZZZ
88            : <<<'ZZZZZZZZZZ'
89                type='button'
90                data-bs-toggle='dropdown'
91                aria-expanded='false'
92                ZZZZZZZZZZ;
93        if (!$is_logged_in) {
94            $out .= "<div class='dropdown create-news-container'>";
95        }
96        $out .= <<<ZZZZZZZZZZ
97            <button
98                id='create-news-button'
99                class='btn btn-secondary{$class}'
100                {$properties}
101            >
102                <img src='{$code_href}assets/icns/new_white_16.svg' class='noborder' />
103                Neuer Eintrag
104            </button>
105            ZZZZZZZZZZ;
106        if (!$is_logged_in) {
107            $out .= <<<'ZZZZZZZZZZ'
108                <div
109                    class='dropdown-menu dropdown-menu-end'
110                    aria-labelledby='create-news-button'
111                >
112                    <li><button
113                        class='dropdown-item'
114                        onclick='return olz.initOlzLoginModal({})'
115                    >
116                        Login
117                    </button></li>
118                    <li><hr class="dropdown-divider"></li>
119                    <li><div class='dropdown-item disabled should-login'>
120                        <b>Achtung</b>: Bild-Upload und nachträgliches Bearbeiten des Eintrags nur mit Login möglich!
121                    </div></li>
122                    <li><button
123                        id='create-anonymous-button'
124                        class='dropdown-item'
125                        onclick='return olz.initOlzEditNewsModal(&quot;anonymous&quot;)'
126                    >
127                        Forumseintrag ohne Login
128                    </button></li>
129                </div>
130                ZZZZZZZZZZ;
131            $out .= "</div>";
132        }
133
134        $newsletter_link = '';
135        $newsletter_app = OlzApps::getApp('Newsletter');
136        if ($newsletter_app) {
137            $newsletter_link = <<<ZZZZZZZZZZ
138                <a href='{$code_href}{$newsletter_app->getHref()}' class='newsletter-link'>
139                    <img
140                        src='{$newsletter_app->getIcon()}'
141                        alt='newsletter'
142                        class='newsletter-link-icon'
143                        title='Newsletter abonnieren!'
144                    />
145                </a>
146                ZZZZZZZZZZ;
147        } else {
148            $this->log()->error('Newsletter App does not exist!');
149        }
150        $out .= "<h1>{$news_list_title} {$newsletter_link}</h1>";
151
152        $filter_where = $news_utils->getSqlFromFilter($valid_filter);
153        $first_index = $page_index * $this::$page_size;
154        $sql = <<<ZZZZZZZZZZ
155            SELECT
156                COUNT(n.id) as count
157            FROM news n
158            WHERE
159                {$filter_where}
160                AND n.on_off='1'
161            ORDER BY published_date DESC, published_time DESC
162            ZZZZZZZZZZ;
163        // @phpstan-ignore-next-line
164        $count = intval($db->query($sql)->fetch_assoc()['count']);
165        $num_pages = intval($count / $this::$page_size) + 1;
166
167        $sql = <<<ZZZZZZZZZZ
168            SELECT
169                id,
170                owner_user_id,
171                owner_role_id,
172                published_date,
173                published_time,
174                format,
175                author_user_id,
176                author_role_id,
177                author_name,
178                author_email,
179                title,
180                teaser,
181                content,
182                image_ids
183            FROM news n
184            WHERE
185                {$filter_where}
186                AND n.on_off='1'
187            ORDER BY published_date DESC, published_time DESC
188            LIMIT {$first_index}{$this::$page_size}
189            ZZZZZZZZZZ;
190        $res = $db->query($sql);
191
192        $user_repo = $entityManager->getRepository(User::class);
193        $role_repo = $entityManager->getRepository(Role::class);
194
195        $page_content = '';
196        // @phpstan-ignore-next-line
197        for ($index = 0; $index < $res->num_rows; $index++) {
198            // @phpstan-ignore-next-line
199            $row = $res->fetch_assoc();
200
201            // TODO: Directly use doctrine to run the DB query.
202            // @phpstan-ignore-next-line
203            $owner_user = $row['owner_user_id'] ?
204                $user_repo->findOneBy(['id' => $row['owner_user_id']]) : null;
205            $owner_role = $row['owner_role_id'] ?
206                $role_repo->findOneBy(['id' => $row['owner_role_id']]) : null;
207            $author_user = $row['author_user_id'] ?
208                $user_repo->findOneBy(['id' => $row['author_user_id']]) : null;
209            $author_role = $row['author_role_id'] ?
210                $role_repo->findOneBy(['id' => $row['author_role_id']]) : null;
211
212            $news_entry = new NewsEntry();
213            $news_entry->setOwnerUser($owner_user);
214            $news_entry->setOwnerRole($owner_role);
215            // @phpstan-ignore-next-line
216            $news_entry->setPublishedDate(new \DateTime($row['published_date']));
217            // @phpstan-ignore-next-line
218            $news_entry->setFormat($row['format']);
219            $news_entry->setAuthorUser($author_user);
220            $news_entry->setAuthorRole($author_role);
221            // @phpstan-ignore-next-line
222            $news_entry->setAuthorName($row['author_name']);
223            // @phpstan-ignore-next-line
224            $news_entry->setAuthorEmail($row['author_email']);
225            // @phpstan-ignore-next-line
226            $news_entry->setTitle($row['title']);
227            // @phpstan-ignore-next-line
228            $news_entry->setTeaser($row['teaser']);
229            // @phpstan-ignore-next-line
230            $news_entry->setContent($row['content']);
231            $news_entry->setId(intval($row['id']));
232            // @phpstan-ignore-next-line
233            $news_entry->setImageIds($row['image_ids'] ? json_decode($row['image_ids'], true) : null);
234
235            $page_content .= OlzNewsListItem::render([
236                'json_mode' => $json_mode,
237                'news_entry' => $news_entry,
238            ]);
239        }
240        if ($page_content === '') {
241            $page_content = "<div class='no-entries'>Keine Einträge. Bitte Filter anpassen.</div>";
242        }
243        $out .= $page_content;
244        if ($num_pages > 1) {
245            $pages = '';
246            for ($page_number = 1; $page_number <= $num_pages; $page_number++) {
247                $is_current_page = $page_number === $page_index + 1;
248                $page_link_class = $is_current_page ? ' active' : '';
249                $pages .= <<<ZZZZZZZZZZ
250                    <li class='page-item'>
251                        <a
252                            class='page-link{$page_link_class}'
253                            href='?filter={$serialized_filter}&seite={$page_number}'
254                        >
255                            {$page_number}
256                        </a>
257                    </li>
258                    ZZZZZZZZZZ;
259            }
260            $out .= "<nav><ul class='no-style pagination justify-content-center'>{$pages}</ul></nav>";
261        }
262
263        $out .= "</div>";
264
265        $out .= OlzFooter::render();
266
267        return $out;
268    }
269}