Passed
Pull Request — master (#6835)
by Angel Fernando Quiroz
17:36 queued 08:49
created

AbstractResource::addLink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Entity;
8
9
use ApiPlatform\Metadata\ApiProperty;
10
use Chamilo\CoreBundle\Entity\Listener\ResourceListener;
11
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
12
use Chamilo\CoreBundle\Traits\UserCreatorTrait;
13
use Chamilo\CourseBundle\Entity\CGroup;
14
use DateTime;
15
use Doctrine\ORM\Mapping as ORM;
16
use Exception;
17
use Symfony\Component\HttpFoundation\File\UploadedFile;
18
use Symfony\Component\Serializer\Annotation\Groups;
19
use Symfony\Component\Validator\Constraints as Assert;
20
21
#[ORM\MappedSuperclass]
22
#[ORM\HasLifecycleCallbacks]
23
#[ORM\EntityListeners([ResourceListener::class])]
24
abstract class AbstractResource
25
{
26
    use UserCreatorTrait;
27
28
    #[ApiProperty(types: ['https://schema.org/contentUrl'])]
29
    #[Groups(['resource_file:read', 'resource_node:read', 'document:read', 'media_object_read', 'message:read', 'student_publication:read', 'student_publication_comment:read'])]
30
    public ?string $contentUrl = null;
31
32
    /**
33
     * Download URL of the Resource File Property set by ResourceNormalizer.php.
34
     */
35
    #[ApiProperty(types: ['https://schema.org/contentUrl'])]
36
    #[Groups(['resource_file:read', 'resource_node:read', 'document:read', 'media_object_read', 'message:read', 'student_publication:read', 'student_publication_comment:read', 'student_publication_rel_document:read'])]
37
    public ?string $downloadUrl = null;
38
39
    /**
40
     * Content from ResourceFile - Property set by ResourceNormalizer.php.
41
     */
42
    #[Groups(['resource_file:read', 'resource_node:read', 'document:read', 'document:write', 'media_object_read', 'student_publication:read'])]
43
    public ?string $contentFile = null;
44
45
    /**
46
     * Resource illustration URL - Property set by ResourceNormalizer.php.
47
     */
48
    #[ApiProperty(types: ['https://schema.org/contentUrl'])]
49
    #[Groups([
50
        'resource_node:read',
51
        'document:read',
52
        'media_object_read',
53
        'course:read',
54
        'session:read',
55
        'course_rel_user:read',
56
        'session_rel_course:read',
57
        'session_rel_user:read',
58
        'session_rel_course_rel_user:read',
59
        'user_subscriptions:sessions',
60
    ])]
61
    public ?string $illustrationUrl = null;
62
63
    #[Assert\Valid]
64
    #[Groups([
65
        'resource_node:read',
66
        'resource_node:write',
67
        'personal_file:write',
68
        'document:write',
69
        'ctool:read',
70
        'course:read',
71
        'illustration:read',
72
        'message:read',
73
        'c_tool_intro:read',
74
        'attendance:read',
75
        'student_publication:read',
76
        'student_publication_comment:read',
77
    ])]
78
    #[ORM\OneToOne(targetEntity: ResourceNode::class, cascade: ['persist'])]
79
    #[ORM\JoinColumn(name: 'resource_node_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
80
    public ?ResourceNode $resourceNode = null;
81
82
    /**
83
     * This property is used when using api platform.
84
     */
85
    #[Groups([
86
        'resource_node:read',
87
        'resource_node:write',
88
        'document:read',
89
        'document:write',
90
        'c_student_publication:write',
91
        'calendar_event:write',
92
    ])]
93
    public ?int $parentResourceNode = 0;
94
95
    #[ApiProperty(types: ['https://schema.org/image'])]
96
    public ?UploadedFile $uploadFile = null;
97
98
    /**
99
     * @var AbstractResource|ResourceInterface|null
100
     */
101
    public $parentResource;
102
103
    #[Groups(['resource_node:read', 'document:read', 'attendance:read', 'student_publication:read', 'student_publication_comment:read'])]
104
    public ?array $resourceLinkListFromEntity = null;
105
106
    /**
107
     * Use when sending a request to Api platform.
108
     * Temporal array that saves the resource link list that will be filled by CreateDocumentFileAction.php.
109
     *
110
     * @var array<int, array<string, int>>
111
     */
