Passed
Push — master ( dd8cf8...fd60f2 )
by Julito
08:33
created

ResourceNode::hasSession()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A ResourceNode::getResourceFile() 0 3 1
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\Core\Annotation\ApiFilter;
10
use ApiPlatform\Core\Annotation\ApiResource;
11
use ApiPlatform\Core\Annotation\ApiSubresource;
12
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
13
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
14
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
15
use Chamilo\CoreBundle\Traits\TimestampableAgoTrait;
16
use Chamilo\CoreBundle\Traits\TimestampableTypedEntity;
17
use Chamilo\CourseBundle\Entity\CShortcut;
18
use DateTime;
19
use Doctrine\Common\Collections\ArrayCollection;
20
use Doctrine\Common\Collections\Collection;
21
use Doctrine\ORM\Mapping as ORM;
22
use Gedmo\Mapping\Annotation as Gedmo;
23
use InvalidArgumentException;
24
use Symfony\Component\Routing\RouterInterface;
25
use Symfony\Component\Serializer\Annotation\Groups;
26
use Symfony\Component\Uid\Uuid;
27
use Symfony\Component\Uid\UuidV4;
28
use Symfony\Component\Validator\Constraints as Assert;
29
30
//*     attributes={"security"="is_granted('ROLE_ADMIN')"},
31
/**
32
 * Base entity for all resources.
33
 *
34
 * @ORM\Entity(repositoryClass="Chamilo\CoreBundle\Repository\ResourceNodeRepository")
35
 *
36
 * @ORM\HasLifecycleCallbacks
37
 * @ORM\Table(name="resource_node")
38
 * @ORM\EntityListeners({"Chamilo\CoreBundle\Entity\Listener\ResourceNodeListener"})
39
 *
40
 * @Gedmo\Tree(type="materializedPath")
41
 */
42
#[ApiResource(
43
    collectionOperations: [
44
        'get',
45
    ],
46
    denormalizationContext: [
47
        'groups' => ['resource_node:write', 'document:write'],
48
    ],
49
    normalizationContext: [
50
        'groups' => ['resource_node:read', 'document:read'],
51
    ],
52
)]
53
#[ApiFilter(OrderFilter::class, properties: [
54
    'id',
55
    'title',
56
    'resourceFile',
57
    'createdAt',
58
    'updatedAt',
59
])]
60
#[ApiFilter(PropertyFilter::class)]
61
#[ApiFilter(SearchFilter::class, properties: [
62
    'title' => 'partial',
