Passed
Push — master ( 0c4c4e...172726 )
by
unknown
09:40
created

CourseController::about()   C

Complexity

Conditions 13
Paths 80

Size

Total Lines 145
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 91
nc 80
nop 5
dl 0
loc 145
rs 5.4896
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Entity\Course;
10
use Chamilo\CoreBundle\Entity\CourseRelUser;
11
use Chamilo\CoreBundle\Entity\ExtraField;
12
use Chamilo\CoreBundle\Entity\SequenceResource;
13
use Chamilo\CoreBundle\Entity\Session;
14
use Chamilo\CoreBundle\Entity\SessionRelUser;
15
use Chamilo\CoreBundle\Entity\Tag;
16
use Chamilo\CoreBundle\Entity\Tool;
17
use Chamilo\CoreBundle\Entity\User;
18
use Chamilo\CoreBundle\Framework\Container;
19
use Chamilo\CoreBundle\Helpers\AccessUrlHelper;
20
use Chamilo\CoreBundle\Helpers\CidReqHelper;
21
use Chamilo\CoreBundle\Helpers\CourseHelper;
22
use Chamilo\CoreBundle\Helpers\UserHelper;
23
use Chamilo\CoreBundle\Repository\AssetRepository;
24
use Chamilo\CoreBundle\Repository\CourseCategoryRepository;
25
use Chamilo\CoreBundle\Repository\ExtraFieldValuesRepository;
26
use Chamilo\CoreBundle\Repository\LanguageRepository;
27
use Chamilo\CoreBundle\Repository\LegalRepository;
28
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
29
use Chamilo\CoreBundle\Repository\Node\IllustrationRepository;
30
use Chamilo\CoreBundle\Repository\SequenceResourceRepository;
31
use Chamilo\CoreBundle\Repository\TagRepository;
32
use Chamilo\CoreBundle\Security\Authorization\Voter\CourseVoter;
33
use Chamilo\CoreBundle\Settings\SettingsManager;
34
use Chamilo\CoreBundle\Tool\ToolChain;
35
use Chamilo\CourseBundle\Controller\ToolBaseController;
36
use Chamilo\CourseBundle\Entity\CBlog;
37
use Chamilo\CourseBundle\Entity\CCourseDescription;
38
use Chamilo\CourseBundle\Entity\CLink;
39
use Chamilo\CourseBundle\Entity\CShortcut;
40
use Chamilo\CourseBundle\Entity\CThematicAdvance;
41
use Chamilo\CourseBundle\Entity\CTool;
42
use Chamilo\CourseBundle\Entity\CToolIntro;
43
use Chamilo\CourseBundle\Repository\CCourseDescriptionRepository;
44
use Chamilo\CourseBundle\Repository\CLpRepository;
45
use Chamilo\CourseBundle\Repository\CQuizRepository;
46
use Chamilo\CourseBundle\Repository\CShortcutRepository;
47
use Chamilo\CourseBundle\Repository\CThematicRepository;
48
use Chamilo\CourseBundle\Repository\CToolRepository;
49
use Chamilo\CourseBundle\Settings\SettingsCourseManager;
50
use Chamilo\CourseBundle\Settings\SettingsFormFactory;
51
use CourseManager;
52
use Database;
53
use Display;
54
use Doctrine\ORM\EntityManagerInterface;
55
use Event;
56
use Exception;
57
use Exercise;
58
use ExtraFieldValue;
59
use Graphp\GraphViz\GraphViz;
60
use IntlDateFormatter;
61
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
62
use Symfony\Bundle\SecurityBundle\Security;
63
use Symfony\Component\HttpFoundation\JsonResponse;
64
use Symfony\Component\HttpFoundation\RedirectResponse;
65
use Symfony\Component\HttpFoundation\Request;
66
use Symfony\Component\HttpFoundation\Response;
67
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
68
use Symfony\Component\Routing\Attribute\Route;
69
use Symfony\Component\Security\Http\Attribute\IsGranted;
70
use Symfony\Component\Serializer\SerializerInterface;
71
use Symfony\Component\Validator\Exception\ValidatorException;
72
use Symfony\Contracts\Translation\TranslatorInterface;
73
use UserManager;
74
75
/**
76
 * @author Julio Montoya <[email protected]>
77
 */
