PostModel::getAllPublishedPosts()   B
last analyzed

Complexity

Conditions 7
Paths 10

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 20
nc 10
nop 4
dl 0
loc 33
rs 8.6666
c 0
b 0
f 0
1
<?php
2
3
namespace App\Models;
4
5
use Core\Constant;
6
use Core\Container;
7
use Core\Model;
8
use Core\Traits\StringFunctions;
9
use Exception;
10
11
class PostModel extends Model
12
{
13
    use StringFunctions;
14
15
    private $postsTbl;
16
    private $categoriesTbl;
17
    private $usersTbl;
18
    private $postTagTbl;
19
20
    //does our query need the tags table to be joined ?
21
    private $queryWithTags = false;
22
23
    public function __construct(Container $container)
24
    {
25
        parent::__construct($container);
26
        $this->postsTbl = $this->getTablePrefix("posts");
27
        $this->categoriesTbl = $this->getTablePrefix("categories");
28
        $this->usersTbl = $this->getTablePrefix("users");
29
        $this->postTagTbl = $this->getTablePrefix("posts_has_tags");
30
    }
31
32
    /**
33
     * the base Select SQL to get the information from the post table and joined tables
34
     * @param bool $withTags
35
     * @return string
36
     */
37
    private function basePostSelect(): string
38
    {
39
        $sql = "SELECT idposts, title, post_image,article,$this->postsTbl.last_update, posts_slug, categories_idcategories, category_name, published, on_front_page, categories_slug, username as author, idusers
40
                FROM $this->postsTbl 
41
                LEFT JOIN $this->categoriesTbl ON $this->postsTbl.categories_idcategories = $this->categoriesTbl.idcategories 
42
                LEFT JOIN $this->usersTbl ON $this->postsTbl.author_iduser = $this->usersTbl.idusers";
43
        if ($this->queryWithTags) {
44
            $sql .= " LEFT JOIN $this->postTagTbl ON $this->postsTbl.idposts = $this->postTagTbl.post_idposts";
45
        }
46
        return $sql;
47
    }
48
49
    /**
50
     * add the excerpt to a post list
51
     * @param array $posts
52
     * @return array
53
     * @throws \ErrorException
54
     */
55
    private function addExcerpt(array $posts): array
56
    {
57
        $sendResults = [];
58
        //we create the excerpt for the text and add it to the object
59
        foreach ($posts as $post) {
60
            $post->{'excerpt'} = $this->getExcerpt($post->article);
61
            $sendResults[] = $post;
62
        }
63
        return $sendResults;
64
    }
65
66
    /**
67
     * get all posts, no restriction
68
     */
69
    private function getAllPosts(int $offset, int $limit)
70
    {
71
        $sql = $this->basePostSelect();
72
        $sql .= " ORDER BY $this->postsTbl.creation_date DESC";
73
        $sql .= " LIMIT :limit OFFSET :offset";
74
        $this->query($sql);
75
        $this->bind(":limit", $limit);
76
        $this->bind(":offset", $offset);
77
        $this->execute();
78
        $results = $this->fetchAll();
79
        return $this->addExcerpt($results);
80
    }
81
82
    /**
83
     * get all the posts with details. Only selecting posts that are published
84
     * @param int $offset where to start (for pagination)
85
     * @param int $limit the number of posts
86
     * @param bool $isFrontPage extract only front page posts
87
     * @param array $select list of select limiters
88
     * @return array list of posts
89
     * @throws \ErrorException
90
     */
91
    private function getAllPublishedPosts(
92
        int $offset,
93
        int $limit,
94
        bool $isFrontPage = false,
95
        array $select = []
96
    ): array {
97
        $sql = $this->basePostSelect();
98
        $sql .= " WHERE published = 1";
99
        if ($isFrontPage) {
100
            $sql .= " AND on_front_page = 1";
101
        }
102
        //if we have a limiting parameter
103
        if ($select != null) {
104
            foreach ($select as $col => $val) {
105
                if (!$this->isAlphaNum($col)) {
106
                    throw new Exception("Invalid column name");
107
                }
108
                $sql .= " AND $col = :$col";
109
            }
110
        }
111
        $sql .= " ORDER BY $this->postsTbl.creation_date DESC";
112
        $sql .= " LIMIT :limit OFFSET :offset";
113
        $this->query($sql);
114
        if ($select != null) {
115
            foreach ($select as $col => $val) {
116
                $this->bind(":" . $col, $val);
117
            }
118
        }
119
        $this->bind(":limit", $limit);
120
        $this->bind(":offset", $offset);
121
        $this->execute();
122
        $results = $this->fetchAll();
123
        return $this->addExcerpt($results);
124
    }
125
126
    /**
127
     * Count the number of published posts
128
     * @param array $select list of select limiters
129
     * @param bool $published
130
     * @return int number of posts
131
     * @throws Exception
132
     */
133
    private function countNumberPosts(array $select = [], $published = true): int
134
    {
135
        $sql = "SELECT COUNT(*) FROM $this->postsTbl";
136
        if ($this->queryWithTags) {
137
            $sql .= " LEFT JOIN $this->postTagTbl ON $this->postsTbl.idposts = $this->postTagTbl.post_idposts";
138
        }
139
        if ($published) {
140
            $sql .= " WHERE published = 1";
141
        }
142
        if ($select != null) {
143
            foreach ($select as $col => $val) {
144
                if (!$this->isAlphaNum($col)) {
145
                    throw new Exception("Invalid column name");
146
                }
147
                $sql .= " AND $col = :$col";
148
            }
149
        }
150
        $this->query($sql);
151
        if ($select != null) {
152
            foreach ($select as $col => $val) {
153
                $this->bind(":" . $col, $val);
154
            }
155
        }
156
        $this->execute();
157
        return $this->stmt->fetchColumn();
158
    }
159
160
    /**
161
     * get the total number of posts
162
     * @return int
163
     * @throws Exception
164
     */
165
    public function totalNumberPosts(): int
166
    {
167
        return $this->countNumberPosts();
168
    }
169
170
    /**
171
     * get the total number of posts + unpublished
172
     * @return int
173
     * @throws Exception
174
     */
175
    public function totalNumberFullPosts(): int
176
    {
177
        return $this->countNumberPosts([], false);
178
    }
179
180
    /**
181
     * get the total number of posts in a category
182
     * @param int $categoryId
183
     * @return int
184
     * @throws Exception
185
     */
186
    public function totalNumberPostsInCategory(int $categoryId): int
187
    {
188
        return $this->countNumberPosts(["categories_idcategories" => $categoryId]);
189
    }
190
191
    /**
192
     * get the total number of posts by an author
193
     * @param int $authorId
194
     * @return int
195
     * @throws Exception
196
     */
197
    public function totalNumberPostsByAuthor(int $authorId): int
198
    {
199
        return $this->countNumberPosts(["author_iduser" => $authorId]);
200
    }
201
202
    /**
203
     * get the total number of posts with tag
204
     * @param int $tagId
205
     * @return int
206
     * @throws Exception
207
     */
208
    public function totalNumberPostsByTag(int $tagId): int
209
    {
210
        $this->queryWithTags = true;
211
        return $this->countNumberPosts(["tag_idtags" => $tagId]);
212
    }
213
214
    /**
215
     * get the list of front posts
216
     * @param int $offset
217
     * @param int $limit
218
     * @return array
219
     * @throws \ErrorException
220
     */
221
    public function getFrontPosts(int $offset = 0, int $limit = Constant::FRONT_PAGE_POSTS): array
222
    {
223
        return $this->getAllPublishedPosts($offset, $limit, true);
224
    }
225
226
    /**
227
     * get the list of all the posts.
228
     * @param int $offset
229
     * @param array $select array of limiters [$key => $val] will convert to "where $key = $val"
230
     * @param int $limit
231
     * @return array
232
     * @throws \ErrorException
233
     */
234
    public function getPosts(int $offset = 0, array $select = [], int $limit = Constant::POSTS_PER_PAGE): array
235
    {
236
        return $this->getAllPublishedPosts($offset, $limit, false, $select);
237
    }
238
239
    /**
240
     *gets all the posts
241
     * @param int $offset
242
     * @param int $limit
243
     * @return array
244
     */
245
    public function getFullPosts(int $offset = 0, int $limit = Constant::POSTS_PER_PAGE): array
246
    {
247
        return $this->getAllPosts($offset, $limit);
248
    }
249
250
251
    /**
252
     * get all the posts from a certain category
253
     * @param int $categoryId the id of the category
254
     * @param int $offset the offset for pagination
255
     * @param int $limit the limit to display
256
     * @return array list of posts in set category
257
     * @throws Exception
258
     */
259
    public function getPostsInCategory(int $categoryId, int $offset = 0, int $limit = Constant::POSTS_PER_PAGE): array
260
    {
261
        return $this->getPosts($offset, ["categories_idcategories" => $categoryId], $limit);
262
    }
263
264
    /**
265
     * get all the posts with a specific author
266
     * @param int $authorId
267
     * @param int $offset
268
     * @param int $limit
269
     * @return array
270
     * @throws \ErrorException
271
     */
272
    public function getPostsWithAuthor(int $authorId, int $offset = 0, int $limit = Constant::POSTS_PER_PAGE): array
273
    {
274
        return $this->getPosts($offset, ["author_iduser" => $authorId], $limit);
275
    }
276
277
    /**
278
     * get all the posts with a certain tag
279
     * @param int $tagId
280
     * @param int $offset
281
     * @param int $limit
282
     * @return array
283
     * @throws \ErrorException
284
     */
285
    public function getPostsWithTag(int $tagId, int $offset = 0, int $limit = Constant::POSTS_PER_PAGE): array
286
    {
287
        $this->queryWithTags = true;
288
        return $this->getPosts($offset, ["tag_idtags" => $tagId], $limit);
289
    }
290
291
    /**
292
     * get a single post from it's ID
293
     * @param int $postId the post ID to get
294
     * @return array the single post details
295
     * @throws Exception
296
     */
297
    public function getSinglePost(int $postId)
298
    {
299
        $sql = $this->basePostSelect();
300
        $sql .= " WHERE idposts = :postId;";
301
        $this->query($sql);
302
        $this->bind(":postId", $postId, \PDO::PARAM_INT);
303
        $this->execute();
304
305
        return $this->fetch();
306
    }
307
308
    /**
309
     * Create a new post
310
     * @param string $title
311
     * @param string $postImage
312
     * @param int $idCategory
313
     * @param string $article
314
     * @param int $idUser
315
     * @param int $published
316
     * @param int $onFrontPage
317
     * @param string $postSlug
318
     * @return int the id of created post
319
     * @throws Exception
320
     */
321
    public function newPost(
322
        string $title,
323
        string $postImage,
324
        int $idCategory,
325
        string $article,
326
        int $idUser,
327
        int $published,
328
        int $onFrontPage,
329
        string $postSlug
330
    ): int {
331
        $sql = "
332
          INSERT INTO $this->postsTbl (title, post_image, categories_idcategories, article, author_iduser, creation_date, last_update, published, on_front_page, posts_slug)
333
          VALUES (:title, :post_image, :categories_idcategories, :article, :author_iduser, NOW(), NOW(), :published, :on_front_page, :posts_slug)
334
        ";
335
        $this->query($sql);
336
        $this->bind(':title', $title);
337
        $this->bind(':post_image', $postImage);
338
        $this->bind(':categories_idcategories', $idCategory);
339
        $this->bind(':article', $article);
340
        $this->bind(':author_iduser', $idUser);
341
        $this->bind(':published', $published);
342
        $this->bind(':on_front_page', $onFrontPage);
343
        $this->bind(':posts_slug', $postSlug);
344
345
        $this->execute();
346
347
        return (int)$this->dbh->lastInsertId();
348
    }
349
350
    /**
351
     * Update a post with new values
352
     * @param int $postId
353
     * @param string $title
354
     * @param string $postImage
355
     * @param int $idCategory
356
     * @param string $article
357
     * @param int $published
358
     * @param int $onFrontPage
359
     * @param string $postSlug
360
     * @return bool success
361
     * @throws Exception
362
     */
363
    public function modifyPost(
364
        int $postId,
365
        string $title,
366
        string $postImage,
367
        int $idCategory,
368
        string $article,
369
        int $published,
370
        int $onFrontPage,
371
        string $postSlug
372
    ): bool {
373
        $sql = "
374
            UPDATE $this->postsTbl 
375
            SET 
376
                title = :title,
377
                post_image = :postImage,
378
                categories_idcategories = :idCategory,
379
                article = :article,
380
                last_update = NOW(),
381
                published = :published,
382
                on_front_page = :onFrontPage,
383
                posts_slug = :postSlug
384
            WHERE
385
              idposts = :postId
386
        ;";
387
        $this->query($sql);
388
        $this->bind(":title", $title);
389
        $this->bind(":postImage", $postImage);
390
        $this->bind(":idCategory", $idCategory);
391
        $this->bind(":article", $article);
392
        $this->bind(":published", $published);
393
        $this->bind(":onFrontPage", $onFrontPage);
394
        $this->bind(":postSlug", $postSlug);
395
        $this->bind(":postId", $postId);
396
397
        return $this->finalExecute();
398
    }
399
400
    /**
401
     * Removes a post from the DataBase
402
     * @param int $postId
403
     * @return bool
404
     * @throws Exception
405
     */
406
    public function deletePost(int $postId): bool
407
    {
408
        $sql = "
409
        DELETE FROM $this->postsTbl 
410
        WHERE idposts = :postId
411
        ";
412
        $this->query($sql);
413
        $this->bind(":postId", $postId);
414
        return $this->finalExecute();
415
    }
416
417
418
    /**
419
     * get the post title from ID
420
     * @param int $postId
421
     * @return string
422
     * @throws Exception
423
     */
424
    public function getTitleFromId(int $postId): string
425
    {
426
        $sql = "SELECT title from $this->postsTbl WHERE idposts = :postId";
427
        $this->query($sql);
428
        $this->bind(":postId", $postId);
429
        $this->execute();
430
        return $this->stmt->fetchColumn();
431
    }
432
433
434
    /**
435
     * Set or unset the published state of a post
436
     * @param bool $state
437
     * @param int $postId
438
     * @return bool
439
     * @throws Exception
440
     */
441
    public function setPublished(bool $state, int $postId):bool
442
    {
443
        $sql = "
444
            UPDATE $this->postsTbl 
445
            SET
446
              last_update = NOW(),
447
              published = :published
448
            WHERE
449
              idposts = :postId
450
        ";
451
        $this->query($sql);
452
        $this->bind(":postId", $postId);
453
        $this->bind(":published", $state);
454
455
        return $this->finalExecute();
456
    }
457
458
    /**
459
     * set or unset the on front page state of a post
460
     * @param bool $state
461
     * @param int $postId
462
     * @return bool
463
     * @throws Exception
464
     */
465
    public function setOnFrontPage(bool $state, int $postId):bool
466
    {
467
        $sql = "
468
            UPDATE $this->postsTbl 
469
            SET
470
              last_update = NOW(),
471
              on_front_page = :onFrontPage
472
            WHERE
473
              idposts = :postId
474
        ";
475
        $this->query($sql);
476
        $this->bind(":postId", $postId);
477
        $this->bind(":onFrontPage", $state);
478
479
        return $this->finalExecute();
480
    }
481
482
    /**
483
     *
484
     * @param string $postSlug
485
     * @return bool
486
     * @throws Exception
487
     */
488
    public function isPostSlugUnique(string $postSlug): bool
489
    {
490
        return $this->isSlugUnique($postSlug, "posts_slug", "posts");
491
    }
492
493
    /**
494
     * Get the post slug from an ID
495
     * @param int $postId
496
     * @return string
497
     * @throws \ReflectionException
498
     */
499
    public function getPostSlugFromId(int $postId)
500
    {
501
        return $this->getSlugFromId($postId, "idposts", "posts_slug");
502
    }
503
504
505
    /**
506
     * get the ID from the slug
507
     * @param string $postSlug
508
     * @return int
509
     * @throws Exception
510
     */
511
    public function getPostIdFromSlug(string $postSlug)
512
    {
513
        return $this->getIdFromSlug($postSlug, "idposts", "posts_slug");
514
    }
515
}