63
])]
64
class ResourceNode
65
{
66
    use TimestampableTypedEntity;
67
    use TimestampableAgoTrait;
68
69
    public const PATH_SEPARATOR = '/';
70
71
    /**
72
     * @ORM\Id
73
     * @ORM\Column(type="bigint")
74
     * @ORM\GeneratedValue(strategy="AUTO")
75
     */
76
    #[Groups(['resource_node:read', 'document:read', 'ctool:read', 'user_json:read'])]
77
    protected ?int $id = null;
78
79
    /**
80
     * @Gedmo\TreePathSource
81
     *
82
     * @ORM\Column(name="title", type="string", length=255, nullable=false)
83
     */
84
    #[Groups(['resource_node:read', 'resource_node:write', 'document:read', 'document:write'])]
85
    #[Assert\NotBlank]
86
    protected string $title;
87
88
    /**
89
     * @Gedmo\Slug(fields={"title"})
90
     * @ORM\Column(name="slug", type="string", length=255, nullable=false)
91
     */
92
    #[Assert\NotBlank]
93
    protected string $slug;
94
95
    /**
96
     * @ORM\ManyToOne(targetEntity="ResourceType", inversedBy="resourceNodes")
97
     * @ORM\JoinColumn(name="resource_type_id", referencedColumnName="id", nullable=false)
98
     */
99
    #[Assert\NotNull]
100
    protected ResourceType $resourceType;
101
102
    /**
103
     * @var Collection|ResourceLink[]
104
     *
105
     * @ORM\OneToMany(targetEntity="ResourceLink", mappedBy="resourceNode", cascade={"persist", "remove"})
106
     */
107
    #[ApiSubresource]
108
    #[Groups(['ctool:read', 'c_tool_intro:read'])]
109
    protected Collection $resourceLinks;
110
111
    /**
112
     * ResourceFile available file for this node.
113
     *
114
     * @ORM\OneToOne(targetEntity="ResourceFile", inversedBy="resourceNode", orphanRemoval=true)
115
     * @ORM\JoinColumn(name="resource_file_id", referencedColumnName="id", onDelete="CASCADE")
116
     */
117
    #[Groups(['resource_node:read', 'resource_node:write', 'document:read', 'document:write', 'message:read'])]
118
    protected ?ResourceFile $resourceFile = null;
119
120
    /**
121
     * @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\User", inversedBy="resourceNodes")
122
     * @ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
123
     */
124
    #[Assert\NotNull]
125
    #[Groups(['resource_node:read', 'resource_node:write', 'document:write'])]
126
    protected User $creator;
127
128
    /**
129
     * @Gedmo\TreeParent
130
     * @ORM\ManyToOne(targetEntity="ResourceNode", inversedBy="children")
131
     * @ORM\JoinColumns({
132
     *     @ORM\JoinColumn(name="parent_id", onDelete="CASCADE")
133
     * })
134
     */
135
    #[ApiSubresource]
136
    protected ?ResourceNode $parent = null;
137
138
    /**
139
     * @var Collection|ResourceNode[]
140
     *
141
     * @ORM\OneToMany(targetEntity="ResourceNode", mappedBy="parent")
142
     * @ORM\OrderBy({"id"="ASC"})
143
     */
144
    protected Collection $children;
145
146
    /**
147
     * @Gedmo\TreeLevel
148
     *
149
     * @ORM\Column(name="level", type="integer", nullable=true)
150
     */
151
    protected ?int $level = null;
152
153
    /**
154
     * @Gedmo\TreePath(appendId=true, separator="/")
155
     *
156
     * @ORM\Column(name="path", type="text", nullable=true)
157
     */
158
    #[Groups(['resource_node:read', 'document:read'])]
159
    protected ?string $path = null;
160
161
    /**
162
     * Shortcut to access Course resource from ResourceNode.
163
     * Groups({"resource_node:read", "course:read"}).
164
     *
165
     * ORM\OneToOne(targetEntity="Chamilo\CoreBundle\Entity\Illustration", mappedBy="resourceNode")
166
     */
167
    //protected $illustration;
168
169
    /**
170
     * @var Collection|ResourceComment[]
171
     *
172
     * @ORM\OneToMany(targetEntity="ResourceComment", mappedBy="resourceNode", cascade={"persist", "remove"})
173
     */
174
    protected Collection $comments;
175
176
    /**
177
     * @Gedmo\Timestampable(on="create")
178
     * @ORM\Column(type="datetime")
179
     */
180
    #[Groups(['resource_node:read', 'document:read'])]
181
    protected DateTime $createdAt;
182
183
    /**
184
     * @Gedmo\Timestampable(on="update")
185
     * @ORM\Column(type="datetime")
186
     */
187
    #[Groups(['resource_node:read', 'document:read'])]
188
    protected DateTime $updatedAt;
189
190
    #[Groups(['resource_node:read', 'document:read'])]
191
    protected bool $fileEditableText;
192
193
    /**
194
     * @ORM\Column(type="boolean")
195
     */
196
    #[Groups(['resource_node:read', 'document:read'])]
197
    protected bool $public;
198
199
    protected ?string $content = null;
200
201
    /**
202
     * @ORM\OneToOne(
203
     *     targetEntity="Chamilo\CourseBundle\Entity\CShortcut",
204
     *     mappedBy="shortCutNode",
205
     *     cascade={"persist", "remove"}
206
     * )
207
     */
208
    protected ?CShortcut $shortCut = null;
209
210
    /**
211
     * @ORM\Column(type="uuid", unique=true)
212
     */
213
    #[Groups(['resource_node:read', 'document:read'])]
214
    protected ?UuidV4 $uuid = null;
215
216
    public function __construct()
217
    {
218
        $this->public = false;
219
        $this->uuid = Uuid::v4();
220
        $this->children = new ArrayCollection();
221
        $this->resourceLinks = new ArrayCollection();
222
        $this->comments = new ArrayCollection();
223
        $this->createdAt = new DateTime();
224
        $this->fileEditableText = false;
225
    }
226
227
    public function __toString(): string
228
    {
229
        return $this->getPathForDisplay();
230
    }
231
232
    public function getUuid(): ?UuidV4
233
    {
234
        return $this->uuid;
235
    }
236
237
    /**
238
     * Returns the resource id.
239
     *
240
     * @return int
241
     */
242
    public function getId()
243
    {
244
        return $this->id;
245
    }
246
247
    public function hasCreator(): bool
248
    {
249
        return null !== $this->creator;
250
    }
251
252
    public function getCreator(): ?User
253
    {
254
        return $this->creator;
255
    }
256
257
    public function setCreator(User $creator): self
258
    {
259
        $this->creator = $creator;
260
261
        return $this;
262
    }
263
264
    /**
265
     * Returns the children resource instances.
266
     *
267
     * @return Collection|ResourceNode[]
268
     */
269
    public function getChildren()
270
    {
271
        return $this->children;
272
    }
273
274
    /**
275
     * Sets the parent resource.
276
     */
277
    public function setParent(self $parent = null): self
278
    {
279
        $this->parent = $parent;
280
281
        return $this;
282
    }
283
284
    /**
285
     * Returns the parent resource.
286
     *
287
     * @return null|ResourceNode
288
     */
289
    public function getParent()
290
    {
291
        return $this->parent;
292
    }
293
294
    /**
295
     * Return the lvl value of the resource in the tree.
296
     */
297
    public function getLevel(): int
298
    {
299
        return $this->level;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->level could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
300
    }
301
302
    /**
303
     * Returns the "raw" path of the resource
304
     * (the path merge names and ids of all items).
305
     * Eg.: "Root-1/subdir-2/file.txt-3/".
306
     *
307
     * @return string
308
     */
309
    public function getPath()
310
    {
311
        return $this->path;
312
    }
313
314
    /**
315
     * @return Collection|ResourceComment[]
316
     */
317
    public function getComments()
318
    {
319
        return $this->comments;
320
    }
321
322
    public function addComment(ResourceComment $comment): self
323
    {
324
        $comment->setResourceNode($this);
325
326
        $this->comments->add($comment);
327
328
        return $this;
329
    }
330
331
    /**
332
     * Returns the path cleaned from its ids.
333
     * Eg.: "Root/subdir/file.txt".
334
     */
335
    public function getPathForDisplay(): string
336
    {
337
        return $this->path;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->path could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
338
        //return $this->convertPathForDisplay($this->path);
339
    }
340
341
    public function getPathForDisplayToArray(?int $baseRoot = null): array
342
    {
343
        $parts = explode(self::PATH_SEPARATOR, $this->path);
344
        $list = [];
345
        foreach ($parts as $part) {
346
            $parts = explode('-', $part);
347
            if (empty($parts[1])) {
348
                continue;
349
            }
350
351
            $value = $parts[0];
352
            $id = $parts[1];
353
354
            if (!empty($baseRoot) && $id < $baseRoot) {
355
                continue;
356
            }
357
            $list[$id] = $value;
358
        }
359
360
        return $list;
361
    }
362
363
    public function getPathForDisplayRemoveBase(string $base): string
364
    {
365
        $path = str_replace($base, '', $this->path);
366
367
        return $this->convertPathForDisplay($path);
368
    }
369
370
    public function getSlug(): string
371
    {
372
        return $this->slug;
373
    }
374
375
    public function getTitle(): string
376
    {
377
        return $this->title;
378
    }
379
380
    public function setTitle(string $title): self
381
    {
382
        $title = str_replace('/', '-', $title);
383
384
        $this->title = $title;
385
386
        return $this;
387
    }
388
389
    public function setSlug(string $slug): self
390
    {
391
        if (str_contains(self::PATH_SEPARATOR, $slug)) {
392
            $message = 'Invalid character "'.self::PATH_SEPARATOR.'" in resource name';
393
394
            throw new InvalidArgumentException($message);
395
        }
396
397
        $this->slug = $slug;
398
399
        return $this;
400
    }
401
402
    /**
403
     * Convert a path for display: remove ids.
404
     */
405
    public function convertPathForDisplay(string $path): string
406
    {
407
        /*$pathForDisplay = preg_replace(
408
            '/-\d+'.self::PATH_SEPARATOR.'/',
409
            ' / ',
410
            $path
411
        );
412
        if ($pathForDisplay !== null && strlen($pathForDisplay) > 0) {
413
            $pathForDisplay = substr_replace($pathForDisplay, '', -3);
414
        }
415
        */
416
        $pathForDisplay = preg_replace(
417
            '/-\d+\\'.self::PATH_SEPARATOR.'/',
418
            '/',
419
            $path
420
        );
421
422
        if (null !== $pathForDisplay && '' !== $pathForDisplay) {
423
            $pathForDisplay = substr_replace($pathForDisplay, '', -1);
424
        }
425
426
        return $pathForDisplay;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $pathForDisplay could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
427
    }
428
429
    public function getResourceType(): ResourceType
430
    {
431
        return $this->resourceType;
432
    }
433
434
    public function setResourceType(ResourceType $resourceType): self
435
    {
436
        $this->resourceType = $resourceType;
437
438
        return $this;
439
    }
440
441
    /**
442
     * @return Collection|ResourceLink[]
443
     */
444
    public function getResourceLinks()
445
    {
446
        return $this->resourceLinks;
447
    }
448
449
    public function addResourceLink(ResourceLink $link): self
450
    {
451
        $link->setResourceNode($this);
452
        $this->resourceLinks->add($link);
453
454
        return $this;
455
    }
456
457
    /**
458
     * @param Collection|ResourceLink[] $resourceLinks
459
     */
460
    public function setResourceLinks($resourceLinks): self
461
    {
462
        $this->resourceLinks = $resourceLinks;
463
464
        return $this;
465
    }
466
467
    public function hasResourceFile(): bool
468
    {
469
        return null !== $this->resourceFile;
470
    }
471
472
    public function getResourceFile(): ?ResourceFile
473
    {
474
        return $this->resourceFile;
475
    }
476
477
    public function hasEditableTextContent(): bool
478
    {
479
        if ($this->hasResourceFile()) {
480
            $mimeType = $this->getResourceFile()->getMimeType();
481
            if (str_contains($mimeType, 'text')) {
482
                return true;
483
            }
484
        }
485
486
        return false;
487
    }
488
489
    public function isResourceFileAnImage(): bool
490
    {
491
        if ($this->hasResourceFile()) {
492
            $mimeType = $this->getResourceFile()->getMimeType();
493
            if (str_contains($mimeType, 'image')) {
494
                return true;
495
            }
496
        }
497
498
        return false;
499
    }
500
501
    public function isResourceFileAVideo(): bool
502
    {
503
        if ($this->hasResourceFile()) {
504
            $mimeType = $this->getResourceFile()->getMimeType();
505
            if (str_contains($mimeType, 'video')) {
506
                return true;
507
            }
508
        }
509
510
        return false;
511
    }
512
513
    public function setResourceFile(?ResourceFile $resourceFile = null): self
514
    {
515
        $this->resourceFile = $resourceFile;
516
        if (null !== $resourceFile) {
517
            $resourceFile->setResourceNode($this);
518
        }
519
520
        return $this;
521
    }
522
523
    public function getIcon(): string
524
    {
525
        $class = 'fa fa-folder';
526
        if ($this->hasResourceFile()) {
527
            $class = 'far fa-file';
528
529
            if ($this->isResourceFileAnImage()) {
530
                $class = 'far fa-file-image';
531
            }
532
            if ($this->isResourceFileAVideo()) {
533
                $class = 'far fa-file-video';
534
            }
535
        }
536
537
        return '<i class="'.$class.'"></i>';
538
    }
539
540
    public function getThumbnail(RouterInterface $router): string
541
    {
542
        $size = 'fa-3x';
543
        $class = sprintf('fa fa-folder %s', $size);
544
        if ($this->hasResourceFile()) {
545
            $class = sprintf('far fa-file %s', $size);
546
547
            if ($this->isResourceFileAnImage()) {
548
                $class = sprintf('far fa-file-image %s', $size);
549
550
                $params = [
551
                    'id' => $this->getId(),
552
                    'tool' => $this->getResourceType()->getTool(),
553
                    'type' => $this->getResourceType()->getName(),
554
                    'filter' => 'editor_thumbnail',
555
                ];
556
                $url = $router->generate(
557
                    'chamilo_core_resource_view',
558
                    $params
559
                );
560
561
                return sprintf("<img src='%s'/>", $url);
562
            }
563
            if ($this->isResourceFileAVideo()) {
564
                $class = sprintf('far fa-file-video %s', $size);
565
            }
566
        }
567
568
        return '<i class="'.$class.'"></i>';
569
    }
570
571
    public function getContent(): ?string
572
    {
573
        return $this->content;
574
    }
575
576
    public function setContent(string $content): self
577
    {
578
        $this->content = $content;
579
580
        return $this;
581
    }
582
583
    public function getShortCut(): ?CShortcut
584
    {
585
        return $this->shortCut;
586
    }
587
588
    public function setShortCut(?CShortcut $shortCut): self
589
    {
590
        $this->shortCut = $shortCut;
591
592
        return $this;
593
    }
594
595
    public function isPublic(): bool
596
    {
597
        return $this->public;
598
    }
599
600
    public function setPublic(bool $public): self
601
    {
602
        $this->public = $public;
603
604
        return $this;
605
    }
606
}
607