78
#[Route('/course')]
79
class CourseController extends ToolBaseController
80
{
81
    public function __construct(
82
        private readonly EntityManagerInterface $em,
83
        private readonly SerializerInterface $serializer,
84
        private readonly UserHelper $userHelper,
85
    ) {}
86
87
    #[IsGranted('ROLE_USER')]
88
    #[Route('/{cid}/checkLegal.json', name: 'chamilo_core_course_check_legal_json')]
89
    public function checkTermsAndConditionJson(
90
        Request $request,
91
        LegalRepository $legalTermsRepo,
92
        LanguageRepository $languageRepository,
93
        ExtraFieldValuesRepository $extraFieldValuesRepository,
94
        SettingsManager $settingsManager
95
    ): Response {
96
        $user = $this->userHelper->getCurrent();
97
        $course = $this->getCourse();
98
        $sid = $this->getSessionId();
99
100
        $responseData = [
101
            'redirect' => false,
102
            'url' => '#',
103
        ];
104
105
        if ($user->isStudent()
106
            && 'true' === $settingsManager->getSetting('registration.allow_terms_conditions', true)
107
            && 'course' === $settingsManager->getSetting('workflows.load_term_conditions_section', true)
108
        ) {
109
            $termAndConditionStatus = false;
110
            $extraValue = $extraFieldValuesRepository->findLegalAcceptByItemId($user->getId());
111
            if (!empty($extraValue['value'])) {
112
                $result = $extraValue['value'];
113
                $userConditions = explode(':', $result);
114
                $version = $userConditions[0];
115
                $langId = (int) $userConditions[1];
116
                $realVersion = $legalTermsRepo->getLastVersion($langId);
117
                $termAndConditionStatus = ($version >= $realVersion);
118
            }
119
120
            if (false === $termAndConditionStatus) {
121
                $request->getSession()->set('term_and_condition', ['user_id' => $user->getId()]);
122
123
                $redirect = true;
124
125
                if ('true' === $settingsManager->getSetting('course.allow_public_course_with_no_terms_conditions', true)
126
                    && Course::OPEN_WORLD === $course->getVisibility()
127
                ) {
128
                    $redirect = false;
129
                }
130
131
                if ($redirect && !$this->isGranted('ROLE_ADMIN')) {
132
                    $request->getSession()->remove('cid');
133
                    $request->getSession()->remove('course');
134
135
                    // Build return URL
136
                    $returnUrl = '/course/'.$course->getId().'/home?sid='.$sid;
137
138
                    $responseData = [
139
                        'redirect' => true,
140
                        'url' => '/main/auth/tc.php?return='.urlencode($returnUrl),
141
                    ];
142
                }
143
            } else {
144
                $request->getSession()->remove('term_and_condition');
145
            }
146
        }
147
148
        return new JsonResponse($responseData);
149
    }
150
151
    #[Route('/{cid}/home.json', name: 'chamilo_core_course_home_json')]
152
    public function indexJson(
153
        Request $request,
154
        CShortcutRepository $shortcutRepository,
155
        EntityManagerInterface $em,
156
        AssetRepository $assetRepository
157
    ): Response {
158
        $requestData = json_decode($request->getContent(), true);
159
        // Sort behaviour
160
        if (!empty($requestData) && isset($requestData['toolItem'])) {
161
            $index = $requestData['index'];
162
            $toolItem = $requestData['toolItem'];
163
            $toolId = (int) $toolItem['iid'];
164
165
            /** @var CTool $cTool */
166
            $cTool = $em->find(CTool::class, $toolId);
167
168
            if ($cTool) {
169
                $cTool->setPosition($index + 1);
170
                $em->persist($cTool);
171
                $em->flush();
172
            }
173
        }
174
175
        $course = $this->getCourse();
176
        $sessionId = $this->getSessionId();
177
        $isInASession = $sessionId > 0;
178
179
        if (null === $course) {
180
            throw $this->createAccessDeniedException();
181
        }
182
183
        if (empty($sessionId)) {
184
            $this->denyAccessUnlessGranted(CourseVoter::VIEW, $course);
185
        }
186
187
        $sessionHandler = $request->getSession();
188
189
        $userId = 0;
190
191
        $user = $this->userHelper->getCurrent();
192
        if (null !== $user) {
193
            $userId = $user->getId();
194
        }
195
196
        $courseCode = $course->getCode();
197
        $courseId = $course->getId();
198
199
        if ($user && $user->isInvitee()) {
200
            $isSubscribed = CourseManager::is_user_subscribed_in_course(
201
                $userId,
202
                $courseCode,
203
                $isInASession,
204
                $sessionId
205
            );
206
207
            if (!$isSubscribed) {
208
                throw $this->createAccessDeniedException();
209
            }
210
        }
211
212
        $isSpecialCourse = CourseManager::isSpecialCourse($courseId);
213
214
        if ($user && $isSpecialCourse && (isset($_GET['autoreg']) && 1 === (int) $_GET['autoreg'])
215
            && CourseManager::subscribeUser($userId, $courseId, STUDENT)
216
        ) {
217
            $sessionHandler->set('is_allowed_in_course', true);
218
        }
219
220
        $logInfo = [
221
            'tool' => 'course-main',
222
        ];
223
        Event::registerLog($logInfo);
224
225
        // Deleting the objects
226
        $sessionHandler->remove('toolgroup');
227
        $sessionHandler->remove('_gid');
228
        $sessionHandler->remove('oLP');
229
        $sessionHandler->remove('lpobject');
230
231
        api_remove_in_gradebook();
232
        Exercise::cleanSessionVariables();
233
234
        $shortcuts = [];
235
        if (null !== $user) {
236
            $shortcutQuery = $shortcutRepository->getResources($course->getResourceNode());
237
            $shortcuts = $shortcutQuery->getQuery()->getResult();
238
239
            $courseNodeId = $course->getResourceNode()->getId();
240
            $cid = $course->getId();
241
            $sid = $this->getSessionId() ?: null;
242
243
            /** @var CShortcut $shortcut */
244
            /** @var CShortcut $shortcut */
245
            foreach ($shortcuts as $shortcut) {
246
                $resourceNode = $shortcut->getShortCutNode();
247
248
                // Try as CLink
249
                $cLink = $em->getRepository(CLink::class)->findOneBy(['resourceNode' => $resourceNode]);
250
                if ($cLink) {
251
                    // Image (if any)
252
                    $shortcut->setCustomImageUrl(
253
                        $cLink->getCustomImage()
254
                            ? $assetRepository->getAssetUrl($cLink->getCustomImage())
255
                            : null
256
                    );
257
258
                    // External link behavior
259
                    $shortcut->setUrlOverride($cLink->getUrl()); // open external URL
260
                    $shortcut->setIcon(null);                    // keep default icon for links
261
                    $shortcut->target = $cLink->getTarget();     // e.g. "_blank"
262
263
                    continue;
264
                }
265
266
                // Try as CBlog
267
                $cBlog = $em->getRepository(CBlog::class)
268
                    ->findOneBy(['resourceNode' => $resourceNode])
269
                ;
270
271
                if ($cBlog) {
272
                    $courseNodeId = $course->getResourceNode()->getId();
273
                    $cid = $course->getId();
274
                    $sid = $this->getSessionId() ?: null;
275
276
                    $qs = http_build_query(array_filter([
277
                        'cid' => $cid,
278
                        'sid' => $sid ?: null,
279
                        'gid' => 0,
280
                    ], static fn ($v) => null !== $v));
281
282
                    $shortcut->setUrlOverride(\sprintf(
283
                        '/resources/blog/%d/%d/posts?%s',
284
                        $courseNodeId,
285
                        $cBlog->getIid(),
286
                        $qs
287
                    ));
288
                    $shortcut->setIcon('mdi-notebook-outline');  // blog icon
289
                    $shortcut->setCustomImageUrl(null);          // blogs use icon by default
290
                    $shortcut->target = '_self';
291
292
                    continue;
293
                }
294
295
                // Fallback
296
                $shortcut->setCustomImageUrl(null);
297
                $shortcut->setUrlOverride(null);
298
                $shortcut->setIcon(null);
299
                $shortcut->target = '_self';
300
            }
301
        }
302
        $responseData = [
303
            'shortcuts' => $shortcuts,
304
            'diagram' => '',
305
        ];
306
307
        $json = $this->serializer->serialize(
308
            $responseData,
309
            'json',
310
            [
311
                'groups' => ['course:read', 'ctool:read', 'tool:read', 'cshortcut:read'],
312
            ]
313
        );
314
315
        return new Response(
316
            $json,
317
            Response::HTTP_OK,
318
            [
319
                'Content-type' => 'application/json',
320
            ]
321
        );
322
    }
323
324
    #[Route('/{cid}/thematic_progress.json', name: 'chamilo_core_course_thematic_progress_json', methods: ['GET'])]
325
    public function thematicProgressJson(
326
        Request $request,
327
        CThematicRepository $thematicRepository,
328
        UserHelper $userHelper,
329
        CidReqHelper $cidReqHelper,
330
        TranslatorInterface $translator,
331
        SettingsCourseManager $courseSettingsManager
332
    ): JsonResponse {
333
        $course = $this->getCourse();
334
        if (null === $course) {
335
            throw $this->createAccessDeniedException();
336
        }
337
338
        if (0 === $this->getSessionId()) {
339
            $this->denyAccessUnlessGranted(CourseVoter::VIEW, $course);
340
        }
341
342
        $courseSettingsManager->setCourse($course);
343
        $displayMode = (string) $courseSettingsManager->getCourseSettingValue('display_info_advance_inside_homecourse');
344
345
        if ('' === $displayMode || '0' === $displayMode || '4' === $displayMode) {
346
            return new JsonResponse(['enabled' => false]);
347
        }
348
349
        $sessionEntity = $cidReqHelper->getSessionEntity();
350
        $currentUser = $userHelper->getCurrent();
351
352
        $advance1 = null;
353
        $advance2 = null;
354
        $subtitle1 = '';
355
        $subtitle2 = '';
356
357
        if ('1' === $displayMode) {
358
            // Last completed topic only
359
            $advance1 = $thematicRepository->findLastDoneAdvanceForCourse($course, $sessionEntity);
360
            if (null !== $advance1) {
361
                $subtitle1 = $translator->trans('Current topic');
362
            }
363
        } elseif ('2' === $displayMode) {
364
            // Two next not done topics
365
            $nextList = $thematicRepository->findNextNotDoneAdvancesForCourse($course, $sessionEntity, 2);
366
367
            if (isset($nextList[0]) && $nextList[0] instanceof CThematicAdvance) {
368
                $advance1 = $nextList[0];
369
                $subtitle1 = $translator->trans('Next topic');
370
            }
371
372
            if (isset($nextList[1]) && $nextList[1] instanceof CThematicAdvance) {
373
                $advance2 = $nextList[1];
374
                $subtitle2 = $translator->trans('Next topic');
375
            }
376
        } elseif ('3' === $displayMode) {
377
            // Current (last done) + next not done
378
            $advance1 = $thematicRepository->findLastDoneAdvanceForCourse($course, $sessionEntity);
379
            $nextList = $thematicRepository->findNextNotDoneAdvancesForCourse($course, $sessionEntity, 1);
380
381
            if (null !== $advance1) {
382
                $subtitle1 = $translator->trans('Current topic');
383
            }
384
385
            if (isset($nextList[0]) && $nextList[0] instanceof CThematicAdvance) {
386
                $advance2 = $nextList[0];
387
                $subtitle2 = $translator->trans('Next topic');
388
            }
389
        } else {
390
            return new JsonResponse(['enabled' => false]);
391
        }
392
393
        if (null === $advance1 && null === $advance2) {
394
            return new JsonResponse(['enabled' => false]);
395
        }
396
397
        $locale = $request->getLocale();
398
        $timezoneId = null;
399
400
        if ($currentUser && method_exists($currentUser, 'getTimezone') && $currentUser->getTimezone()) {
401
            $timezoneId = $currentUser->getTimezone();
402
        }
403
404
        if (empty($timezoneId)) {
405
            $timezoneId = date_default_timezone_get();
406
        }
407
408
        $dateFormatter = new IntlDateFormatter(
409
            $locale,
410
            IntlDateFormatter::MEDIUM,
411
            IntlDateFormatter::SHORT,
412
            $timezoneId
413
        );
414
415
        $buildItem = function (CThematicAdvance $advance, string $type, string $label) use ($dateFormatter): array {
416
            $thematic = $advance->getThematic();
417
418
            $startDate = $advance->getStartDate();
419
            $formattedDate = $startDate instanceof \DateTimeInterface
420
                ? (string) $dateFormatter->format($startDate)
421
                : '';
422
423
            return [
424
                'type' => $type,
425
                'label' => $label,
426
                'title' => strip_tags($thematic->getTitle() ?? ''),
427
                'startDate' => $formattedDate,
428
                'content' => strip_tags($advance->getContent() ?? ''),
429
                'duration' => (float) $advance->getDuration(),
430
            ];
431
        };
432
433
        $items = [];
434
435
        if (null !== $advance1) {
436
            $firstType = ('1' === $displayMode || '3' === $displayMode) ? 'current' : 'next';
437
            $items[] = $buildItem($advance1, $firstType, $subtitle1);
438
        }
439
440
        if (null !== $advance2) {
441
            $items[] = $buildItem($advance2, 'next', $subtitle2);
442
        }
443
444
        $userPayload = null;
445
        if ($currentUser) {
446
            $name = method_exists($currentUser, 'getCompleteName')
447
                ? $currentUser->getCompleteName()
448
                : trim(sprintf('%s %s', $currentUser->getFirstname(), $currentUser->getLastname()));
449
450
            $userPayload = [
451
                'name' => $name,
452
                'avatar' => null,
453
            ];
454
        }
455
456
        $thematicUrl = '/main/course_progress/index.php?cid='.$course->getId().'&sid='.$this->getSessionId().'&action=thematic_details';
457
        $thematicScoreRaw = $thematicRepository->calculateTotalAverageForCourse($course, $sessionEntity);
458
        $thematicScore = $thematicScoreRaw.'%';
459
460
        $payload = [
461
            'enabled' => true,
462
            'displayMode' => (int) $displayMode,
463
            'title' => $translator->trans('Course thematic advance'),
464
            'score' => $thematicScore,
465
            'scoreRaw' => $thematicScoreRaw,
466
            'user' => $userPayload,
467
            'items' => $items,
468
            'detailUrl' => $thematicUrl,
469
            'labels' => [
470
                'duration' => $translator->trans('Duration in hours'),
471
                'seeDetail' => $translator->trans('See detail'),
472
            ],
473
        ];
474
475
        return new JsonResponse($payload);
476
    }
477
478
    #[Route('/{courseId}/next-course', name: 'chamilo_course_next_course')]
479
    public function getNextCourse(
480
        int $courseId,
481
        Request $request,
482
        SequenceResourceRepository $repo,
483
        Security $security,
484
        SettingsManager $settingsManager,
485
        EntityManagerInterface $em
486
    ): JsonResponse {
487
        $sessionId = $request->query->getInt('sid');
488
        $useDependents = $request->query->getBoolean('dependents', false);
489
        $user = $security->getUser();
490
        $userId = $user->getId();
491
492
        if ($useDependents) {
493
            $sequences = $repo->getDependents($courseId, SequenceResource::COURSE_TYPE);
494
            $checked = $repo->checkDependentsForUser($sequences, SequenceResource::COURSE_TYPE, $userId, $sessionId, $courseId);
495
            $isUnlocked = $repo->checkSequenceAreCompleted($checked);
496
            $sequenceResource = $repo->findRequirementForResource($courseId, SequenceResource::COURSE_TYPE);
497
        } else {
498
            $sequences = $repo->getRequirements($courseId, SequenceResource::COURSE_TYPE);
499
500
            $hasValidRequirement = false;
501
            foreach ($sequences as $sequence) {
502
                foreach ($sequence['requirements'] ?? [] as $resource) {
503
                    if ($resource instanceof Course) {
504
                        $hasValidRequirement = true;
505
506
                        break 2;
507
                    }
508
                }
509
            }
510
511
            if (!$hasValidRequirement) {
512
                return new JsonResponse([]);
513
            }
514
515
            $checked = $repo->checkRequirementsForUser($sequences, SequenceResource::COURSE_TYPE, $userId, $sessionId);
516
            $isUnlocked = $repo->checkSequenceAreCompleted($checked);
517
            $sequenceResource = $repo->findRequirementForResource($courseId, SequenceResource::COURSE_TYPE);
518
        }
519
520
        $graphImage = null;
521
522
        if ($sequenceResource && $sequenceResource->hasGraph()) {
523
            $graph = $sequenceResource->getSequence()->getUnSerializeGraph();
524
            if (null !== $graph) {
525
                $graph->setAttribute('graphviz.node.fontname', 'arial');
526
                $graphviz = new GraphViz();
527
                $graphImage = $graphviz->createImageSrc($graph);
528
            }
529
        }
530
531
        return new JsonResponse([
532
            'sequenceList' => array_values($checked),
533
            'allowSubscription' => $isUnlocked,
534
            'graph' => $graphImage,
535
        ]);
536
    }
537
538
    /**
539
     * Redirects the page to a tool, following the tools settings.
540
     */
541
    #[Route('/{cid}/tool/{toolName}', name: 'chamilo_core_course_redirect_tool')]
542
    public function redirectTool(
543
        Request $request,
544
        string $toolName,
545
        CToolRepository $repo,
546
        ToolChain $toolChain
547
    ): RedirectResponse {
548
        /** @var CTool|null $tool */
549
        $tool = $repo->findOneBy([
550
            'title' => $toolName,
551
        ]);
552
553
        if (null === $tool) {
554
            throw new NotFoundHttpException($this->trans('Tool not found'));
555
        }
556
557
        $tool = $toolChain->getToolFromName($tool->getTool()->getTitle());
558
        $link = $tool->getLink();
559
560
        if (null === $this->getCourse()) {
561
            throw new NotFoundHttpException($this->trans('Course not found'));
562
        }
563
        $optionalParams = '';
564
565
        $optionalParams = $request->query->get('cert') ? '&cert='.$request->query->get('cert') : '';
566
567
        if (strpos($link, 'nodeId')) {
568
            $nodeId = (string) $this->getCourse()->getResourceNode()->getId();
569
            $link = str_replace(':nodeId', $nodeId, $link);
570
        }
571
572
        $url = $link.'?'.$this->getCourseUrlQuery().$optionalParams;
573
574
        return $this->redirect($url);
575
    }
576
577
    /*public function redirectToShortCut(string $toolName, CToolRepository $repo, ToolChain $toolChain): RedirectResponse
578
     * {
579
     * $tool = $repo->findOneBy([
580
     * 'name' => $toolName,
581
     * ]);
582
     * if (null === $tool) {
583
     * throw new NotFoundHttpException($this->trans('Tool not found'));
584
     * }
585
     * $tool = $toolChain->getToolFromName($tool->getTool()->getTitle());
586
     * $link = $tool->getLink();
587
     * if (strpos($link, 'nodeId')) {
588
     * $nodeId = (string) $this->getCourse()->getResourceNode()->getId();
589
     * $link = str_replace(':nodeId', $nodeId, $link);
590
     * }
591
     * $url = $link.'?'.$this->getCourseUrlQuery();
592
     * return $this->redirect($url);
593
     * }*/
594
595
    /**
596
     * Edit configuration with given namespace.
597
     */
598
    #[Route('/{course}/settings/{namespace}', name: 'chamilo_core_course_settings')]
599
    public function updateSettings(
600
        Request $request,
601
        #[MapEntity(expr: 'repository.find(cid)')]
602
        Course $course,
603
        string $namespace,
604
        SettingsCourseManager $manager,
605
        SettingsFormFactory $formFactory
606
    ): Response {
607
        $this->denyAccessUnlessGranted(CourseVoter::VIEW, $course);
608
609
        $schemaAlias = $manager->convertNameSpaceToService($namespace);
610
        $settings = $manager->load($namespace);
611
612
        $form = $formFactory->create($schemaAlias);
613
614
        $form->setData($settings);
615
        $form->handleRequest($request);
616
617
        if ($form->isSubmitted() && $form->isValid()) {
618
            $messageType = 'success';
619
620
            try {
621
                $manager->setCourse($course);
622
                $manager->save($form->getData());
623
                $message = $this->trans('Update');
624
            } catch (ValidatorException $validatorException) {
625
                $message = $this->trans($validatorException->getMessage());
626
                $messageType = 'error';
627
            }
628
            $this->addFlash($messageType, $message);
629
630
            if ($request->headers->has('referer')) {
631
                return $this->redirect($request->headers->get('referer'));
632
            }
633
        }
634
635
        $schemas = $manager->getSchemas();
636
637
        return $this->render(
638
            '@ChamiloCore/Course/settings.html.twig',
639
            [
640
                'course' => $course,
641
                'schemas' => $schemas,
642
                'settings' => $settings,
643
                'form' => $form,
644
            ]
645
        );
646
    }
647
648
    #[Route('/{id}/about', name: 'chamilo_core_course_about')]
649
    public function about(
650
        Course $course,
651
        IllustrationRepository $illustrationRepository,
652
        CCourseDescriptionRepository $courseDescriptionRepository,
653
        EntityManagerInterface $em,
654
        Request $request
655
    ): Response {
656
        $courseId = $course->getId();
657
658
        $user = $this->userHelper->getCurrent();
659
660
        $fieldsRepo = $em->getRepository(ExtraField::class);
661
662
        /** @var TagRepository $tagRepo */
663
        $tagRepo = $em->getRepository(Tag::class);
664
665
        $courseDescriptions = $courseDescriptionRepository->getResourcesByCourse($course)->getQuery()->getResult();
666
667
        $courseValues = new ExtraFieldValue('course');
668
669
        $urlCourse = api_get_path(WEB_PATH).\sprintf('course/%s/about', $courseId);
670
        $courseTeachers = $course->getTeachersSubscriptions();
671
        $teachersData = [];
672
673
        foreach ($courseTeachers as $teacherSubscription) {
674
            $teacher = $teacherSubscription->getUser();
675
            $userData = [
676
                'complete_name' => UserManager::formatUserFullName($teacher),
677
                'image' => $illustrationRepository->getIllustrationUrl($teacher),
678
                'diploma' => $teacher->getDiplomas(),
679
                'openarea' => $teacher->getOpenarea(),
680
            ];
681
682
            $teachersData[] = $userData;
683
        }
684
685
        /** @var ExtraField $tagField */
686
        $tagField = $fieldsRepo->findOneBy([
687
            'itemType' => ExtraField::COURSE_FIELD_TYPE,
688
            'variable' => 'tags',
689
        ]);
690
691
        $courseTags = [];
692
        if (null !== $tagField) {
693
            $courseTags = $tagRepo->getTagsByItem($tagField, $courseId);
694
        }
695
696
        $courseDescription = $courseObjectives = $courseTopics = $courseMethodology = '';
697
        $courseMaterial = $courseResources = $courseAssessment = '';
698
        $courseCustom = [];
699
        foreach ($courseDescriptions as $descriptionTool) {
700
            switch ($descriptionTool->getDescriptionType()) {
701
                case CCourseDescription::TYPE_DESCRIPTION:
702
                    $courseDescription = $descriptionTool->getContent();
703
704
                    break;
705
706
                case CCourseDescription::TYPE_OBJECTIVES:
707
                    $courseObjectives = $descriptionTool;
708
709
                    break;
710
711
                case CCourseDescription::TYPE_TOPICS:
712
                    $courseTopics = $descriptionTool;
713
714
                    break;
715
716
                case CCourseDescription::TYPE_METHODOLOGY:
717
                    $courseMethodology = $descriptionTool;
718
719
                    break;
720
721
                case CCourseDescription::TYPE_COURSE_MATERIAL:
722
                    $courseMaterial = $descriptionTool;
723
724
                    break;
725
726
                case CCourseDescription::TYPE_RESOURCES:
727
                    $courseResources = $descriptionTool;
728
729
                    break;
730
731
                case CCourseDescription::TYPE_ASSESSMENT:
732
                    $courseAssessment = $descriptionTool;
733
734
                    break;
735
736
                case CCourseDescription::TYPE_CUSTOM:
737
                    $courseCustom[] = $descriptionTool;
738
739
                    break;
740
            }
741
        }
742
743
        $topics = [
744
            'objectives' => $courseObjectives,
745
            'topics' => $courseTopics,
746
            'methodology' => $courseMethodology,
747
            'material' => $courseMaterial,
748
            'resources' => $courseResources,
749
            'assessment' => $courseAssessment,
750
            'custom' => array_reverse($courseCustom),
751
        ];
752
753
        $subscriptionUser = false;
754
755
        if ($user) {
756
            $subscriptionUser = CourseManager::is_user_subscribed_in_course($user->getId(), $course->getCode());
757
        }
758
759
        $allowSubscribe = CourseManager::canUserSubscribeToCourse($course->getCode());
760
761
        $image = Container::getIllustrationRepository()->getIllustrationUrl($course, 'course_picture_medium');
762
763
        $params = [
764
            'course' => $course,
765
            'description' => $courseDescription,
766
            'image' => $image,
767
            'syllabus' => $topics,
768
            'tags' => $courseTags,
769
            'teachers' => $teachersData,
770
            'extra_fields' => $courseValues->getAllValuesForAnItem(
771
                $course->getId(),
772
                null,
773
                true
774
            ),
775
            'subscription' => $subscriptionUser,
776
            'url' => '',
777
            'is_premium' => '',
778
            'token' => '',
779
            'base_url' => $request->getSchemeAndHttpHost(),
780
            'allow_subscribe' => $allowSubscribe,
781
        ];
782
783
        $metaInfo = '<meta property="og:url" content="'.$urlCourse.'" />';
784
        $metaInfo .= '<meta property="og:type" content="website" />';
785
        $metaInfo .= '<meta property="og:title" content="'.$course->getTitle().'" />';
786
        $metaInfo .= '<meta property="og:description" content="'.strip_tags($courseDescription).'" />';
787
        $metaInfo .= '<meta property="og:image" content="'.$image.'" />';
788
789
        $htmlHeadXtra[] = $metaInfo;
790
        $htmlHeadXtra[] = api_get_asset('readmore-js/readmore.js');
791
792
        return $this->render('@ChamiloCore/Course/about.html.twig', $params);
793
    }
794
795
    #[Route('/{id}/welcome', name: 'chamilo_core_course_welcome')]
796
    public function welcome(Course $course): Response
797
    {
798
        return $this->render('@ChamiloCore/Course/welcome.html.twig', [
799
            'course' => $course,
800
        ]);
801
    }
802
803
    private function findIntroOfCourse(Course $course): ?CTool
804
    {
805
        $qb = $this->em->createQueryBuilder();
806
807
        $query = $qb->select('ct')
808
            ->from(CTool::class, 'ct')
809
            ->where('ct.course = :c_id')
810
            ->andWhere('ct.title = :title')
811
            ->andWhere(
812
                $qb->expr()->orX(
813
                    $qb->expr()->eq('ct.session', ':session_id'),
814
                    $qb->expr()->isNull('ct.session')
815
                )
816
            )
817
            ->setParameters([
818
                'c_id' => $course->getId(),
819
                'title' => 'course_homepage',
820
                'session_id' => 0,
821
            ])
822
            ->getQuery()
823
        ;
824
825
        $results = $query->getResult();
826
827
        return \count($results) > 0 ? $results[0] : null;
828
    }
829
830
    #[Route('/{id}/getToolIntro', name: 'chamilo_core_course_gettoolintro')]
831
    public function getToolIntro(Request $request, Course $course, EntityManagerInterface $em): Response
832
    {
833
        $sessionId = (int) $request->get('sid');
834
835
        // $session = $this->getSession();
836
        $responseData = [];
837
        $ctoolRepo = $em->getRepository(CTool::class);
838
        $sessionRepo = $em->getRepository(Session::class);
839
        $createInSession = false;
840
841
        $session = null;
842
843
        if (!empty($sessionId)) {
844
            $session = $sessionRepo->find($sessionId);
845
        }
846
847
        $ctool = $this->findIntroOfCourse($course);
848
849
        if ($session) {
850
            $ctoolSession = $ctoolRepo->findOneBy(['title' => 'course_homepage', 'course' => $course, 'session' => $session]);
851
852
            if (!$ctoolSession) {
853
                $createInSession = true;
854
            } else {
855
                $ctool = $ctoolSession;
856
            }
857
        }
858
859
        if ($ctool) {
860
            $ctoolintroRepo = $em->getRepository(CToolIntro::class);
861
862
            /** @var CToolIntro $ctoolintro */
863
            $ctoolintro = $ctoolintroRepo->findOneBy(['courseTool' => $ctool]);
864
            if ($ctoolintro) {
865
                $responseData = [
866
                    'iid' => $ctoolintro->getIid(),
867
                    'introText' => $ctoolintro->getIntroText(),
868
                    'createInSession' => $createInSession,
869
                    'cToolId' => $ctool->getIid(),
870
                ];
871
            }
872
            $responseData['c_tool'] = [
873
                'iid' => $ctool->getIid(),
874
                'title' => $ctool->getTitle(),
875
            ];
876
        }
877
878
        return new JsonResponse($responseData);
879
    }
880
881
    #[Route('/{id}/addToolIntro', name: 'chamilo_core_course_addtoolintro')]
882
    public function addToolIntro(Request $request, Course $course, EntityManagerInterface $em): Response
883
    {
884
        $data = json_decode($request->getContent());
885
        $sessionId = $data->sid ?? ($data->resourceLinkList[0]->sid ?? 0);
886
        $introText = $data->introText ?? null;
887
888
        $session = $sessionId ? $em->getRepository(Session::class)->find($sessionId) : null;
889
        $ctoolRepo = $em->getRepository(CTool::class);
890
        $ctoolintroRepo = $em->getRepository(CToolIntro::class);
891
892
        $ctoolSession = $ctoolRepo->findOneBy([
893
            'title' => 'course_homepage',
894
            'course' => $course,
895
            'session' => $session,
896
        ]);
897
898
        if (!$ctoolSession) {
899
            $toolEntity = $em->getRepository(Tool::class)->findOneBy(['title' => 'course_homepage']);
900
            if ($toolEntity) {
901
                $ctoolSession = (new CTool())
902
                    ->setTool($toolEntity)
903
                    ->setTitle('course_homepage')
904
                    ->setCourse($course)
905
                    ->setPosition(1)
906
                    ->setVisibility(true)
907
                    ->setParent($course)
908
                    ->setCreator($course->getCreator())
909
                    ->setSession($session)
910
                    ->addCourseLink($course)
911
                ;
912
913
                $em->persist($ctoolSession);
914
                $em->flush();
915
            }
916
        }
917
918
        $ctoolIntro = $ctoolintroRepo->findOneBy(['courseTool' => $ctoolSession]);
919
        if (!$ctoolIntro) {
920
            $ctoolIntro = (new CToolIntro())
921
                ->setCourseTool($ctoolSession)
922
                ->setIntroText($introText ?? '')
923
                ->setParent($course)
924
            ;
925
926
            $em->persist($ctoolIntro);
927
            $em->flush();
928
929
            return new JsonResponse([
930
                'status' => 'created',
931
                'cToolId' => $ctoolSession->getIid(),
932
                'introIid' => $ctoolIntro->getIid(),
933
                'introText' => $ctoolIntro->getIntroText(),
934
            ]);
935
        }
936
937
        if (null !== $introText) {
938
            $ctoolIntro->setIntroText($introText);
939
            $em->persist($ctoolIntro);
940
            $em->flush();
941
942
            return new JsonResponse([
943
                'status' => 'updated',
944
                'cToolId' => $ctoolSession->getIid(),
945
                'introIid' => $ctoolIntro->getIid(),
946
                'introText' => $ctoolIntro->getIntroText(),
947
            ]);
948
        }
949
950
        return new JsonResponse(['status' => 'no_action']);
951
    }
952
953
    #[Route('/check-enrollments', name: 'chamilo_core_check_enrollments', methods: ['GET'])]
954
    public function checkEnrollments(EntityManagerInterface $em, SettingsManager $settingsManager): JsonResponse
955
    {
956
        $user = $this->userHelper->getCurrent();
957
958
        if (!$user) {
959
            return new JsonResponse(['error' => 'User not found'], Response::HTTP_UNAUTHORIZED);
960
        }
961
962
        $isEnrolledInCourses = $this->isUserEnrolledInAnyCourse($user, $em);
963
        $isEnrolledInSessions = $this->isUserEnrolledInAnySession($user, $em);
964
965
        if (!$isEnrolledInCourses && !$isEnrolledInSessions) {
966
            $defaultMenuEntry = $settingsManager->getSetting('workflows.default_menu_entry_for_course_or_session');
967
            $isEnrolledInCourses = 'my_courses' === $defaultMenuEntry;
968
            $isEnrolledInSessions = 'my_sessions' === $defaultMenuEntry;
969
        }
970
971
        return new JsonResponse([
972
            'isEnrolledInCourses' => $isEnrolledInCourses,
973
            'isEnrolledInSessions' => $isEnrolledInSessions,
974
        ]);
975
    }
976
977
    #[Route('/categories', name: 'chamilo_core_course_form_lists')]
978
    public function getCategories(
979
        SettingsManager $settingsManager,
980
        AccessUrlHelper $accessUrlHelper,
981
        CourseCategoryRepository $courseCategoriesRepo
982
    ): JsonResponse {
983
        $allowBaseCourseCategory = 'true' === $settingsManager->getSetting('course.allow_base_course_category');
984
        $accessUrlId = $accessUrlHelper->getCurrent()->getId();
985
986
        $categories = $courseCategoriesRepo->findAllInAccessUrl(
987
            $accessUrlId,
988
            $allowBaseCourseCategory
989
        );
990
991
        $data = [];
992
        $categoryToAvoid = '';
993
        if (!$this->isGranted('ROLE_ADMIN')) {
994
            $categoryToAvoid = $settingsManager->getSetting('course.course_category_code_to_use_as_model');
995
        }
996
997
        foreach ($categories as $category) {
998
            $categoryCode = $category->getCode();
999
            if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) {
1000
                continue;
1001
            }
1002
            $data[] = ['id' => $category->getId(), 'name' => $category->__toString()];
1003
        }
1004
1005
        return new JsonResponse($data);
1006
    }
