Forum::getSlug()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProjetNormandie\ForumBundle\Entity;
6
7
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
8
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
9
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
10
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
11
use ApiPlatform\Metadata\ApiFilter;
12
use ApiPlatform\Metadata\ApiResource;
13
use ApiPlatform\Metadata\Get;
14
use ApiPlatform\Metadata\GetCollection;
15
use ApiPlatform\OpenApi\Model\Operation;
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Collection;
18
use Doctrine\ORM\Mapping as ORM;
19
use Gedmo\Mapping\Annotation as Gedmo;
20
use Gedmo\Timestampable\Traits\TimestampableEntity;
21
use ProjetNormandie\ForumBundle\Controller\Forum\GetStats;
22
use ProjetNormandie\ForumBundle\Controller\Forum\MarkAsRead;
23
use ProjetNormandie\ForumBundle\Controller\ReadAll;
24
use ProjetNormandie\ForumBundle\Repository\ForumRepository;
25
use ProjetNormandie\ForumBundle\ValueObject\ForumStatus;
26
use Symfony\Component\Serializer\Annotation\Groups;
27
use Symfony\Component\Validator\Constraints as Assert;
28
29
#[ORM\Table(name:'pnf_forum')]
30
#[ORM\Entity(repositoryClass: ForumRepository::class)]
31
#[ORM\Index(name: "idx_position", columns: ["position"])]
32
#[ORM\Index(name: "idx_lib_forum", columns: ["lib_forum"])]
33
#[ApiResource(
34
    shortName: 'ForumForum',
35
    operations: [
36
        new GetCollection(
37
            uriTemplate: '/forum_forums',
38
        ),
39
        new Get(
40
            uriTemplate: '/forum_forums/{id}',
41
            security: 'object.getStatus() == "public" or is_granted(object.getRole())',
42
        ),
43
        new Get(
44
            uriTemplate: '/forum_forums/read-all',
45
            read: false,
46
            controller: ReadAll::class,
47
            openapi: new Operation(
48
                summary: 'Mark all forums as read',
49
                description: 'Mark all forums as read'
50
            ),
51
            security: 'is_granted("ROLE_USER")',
52
        ),
53
        new Get(
54
            uriTemplate: '/forum_forums/{id}/stats',
55
            controller: GetStats::class,
56
            openapi: new Operation(
57
                responses: [
58
                    '200' => [
59
                        'description' => 'Forum statistics',
60
                        'content' => [
61
                            'application/json' => [
62
                                'schema' => [
63
                                    'type' => 'object',
64
                                    'properties' => [
65
                                        'nbTopic' => [
66
                                            'type' => 'integer',
67
                                            'description' => 'Number of non-archived topics in this forum'
68
                                        ],
69
                                        'nbMessage' => [
70
                                            'type' => 'integer',
71
                                            'description' => 'Number of messages in this forum'
72
                                        ],
73
                                        'activeUsers' => [
74
                                            'type' => 'integer',
75
                                            'description' => 'Number of active users in this forum in the last 24 hours'
76
                                        ],
77
                                        'todayActivity' => [
78
                                            'type' => 'object',
79
                                            'properties' => [
80
                                                'nbNewTopic' => [
81
                                                    'type' => 'integer',
82
                                                    'description' => 'Number of new topics created today in this forum'
83
                                                ],
84
                                                'nbNewMessage' => [
85
                                                    'type' => 'integer',
86
                                                    'description' => 'Number of new messages created today in this forum'
87
                                                ]
88
                                            ]
89
                                        ],
90
                                        'lastMessage' => [
91
                                            'type' => 'object',
92
                                            'nullable' => true,
93
                                            'properties' => [
94
                                                'createdAt' => ['type' => 'string'],
95
                                                'username' => ['type' => 'string']
96
                                            ]
97
                                        ],
98
                                        'lastUpdate' => [
99
                                            'type' => 'string',
100
                                            'format' => 'date-time',
101
                                            'description' => 'Timestamp of when statistics were generated'
102
                                        ],
103
                                        'weekActivity' => [
104
                                            'type' => 'object',
105
                                            'description' => 'Week activity (only when extended=true)',
106
                                            'properties' => [
107
                                                'nbNewTopicWeek' => [
108
                                                    'type' => 'integer',
109
                                                    'description' => 'Number of new topics created this week in this forum'
110
                                                ],
111
                                                'nbNewMessageWeek' => [
112
                                                    'type' => 'integer',
113
                                                    'description' => 'Number of new messages created this week in this forum'
114
                                                ]
115
                                            ]
116
                                        ],
117
                                        'topActiveUsers' => [
118
                                            'type' => 'array',
119
                                            'description' => 'Top active users in this forum (only when extended=true)',
120
                                            'items' => [
121
                                                'type' => 'object',
122
                                                'properties' => [
123
                                                    'user_id' => ['type' => 'integer'],
124
                                                    'pseudo' => ['type' => 'string'],
125
                                                    'activity_count' => ['type' => 'integer']
126
                                                ]
127
                                            ]
128
                                        ],
129
                                        'topTopics' => [
130
                                            'type' => 'array',
131
                                            'description' => 'Most active topics in this forum (only when extended=true)',
132
                                            'items' => [
133
                                                'type' => 'object',
134
                                                'properties' => [
135
                                                    'id' => ['type' => 'integer'],
136
                                                    'name' => ['type' => 'string'],
137
                                                    'nbMessage' => ['type' => 'integer'],
138
                                                    'createdAt' => ['type' => 'string', 'format' => 'date-time']
139
                                                ]
140
                                            ]
141
                                        ],
142
                                        'recentActivity' => [
143
                                            'type' => 'array',
144
                                            'description' => 'Recent activity in this forum (only when extended=true)',
145
                                            'items' => [
146
                                                'type' => 'object',
147
                                                'properties' => [
148
                                                    'messageId' => ['type' => 'integer'],
149
                                                    'topicId' => ['type' => 'integer'],
150
                                                    'topicName' => ['type' => 'string'],
151
                                                    'userPseudo' => ['type' => 'string'],
152
                                                    'createdAt' => ['type' => 'string', 'format' => 'date-time']
153
                                                ]
154
                                            ]
155
                                        ]
156
                                    ]
157
                                ]
158
                            ]
159
                        ]
160
                    ],
161
                    '404' => [
162
                        'description' => 'Forum not found'
163
                    ],
164
                    '403' => [
165
                        'description' => 'Access denied to private forum'
166
                    ]
167
                ],
168
                summary: 'Get forum specific statistics',
169
                description: 'Returns statistics for a specific forum including topics, messages, active users and activity data',
170
                /*parameters: [
171
                    [
172
                        'name' => 'extended',
173
                        'in' => 'query',
174
                        'required' => false,
175
                        'schema' => ['type' => 'boolean'],
176
                        'description' => 'Include extended statistics (week activity, top users, top topics, recent activity)'
177
                    ],
178
                    [
179
                        'name' => 'refresh',
180
                        'in' => 'query',
181
                        'required' => false,
182
                        'schema' => ['type' => 'boolean'],
183
                        'description' => 'Force refresh of cached statistics'
184
                    ]
185
                ]*/
186
            ),
187
            security: 'object.getStatus() == "public" or is_granted(object.getRole())',
188
        ),
189
        new Get(
190
            uriTemplate: '/forum_forums/{id}/mark-as-read',
191
            controller: MarkAsRead::class,
192
            security: 'is_granted("ROLE_USER")',
193
        ),
194
    ],