112
    #[Groups(['c_tool_intro:write', 'resource_node:write', 'c_student_publication:write', 'calendar_event:write', 'attendance:write'])]
113
    public array $resourceLinkList = [];
114
115
    /**
116
     * @var array<ResourceLink>
117
     */
118
    public array $resourceLinkEntityList = [];
119
120
    /**
121
     * This function separates the users from the groups users have a value
122
     * USER:XXX (with XXX the groups id have a value
123
     * GROUP:YYY (with YYY the group id).
124
     *
125
     * @param array $to Array of strings that define the type and id of each destination
126
     *
127
     * @return array Array of groups and users (each an array of IDs)
128
     */
129
    public static function separateUsersGroups(array $to): array
130
    {
131
        $sendTo = ['groups' => [], 'users' => []];
132
133
        foreach ($to as $toItem) {
134
            if (empty($toItem)) {
135
                continue;
136
            }
137
138
            $parts = explode(':', $toItem);
139
            $type = $parts[0] ?? '';
140
            $id = $parts[1] ?? '';
141
142
            switch ($type) {
143
                case 'GROUP':
144
                    $sendTo['groups'][] = (int) $id;
145
146
                    break;
147
148
                case 'USER':
149
                    $sendTo['users'][] = (int) $id;
150
151
                    break;
152
            }
153
        }
154
155
        return $sendTo;
156
    }
157
158
    abstract public function getResourceName(): string;
159
160
    abstract public function setResourceName(string $name);
161
162
    public function getResourceLinkEntityList(): array
163
    {
164
        return $this->resourceLinkEntityList;
165
    }
166
167
    /**
168
     * @throws Exception
169
     */
170
    public function addCourseLink(
171
        Course $course,
172
        ?Session $session = null,
173
        ?CGroup $group = null,
174
        int $visibility = ResourceLink::VISIBILITY_PUBLISHED,
175
        ?DateTime $createdAt = null,
176
        ?DateTime $updatedAt = null,
177
    ): self {
178
        if (null === $this->getParent()) {
179
            throw new Exception('$resource->addCourseLink requires to set the parent first.');
180
        }
181
182
        $resourceLink = (new ResourceLink())
183
            ->setVisibility($visibility)
184
            ->setCourse($course)
185
            ->setSession($session)
186
            ->setGroup($group)
187
        ;
188
189
        if ($createdAt) {
190
            $resourceLink->setCreatedAt($createdAt);
191
        }
192
193
        if ($updatedAt) {
194
            $resourceLink->setUpdatedAt($updatedAt);
195
        }
196
197
        $rights = [];
198
199
        switch ($visibility) {
200
            case ResourceLink::VISIBILITY_PENDING:
201
            case ResourceLink::VISIBILITY_DRAFT:
202
                $editorMask = ResourceNodeVoter::getEditorMask();
203
                $resourceRight = (new ResourceRight())
204
                    ->setMask($editorMask)
205
                    ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
206
                ;
207
                $rights[] = $resourceRight;
208
209
                break;
210
        }
211
212
        if (!empty($rights)) {
213
            foreach ($rights as $right) {
214
                $resourceLink->addResourceRight($right);
215
            }
216
        }
217
218
        if ($this->hasResourceNode()) {
219
            $resourceNode = $this->getResourceNode();
220
            $exists = $resourceNode->getResourceLinks()->exists(
221
                fn ($key, $element) => $course === $element->getCourse()
222
                    && $session === $element->getSession()
223
                    && $group === $element->getGroup()
224
            );
225
226
            if ($exists) {
227
                return $this;
228
            }
229
            $resourceNode->addResourceLink($resourceLink);
230
        } else {
231
            $this->addLink($resourceLink);
232
        }
233
234
        return $this;
235
    }
236
237
    public function getParent()
238
    {
239
        return $this->parentResource;
240
    }
241
242
    public function hasResourceNode(): bool
243
    {
244
        return $this->resourceNode instanceof ResourceNode;
245
    }
246
247
    public function getResourceNode(): ?ResourceNode
248
    {
249
        return $this->resourceNode;
250
    }
251
252
    public function setResourceNode(?ResourceNode $resourceNode): self
253
    {
254
        $this->resourceNode = $resourceNode;
255
256
        return $this;
257
    }