1007
1008
    #[Route('/search_templates', name: 'chamilo_core_course_search_templates')]
1009
    public function searchCourseTemplates(
1010
        Request $request,
1011
        AccessUrlHelper $accessUrlUtil,
1012
        CourseRepository $courseRepository
1013
    ): JsonResponse {
1014
        $searchTerm = $request->query->get('search', '');
1015
        $accessUrl = $accessUrlUtil->getCurrent();
1016
1017
        $user = $this->userHelper->getCurrent();
1018
1019
        $courseList = $courseRepository->getCoursesInfoByUser($user, $accessUrl, 1, $searchTerm);
1020
        $results = ['items' => []];
1021
        foreach ($courseList as $course) {
1022
            $title = $course['title'];
1023
            $results['items'][] = [
1024
                'id' => $course['id'],
1025
                'name' => $title.' ('.$course['code'].') ',
1026
            ];
1027
        }
1028
1029
        return new JsonResponse($results);
1030
    }
1031
1032
    #[Route('/create', name: 'chamilo_core_course_create')]
1033
    public function createCourse(
1034
        Request $request,
1035
        TranslatorInterface $translator,
1036
        CourseHelper $courseHelper
1037
    ): JsonResponse {
1038
        $courseData = json_decode($request->getContent(), true);
1039
1040
        $title = $courseData['name'] ?? null;
1041
        $wantedCode = $courseData['code'] ?? null;
1042
        $courseLanguage = $courseData['language'] ?? null;
1043
        $categoryCode = $courseData['category'] ?? null;
1044
        $exemplaryContent = $courseData['fillDemoContent'] ?? false;
1045
        $template = $courseData['template'] ?? '';
1046
1047
        $params = [
1048
            'title' => $title,
1049
            'wanted_code' => $wantedCode,
1050
            'course_language' => $courseLanguage,
1051
            'exemplary_content' => $exemplaryContent,
1052
            'course_template' => $template,
1053
        ];
1054
1055
        if ($categoryCode) {
1056
            $params['course_categories'] = $categoryCode;
1057
        }
1058
1059
        try {
1060
            $course = $courseHelper->createCourse($params);
1061
            if ($course) {
1062
                return new JsonResponse([
1063
                    'success' => true,
1064
                    'message' => $translator->trans('Course created successfully.'),
1065
                    'courseId' => $course->getId(),
1066
                ]);
1067
            }
1068
        } catch (Exception $e) {
1069
            return new JsonResponse([
1070
                'success' => false,
1071
                'message' => $translator->trans($e->getMessage()),
1072
            ], Response::HTTP_BAD_REQUEST);
1073
        }
1074
1075
        return new JsonResponse(['success' => false, 'message' => $translator->trans('An error occurred while creating the course.')]);
1076
    }
