Passed
Pull Request — master (#6330)
by
unknown
11:18
created

SequenceResourceRepository::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Repository;
8
9
use Category;
10
use Chamilo\CoreBundle\Entity\Course;
11
use Chamilo\CoreBundle\Entity\GradebookCategory;
12
use Chamilo\CoreBundle\Entity\SequenceResource;
13
use Chamilo\CoreBundle\Entity\Session;
14
use Chamilo\CoreBundle\Entity\SessionRelCourse;
15
use Chamilo\CoreBundle\Entity\SessionRelUser;
16
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
17
use Doctrine\Persistence\ManagerRegistry;
18
use Fhaculty\Graph\Set\Vertices;
19
use Fhaculty\Graph\Vertex;
20
use SessionManager;
21
22
class SequenceResourceRepository extends ServiceEntityRepository
23
{
24
    public function __construct(ManagerRegistry $registry)
25
    {
26
        parent::__construct($registry, SequenceResource::class);
27
    }
28
29
    /**
30
     * Find the SequenceResource based in the resourceId and type.
31
     */
32
    public function findRequirementForResource(int $resourceId, int $type): ?SequenceResource
33
    {
34
        return $this->findOneBy([
35
            'resourceId' => $resourceId,
36
            'type' => $type,
37
        ]);
38
    }
39
40
    /**
41
     * @todo implement for all types only work for sessions
42
     *
43
     * @return array
44
     */
45
    public function getRequirementAndDependencies(int $resourceId, int $type)
46
    {
47
        $sequence = $this->findRequirementForResource($resourceId, $type);
48
        $result = [
49
            'requirements' => [],
50
            'dependencies' => [],
51
        ];
52
        if ($sequence && $sequence->hasGraph()) {
53
            $graph = $sequence->getSequence()->getUnSerializeGraph();
54
            $vertex = $graph->getVertex($resourceId);
55
            $from = $vertex->getVerticesEdgeFrom();
56
57
            foreach ($from as $subVertex) {
58
                $vertexId = $subVertex->getId();
59
                $sessionInfo = api_get_session_info($vertexId);
60
                $sessionInfo['admin_link'] = '<a href="'.SessionManager::getAdminPath($vertexId).'">'.$sessionInfo['name'].'</a>';
0 ignored issues
show
Bug introduced by
Are you sure SessionManager::getAdminPath($vertexId) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

60
                $sessionInfo['admin_link'] = '<a href="'./** @scrutinizer ignore-type */ SessionManager::getAdminPath($vertexId).'">'.$sessionInfo['name'].'</a>';
Loading history...
61
                $result['requirements'][] = $sessionInfo;
62
            }
63
64
            $to = $vertex->getVerticesEdgeTo();
65
            foreach ($to as $subVertex) {
66
                $vertexId = $subVertex->getId();
67
                $sessionInfo = api_get_session_info($vertexId);
68
                $sessionInfo['admin_link'] = '<a href="'.SessionManager::getAdminPath($vertexId).'">'.$sessionInfo['name'].'</a>';
69
                $result['dependencies'][] = $sessionInfo;
70
            }
71
        }
72
73
        return $result;
74
    }
75
76
    /**
77
     * Deletes a node and check in all the dependencies if the node exists in
78
     * order to deleted.
79
     */
80
    public function deleteSequenceResource(int $resourceId, int $type): void
81
    {
82
        $sequence = $this->findRequirementForResource($resourceId, $type);
83
        if ($sequence && $sequence->hasGraph()) {
84
            $em = $this->getEntityManager();
85
            $graph = $sequence->getSequence()->getUnSerializeGraph();
86
            $mainVertex = $graph->getVertex($resourceId);
87
            $vertices = $graph->getVertices();
88
89
            /** @var Vertex $vertex */
90
            foreach ($vertices as $vertex) {
91
                $subResourceId = $vertex->getId();
92
                $subSequence = $this->findRequirementForResource($subResourceId, $type);
93
                if ($subSequence->hasGraph()) {
94
                    $graph = $subSequence->getSequence()->getUnSerializeGraph();
95
                    $subMainVertex = $graph->getVertex($resourceId);
96
                    $subMainVertex->destroy();
97
                    $subSequence->getSequence()->setGraphAndSerialize($graph);
98
                    $em->persist($subSequence);
99
                }
100
            }
101
102
            $mainVertex->destroy();
103
            $em->remove($sequence);
104
            $em->flush();
105
        }
106
    }
107
108
    /**
109
     * Get the requirements for a resource only.
110
     *
111
     * @param int $resourceId The resource ID
112
     * @param int $type       The type of sequence resource
113
     *
114
     * @return array
115
     */
116
    public function getRequirements(int $resourceId, int $type)
117
    {
118
        $sequencesResource = $this->findBy([
119
            'resourceId' => $resourceId,
120
            'type' => $type,
121
        ]);
122
        $em = $this->getEntityManager();
123
        $result = [];
124
125
        /** @var SequenceResource $sequenceResource */
126
        foreach ($sequencesResource as $sequenceResource) {
127
            if (!$sequenceResource->hasGraph()) {
128
                continue;
129
            }
130
131
            $sequence = $sequenceResource->getSequence();
132
            $graph = $sequence->getUnSerializeGraph();
133
            $vertex = $graph->getVertex($resourceId);
134
            $from = $vertex->getVerticesEdgeFrom();
135
136
            $sequenceInfo = [
137
                'name' => $sequence->getTitle(),
138
                'requirements' => [],
139
            ];
140
141
            foreach ($from as $subVertex) {
142
                $vertexId = $subVertex->getId();
143
                $resource = null;
144
145
                switch ($type) {
146
                    case SequenceResource::SESSION_TYPE:
147
                        $repo = $em->getRepository(Session::class);
148
                        $resource = $repo->find($vertexId);
149
150
                        break;
151
152
                    case SequenceResource::COURSE_TYPE:
153
                        $repo = $em->getRepository(Course::class);
154
                        $resource = $repo->find($vertexId);
155
156
                        break;
157
                }
158
159
                if (null === $resource) {
160
                    continue;
161
                }
162
163
                $sequenceInfo['requirements'][$vertexId] = $resource;
164
            }
165
166
            $result[$sequence->getId()] = $sequenceInfo;
167
        }
168
169
        return $result;
170
    }
171
172
    /**
173
     * Get the requirements and dependencies within a sequence for a resource.
174
     *
175
     * @param int $resourceId The resource ID
176
     * @param int $type       The type of sequence resource
177
     *
178
     * @return array
179
     */
180
    public function getRequirementsAndDependenciesWithinSequences(int $resourceId, int $type)
181
    {
182
        $sequencesResource = $this->findBy([
183
            'resourceId' => $resourceId,
184
            'type' => $type,
185
        ]);
186
187
        $result = [];
188
189
        /** @var SequenceResource $sequenceResource */
190
        foreach ($sequencesResource as $sequenceResource) {
191
            if (!$sequenceResource->hasGraph()) {
192
                continue;
193
            }
194
195
            $sequence = $sequenceResource->getSequence();
196
            $graph = $sequence->getUnSerializeGraph();
197
            $vertex = $graph->getVertex($resourceId);
198
            $from = $vertex->getVerticesEdgeFrom();
199
            $to = $vertex->getVerticesEdgeTo();
200
201
            $requirements = $this->findVerticesEdges($from, $type);
202
            $dependencies = $this->findVerticesEdges($to, $type);
203
204
            $result[$sequence->getId()] = [
205
                'name' => $sequence->getTitle(),
206
                'requirements' => $requirements,
207
                'dependencies' => $dependencies,
208
            ];
209
        }
210
211
        return $result;
212
    }
213
214
    /**
215
     * Check if the ser has completed the requirements for the sequences.
216
     *
217
     * @param array $sequences The sequences
218
     * @param int   $type      The type of sequence resource
219
     *
220
     * @return array
221
     */
222
    public function checkRequirementsForUser(array $sequences, int $type, int $userId)
223
    {
224
        $sequenceList = [];
225
        $em = $this->getEntityManager();
226
        $gradebookCategoryRepo = $em->getRepository(GradebookCategory::class);
227
228
        $sessionUserList = [];
229
        if (SequenceResource::COURSE_TYPE === $type) {
230
            $criteria = [
231
                'user' => $userId,
232
            ];
233
            $sessions = $em->getRepository(SessionRelUser::class)->findBy($criteria);
234
            if ([] !== $sessions) {
235
                foreach ($sessions as $sessionRelUser) {
236
                    $sessionUserList[] = $sessionRelUser->getSession()->getId();
237
                }
238
            }
239
        }
240
241
        foreach ($sequences as $sequenceId => $sequence) {
242
            $item = [
243
                'name' => $sequence['name'],
244
                'requirements' => [],
245
            ];
246
            $resourceItem = null;
247
248
            foreach ($sequence['requirements'] as $resource) {
249
                switch ($type) {
250
                    case SequenceResource::SESSION_TYPE:
251
                        $id = $resource->getId();
252
                        $resourceItem = [
253
                            'name' => $resource->getTitle(),
254
                            'status' => true,
255
                        ];
256
257
                        $sessionsCourses = $resource->getCourses();
258
259
                        foreach ($sessionsCourses as $sessionCourse) {
260
                            $course = $sessionCourse->getCourse();
261
                            $categories = $gradebookCategoryRepo->findBy(
262
                                [
263
                                    'course' => $course,
264
                                    'session' => $resource,
265
                                    'isRequirement' => true,
266
                                ]
267
                            );
268
269
                            foreach ($categories as $category) {
270
                                if (!empty($userId)) {
271
                                    $resourceItem['status'] = $resourceItem['status'] && Category::userFinishedCourse(
272
                                        $userId,
273
                                        $category
274
                                    );
275
                                }
276
                            }
277
                        }
278
279
                        break;
280
281
                    case SequenceResource::COURSE_TYPE:
282
                        $id = $resource->getId();
283
                        $status = $this->checkCourseRequirements($userId, $resource, 0);
284
285
                        if (!$status) {
286
                            $sessionsInCourse = SessionManager::get_session_by_course($id);
287
                            foreach ($sessionsInCourse as $session) {
288
                                if (\in_array($session['id'], $sessionUserList, true)) {
289
                                    $status = $this->checkCourseRequirements($userId, $resource, $session['id']);
290
                                    if ($status) {
291
                                        break;
292
                                    }
293
                                }
294
                            }
295
                        }
296
297
                        $resourceItem = [
298
                            'name' => $resource->getTitle(),
299
                            'status' => $status,
300
                        ];
301
302
                        break;
303
                }
304
305
                if (empty($id)) {
306
                    continue;
307
                }
308
309
                $item['requirements'][$id] = $resourceItem;
310
            }
311
            $sequenceList[$sequenceId] = $item;
312
        }
313
314
        return $sequenceList;
315
    }
316
317
    public function checkCourseRequirements(int $userId, Course $course, int $sessionId = 0): bool
318
    {
319
        $em = $this->getEntityManager();
320
        $session = $sessionId > 0
321
            ? $em->getRepository(Session::class)->find($sessionId)
322
            : null;
323
        $gradebookCategoryRepo = $em->getRepository(GradebookCategory::class);
324
        $categories = $gradebookCategoryRepo->findBy(
325
            [
326
                'course' => $course,
327
                'session' => $session,
328
                'isRequirement' => true,
329
            ]
330
        );
331
332
        if (empty($categories)) {
333
            return false;
334
        }
335
336
        $status = true;
337
        foreach ($categories as $category) {
338
            $userFinishedCourse = Category::userFinishedCourse(
339
                $userId,
340
                $category,
341
                true
342
            );
343
344
            if (0 === $sessionId) {
345
                if (!$userFinishedCourse) {
346
                    $status = false;
347
348
                    break;
349
                }
350
            } elseif (!$userFinishedCourse) {
351
                $status = false;
352
353
                break;
354
            }
355
        }
356
357
        return $status;
358
    }
359
360
    /**
361
     * Check if at least one sequence are completed.
362
     *
363
     * @param array $sequences The sequences
364
     *
365
     * @return bool
366
     */
367
    public function checkSequenceAreCompleted(array $sequences)
368
    {
369
        foreach ($sequences as $sequence) {
370
371
            if (!isset($sequence['requirements'])) {
372
                continue;
373
            }
374
375
            $status = true;
376
377
            foreach ($sequence['requirements'] as $item) {
378
                $status = $status && $item['status'];
379
            }
380
381
            if ($status) {
382
                return true;
383
            }
384
        }
385
386
        return false;
387
    }
388
389
    /**
390
     * Get sessions from vertices.
391
     *
392
     * @param Vertices $verticesEdges The vertices
393
     *
394
     * @return array
395
     */
396
    protected function findVerticesEdges(Vertices $verticesEdges, int $type)
397
    {
398
        $sessionVertices = [];
399
        $em = $this->getEntityManager();
400
401
        foreach ($verticesEdges as $supVertex) {
402
            $vertexId = $supVertex->getId();
403
404
            switch ($type) {
405
                case SequenceResource::SESSION_TYPE:
406
                    $resource = $em->getRepository(Session::class)->find($vertexId);
407
408
                    break;
409
410
                case SequenceResource::COURSE_TYPE:
411
                    $resource = $em->getRepository(Course::class)->find($vertexId);
412
413
                    break;
414
            }
415
416
            if (empty($resource)) {
417
                continue;
418
            }
419
420
            $sessionVertices[$vertexId] = $resource;
421
        }
422
423
        return $sessionVertices;
424
    }
425
426
    public function getDependents(int $resourceId, int $type): array
427
    {
428
        return $this->getRequirementsOrDependents($resourceId, $type, 'dependents');
429
    }
430
431
    public function checkDependentsForUser(array $sequences, int $type, int $userId, int $sessionId = 0): array
432
    {
433
        return $this->checkRequirementsOrDependentsForUser(
434
            $sequences,
435
            $type,
436
            'dependents',
437
            $userId,
438
            $sessionId
439
        );
440
    }
441
442
    private function getRequirementsOrDependents(int $resourceId, int $resourceType, string $itemType): array
443
    {
444
        $em = $this->getEntityManager();
445
446
        $sequencesResource = $this->findBy(['resourceId' => $resourceId, 'type' => $resourceType]);
447
        $result = [];
448
449
        foreach ($sequencesResource as $sequenceResource) {
450
            if (!$sequenceResource->hasGraph()) {
451
                continue;
452
            }
453
454
            $sequence = $sequenceResource->getSequence();
455
            $graph = $sequence->getUnSerializeGraph();
456
            $vertex = $graph->getVertex($resourceId);
457
458
            $edges = $itemType === 'requirements'
459
                ? $vertex->getVerticesEdgeFrom()
460
                : $vertex->getVerticesEdgeTo();
461
462
            $sequenceInfo = [
463
                'name' => $sequence->getTitle(),
464
                $itemType => [],
465
            ];
466
467
            foreach ($edges as $edge) {
468
                $vertexId = $edge->getId();
469
                $resource = null;
470
471
                switch ($resourceType) {
472
                    case SequenceResource::SESSION_TYPE:
473
                        $resource = $em->getRepository(Session::class)->find($vertexId);
474
                        break;
475
                    case SequenceResource::COURSE_TYPE:
476
                        $resource = $em->getRepository(Course::class)->find($vertexId);
477
                        break;
478
                }
479
480
                if (null === $resource) {
481
                    continue;
482
                }
483
484
                $sequenceInfo[$itemType][$vertexId] = $resource;
485
            }
486
487
            $result[$sequence->getId()] = $sequenceInfo;
488
        }
489
490
        return $result;
491
    }
492
493
    private function checkRequirementsOrDependentsForUser(
494
        array $sequences,
495
        int $resourceType,
496
        string $itemType,
497
        int $userId,
498
        int $sessionId = 0
499
    ): array {
500
        $sequenceList = [];
501
        $em = $this->getEntityManager();
502
        $gradebookCategoryRepo = $em->getRepository(GradebookCategory::class);
503
504
        $sessionUserList = [];
505
        $checkOnlySameSession = true; //api_get_configuration_value('course_sequence_valid_only_in_same_session');
506
507
        if (SequenceResource::COURSE_TYPE === $resourceType) {
508
            if ($checkOnlySameSession) {
509
                $sessionUserList = [$sessionId];
510
            } else {
511
                $sessions = $em->getRepository(SessionRelUser::class)->findBy(['user' => $userId]);
512
                foreach ($sessions as $sessionRelUser) {
513
                    $sessionUserList[] = $sessionRelUser->getSession()->getId();
514
                }
515
            }
516
        }
517
518
        foreach ($sequences as $sequenceId => $sequence) {
519
            $item = ['name' => $sequence['name'], $itemType => []];
520
521
            foreach ($sequence[$itemType] as $resource) {
522
                switch ($resourceType) {
523
                    case SequenceResource::SESSION_TYPE:
524
                        $id = $resource->getId();
525
                        $resourceItem = ['name' => $resource->getName(), 'status' => true];
526
527
                        /* @var SessionRelCourse $sessionCourse */
528
                        foreach ($resource->getCourses() as $sessionCourse) {
529
                            $course = $sessionCourse->getCourse();
530
                            $session = $sessionCourse->getSession();
531
                            $categories = $gradebookCategoryRepo->findBy([
532
                                'course' => $course,
533
                                'session' => $session,
534
                                'isRequirement' => true,
535
                            ]);
536
537
                            foreach ($categories as $category) {
538
                                $resourceItem['status'] = $resourceItem['status'] && Category::userFinishedCourse(
539
                                        $userId,
540
                                        $category
541
                                    );
542
                            }
543
                        }
544
                        break;
545
546
                    case SequenceResource::COURSE_TYPE:
547
                        $id = $resource->getId();
548
                        $status = $this->checkCourseRequirements($userId, $resource, $sessionId);
549
550
                        if (!$status) {
551
                            foreach (SessionManager::get_session_by_course($id) as $session) {
552
                                if (in_array($session['id'], $sessionUserList)) {
553
                                    $status = $this->checkCourseRequirements($userId, $resource, $session['id']);
554
                                    if ($status) break;
555
                                }
556
                            }
557
                        }
558
559
                        $resourceItem = [
560
                            'name' => $resource->getTitle(),
561
                            'code' => $resource->getCode(),
562
                            'status' => $status,
563
                        ];
564
                        break;
565
                }
566
567
                if (!empty($id)) {
568
                    $item[$itemType][$id] = $resourceItem;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $resourceItem does not seem to be defined for all execution paths leading up to this point.
Loading history...
569
                }
570
            }
571
572
            $sequenceList[$sequenceId] = $item;
573
        }
574
575
        return $sequenceList;
576
    }
577
}
578