258
259
    /**
260
     * $this->resourceLinkEntityList will be loaded in the ResourceListener in the setLinks() function.
261
     */
262
    public function addLink(ResourceLink $link): static
263
    {
264
        $this->resourceLinkEntityList[] = $link;
265
266
        return $this;
267
    }
268
269
    public function setParent(ResourceInterface $parent): static
270
    {
271
        $this->parentResource = $parent;
272
273
        return $this;
274
    }
275
276
    public function addResourceToUserList(
277
        array $userList,
278
        ?Course $course = null,
279
        ?Session $session = null,
280
        ?CGroup $group = null
281
    ): static {
282
        if (!empty($userList)) {
283
            foreach ($userList as $user) {
284
                $this->addUserLink($user, $course, $session, $group);
285
            }
286
        }
287
288
        return $this;
289
    }
290
291
    public function addUserLink(
292
        User $user,
293
        ?Course $course = null,
294
        ?Session $session = null,
295
        ?CGroup $group = null,
296
        ?DateTime $createdAt = null,
297
        ?DateTime $updatedAt = null,
298
    ): static {
299
        $resourceLink = (new ResourceLink())
300
            ->setVisibility(ResourceLink::VISIBILITY_PUBLISHED)
301
            ->setUser($user)
302
            ->setCourse($course)
303
            ->setSession($session)
304
            ->setGroup($group)
305
        ;
306
307
        if ($createdAt) {
308
            $resourceLink->setCreatedAt($createdAt);
309
        }
310
311
        if ($updatedAt) {
312
            $resourceLink->setUpdatedAt($updatedAt);
313
        }
314
315
        if ($this->hasResourceNode()) {
316
            $resourceNode = $this->getResourceNode();
317
            $exists = $resourceNode->getResourceLinks()->exists(
318
                function ($key, $element) use ($user) {
319
                    if ($element->hasUser()) {
320
                        return $user->getId() === $element->getUser()->getId();
321
                    }
322
323
                    return false;
324
                }
325
            );
326
327
            if ($exists) {
328
                return $this;
329
            }
330
331
            $resourceNode->addResourceLink($resourceLink);
332
        } else {
333
            $this->addLink($resourceLink);
334
        }
335
336
        return $this;
337
    }
338
339
    public function addResourceToGroupList(
340
        array $groupList,
341
        ?Course $course = null,
342
        ?Session $session = null,
343
    ): static {
344
        foreach ($groupList as $group) {
345
            $this->addGroupLink($course, $group, $session);
346
        }
347
348
        return $this;
349
    }
350
351
    public function addGroupLink(Course $course, CGroup $group, ?Session $session = null): static
352
    {
353
        $resourceLink = (new ResourceLink())
354
            ->setCourse($course)
355
            ->setSession($session)
356
            ->setGroup($group)
357
            ->setVisibility(ResourceLink::VISIBILITY_PUBLISHED)
358
        ;
359
360
        if ($this->hasResourceNode()) {
361
            $resourceNode = $this->getResourceNode();
362
            $exists = $resourceNode->getResourceLinks()->exists(
363
                function ($key, $element) use ($group) {
364
                    if ($element->getGroup()) {
365
                        return $group->getIid() === $element->getGroup()->getIid();
366
                    }
367
                }
368
            );
369
370
            if ($exists) {
371
                return $this;
372
            }
373
            $resourceNode->addResourceLink($resourceLink);
374
        } else {
375
            $this->addLink($resourceLink);
376
        }
377
378
        return $this;
379
    }
380
381
    public function getResourceLinkArray(): array
382
    {
383
        return $this->resourceLinkList;
384
    }
385
386
    public function setResourceLinkArray(array $links): static
387
    {
388
        $this->resourceLinkList = $links;
389
390
        return $this;
391
    }
392
393
    public function getResourceLinkListFromEntity(): ?array
394
    {
395
        return $this->resourceLinkListFromEntity;
396
    }
397
398
    public function setResourceLinkListFromEntity(): void