1077
1078
    #[Route('/{id}/getAutoLaunchExerciseId', name: 'chamilo_core_course_get_auto_launch_exercise_id', methods: ['GET'])]
1079
    public function getAutoLaunchExerciseId(
1080
        Request $request,
1081
        Course $course,
1082
        CQuizRepository $quizRepository,
1083
        EntityManagerInterface $em
1084
    ): JsonResponse {
1085
        $data = $request->getContent();
1086
        $data = json_decode($data);
1087
        $sessionId = $data->sid ?? 0;
1088
1089
        $sessionRepo = $em->getRepository(Session::class);
1090
        $session = null;
1091
        if (!empty($sessionId)) {
1092
            $session = $sessionRepo->find($sessionId);
1093
        }
1094
1095
        $autoLaunchExerciseId = $quizRepository->findAutoLaunchableQuizByCourseAndSession($course, $session);
1096
1097
        return new JsonResponse(['exerciseId' => $autoLaunchExerciseId], Response::HTTP_OK);
1098
    }
1099
1100
    #[Route('/{id}/getAutoLaunchLPId', name: 'chamilo_core_course_get_auto_launch_lp_id', methods: ['GET'])]
1101
    public function getAutoLaunchLPId(
1102
        Request $request,
1103
        Course $course,
1104
        CLpRepository $lpRepository,
1105
        EntityManagerInterface $em
1106
    ): JsonResponse {
1107
        $data = $request->getContent();
1108
        $data = json_decode($data);
1109
        $sessionId = $data->sid ?? 0;
1110
1111
        $sessionRepo = $em->getRepository(Session::class);
1112
        $session = null;
1113
        if (!empty($sessionId)) {
1114
            $session = $sessionRepo->find($sessionId);
1115
        }
1116
1117
        $autoLaunchLPId = $lpRepository->findAutoLaunchableLPByCourseAndSession($course, $session);
1118
1119
        return new JsonResponse(['lpId' => $autoLaunchLPId], Response::HTTP_OK);
1120
    }
