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