195
    normalizationContext: ['groups' => ['forum:read']
196
    ]
197
)]
198
#[ApiFilter(
199
    SearchFilter::class,
200
    properties: [
201
        'parent' => 'exact',
202
    ]
203
)]
204
#[ApiFilter(
205
    OrderFilter::class,
206
    properties: [
207
        'lastMessage.id' => 'DESC'
208
    ]
209
)]
210
#[ApiFilter(DateFilter::class, properties: ['lastMessage.createdAt' => DateFilterInterface::EXCLUDE_NULL])]
211
class Forum
212
{
213
    use TimestampableEntity;
214
215
    #[Groups(['forum:read'])]
216
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
217
    private int $id;
218
219
    #[Groups(['forum:read'])]
220
    #[Assert\Length(max: 255)]
221
    #[ORM\Column(length: 255, nullable: false)]
222
    private string $libForum;
223
224
    #[Groups(['forum:read'])]
225
    #[Assert\Length(max: 255)]
226
    #[ORM\Column(length: 255, nullable: true)]
227
    private string $libForumFr;
228
229
    #[ORM\Column(nullable: true, options: ['default' => 0])]
230
    private int $position = 0;
231
232
    #[Groups(['forum:read'])]
233
    #[ORM\Column(length: 20, nullable: false)]
234
    private string $status = ForumStatus::PUBLIC;
235
236
    #[Groups(['forum:read'])]
237
    #[ORM\Column(length: 50, nullable: true)]
238
    private ?string $role = null;
239
240
    #[Groups(['forum:read'])]
241
    #[ORM\Column(nullable: true, options: ['default' => 0])]
242
    private int $nbMessage = 0;
243
244
    #[Groups(['forum:read'])]
245
    #[ORM\Column(nullable: true, options: ['default' => 0])]
246
    private int $nbTopic = 0;
247
248
    #[Groups(['forum:read'])]
249
    #[ORM\Column(length: 128)]
250
    #[Gedmo\Slug(fields: ['libForum'])]
251
    protected string $slug;
252
253
    #[ORM\ManyToOne(targetEntity: Category::class, inversedBy: 'forums')]
254
    #[ORM\JoinColumn(name:'category_id', referencedColumnName:'id', nullable:true)]
255
    private ?Category $category;
256
257
    #[ORM\OneToMany(targetEntity: Topic::class, mappedBy: 'forum')]
258
    private Collection $topics;
259
260
    #[Groups(['forum:last-message'])]
261
    #[ORM\ManyToOne(targetEntity: Message::class, cascade: ['persist'])]
262
    #[ORM\JoinColumn(name:'max_message_id', referencedColumnName:'id', nullable:true, onDelete: 'SET NULL')]
263
    private ?Message $lastMessage;
264
265
    #[Groups(['forum:forum-user'])]
266
    #[ORM\OneToMany(targetEntity: ForumUserLastVisit::class, mappedBy: 'forum')]
267
    private Collection $userLastVisits;
268
269
    #[Groups(['forum:read-status'])]
270
    public ?int $unreadTopicsCount = null;
271
272
    #[Groups(['forum:read-status'])]
273
    public ?bool $isUnread = null;
274
275
    #[Groups(['forum:read-status'])]
276
    public ?bool $hasNewContent = null;
277
278
    #[Groups(['forum:read-status'])]
279
    public ?bool $hasBeenVisited = null;
280
281
282
    public function __construct()
283
    {
284
        $this->topics = new ArrayCollection();
285
        $this->userLastVisits = new ArrayCollection();
286
    }
287
288
    public function __toString()
289
    {
290
        return sprintf('%s [%s]', $this->getLibForum(), $this->getId());
291
    }
292
293
    public function setId(int $id): void
294
    {
295
        $this->id = $id;
296
    }
297
298
    public function getId(): ?int
299
    {
300
        return $this->id;
301
    }
302
303
    public function setLibForum(string $libForum): void
304
    {
305
        $this->libForum = $libForum;
306
    }
307
308
    public function getLibForum(): string
309
    {
310
        return $this->libForum;
311
    }
312
313
    public function setLibForumFr(string $libForumFr): void
314
    {
315
        $this->libForumFr = $libForumFr;
316
    }
317
318
    public function getLibForumFr(): string
319
    {
320
        return $this->libForumFr;
321
    }
322
323
    public function setPosition(int $position): void
324
    {
325
        $this->position = $position;
326
    }
327
328
    public function getPosition(): int
329
    {
330
        return $this->position;
331
    }
332
333
    public function setStatus(string $status): void
334
    {
335
        $this->status = $status;
336
    }
337
338
    public function getStatus(): string
339
    {
340
        return $this->status;
341
    }
342
343
    public function setRole(string $role): void
344
    {
345
        $this->role = $role;
346
    }
347
348
    public function getRole(): ?string
349
    {
350
        return $this->role;
351
    }
352
353
    public function setNbMessage(int $nbMessage): void
354
    {
355
        $this->nbMessage = $nbMessage;
356
    }
357
358
    public function getNbMessage(): int
359
    {
360
        return $this->nbMessage;
361
    }
362
363
    public function setNbTopic(int $nbTopic): void
364
    {
365
        $this->nbTopic = $nbTopic;
366
    }
367
368
369
    public function getNbTopic(): int
370
    {
371
        return $this->nbTopic;
372
    }
373
374
    public function getSlug(): string
375
    {
376
        return $this->slug;
377
    }
378
379
    public function setCategory(?Category $category = null): void
380
    {
381
        $this->category = $category;
382
    }
383
384
    public function getCategory(): ?Category
385
    {
386
        return $this->category;
387
    }
388
389
390
    public function getTopics(): Collection
391
    {
392
        return $this->topics;
393
    }
394
395
    public function setLastMessage(?Message $message = null): void
396
    {
397
        $this->lastMessage = $message;
398
    }
399
400
    public function getLastMessage(): ?Message
401
    {
402
        return $this->lastMessage;
403
    }
404
405
    public function getLastVisitData(): ?ForumUserLastVisit
406
    {
407
        if ($this->userLastVisits->first()) {
408
            return $this->userLastVisits->first();
409
        }
410
        return null;
411
    }
412
413
    #[Groups(['forum:read-status'])]
414
    public function getHasNewContent(): ?bool
415
    {
416
        $forumVisit = $this->getLastVisitData();
417
        if ($forumVisit && $this->getLastMessage()) {
418
            return $this->getLastMessage()->getCreatedAt() > $forumVisit->getLastVisitedAt();
419
        } else {
420
            return $this->getLastMessage() !== null;
421
        }
422
    }
423
424
    #[Groups(['forum:read-status'])]
425
    public function getHasBeenVisited(): ?bool
426
    {
427
        $forumVisit = $this->getLastVisitData();
428
        return $forumVisit !== null;
429
    }
430
431
    #[Groups(['forum:read-status'])]
432
    public function getLastVisitedAt(): ?\DateTime
433
    {
434
        $forumVisit = $this->getLastVisitData();
435
        return $forumVisit?->getLastVisitedAt();
436
    }
437
438
}
439