1121
1122
    private function autoLaunch(): void
1123
    {
1124
        $autoLaunchWarning = '';
1125
        $showAutoLaunchLpWarning = false;
1126
        $course_id = api_get_course_int_id();
1127
        $lpAutoLaunch = api_get_course_setting('enable_lp_auto_launch');
1128
        $session_id = api_get_session_id();
1129
        $allowAutoLaunchForCourseAdmins =
1130
            api_is_platform_admin()
1131
            || api_is_allowed_to_edit(true, true)
1132
            || api_is_coach();
1133
1134
        if (!empty($lpAutoLaunch)) {
1135
            if (2 === $lpAutoLaunch) {
1136
                // LP list
1137
                if ($allowAutoLaunchForCourseAdmins) {
1138
                    $showAutoLaunchLpWarning = true;
1139
                } else {
1140
                    $session_key = 'lp_autolaunch_'.$session_id.'_'.$course_id.'_'.api_get_user_id();
1141
                    if (!isset($_SESSION[$session_key])) {
1142
                        // Redirecting to the LP
1143
                        $url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq();
1144
                        $_SESSION[$session_key] = true;
1145
                        header(\sprintf('Location: %s', $url));
1146
1147
                        exit;
1148
                    }
1149
                }
1150
            } else {
1151
                $lp_table = Database::get_course_table(TABLE_LP_MAIN);
1152
                $condition = '';
1153
                if (!empty($session_id)) {
1154
                    $condition = api_get_session_condition($session_id);
1155
                    $sql = "SELECT id FROM {$lp_table}
1156
                            WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
1157
                            LIMIT 1";
1158
                    $result = Database::query($sql);
1159
                    // If we found nothing in the session we just called the session_id =  0 autolaunch
1160
                    if (0 === Database::num_rows($result)) {
1161
                        $condition = '';
1162
                    }
1163
                }
1164
1165
                $sql = "SELECT iid FROM {$lp_table}
1166
                        WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
1167
                        LIMIT 1";
1168
                $result = Database::query($sql);
1169
                if (Database::num_rows($result) > 0) {
1170
                    $lp_data = Database::fetch_array($result);
1171
                    if (!empty($lp_data['iid'])) {
1172
                        if ($allowAutoLaunchForCourseAdmins) {
1173
                            $showAutoLaunchLpWarning = true;
1174
                        } else {
1175
                            $session_key = 'lp_autolaunch_'.$session_id.'_'.api_get_course_int_id().'_'.api_get_user_id();
1176
                            if (!isset($_SESSION[$session_key])) {
1177
                                // Redirecting to the LP
1178
                                $url = api_get_path(WEB_CODE_PATH).
1179
                                    'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$lp_data['iid'];
1180
1181
                                $_SESSION[$session_key] = true;
1182
                                header(\sprintf('Location: %s', $url));
1183
1184
                                exit;
1185
                            }
1186
                        }
1187
                    }
1188
                }
1189
            }
1190
        }
1191
1192
        if ($showAutoLaunchLpWarning) {
1193
            $autoLaunchWarning = get_lang(
1194
                'The learning path auto-launch setting is ON. When learners enter this course, they will be automatically redirected to the learning path marked as auto-launch.'
1195
            );
1196
        }
1197
1198
        $forumAutoLaunch = (int) api_get_course_setting('enable_forum_auto_launch');
1199
        if (1 === $forumAutoLaunch) {
1200
            if ($allowAutoLaunchForCourseAdmins) {
1201
                if (empty($autoLaunchWarning)) {
1202
                    $autoLaunchWarning = get_lang(
1203
                        "The forum's auto-launch setting is on. Students will be redirected to the forum tool when entering this course."
1204
                    );
1205
                }
1206
            } else {
1207
                $url = api_get_path(WEB_CODE_PATH).'forum/index.php?'.api_get_cidreq();
1208
                header(\sprintf('Location: %s', $url));
1209
1210
                exit;
1211
            }
1212
        }
1213
1214
        $exerciseAutoLaunch = (int) api_get_course_setting('enable_exercise_auto_launch');
1215
        if (2 === $exerciseAutoLaunch) {
1216
            if ($allowAutoLaunchForCourseAdmins) {
1217
                if (empty($autoLaunchWarning)) {
1218
                    $autoLaunchWarning = get_lang(
1219
                        'TheExerciseAutoLaunchSettingIsONStudentsWillBeRedirectToTheExerciseList'
1220
                    );
1221
                }
1222
            } else {
1223
                // Redirecting to the document
1224
                $url = api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq();
1225
                header(\sprintf('Location: %s', $url));
1226
1227
                exit;
1228
            }
1229
        } elseif (1 === $exerciseAutoLaunch) {
1230
            if ($allowAutoLaunchForCourseAdmins) {
1231
                if (empty($autoLaunchWarning)) {
1232
                    $autoLaunchWarning = get_lang(
1233
                        'TheExerciseAutoLaunchSettingIsONStudentsWillBeRedirectToAnSpecificExercise'
1234
                    );
1235
                }
1236
            } else {
1237
                // Redirecting to an exercise
1238
                $table = Database::get_course_table(TABLE_QUIZ_TEST);
1239
                $condition = '';
1240
                if (!empty($session_id)) {
1241
                    $condition = api_get_session_condition($session_id);
1242
                    $sql = "SELECT iid FROM {$table}
1243
                            WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
1244
                            LIMIT 1";
1245
                    $result = Database::query($sql);
1246
                    // If we found nothing in the session we just called the session_id = 0 autolaunch
1247
                    if (0 === Database::num_rows($result)) {
1248
                        $condition = '';
1249
                    }
1250
                }
1251
1252
                $sql = "SELECT iid FROM {$table}
1253
                        WHERE c_id = {$course_id} AND autolaunch = 1 {$condition}
1254
                        LIMIT 1";
1255
                $result = Database::query($sql);
1256
                if (Database::num_rows($result) > 0) {
1257
                    $row = Database::fetch_array($result);
1258
                    $exerciseId = $row['iid'];
1259
                    $url = api_get_path(WEB_CODE_PATH).
1260
                        'exercise/overview.php?exerciseId='.$exerciseId.'&'.api_get_cidreq();
1261
                    header(\sprintf('Location: %s', $url));
1262
1263
                    exit;
1264
                }
1265
            }
1266
        }
1267
1268
        $documentAutoLaunch = (int) api_get_course_setting('enable_document_auto_launch');
1269
        if (1 === $documentAutoLaunch) {
1270
            if ($allowAutoLaunchForCourseAdmins) {
1271
                if (empty($autoLaunchWarning)) {
1272
                    $autoLaunchWarning = get_lang(
1273
                        'The document auto-launch feature configuration is enabled. Learners will be automatically redirected to document tool.'
1274
                    );
1275
                }
1276
            } else {
1277
                // Redirecting to the document
1278
                $url = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq();
1279
                header("Location: $url");
1280
1281
                exit;
1282
            }
1283
        }
1284
1285
        /*  SWITCH TO A DIFFERENT HOMEPAGE VIEW
1286
         the setting homepage_view is adjustable through
1287
         the platform administration section */
1288
        if (!empty($autoLaunchWarning)) {
1289
            $this->addFlash(
1290
                'warning',
1291
                Display::return_message(
1292
                    $autoLaunchWarning,
1293
                    'warning'
1294
                )
1295
            );
1296
        }
1297
    }
1298
1299
    // Implement the real logic to check course enrollment
1300
    private function isUserEnrolledInAnyCourse(User $user, EntityManagerInterface $em): bool
1301
    {
1302
        $enrollmentCount = $em
1303
            ->getRepository(CourseRelUser::class)
1304
            ->count(['user' => $user])
1305
        ;
1306
1307
        return $enrollmentCount > 0;
1308
    }
1309
1310
    // Implement the real logic to check session enrollment
1311
    private function isUserEnrolledInAnySession(User $user, EntityManagerInterface $em): bool
1312
    {
1313
        $enrollmentCount = $em->getRepository(SessionRelUser::class)
1314
            ->count(['user' => $user])
1315
        ;
1316
1317
        return $enrollmentCount > 0;
1318
    }
1319
}
1320