Issues (281)

Branch: master

src/Frontend/Modules/Blog/Engine/Model.php (1 issue)

1
<?php
2
3
namespace Frontend\Modules\Blog\Engine;
4
5
use Common\Mailer\Message;
6
use ForkCMS\Utility\Thumbnails;
7
use Frontend\Core\Language\Language as FL;
8
use Frontend\Core\Engine\Model as FrontendModel;
9
use Frontend\Core\Engine\Navigation as FrontendNavigation;
10
use Frontend\Core\Engine\Url as FrontendUrl;
11
use Frontend\Core\Language\Locale;
12
use Frontend\Modules\Tags\Engine\Model as FrontendTagsModel;
13
use Frontend\Modules\Tags\Engine\TagsInterface as FrontendTagsInterface;
14
15
/**
16
 * In this file we store all generic functions that we will be using in the blog module
17
 */
18
class Model implements FrontendTagsInterface
19
{
20 3
    public static function get(string $url): array
21
    {
22 3
        $blogPost = (array) FrontendModel::getContainer()->get('database')->getRecord(
23 3
            'SELECT i.id, i.revision_id, i.language, i.title, i.introduction, i.text,
24
             c.title AS category_title, m2.url AS category_url, i.image,
25
             UNIX_TIMESTAMP(i.publish_on) AS publish_on, i.user_id,
26
             i.allow_comments, m.id AS meta_id,
27
             m.keywords AS meta_keywords, m.keywords_overwrite AS meta_keywords_overwrite,
28
             m.description AS meta_description, m.description_overwrite AS meta_description_overwrite,
29
             m.title AS meta_title, m.title_overwrite AS meta_title_overwrite, m.custom AS meta_custom,
30
             m.url,
31
             m.data AS meta_data, m.seo_follow AS meta_seo_follow, m.seo_index AS meta_seo_index
32
             FROM blog_posts AS i
33
             INNER JOIN blog_categories AS c ON i.category_id = c.id
34
             INNER JOIN meta AS m ON i.meta_id = m.id
35
             INNER JOIN meta AS m2 ON c.meta_id = m2.id
36
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ? AND m.url = ?
37
             LIMIT 1',
38 3
            ['active', LANGUAGE, false, FrontendModel::getUTCDate('Y-m-d H:i'), $url]
39
        );
40
41 3
        return self::completeBlogPost($blogPost);
42
    }
43
44 3
    public static function getAll(int $limit = 10, int $offset = 0): array
45
    {
46 3
        $items = (array) FrontendModel::getContainer()->get('database')->getRecords(
47 3
            'SELECT i.id, i.revision_id, i.language, i.title, i.introduction, i.text, i.num_comments AS comments_count,
48
             c.title AS category_title, m2.url AS category_url, i.image,
49
             UNIX_TIMESTAMP(i.publish_on) AS publish_on, i.user_id, i.allow_comments,
50
             m.url
51
             FROM blog_posts AS i
52
             INNER JOIN blog_categories AS c ON i.category_id = c.id
53
             INNER JOIN meta AS m ON i.meta_id = m.id
54
             INNER JOIN meta AS m2 ON c.meta_id = m2.id
55
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ?
56
             ORDER BY i.publish_on DESC, i.id DESC
57
             LIMIT ?, ?',
58
            [
59 3
                'active',
60 3
                LANGUAGE,
61
                false,
62 3
                FrontendModel::getUTCDate('Y-m-d H:i'),
63 3
                $offset,
64 3
                $limit,
65
            ],
66 3
            'id'
67
        );
68
69
        // no results?
70 3
        if (empty($items)) {
71 1
            return [];
72
        }
73
74
        // init var
75 2
        $link = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
76 2
        $categoryLink = FrontendNavigation::getUrlForBlock('Blog', 'Category');
77 2
        $folders = FrontendModel::get(Thumbnails::class)->getFolders(FRONTEND_FILES_PATH . '/Blog/images', true);
78
79
        // loop
80 2
        foreach ($items as $key => $row) {
81
            // URLs
82 2
            $items[$key]['full_url'] = $link . '/' . $row['url'];
83 2
            $items[$key]['category_full_url'] = $categoryLink . '/' . $row['category_url'];
84
85
            // comments
86 2
            if ($row['comments_count'] > 0) {
87
                $items[$key]['comments'] = true;
88
            }
89 2
            if ($row['comments_count'] > 1) {
90
                $items[$key]['comments_multiple'] = true;
91
            }
92
93
            // allow comments as boolean
94 2
            $items[$key]['allow_comments'] = (bool) $row['allow_comments'];
95
96
            // reset allow comments
97 2
            if (!FrontendModel::get('fork.settings')->get('Blog', 'allow_comments')) {
98
                $items[$key]['allow_comments'] = false;
99
            }
100
101
            // image?
102 2
            if (isset($row['image'])) {
103
                foreach ($folders as $folder) {
104 2
                    $items[$key]['image_' . $folder['dirname']] = $folder['url'] . '/' . $folder['dirname'] . '/' . $row['image'];
105
                }
106
            }
107
        }
108
109
        // get all tags
110 2
        $tags = FrontendTagsModel::getForMultipleItems('Blog', array_keys($items));
111
112
        // loop tags and add to correct item
113 2
        foreach ($tags as $postId => $data) {
114
            if (isset($items[$postId])) {
115
                $items[$postId]['tags'] = $data;
116
            }
117
        }
118
119
        // return
120 2
        return $items;
121
    }
122
123 2
    public static function getAllCategories(): array
124
    {
125 2
        $return = (array) FrontendModel::getContainer()->get('database')->getRecords(
126 2
            'SELECT c.id, c.title AS label, m.url, COUNT(c.id) AS total, m.data AS meta_data,
127
                 m.seo_follow AS meta_seo_follow, m.seo_index AS meta_seo_index
128
             FROM blog_categories AS c
129
             INNER JOIN blog_posts AS i ON c.id = i.category_id AND c.language = i.language
130
             INNER JOIN meta AS m ON c.meta_id = m.id
131
             WHERE c.language = ? AND i.status = ? AND i.hidden = ? AND i.publish_on <= ?
132
             GROUP BY c.id',
133 2
            [LANGUAGE, 'active', false, FrontendModel::getUTCDate('Y-m-d H:i')],
134 2
            'id'
135
        );
136
137
        // loop items and unserialize
138 2
        foreach ($return as &$row) {
139 2
            if (isset($row['meta_data'])) {
140 2
                $row['meta_data'] = @unserialize($row['meta_data'], ['allowed_classes' => false]);
141
            }
142
        }
143
144 2
        return $return;
145
    }
146
147 4
    public static function getCategory(string $slug): array
148
    {
149 4
        $category = (array) FrontendModel::getContainer()->get('database')->getRecord(
150 4
            'SELECT c.id, c.title AS label, m.url, m.id AS meta_id, COUNT(c.id) AS total
151
             FROM blog_categories AS c
152
             INNER JOIN blog_posts AS i ON c.id = i.category_id AND c.language = i.language
153
             INNER JOIN meta AS m ON c.meta_id = m.id AND m.url = ?
154
             WHERE c.language = ? AND i.status = ? AND i.hidden = ? AND i.publish_on <= ?
155
             GROUP BY c.id',
156 4
            [$slug, LANGUAGE, 'active', false, FrontendModel::getUTCDate('Y-m-d H:i')],
157 4
            'id'
158
        );
159
160 4
        if (empty($category)) {
161 1
            return [];
162
        }
163
164 3
        $category['meta'] = FrontendModel::get('fork.repository.meta')->find($category['meta_id']);
165
166 3
        return $category;
167
    }
168
169
    public static function getAllComments(int $limit = 10, int $offset = 0): array
170
    {
171
        $comments = (array) FrontendModel::getContainer()->get('database')->getRecords(
172
            'SELECT i.id, UNIX_TIMESTAMP(i.created_on) AS created_on, i.author, i.text,
173
             p.id AS post_id, p.title AS post_title, m.url AS post_url, i.email
174
             FROM blog_comments AS i
175
             INNER JOIN blog_posts AS p ON i.post_id = p.id AND i.language = p.language
176
             INNER JOIN meta AS m ON p.meta_id = m.id
177
             WHERE i.status = ? AND i.language = ?
178
             GROUP BY i.id
179
             ORDER BY i.created_on DESC
180
             LIMIT ?, ?',
181
            ['published', LANGUAGE, $offset, $limit]
182
        );
183
184
        // loop comments and create gravatar id
185
        foreach ($comments as &$row) {
186
            $row['author'] = htmlspecialchars($row['author']);
187
            $row['text'] = htmlspecialchars($row['text']);
188
            $row['gravatar_id'] = md5($row['email']);
189
        }
190
191
        return $comments;
192
    }
193
194 3
    public static function getAllCount(): int
195
    {
196 3
        return (int) FrontendModel::getContainer()->get('database')->getVar(
197 3
            'SELECT COUNT(i.id) AS count
198
             FROM blog_posts AS i
199
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ?',
200 3
            ['active', LANGUAGE, false, FrontendModel::getUTCDate('Y-m-d H:i')]
201
        );
202
    }
203
204 3
    public static function getAllForCategory(string $categoryUrl, int $limit = 10, int $offset = 0): array
205
    {
206 3
        $items = (array) FrontendModel::getContainer()->get('database')->getRecords(
207 3
            'SELECT i.id, i.revision_id, i.language, i.title, i.introduction, i.text, i.num_comments AS comments_count,
208
             c.title AS category_title, m2.url AS category_url, i.image,
209
             UNIX_TIMESTAMP(i.publish_on) AS publish_on, i.user_id, i.allow_comments,
210
             m.url
211
             FROM blog_posts AS i
212
             INNER JOIN blog_categories AS c ON i.category_id = c.id
213
             INNER JOIN meta AS m ON i.meta_id = m.id
214
             INNER JOIN meta AS m2 ON c.meta_id = m2.id
215
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ? AND m2.url = ?
216
             ORDER BY i.publish_on DESC
217
             LIMIT ?, ?',
218
            [
219 3
                'active',
220 3
                LANGUAGE,
221
                false,
222 3
                FrontendModel::getUTCDate('Y-m-d H:i'),
223 3
                $categoryUrl,
224 3
                $offset,
225 3
                $limit,
226
            ],
227 3
            'id'
228
        );
229
230
        // no results?
231 3
        if (empty($items)) {
232
            return [];
233
        }
234
235
        // init var
236 3
        $link = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
237 3
        $categoryLink = FrontendNavigation::getUrlForBlock('Blog', 'Category');
238 3
        $folders = FrontendModel::get(Thumbnails::class)->getFolders(FRONTEND_FILES_PATH . '/Blog/images', true);
239
240
        // loop
241 3
        foreach ($items as $key => $row) {
242
            // URLs
243 3
            $items[$key]['full_url'] = $link . '/' . $row['url'];
244 3
            $items[$key]['category_full_url'] = $categoryLink . '/' . $row['category_url'];
245
246
            // comments
247 3
            if ($row['comments_count'] > 0) {
248
                $items[$key]['comments'] = true;
249
            }
250 3
            if ($row['comments_count'] > 1) {
251
                $items[$key]['comments_multiple'] = true;
252
            }
253
254
            // allow comments as boolean
255 3
            $items[$key]['allow_comments'] = (bool) $row['allow_comments'];
256
257
            // reset allow comments
258 3
            if (!FrontendModel::get('fork.settings')->get('Blog', 'allow_comments')) {
259
                $items[$key]['allow_comments'] = false;
260
            }
261
262
            // image?
263 3
            if (isset($row['image'])) {
264
                foreach ($folders as $folder) {
265
                    $items[$key]['image_' . $folder['dirname']] = $folder['url'] . '/' . $folder['dirname'] .
266 3
                                                                  '/' . $row['image'];
267
                }
268
            }
269
        }
270
271
        // get all tags
272 3
        $tags = FrontendTagsModel::getForMultipleItems('Blog', array_keys($items));
273
274
        // loop tags and add to correct item
275 3
        foreach ($tags as $postId => $data) {
276
            $items[$postId]['tags'] = $data;
277
        }
278
279
        // return
280 3
        return $items;
281
    }
282
283 3
    public static function getAllForCategoryCount(string $url): int
284
    {
285 3
        return (int) FrontendModel::getContainer()->get('database')->getVar(
286 3
            'SELECT COUNT(i.id) AS count
287
             FROM blog_posts AS i
288
             INNER JOIN blog_categories AS c ON i.category_id = c.id
289
             INNER JOIN meta AS m ON c.meta_id = m.id
290
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ? AND m.url = ?',
291 3
            ['active', LANGUAGE, false, FrontendModel::getUTCDate('Y-m-d H:i'), $url]
292
        );
293
    }
294
295
    /**
296
     * Get all items between a start and end-date
297
     *
298
     * @param int $start The start date as a UNIX-timestamp.
299
     * @param int $end The end date as a UNIX-timestamp.
300
     * @param int $limit The number of items to get.
301
     * @param int $offset The offset.
302
     *
303
     * @return array
304
     */
305 2
    public static function getAllForDateRange(int $start, int $end, int $limit = 10, int $offset = 0): array
306
    {
307
        // get the items
308 2
        $items = (array) FrontendModel::getContainer()->get('database')->getRecords(
309 2
            'SELECT i.id, i.revision_id, i.language, i.title, i.introduction, i.text, i.num_comments AS comments_count,
310
             c.title AS category_title, m2.url AS category_url, i.image,
311
             UNIX_TIMESTAMP(i.publish_on) AS publish_on, i.user_id, i.allow_comments,
312
             m.url
313
             FROM blog_posts AS i
314
             INNER JOIN blog_categories AS c ON i.category_id = c.id
315
             INNER JOIN meta AS m ON i.meta_id = m.id
316
             INNER JOIN meta AS m2 ON c.meta_id = m2.id
317
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on BETWEEN ? AND ?
318
             ORDER BY i.publish_on DESC
319
             LIMIT ?, ?',
320
            [
321 2
                'active',
322 2
                LANGUAGE,
323
                false,
324 2
                FrontendModel::getUTCDate('Y-m-d H:i', $start),
325 2
                FrontendModel::getUTCDate('Y-m-d H:i', $end),
326 2
                $offset,
327 2
                $limit,
328
            ],
329 2
            'id'
330
        );
331
332
        // no results?
333 2
        if (empty($items)) {
334
            return [];
335
        }
336
337
        // init var
338 2
        $link = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
339 2
        $folders = FrontendModel::get(Thumbnails::class)->getFolders(FRONTEND_FILES_PATH . '/Blog/images', true);
340
341
        // loop
342 2
        foreach ($items as $key => $row) {
343
            // URLs
344 2
            $items[$key]['full_url'] = $link . '/' . $row['url'];
345
346
            // comments
347 2
            if ($row['comments_count'] > 0) {
348
                $items[$key]['comments'] = true;
349
            }
350 2
            if ($row['comments_count'] > 1) {
351
                $items[$key]['comments_multiple'] = true;
352
            }
353
354
            // allow comments as boolean
355 2
            $items[$key]['allow_comments'] = (bool) $row['allow_comments'];
356
357
            // reset allow comments
358 2
            if (!FrontendModel::get('fork.settings')->get('Blog', 'allow_comments')) {
359
                $items[$key]['allow_comments'] = false;
360
            }
361
362
            // image?
363 2
            if (isset($row['image'])) {
364
                foreach ($folders as $folder) {
365
                    $items[$key]['image_' . $folder['dirname']] = $folder['url'] . '/' . $folder['dirname'] .
366 2
                                                                  '/' . $row['image'];
367
                }
368
            }
369
        }
370
371
        // get all tags
372 2
        $tags = FrontendTagsModel::getForMultipleItems('Blog', array_keys($items));
373
374
        // loop tags and add to correct item
375 2
        foreach ($tags as $postId => $data) {
376
            $items[$postId]['tags'] = $data;
377
        }
378
379
        // return
380 2
        return $items;
381
    }
382
383
    /**
384
     * Get the number of items in a date range
385
     *
386
     * @param int $start The start date as a UNIX-timestamp.
387
     * @param int $end The end date as a UNIX-timestamp.
388
     *
389
     * @return int
390
     */
391 4
    public static function getAllForDateRangeCount(int $start, int $end): int
392
    {
393
        // return the number of items
394 4
        return (int) FrontendModel::getContainer()->get('database')->getVar(
395 4
            'SELECT COUNT(i.id)
396
             FROM blog_posts AS i
397
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on BETWEEN ? AND ?',
398
            [
399 4
                'active',
400 4
                LANGUAGE,
401
                false,
402 4
                FrontendModel::getUTCDate('Y-m-d H:i:s', $start),
403 4
                FrontendModel::getUTCDate('Y-m-d H:i:s', $end),
404
            ]
405
        );
406
    }
407
408
    /**
409
     * Get the statistics for the archive
410
     *
411
     * @return array
412
     */
413
    public static function getArchiveNumbers(): array
414
    {
415
        // grab stats
416
        $numbers = FrontendModel::getContainer()->get('database')->getPairs(
417
            'SELECT DATE_FORMAT(i.publish_on, "%Y%m") AS month, COUNT(i.id)
418
             FROM blog_posts AS i
419
             INNER JOIN meta AS m ON i.meta_id = m.id
420
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ?
421
             GROUP BY month',
422
            ['active', LANGUAGE, false, FrontendModel::getUTCDate('Y-m-d H:i')]
423
        );
424
425
        $stats = [];
426
        $link = FrontendNavigation::getUrlForBlock('Blog', 'Archive');
427
        $firstYear = (int) date('Y');
428
        $lastYear = 0;
429
430
        // loop the numbers
431
        foreach ($numbers as $key => $count) {
432
            $year = mb_substr($key, 0, 4);
433
            $month = mb_substr($key, 4, 2);
434
435
            // reset
436
            if ($year < $firstYear) {
437
                $firstYear = $year;
438
            }
439
            if ($year > $lastYear) {
440
                $lastYear = $year;
441
            }
442
443
            // generate timestamp
444
            $timestamp = gmmktime(00, 00, 00, $month, 01, $year);
0 ignored issues
show
A parse error occurred: The alleged octal '0' is invalid
Loading history...
445
446
            // initialize if needed
447
            if (!isset($stats[$year])) {
448
                $stats[$year] = [
449
                    'url' => $link . '/' . $year,
450
                    'label' => $year,
451
                    'total' => 0,
452
                    'months' => null,
453
                ];
454
            }
455
456
            // increment the total
457
            $stats[$year]['total'] += (int) $count;
458
            $stats[$year]['months'][$key] = [
459
                'url' => $link . '/' . $year . '/' . $month,
460
                'label' => $timestamp,
461
                'total' => $count,
462
            ];
463
        }
464
465
        // loop years
466
        for ($i = $firstYear; $i <= $lastYear; ++$i) {
467
            // year missing
468
            if (!isset($stats[$i])) {
469
                $stats[$i] = ['url' => null, 'label' => $i, 'total' => 0, 'months' => null];
470
            }
471
        }
472
473
        // sort
474
        krsort($stats);
475
476
        // reset stats
477
        foreach ($stats as &$row) {
478
            // remove url for empty years
479
            if ($row['total'] == 0) {
480
                $row['url'] = null;
481
            }
482
483
            // any months?
484
            if (!empty($row['months'])) {
485
                // sort months
486
                ksort($row['months']);
487
            }
488
        }
489
490
        // return
491
        return $stats;
492
    }
493
494 2
    public static function getComments(int $blogPostId): array
495
    {
496 2
        $comments = (array) FrontendModel::getContainer()->get('database')->getRecords(
497 2
            'SELECT c.id, UNIX_TIMESTAMP(c.created_on) AS created_on, c.text, c.data,
498
             c.author, c.email, c.website
499
             FROM blog_comments AS c
500
             WHERE c.post_id = ? AND c.status = ? AND c.language = ?
501
             ORDER BY c.id ASC',
502 2
            [$blogPostId, 'published', LANGUAGE]
503
        );
504
505 2
        foreach ($comments as &$row) {
506
            $row['gravatar_id'] = md5($row['email']);
507
        }
508
509 2
        return $comments;
510
    }
511
512
    /**
513
     * Fetch the list of tags for a list of items
514
     *
515
     * @param array $blogPostIds The ids of the items to grab.
516
     *
517
     * @return array
518
     */
519
    public static function getForTags(array $blogPostIds): array
520
    {
521
        // fetch items
522
        $items = (array) FrontendModel::getContainer()->get('database')->getRecords(
523
            'SELECT i.title, i.image, m.url
524
             FROM blog_posts AS i
525
             INNER JOIN meta AS m ON m.id = i.meta_id
526
             WHERE i.status = ? AND i.hidden = ? AND i.id IN (' . implode(',', $blogPostIds) . ') AND i.publish_on <= ?
527
             ORDER BY i.publish_on DESC',
528
            ['active', false, FrontendModel::getUTCDate('Y-m-d H:i')]
529
        );
530
531
        // has items
532
        if (!empty($items)) {
533
            // init var
534
            $link = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
535
            $folders = FrontendModel::get(Thumbnails::class)->getFolders(FRONTEND_FILES_PATH . '/Blog/images', true);
536
537
            // reset url
538
            foreach ($items as &$row) {
539
                $row['full_url'] = $link . '/' . $row['url'];
540
541
                // image?
542
                if (isset($row['image'])) {
543
                    foreach ($folders as $folder) {
544
                        $row['image_' . $folder['dirname']] = $folder['url'] . '/' . $folder['dirname'] .
545
                                                              '/' . $row['image'];
546
                    }
547
                }
548
            }
549
        }
550
551
        // return
552
        return $items;
553
    }
554
555
    /**
556
     * Get the id of an item by the full URL of the current page.
557
     * Selects the proper part of the full URL to get the item's id from the database.
558
     *
559
     * @param FrontendUrl $url The current URL.
560
     *
561
     * @return int
562
     */
563
    public static function getIdForTags(FrontendUrl $url): int
564
    {
565
        // select the proper part of the full URL
566
        $itemUrl = (string) $url->getParameter(1);
567
568
        // return the item
569
        return self::get($itemUrl)['id'] ?? 0;
570
    }
571
572
    /**
573
     * Get an array with the previous and the next post
574
     *
575
     * @param int $blogPostId The id of the current item.
576
     *
577
     * @return array
578
     */
579 2
    public static function getNavigation(int $blogPostId): array
580
    {
581
        // get database
582 2
        $database = FrontendModel::getContainer()->get('database');
583
584
        // get date for current item
585 2
        $date = (string) $database->getVar(
586 2
            'SELECT i.publish_on
587
             FROM blog_posts AS i
588
             WHERE i.id = ? AND i.status = ?',
589 2
            [$blogPostId, 'active']
590
        );
591
592
        // validate
593 2
        if ($date === '') {
594
            return [];
595
        }
596
597
        // init var
598 2
        $navigation = [];
599 2
        $detailLink = FrontendNavigation::getUrlForBlock('Blog', 'Detail') . '/';
600
601
        // get previous post
602 2
        $navigation['previous'] = $database->getRecord(
603 2
            'SELECT i.id, i.title, CONCAT(?, m.url) AS url
604
             FROM blog_posts AS i
605
             INNER JOIN meta AS m ON i.meta_id = m.id
606
             WHERE i.id != ? AND i.status = ? AND i.hidden = ? AND i.language = ? AND
607
                ((i.publish_on = ? AND i.id < ?) OR i.publish_on < ?)
608
             ORDER BY i.publish_on DESC, i.id DESC
609
             LIMIT 1',
610 2
            [$detailLink, $blogPostId, 'active', false, LANGUAGE, $date, $blogPostId, $date]
611
        );
612
613
        // get next post
614 2
        $navigation['next'] = $database->getRecord(
615 2
            'SELECT i.id, i.title, CONCAT(?, m.url) AS url
616
             FROM blog_posts AS i
617
             INNER JOIN meta AS m ON i.meta_id = m.id
618
             WHERE i.id != ? AND i.status = ? AND i.hidden = ? AND i.language = ? AND
619
                ((i.publish_on = ? AND i.id > ?) OR (i.publish_on > ? AND i.publish_on <= ?))
620
             ORDER BY i.publish_on ASC, i.id ASC
621
             LIMIT 1',
622
            [
623 2
                $detailLink,
624 2
                $blogPostId,
625 2
                'active',
626
                false,
627 2
                LANGUAGE,
628 2
                $date,
629 2
                $blogPostId,
630 2
                $date,
631 2
                FrontendModel::getUTCDate('Y-m-d H:i'),
632
            ]
633
        );
634
635
        // if empty, unset it
636 2
        if (empty($navigation['previous'])) {
637 2
            unset($navigation['previous']);
638
        }
639 2
        if (empty($navigation['next'])) {
640 2
            unset($navigation['next']);
641
        }
642
643
        // return
644 2
        return $navigation;
645
    }
646
647
    public static function getRecentComments(int $limit = 5): array
648
    {
649
        // init var
650
        $return = [];
651
652
        // get comments
653
        $comments = (array) FrontendModel::getContainer()->get('database')->getRecords(
654
            'SELECT c.id, c.author, c.website, c.email, UNIX_TIMESTAMP(c.created_on) AS created_on, c.text,
655
             i.id AS post_id, i.title AS post_title,
656
             m.url AS post_url
657
             FROM blog_comments AS c
658
             INNER JOIN blog_posts AS i ON c.post_id = i.id AND c.language = i.language
659
             INNER JOIN meta AS m ON i.meta_id = m.id
660
             WHERE c.status = ? AND i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ?
661
             ORDER BY c.id DESC
662
             LIMIT ?',
663
            ['published', 'active', LANGUAGE, false, FrontendModel::getUTCDate('Y-m-d H:i'), $limit]
664
        );
665
666
        // validate
667
        if (empty($comments)) {
668
            return $return;
669
        }
670
671
        // get link
672
        $link = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
673
674
        // loop comments
675
        foreach ($comments as &$row) {
676
            // add some URLs
677
            $row['post_full_url'] = $link . '/' . $row['post_url'];
678
            $row['full_url'] = $link . '/' . $row['post_url'] . '#comment-' . $row['id'];
679
            $row['gravatar_id'] = md5($row['email']);
680
        }
681
682
        return $comments;
683
    }
684
685
    public static function getRelated(int $blogPostId, int $limit = 5): array
686
    {
687
        // get the related IDs
688
        $relatedIDs = (array) FrontendTagsModel::getRelatedItemsByTags($blogPostId, 'Blog', 'Blog', $limit);
689
690
        // no items
691
        if (empty($relatedIDs)) {
692
            return [];
693
        }
694
695
        // get link
696
        $link = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
697
698
        // get items
699
        $items = (array) FrontendModel::getContainer()->get('database')->getRecords(
700
            'SELECT i.id, i.title, m.url
701
             FROM blog_posts AS i
702
             INNER JOIN meta AS m ON i.meta_id = m.id
703
             WHERE i.status = ? AND i.language = ? AND i.hidden = ? AND i.publish_on <= ? AND i.id IN(' .
704
            implode(',', $relatedIDs) . ')
705
             ORDER BY i.publish_on DESC, i.id DESC
706
             LIMIT ?',
707
            ['active', LANGUAGE, false, FrontendModel::getUTCDate('Y-m-d H:i'), $limit],
708
            'id'
709
        );
710
711
        // loop items
712
        foreach ($items as &$row) {
713
            $row['full_url'] = $link . '/' . $row['url'];
714
        }
715
716
        return $items;
717
    }
718
719
    public static function getRevision(string $url, int $revisionId): array
720
    {
721
        $blogPost = (array) FrontendModel::getContainer()->get('database')->getRecord(
722
            'SELECT i.id, i.revision_id, i.language, i.title, i.introduction, i.text, i.image,
723
             c.title AS category_title, m2.url AS category_url, m.id AS meta_id,
724
             UNIX_TIMESTAMP(i.publish_on) AS publish_on, i.user_id,
725
             i.allow_comments,
726
             m.keywords AS meta_keywords, m.keywords_overwrite AS meta_keywords_overwrite,
727
             m.description AS meta_description, m.description_overwrite AS meta_description_overwrite,
728
             m.title AS meta_title, m.title_overwrite AS meta_title_overwrite, m.custom AS meta_custom,
729
             m.url,
730
             m.data AS meta_data, m.seo_follow AS meta_seo_follow, m.seo_index AS meta_seo_index
731
             FROM blog_posts AS i
732
             INNER JOIN blog_categories AS c ON i.category_id = c.id
733
             INNER JOIN meta AS m ON i.meta_id = m.id
734
             INNER JOIN meta AS m2 ON c.meta_id = m2.id
735
             WHERE i.language = ? AND i.revision_id = ? AND m.url = ?
736
             LIMIT 1',
737
            [LANGUAGE, $revisionId, $url]
738
        );
739
740
        return self::completeBlogPost($blogPost);
741
    }
742
743 3
    private static function completeBlogPost(array $blogPost): array
744
    {
745 3
        if (isset($blogPost['meta_id'])) {
746 2
            $blogPost['meta'] = FrontendModel::get('fork.repository.meta')->find($blogPost['meta_id']);
747
        }
748
749 3
        if (isset($blogPost['meta_data'])) {
750
            $blogPost['meta_data'] = @unserialize($blogPost['meta_data'], ['allowed_classes' => false]);
751
        }
752
753
        // image?
754 3
        if (isset($blogPost['image'])) {
755
            $folders = FrontendModel::get(Thumbnails::class)->getFolders(FRONTEND_FILES_PATH . '/Blog/images', true);
756
757
            foreach ($folders as $folder) {
758
                $blogPost['image_' . $folder['dirname']] = $folder['url'] . '/' . $folder['dirname'] . '/' . $blogPost['image'];
759
            }
760
        }
761
762 3
        if (isset($blogPost['id'])) {
763 2
            $blogPost['tags'] = FrontendTagsModel::getForItem(
764 2
                'Blog',
765 2
                $blogPost['id'],
766 2
                isset($blogPost['language']) ? Locale::fromString($blogPost['language']) : null
767
            );
768
        }
769
770 3
        return $blogPost;
771
    }
772
773
    public static function insertComment(array $comment): int
774
    {
775
        // get database
776
        $database = FrontendModel::getContainer()->get('database');
777
778
        // insert comment
779
        $comment['id'] = (int) $database->insert('blog_comments', $comment);
780
781
        // recalculate if published
782
        if ($comment['status'] == 'published') {
783
            // num comments
784
            $numComments = (int) FrontendModel::getContainer()->get('database')->getVar(
785
                'SELECT COUNT(i.id) AS comment_count
786
                 FROM blog_comments AS i
787
                 INNER JOIN blog_posts AS p ON i.post_id = p.id AND i.language = p.language
788
                 WHERE i.status = ? AND i.post_id = ? AND i.language = ? AND p.status = ?
789
                 GROUP BY i.post_id',
790
                ['published', $comment['post_id'], LANGUAGE, 'active']
791
            );
792
793
            // update num comments
794
            $database->update('blog_posts', ['num_comments' => $numComments], 'id = ?', $comment['post_id']);
795
        }
796
797
        return $comment['id'];
798
    }
799
800
    /**
801
     * Get moderation status for an author
802
     *
803
     * @param string $author The name for the author.
804
     * @param string $email The email address for the author.
805
     *
806
     * @return bool
807
     */
808
    public static function isModerated(string $author, string $email): bool
809
    {
810
        return (bool) FrontendModel::getContainer()->get('database')->getVar(
811
            'SELECT 1
812
             FROM blog_comments AS c
813
             WHERE c.status = ? AND c.author = ? AND c.email = ?
814
             LIMIT 1',
815
            ['published', $author, $email]
816
        );
817
    }
818
819
    /**
820
     * Notify the admin
821
     *
822
     * @param array $comment The comment that was submitted.
823
     */
824
    public static function notifyAdmin(array $comment): void
825
    {
826
        // don't notify admin in case of spam
827
        if ($comment['status'] == 'spam') {
828
            return;
829
        }
830
831
        // get settings
832
        $notifyByMailOnComment = FrontendModel::get('fork.settings')->get(
833
            'Blog',
834
            'notify_by_email_on_new_comment',
835
            false
836
        );
837
        $notifyByMailOnCommentToModerate = FrontendModel::get('fork.settings')->get(
838
            'Blog',
839
            'notify_by_email_on_new_comment_to_moderate',
840
            false
841
        );
842
843
        // create URLs
844
        $url = SITE_URL . FrontendNavigation::getUrlForBlock('Blog', 'Detail') . '/' .
845
               $comment['post_url'] . '#comment-' . $comment['id'];
846
        $backendUrl = SITE_URL . FrontendNavigation::getBackendUrlForBlock('comments', 'Blog') . '#tabModeration';
847
848
        // notify on all comments
849
        if ($notifyByMailOnComment) {
850
            $variables = [];
851
852
            // comment to moderate
853
            if ($comment['status'] == 'moderation') {
854
                $variables['message'] = vsprintf(
855
                    FL::msg('BlogEmailNotificationsNewCommentToModerate'),
856
                    [$comment['author'], $url, $comment['post_title'], $backendUrl]
857
                );
858
            } elseif ($comment['status'] == 'published') {
859
                // comment was published
860
                $variables['message'] = vsprintf(
861
                    FL::msg('BlogEmailNotificationsNewComment'),
862
                    [$comment['author'], $url, $comment['post_title']]
863
                );
864
            }
865
866
            $to = FrontendModel::get('fork.settings')->get('Core', 'mailer_to');
867
            $from = FrontendModel::get('fork.settings')->get('Core', 'mailer_from');
868
            $replyTo = FrontendModel::get('fork.settings')->get('Core', 'mailer_reply_to');
869
            $message = Message::newInstance(FL::msg('NotificationSubject'))
870
                ->setFrom([$from['email'] => $from['name']])
871
                ->setTo([$to['email'] => $to['name']])
872
                ->setReplyTo([$replyTo['email'] => $replyTo['name']])
873
                ->parseHtml(
874
                    '/Core/Layout/Templates/Mails/Notification.html.twig',
875
                    $variables,
876
                    true
877
                )
878
            ;
879
            FrontendModel::get('mailer')->send($message);
880
        } elseif ($notifyByMailOnCommentToModerate && $comment['status'] == 'moderation') {
881
            // only notify on new comments to moderate and if the comment is one to moderate
882
            // set variables
883
            $variables = [];
884
            $variables['message'] = vsprintf(
885
                FL::msg('BlogEmailNotificationsNewCommentToModerate'),
886
                [$comment['author'], $url, $comment['post_title'], $backendUrl]
887
            );
888
889
            $to = FrontendModel::get('fork.settings')->get('Core', 'mailer_to');
890
            $from = FrontendModel::get('fork.settings')->get('Core', 'mailer_from');
891
            $replyTo = FrontendModel::get('fork.settings')->get('Core', 'mailer_reply_to');
892
            $message = Message::newInstance(FL::msg('NotificationSubject'))
893
                ->setFrom([$from['email'] => $from['name']])
894
                ->setTo([$to['email'] => $to['name']])
895
                ->setReplyTo([$replyTo['email'] => $replyTo['name']])
896
                ->parseHtml(
897
                    '/Core/Layout/Templates/Mails/Notification.html.twig',
898
                    $variables,
899
                    true
900
                )
901
            ;
902
            FrontendModel::get('mailer')->send($message);
903
        }
904
    }
905
906
    /**
907
     * Parse the search results for this module
908
     *
909
     * Note: a module's search function should always:
910
     *        - accept an array of entry id's
911
     *        - return only the entries that are allowed to be displayed, with their array's index being the entry's id
912
     *
913
     *
914
     * @param array $ids The ids of the found results.
915
     *
916
     * @return array
917
     */
918 1
    public static function search(array $ids): array
919
    {
920 1
        $items = (array) FrontendModel::getContainer()->get('database')->getRecords(
921
            'SELECT i.id, i.title, i.introduction, i.text, m.url
922
             FROM blog_posts AS i
923
             INNER JOIN meta AS m ON i.meta_id = m.id
924
             WHERE i.status = ? AND i.hidden = ? AND i.language = ? AND i.publish_on <= ? AND i.id IN (' .
925 1
            implode(',', $ids) . ')',
926 1
            ['active', false, LANGUAGE, date('Y-m-d H:i')],
927 1
            'id'
928
        );
929
930
        // prepare items for search
931 1
        $detailUrl = FrontendNavigation::getUrlForBlock('Blog', 'Detail');
932 1
        foreach ($items as &$item) {
933 1
            $item['full_url'] = $detailUrl . '/' . $item['url'];
934
        }
935
936
        // return
937 1
        return $items;
938
    }
939
}
940