• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fnagel / t3extblog / 23771092563

30 Mar 2026 10:36PM UTC coverage: 45.286%. Remained the same
23771092563

push

github

fnagel
WIP

1518 of 3352 relevant lines covered (45.29%)

2.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.25
/Classes/Domain/Model/Post.php
1
<?php
2

3
namespace FelixNagel\T3extblog\Domain\Model;
4

5
/**
6
 * This file is part of the "t3extblog" Extension for TYPO3 CMS.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11

12
use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
13
use TYPO3\CMS\Core\Utility\GeneralUtility;
14
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
15
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
16
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
17
use TYPO3\CMS\Extbase\Annotation as Extbase;
18
use TYPO3\CMS\Core\Resource\FileReference;
19
use TYPO3\CMS\Extbase\Domain\Model\FileReference as ExtbaseFileReference;
20

21
/**
22
 * Post.
23
 *
24
 * @SuppressWarnings("PHPMD.ExcessiveClassComplexity")
25
 * @SuppressWarnings("PHPMD.ExcessivePublicCount")
26
 * @SuppressWarnings("PHPMD.TooManyFields")
27
 */
28
class Post extends AbstractLocalizedEntity
29
{
30
    /**
31
     * @var int
32
     */
33
    public const ALLOW_COMMENTS_EVERYONE = 0;
34

35
    /**
36
     * @var int
37
     */
38
    public const ALLOW_COMMENTS_NOBODY = 1;
39

40
    /**
41
     * @var int
42
     */
43
    public const ALLOW_COMMENTS_LOGIN = 2;
44

45
    protected bool $hidden = true;
46

47
    #[Extbase\Validate(['validator' => 'NotEmpty'])]
48
    protected ?string $title = null;
49

50
    protected ?BackendUser $author = null;
51

52
    #[Extbase\Validate(['validator' => 'NotEmpty'])]
53
    protected \DateTime $publishDate;
54

55
    protected ?int $allowComments = null;
56

57
    /**
58
     * This var annotation seems needed for Extbase.
59
     *
60
     * @var string
61
     */
62
    protected string $tagCloud = '';
63

64
    protected int $numberOfViews = 0;
65

66
    /**
67
     * If the notification mails are already sent.
68
     */
69
    protected bool $mailsSent = false;
70

71
    protected ?string $metaDescription = null;
72

73
    protected ?string $metaKeywords = null;
74

75
    protected ?int $previewMode = null;
76

77
    protected ?string $previewText = null;
78

79
    #[Lazy]
80
    protected ExtbaseFileReference|LazyLoadingProxy|null $previewImage = null;
81

82
    /**
83
     * @var ?ObjectStorage<Content>
84
     */
85
    #[Lazy]
86
    protected ?ObjectStorage $content = null;
87

88
    /**
89
     * @var ?ObjectStorage<Category>
90
     */
91
    #[Lazy]
92
    protected ?ObjectStorage $categories = null;
93

94
    /**
95
     * @var ?ObjectStorage<Comment>
96
     */
97
    protected ?ObjectStorage $comments = null;
98

99
    #[Lazy]
100
    protected ?QueryResultInterface $rawComments = null;
101

102
    /**
103
     * @var ?ObjectStorage<PostSubscriber>
104
     */
105
    #[Lazy]
106
    protected ?ObjectStorage $subscriptions = null;
107

108
    public function __construct()
17✔
109
    {
110
        $this->initStorageObjects();
17✔
111
    }
112

113
    protected function getPropertiesForSerialization(): array
×
114
    {
115
        $properties = parent::getPropertiesForSerialization();
×
116

117
        // Remove previewImage due to broken post preview
118
        // @todo Preview: Fix this!
119
        unset($properties['previewImage']);
×
120

121
        return $properties;
×
122
    }
123

124
    /**
125
     * Initializes all ObjectStorage properties.
126
     */
127
    protected function initStorageObjects()
17✔
128
    {
129
        $this->categories = new ObjectStorage();
17✔
130
        $this->subscriptions = new ObjectStorage();
17✔
131
        // @extensionScannerIgnoreLine
132
        $this->content = new ObjectStorage();
17✔
133
    }
134

135
    public function getTitle(): string
8✔
136
    {
137
        return $this->title;
8✔
138
    }
139

140
    public function setTitle(string $title): void
×
141
    {
142
        $this->title = $title;
×
143
    }
144

145
    public function getAuthor(): BackendUser
8✔
146
    {
147
        if (!($this->author instanceof BackendUser)) {
8✔
148
            $this->author = new BackendUser();
8✔
149
            $this->author->setUserName(uniqid('author-unavailable', true));
8✔
150
            $this->author->setRealName('Author unavailable');
8✔
151
        }
152

153
        return $this->author;
8✔
154
    }
155

156
    public function setAuthor(BackendUser $author): void
×
157
    {
158
        $this->author = $author;
×
159
    }
160

161
    public function getPublishDate(): \DateTime
11✔
162
    {
163
        return $this->publishDate;
11✔
164
    }
165

166
    public function getPublishYear(): string
×
167
    {
168
        return $this->publishDate->format('Y');
×
169
    }
170

171
    public function getPublishMonth(): string
×
172
    {
173
        return $this->publishDate->format('m');
×
174
    }
175

176
    public function getPublishDay(): string
×
177
    {
178
        return $this->publishDate->format('d');
×
179
    }
180

181
    /**
182
     * Checks if the post is too old for posting new comments.
183
     */
184
    public function isExpired(string $expireDate = '+1 month'): bool
3✔
185
    {
186
        $now = new \DateTime();
3✔
187
        $expire = clone $this->getPublishDate();
3✔
188

189
        return $now > $expire->modify($expireDate);
3✔
190
    }
191

192
    public function setPublishDate(\DateTime $publishDate): void
3✔
193
    {
194
        $this->publishDate = $publishDate;
3✔
195
    }
196

197
    public function getAllowComments(): int
6✔
198
    {
199
        return $this->allowComments;
6✔
200
    }
201

202
    public function setAllowComments(int $allowComments): void
×
203
    {
204
        $this->allowComments = $allowComments;
×
205
    }
206

207
    public function getTagCloud(): array
12✔
208
    {
209
        return GeneralUtility::trimExplode(',', $this->tagCloud, true);
12✔
210
    }
211

212
    /**
213
     * Returns the tagCloud as in DB (concated string).
214
     */
215
    public function getRawTagCloud(): string
7✔
216
    {
217
        return $this->tagCloud;
7✔
218
    }
219

220
    public function setTagCloud(string|array $tagCloud): void
4✔
221
    {
222
        $this->tagCloud = is_array($tagCloud) ? implode(', ', $tagCloud) : $tagCloud;
4✔
223
    }
224

225
    public function getNumberOfViews(): int
×
226
    {
227
        return $this->numberOfViews;
×
228
    }
229

230
    public function setNumberOfViews(int $numberOfViews): void
×
231
    {
232
        $this->numberOfViews = $numberOfViews;
×
233
    }
234

235
    public function riseNumberOfViews()
×
236
    {
237
        ++$this->numberOfViews;
×
238
    }
239

240
    public function setMailsSent(bool $mailsSent): void
4✔
241
    {
242
        $this->mailsSent = $mailsSent;
4✔
243
    }
244

245
    public function getMailsSent(): bool
4✔
246
    {
247
        return $this->mailsSent;
4✔
248
    }
249

250
    /**
251
     * Is it possible to send post subscription mails?
252
     */
253
    public function isMailSendingAllowed(): bool
4✔
254
    {
255
        return !$this->getMailsSent() && !$this->getHidden() && !$this->getDeleted();
4✔
256
    }
257

258
    public function getMetaDescription(): ?string
6✔
259
    {
260
        return $this->metaDescription;
6✔
261
    }
262

263
    public function setMetaDescription(string $metaDescription): void
×
264
    {
265
        $this->metaDescription = $metaDescription;
×
266
    }
267

268
    public function getMetaKeywords(): string
6✔
269
    {
270
        return $this->metaKeywords;
6✔
271
    }
272

273
    public function setMetaKeywords(string $metaKeywords): void
×
274
    {
275
        $this->metaKeywords = $metaKeywords;
×
276
    }
277

278
    public function getPreviewMode(): int
×
279
    {
280
        return $this->previewMode;
×
281
    }
282

283
    public function setPreviewMode(int $previewMode): void
×
284
    {
285
        $this->previewMode = $previewMode;
×
286
    }
287

288
    public function getPreviewText(): ?string
8✔
289
    {
290
        return $this->previewText;
8✔
291
    }
292

293
    public function setPreviewText(string $previewText): void
2✔
294
    {
295
        $this->previewText = $previewText;
2✔
296
    }
297

298
    public function getPreviewImage(): ?FileReference
6✔
299
    {
300
        $this->loadLazyRelation($this->previewImage);
6✔
301

302
        if (!is_object($this->previewImage)) {
6✔
303
            return null;
6✔
304
        }
305

306
        return $this->previewImage->getOriginalResource();
×
307
    }
308

309
    public function setPreviewImage(ExtbaseFileReference $previewImage): void
×
310
    {
311
        $this->previewImage = $previewImage;
×
312
    }
313

314
    public function getContent(): ObjectStorage
8✔
315
    {
316
        // @extensionScannerIgnoreLine
317
        return $this->content;
8✔
318
    }
319

320
    public function setContent(ObjectStorage $content): void
×
321
    {
322
        // @extensionScannerIgnoreLine
323
        $this->content = $content;
×
324
    }
325

326
    /**
327
     * Adds a content element to the record.
328
     */
329
    public function addContent(Content $content): void
×
330
    {
331
        if ($this->getContent() === null) {
×
332
            // @extensionScannerIgnoreLine
333
            $this->content = new ObjectStorage();
×
334
        }
335

336
        // @extensionScannerIgnoreLine
337
        $this->content->attach($content);
×
338
    }
339

340
    /**
341
     * Get UID list of content elements.
342
     */
343
    public function getContentIdList(): string
×
344
    {
345
        $idList = [];
×
346

347
        foreach ($this->getContent() as $contentElement) {
×
348
            $idList[] = $contentElement->getUid();
×
349
        }
350

351
        return implode(',', $idList);
×
352
    }
353

354
    /**
355
     * Get a plain text only preview of the post.
356
     *
357
     * Either using the preview text or
358
     * all content elements bodytext field values contacted without HTML tags
359
     */
360
    public function getPreview(): string
8✔
361
    {
362
        if ($this->getPreviewText()) {
8✔
363
            return strip_tags($this->getPreviewText());
2✔
364
        }
365

366
        $text = [];
6✔
367
        foreach ($this->getContent() as $contentElement) {
6✔
368
            if (strlen($contentElement->getBodytext()) > 0) {
×
369
                $text[] = $contentElement->getBodytext();
×
370
            }
371
        }
372

373
        return strip_tags(implode('', $text));
6✔
374
    }
375

376
    public function addCategory(Category $category): void
×
377
    {
378
        $this->categories->attach($category);
×
379
    }
380

381
    public function removeCategory(Category $categoryToRemove)
×
382
    {
383
        $this->categories->detach($categoryToRemove);
×
384
    }
385

386
    public function getCategories(): ObjectStorage
8✔
387
    {
388
        return $this->categories;
8✔
389
    }
390

391
    /**
392
     * Inits comments.
393
     *
394
     * Mapping does not work as relation is not bidirectional, using a repository instead
395
     * And: its currently not possible to iterate via paginate widget through storage objects
396
     */
397
    protected function initComments(): void
8✔
398
    {
399
        if ($this->comments === null) {
8✔
400
            $this->rawComments = $this->getCommentRepository()->findValidByPost($this);
8✔
401

402
            $this->comments = new ObjectStorage();
8✔
403
            foreach ($this->rawComments as $comment) {
8✔
404
                $this->comments->attach($comment);
8✔
405
            }
406
        }
407
    }
408

409
    public function addComment(Comment $comment): void
2✔
410
    {
411
        $this->initComments();
2✔
412

413
        $comment->setPostId($this->getLocalizedUid());
2✔
414

415
        $this->comments->attach($comment);
2✔
416
        $this->getCommentRepository()->add($comment);
2✔
417
    }
418

419
    public function removeComment(Comment $commentToRemove): void
×
420
    {
421
        $this->initComments();
×
422

423
        $commentToRemove->setDeleted(true);
×
424

425
        $this->comments->detach($commentToRemove);
×
426
        $this->getCommentRepository()->update($commentToRemove);
×
427
    }
428

429
    public function getComments(): ObjectStorage
8✔
430
    {
431
        $this->initComments();
8✔
432

433
        return $this->comments;
8✔
434
    }
435

436
    public function getCommentsForPaginate(): QueryResultInterface
6✔
437
    {
438
        $this->initComments();
6✔
439

440
        return $this->rawComments;
6✔
441
    }
442

443
    public function setComments(ObjectStorage $comments): void
×
444
    {
445
        $this->comments = $comments;
×
446
    }
447

448
    public function addSubscription(PostSubscriber $subscription): void
×
449
    {
450
        $this->subscriptions->attach($subscription);
×
451
    }
452

453
    public function removeSubscription(PostSubscriber $subscriptionToRemove): void
×
454
    {
455
        $this->subscriptions->detach($subscriptionToRemove);
×
456
    }
457

458
    public function getSubscriptions(): ?ObjectStorage
6✔
459
    {
460
        return $this->subscriptions;
6✔
461
    }
462

463
    public function setSubscriptions(ObjectStorage $subscriptions): void
×
464
    {
465
        $this->subscriptions = $subscriptions;
×
466
    }
467

468
    /**
469
     * Returns the permalink configuration.
470
     */
471
    public function getLinkParameter(): array
8✔
472
    {
473
        return [
8✔
474
            'post' => $this->getLocalizedUid(),
8✔
475
        ];
8✔
476
    }
477
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc