CDocument   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 347
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 24
eloc 197
dl 0
loc 347
rs 10
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A getIid() 0 3 1
A setFiletype() 0 5 1
A addGradebookCategory() 0 8 2
A isTemplate() 0 3 1
A __toString() 0 3 1
A setTitle() 0 5 1
A getFiletype() 0 3 1
A getTitle() 0 3 1
A getResourceName() 0 3 1
A setTemplate() 0 5 1
A getComment() 0 3 1
A setResourceName() 0 3 1
A setComment() 0 5 1
A removeGradebookCategory() 0 10 3
A getFullPath() 0 12 2
A getGradebookCategories() 0 3 1
A __construct() 0 7 1
A setReadonly() 0 5 1
A getResourceIdentifier() 0 3 1
A getReadonly() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CourseBundle\Entity;
8
9
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
10
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
11
use ApiPlatform\Metadata\ApiFilter;
12
use ApiPlatform\Metadata\ApiProperty;
13
use ApiPlatform\Metadata\ApiResource;
14
use ApiPlatform\Metadata\Delete;
15
use ApiPlatform\Metadata\Get;
16
use ApiPlatform\Metadata\GetCollection;
17
use ApiPlatform\Metadata\Post;
18
use ApiPlatform\Metadata\Put;
19
use ApiPlatform\OpenApi\Model\Operation;
20
use ApiPlatform\OpenApi\Model\Parameter;
21
use ApiPlatform\OpenApi\Model\RequestBody;
22
use ApiPlatform\Serializer\Filter\PropertyFilter;
23
use ArrayObject;
24
use Chamilo\CoreBundle\Controller\Api\CreateDocumentFileAction;
25
use Chamilo\CoreBundle\Controller\Api\DocumentLearningPathUsageAction;
26
use Chamilo\CoreBundle\Controller\Api\DownloadSelectedDocumentsAction;
27
use Chamilo\CoreBundle\Controller\Api\ReplaceDocumentFileAction;
28
use Chamilo\CoreBundle\Controller\Api\UpdateDocumentFileAction;
29
use Chamilo\CoreBundle\Controller\Api\UpdateVisibilityDocument;
30
use Chamilo\CoreBundle\Entity\AbstractResource;
31
use Chamilo\CoreBundle\Entity\GradebookCategory;
32
use Chamilo\CoreBundle\Entity\Listener\ResourceListener;
33
use Chamilo\CoreBundle\Entity\ResourceInterface;
34
use Chamilo\CoreBundle\Entity\ResourceNode;
35
use Chamilo\CoreBundle\Entity\ResourceShowCourseResourcesInSessionInterface;
36
use Chamilo\CoreBundle\Filter\CidFilter;
37
use Chamilo\CoreBundle\Filter\SidFilter;
38
use Chamilo\CourseBundle\Repository\CDocumentRepository;
39
use Doctrine\Common\Collections\ArrayCollection;
40
use Doctrine\Common\Collections\Collection;
41
use Doctrine\ORM\Mapping as ORM;
42
use Stringable;
43
use Symfony\Component\Serializer\Annotation\Groups;
44
use Symfony\Component\Uid\Uuid;
45
use Symfony\Component\Validator\Constraints as Assert;
46
47
#[ApiResource(
48
    shortName: 'Document',
49
    operations: [
50
        new Put(
51
            controller: UpdateDocumentFileAction::class,
52
            security: "is_granted('EDIT', object.resourceNode)",
53
            validationContext: [
54
                'groups' => ['media_object_create', 'document:write'],
55
            ],
56
            deserialize: false
57
        ),
58
        new Put(
59
            uriTemplate: '/documents/{iid}/toggle_visibility',
60
            controller: UpdateVisibilityDocument::class,
61
            openapi: new Operation(
62
                summary: 'Change document visibility (visible/invisible to learners)'
63
            ),
64
            security: "is_granted('EDIT', object.resourceNode)",
65
            deserialize: false
66
        ),
67
        new Put(
68
            uriTemplate: '/documents/{iid}/move',
69
            controller: UpdateDocumentFileAction::class,
70
            openapi: new Operation(
71
                summary: 'Move document'
72
            ),
73
            security: "is_granted('EDIT', object.resourceNode)",
74
            deserialize: true
75
        ),
76
        new Post(
77
            uriTemplate: '/documents/{iid}/replace',
78
            controller: ReplaceDocumentFileAction::class,
79
            openapi: new Operation(
80
                summary: 'Replace a document file, maintaining the same IDs.',
81
                requestBody: new RequestBody(
82
                    content: new ArrayObject([
83
                        'multipart/form-data' => [
84
                            'schema' => [
85
                                'type' => 'object',
86
                                'properties' => [
87
                                    'file' => [
88
                                        'type' => 'string',
89
                                        'format' => 'binary',
90
                                    ],
91
                                ],
92
                            ],
93
                        ],
94
                    ]),
95
                ),
96
            ),
97
            security: "is_granted('ROLE_CURRENT_COURSE_TEACHER') or is_granted('ROLE_CURRENT_COURSE_SESSION_TEACHER') or is_granted('ROLE_TEACHER')",
98
            validationContext: ['groups' => ['Default', 'media_object_create', 'document:write']],
99
            deserialize: false
100
        ),
101
        new Get(security: "is_granted('VIEW', object.resourceNode)"),
102
        new Get(
103
            uriTemplate: '/documents/{iid}/lp-usage',
104
            controller: DocumentLearningPathUsageAction::class,
105
            openapi: new Operation(
106
                summary: 'Get a list of learning paths where a document is used'
107
            ),
108
            security: "is_granted('ROLE_USER')",
109
            read: false,
110
            name: 'api_documents_lp_usage'
111
        ),
112
        new Delete(security: "is_granted('DELETE', object.resourceNode)"),
113
        new Post(
114
            controller: CreateDocumentFileAction::class,
115
            openapi: new Operation(
116
                requestBody: new RequestBody(
117
                    content: new ArrayObject([
118
                        'multipart/form-data' => [
119
                            'schema' => [
120
                                'type' => 'object',
121
                                'properties' => [
122
                                    'title' => ['type' => 'string'],
123
                                    'filetype' => [
124
                                        'type' => 'string',
125
                                        'enum' => ['folder', 'file'],
126
                                    ],
127
                                    'comment' => ['type' => 'string'],
128
                                    'contentFile' => ['type' => 'string'],
129
                                    'uploadFile' => [
130
                                        'type' => 'string',
131
                                        'format' => 'binary',
132
                                    ],
133
                                    'parentResourceNodeId' => ['type' => 'integer'],
134
                                    'resourceLinkList' => [
135
                                        'type' => 'array',
136
                                        'items' => [
137
                                            'type' => 'object',
138
                                            'properties' => [
139
                                                'visibility' => ['type' => 'integer'],
140
                                                'cid' => ['type' => 'integer'],
141
                                                'gid' => ['type' => 'integer'],
142
                                                'sid' => ['type' => 'integer'],
143
                                            ],
144
                                        ],
145
                                    ],
146
                                    'isUncompressZipEnabled' => ['type' => 'boolean'],
147
                                    'fileExistsOption' => [
148
                                        'type' => 'string',
149
                                        'enum' => ['overwrite', 'skip', 'rename'],
150
                                    ],
151
                                ],
152
                            ],
153
                        ],
154
                    ]),
155
                ),
156
            ),
157
            security: "is_granted('ROLE_CURRENT_COURSE_TEACHER') or is_granted('ROLE_CURRENT_COURSE_SESSION_TEACHER') or is_granted('ROLE_TEACHER')",
158
            validationContext: ['groups' => ['Default', 'media_object_create', 'document:write']],
159
            deserialize: false
160
        ),
161
        new Post(
162
            uriTemplate: '/documents/download-selected',
163
            controller: DownloadSelectedDocumentsAction::class,
164
            openapi: new Operation(
165
                summary: 'Download selected documents as a ZIP file.',
166
                requestBody: new RequestBody(
167
                    content: new ArrayObject([
168
                        'application/json' => [
169
                            'schema' => [
170
                                'type' => 'object',
171
                                'properties' => [
172
                                    'ids' => [
173
                                        'type' => 'array',
174
                                        'items' => ['type' => 'integer'],
175
                                    ],
176
                                ],
177
                            ],
178
                        ],
179
                    ]),
180
                ),
181
            ),
182
            security: "is_granted('ROLE_USER')",
183
        ),
184
        new GetCollection(
185
            openapi: new Operation(
186
                parameters: [
187
                    new Parameter(
188
                        name: 'resourceNode.parent',
189
                        in: 'query',
190
                        description: 'Resource node Parent',
191
                        required: true,
192
                        schema: ['type' => 'integer'],
193
                    ),
194
                ],
195
            )
196
        ),
197
    ],
198
    normalizationContext: [
199
        'groups' => ['document:read', 'resource_node:read'],
200
    ],
201
    denormalizationContext: [
202
        'groups' => ['document:write'],
203
    ]
204
)]
205
#[ORM\Table(name: 'c_document')]
206
#[ORM\Index(columns: ['filetype'], name: 'idx_cdoc_type')]
207
#[ORM\Entity(repositoryClass: CDocumentRepository::class)]
208
#[ORM\EntityListeners([ResourceListener::class])]
209
#[ApiFilter(filterClass: PropertyFilter::class)]
210
#[ApiFilter(filterClass: SearchFilter::class, properties: ['title' => 'partial', 'resourceNode.parent' => 'exact', 'filetype' => 'exact'])]
211
#[ApiFilter(
212
    filterClass: OrderFilter::class,
213
    properties: [
214
        'iid',
215
        'filetype',
216
        'resourceNode.title',
217
        'resourceNode.createdAt',
218
        'resourceNode.firstResourceFile.size',
219
        'resourceNode.updatedAt',
220
    ]
221
)]
222
#[ApiFilter(filterClass: CidFilter::class)]
223
#[ApiFilter(filterClass: SidFilter::class)]
224
class CDocument extends AbstractResource implements ResourceInterface, ResourceShowCourseResourcesInSessionInterface, Stringable
225
{
226
    #[ApiProperty(identifier: true)]
227
    #[Groups(['document:read'])]
228
    #[ORM\Column(name: 'iid', type: 'integer')]
229
    #[ORM\Id]
230
    #[ORM\GeneratedValue]
231
    protected ?int $iid = null;
232
233
    #[Groups(['document:read', 'document:write', 'document:browse', 'student_publication_rel_document:read'])]
234
    #[Assert\NotBlank]
235
    #[ORM\Column(name: 'title', type: 'string', length: 255, nullable: false)]
236
    protected string $title;
237
238
    #[Groups(['document:read', 'document:write'])]
239
    #[ORM\Column(name: 'comment', type: 'text', nullable: true)]
240
    protected ?string $comment;
241
242
    #[Groups(['document:read', 'document:write'])]
243
    #[Assert\Choice(['folder', 'file', 'certificate', 'video'], message: 'Choose a valid filetype.')]
244
    #[ORM\Column(name: 'filetype', type: 'string', length: 15, nullable: false)]
245
    protected string $filetype;
246
247
    #[ORM\Column(name: 'readonly', type: 'boolean', nullable: false)]
248
    protected bool $readonly;
249
250
    #[Groups(['document:read', 'document:write'])]
251
    #[ORM\Column(name: 'template', type: 'boolean', nullable: false)]
252
    protected bool $template;
253
254
    #[Groups(['document:read'])]
255
    #[ORM\OneToMany(mappedBy: 'document', targetEntity: GradebookCategory::class)]
256
    private Collection $gradebookCategories;
257
258
    public function __construct()
259
    {
260
        $this->comment = '';
261
        $this->filetype = 'folder';
262
        $this->readonly = false;
263
        $this->template = false;
264
        $this->gradebookCategories = new ArrayCollection();
265
    }
266
267
    public function __toString(): string
268
    {
269
        return $this->getTitle();
270
    }
271
272
    public function getTitle(): string
273
    {
274
        return $this->title;
275
    }
276
277
    public function setTitle(string $title): self
278
    {
279
        $this->title = $title;
280
281
        return $this;
282
    }
283
284
    public function isTemplate(): bool
285
    {
286
        return $this->template;
287
    }
288
289
    public function setTemplate(bool $template): self
290
    {
291
        $this->template = $template;
292
293
        return $this;
294
    }
295
296
    public function getComment(): ?string
297
    {
298
        return $this->comment;
299
    }
300
301
    public function setComment(?string $comment): self
302
    {
303
        $this->comment = $comment;
304
305
        return $this;
306
    }
307
308
    public function getFiletype(): string
309
    {
310
        return $this->filetype;
311
    }
312
313
    public function setFiletype(string $filetype): self
314
    {
315
        $this->filetype = $filetype;
316
317
        return $this;
318
    }
319
320
    public function getReadonly(): bool
321
    {
322
        return $this->readonly;
323
    }
324
325
    public function setReadonly(bool $readonly): self
326
    {
327
        $this->readonly = $readonly;
328
329
        return $this;
330
    }
331
332
    public function getResourceIdentifier(): int|Uuid
333
    {
334
        return $this->getIid();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getIid() could return the type null which is incompatible with the type-hinted return Symfony\Component\Uid\Uuid|integer. Consider adding an additional type-check to rule them out.
Loading history...
335
    }
336
337
    public function getIid(): ?int
338
    {
339
        return $this->iid;
340
    }
341
342
    public function getResourceName(): string
343
    {
344
        return $this->getTitle();
345
    }
346
347
    public function setResourceName(string $name): self
348
    {
349
        return $this->setTitle($name);
350
    }
351
352
    /**
353
     * @return Collection<int, GradebookCategory>
354
     */
355
    public function getGradebookCategories(): Collection
356
    {
357
        return $this->gradebookCategories;
358
    }
359
360
    public function addGradebookCategory(GradebookCategory $gradebookCategory): static
361
    {
362
        if (!$this->gradebookCategories->contains($gradebookCategory)) {
363
            $this->gradebookCategories->add($gradebookCategory);
364
            $gradebookCategory->setDocument($this);
365
        }
366
367
        return $this;
368
    }
369
370
    public function removeGradebookCategory(GradebookCategory $gradebookCategory): static
371
    {
372
        if ($this->gradebookCategories->removeElement($gradebookCategory)) {
373
            // set the owning side to null (unless already changed)
374
            if ($gradebookCategory->getDocument() === $this) {
375
                $gradebookCategory->setDocument(null);
376
            }
377
        }
378
379
        return $this;
380
    }
381
382
    #[Groups(['document:read', 'document:fullPath'])]
383
    public function getFullPath(): string
384
    {
385
        $pathParts = [$this->getTitle()];
386
387
        $parent = $this->getParent();
388
        while ($parent instanceof ResourceNode) {
389
            array_unshift($pathParts, $parent->getTitle());
390
            $parent = $parent->getParent();
391
        }
392
393
        return implode('/', $pathParts);
394
    }
395
}
396