399
    {
400
        $resourceLinkList = [];
401
        if ($this->hasResourceNode()) {
402
            $resourceNode = $this->getResourceNode();
403
            $links = $resourceNode->getResourceLinks();
404
            foreach ($links as $link) {
405
                $resourceLinkList[] = [
406
                    'id' => $link->getId(),
407
                    'visibility' => $link->getVisibility(),
408
                    'visibilityName' => $link->getVisibilityName(),
409
                    'session' => $link->getSession(),
410
                    'course' => $link->getCourse(),
411
                    'group' => $link->getGroup(),
412
                    'userGroup' => $link->getUserGroup(),
413
                    'user' => $link->getUser(),
414
                ];
415
            }
416
        }
417
        $this->resourceLinkListFromEntity = $resourceLinkList;
418
    }
419
420
    public function hasParentResourceNode(): bool
421
    {
422
        return null !== $this->parentResourceNode && 0 !== $this->parentResourceNode;
423
    }
424
425
    public function getParentResourceNode(): ?int
426
    {
427
        return $this->parentResourceNode;
428
    }
429
430
    public function setParentResourceNode(?int $resourceNode): self
431
    {
432
        $this->parentResourceNode = $resourceNode;
433
434
        return $this;
435
    }
436
437
    public function hasUploadFile(): bool
438
    {
439
        return null !== $this->uploadFile;
440
    }
441
442
    public function getUploadFile(): ?UploadedFile
443
    {
444
        return $this->uploadFile;
445
    }
446
447
    public function setUploadFile(?UploadedFile $file): self
448
    {
449
        $this->uploadFile = $file;
450
451
        return $this;
452
    }
453
454
    #[Groups([
455
        'student_publication:read',
456
        'student_publication_comment:read',
457
    ])]
458
    public function getFirstResourceLink(): ?ResourceLink
459
    {
460
        $resourceNode = $this->getResourceNode();
461
462
        if ($resourceNode && $resourceNode->getResourceLinks()->count()) {
463
            $result = $resourceNode->getResourceLinks()->first();
464
            if ($result) {
465
                return $result;
466
            }
467
        }
468
469
        return null;
470
    }
471
472
    public function isVisible(Course $course, ?Session $session = null): bool
473
    {
474
        $link = $this->getFirstResourceLinkFromCourseSession($course, $session);
475
476
        if (null === $link && $this instanceof ResourceShowCourseResourcesInSessionInterface) {
477
            $link = $this->getFirstResourceLinkFromCourseSession($course);
478
        }
479
480
        if (null === $link) {
481
            return false;
482
        }
483
484
        return ResourceLink::VISIBILITY_PUBLISHED === $link->getVisibility();
485
    }
486
487
    public function getFirstResourceLinkFromCourseSession(Course $course, ?Session $session = null): ?ResourceLink
488
    {
489
        $resourceNode = $this->getResourceNode();
490
        if ($resourceNode && $resourceNode->getResourceLinks()->count() > 0) {
491
            $links = $resourceNode->getResourceLinks();
492
            $found = false;
493
            $link = null;
494
            foreach ($links as $link) {
495
                if ($session) {
496
                    if ($link->getCourse() === $course && $link->getSession() === $session) {
497
                        $found = true;
498
499
                        break;
500
                    }
501
                } else {
502
                    if ($link->getCourse() === $course) {
503
                        $found = true;
504
505
                        break;
506
                    }
507
                }
508
            }
509
510
            if ($found) {
511
                return $link;
512
            }
513
        }
514
515
        return null;
516
    }
517
518
    public function isUserSubscribedToResource(User $user): bool
519
    {
520
        $links = $this->getResourceNode()->getResourceLinks();
521
522
        $result = false;
523
        foreach ($links as $link) {
524
            if ($link->hasUser() && $link->getUser()->getId() === $user->getId()) {
525
                $result = true;
526
527
                break;
528
            }
529
        }
530
531
        return $result;
532
    }
533
534
    public function getUsersAndGroupSubscribedToResource(): array
535
    {
536
        $users = [];
537
        $groups = [];
538
        $everyone = false;
539
        $links = $this->getResourceNode()->getResourceLinks();
540
        foreach ($links as $link) {
541
            if ($link->hasUser()) {
542
                $users[] = $link->getUser()->getId();
543
544
                continue;
545
            }
546
            if ($link->hasGroup()) {
547
                $groups[] = $link->getGroup()->getIid();
548
            }
549
        }
550
551
        if (empty($users) && empty($groups)) {
552
            $everyone = true;
553
        }
554
555
        return [
556
            'everyone' => $everyone,
557
            'users' => $users,
558
            'groups' => $groups,
559
        ];
560
    }
561
}
562