Passed
Pull Request — master (#6351)
by
unknown
08:05
created

__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 6
rs 10
c 1
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Command;
8
9
use Chamilo\CoreBundle\Entity\Course;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\Service\CourseService;
12
use Chamilo\CoreBundle\Settings\SettingsManager;
13
use Chamilo\CourseBundle\Entity\CDocument;
14
use Chamilo\CourseBundle\Entity\CLp;
15
use Chamilo\CourseBundle\Entity\CLpItem;
16
use Doctrine\ORM\EntityManagerInterface;
17
use Symfony\Component\Console\Attribute\AsCommand;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Style\SymfonyStyle;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Finder\Finder;
24
25
26
#[AsCommand(
27
    name: 'app:create-courses-from-structured-file',
28
    description: 'Create courses and learning paths from a folder containing files',
29
)]
30
class CreateCoursesFromStructuredFileCommand extends Command
31
{
32
    public function __construct(
33
        private readonly EntityManagerInterface $em,
34
        private readonly CourseService $courseService,
35
        private readonly SettingsManager $settingsManager
36
    ) {
37
        parent::__construct();
38
    }
39
40
    protected function configure(): void
41
    {
42
        $this
43
            ->addArgument('folder', InputArgument::REQUIRED, 'Path to folder with course files');
44
    }
45
46
    protected function execute(InputInterface $input, OutputInterface $output): int
47
    {
48
        $io = new SymfonyStyle($input, $output);
49
        $adminUser = $this->getFirstAdmin();
50
        if (!$adminUser) {
51
            $io->error('No admin user found in the system.');
52
            return Command::FAILURE;
53
        }
54
55
        $folder = $input->getArgument('folder');
56
        if (!is_dir($folder)) {
57
            $io->error("Invalid folder: $folder");
58
            return Command::FAILURE;
59
        }
60
61
        $finder = new Finder();
62
        $finder->files()->in($folder);
63
64
        foreach ($finder as $file) {
65
            $basename = $file->getBasename();
66
            $courseCode = pathinfo($basename, PATHINFO_FILENAME);
67
            $filePath = $file->getRealPath();
68
69
            // Skip unsupported extensions
70
            $allowedExtensions = ['pdf', 'html', 'htm', 'mp4'];
71
            if (!in_array(strtolower($file->getExtension()), $allowedExtensions)) {
72
                $io->warning("Skipping unsupported file: $basename");
73
                continue;
74
            }
75
76
            $io->section("Creating course: $courseCode");
77
78
            // Step 1: Create the course
79
            $course = $this->courseService->createCourse([
80
                'title' => $courseCode,
81
                'wanted_code' => $courseCode,
82
                'add_user_as_teacher' => true,
83
                'course_language' => $this->settingsManager->getSetting('language.platform_language'),
84
                'visibility' => Course::OPEN_PLATFORM,
85
                'subscribe' => true,
86
                'unsubscribe' => true,
87
                'disk_quota' => $this->settingsManager->getSetting('document.default_document_quotum'),
88
                'expiration_date' => (new \DateTime('+1 year'))->format('Y-m-d H:i:s')
89
            ]);
90
91
            if (!$course) {
92
                throw new \RuntimeException('Error: Course could not be created.');
93
            }
94
95
            // Step 2: Create learning path (CLp)
96
            $lp = (new CLp())
97
                ->setLpType(1)
98
                ->setTitle($courseCode)
99
                ->setDescription('')
100
                ->setPublishedOn(null)
101
                ->setExpiredOn(null)
102
                ->setCategory(null)
103
                ->setParent($course)
104
                ->addCourseLink($course);
105
            $lp->setCreator($adminUser);
106
107
            $lpRepo = $this->em->getRepository(CLp::class);
108
            $lpRepo->createLp($lp);
109
110
            // Step 3: Create CDocument from uploaded file
111
            $document = new CDocument();
112
            $document->setFiletype('file')
113
                ->setTitle($basename)
114
                ->setComment(null)
115
                ->setReadonly(false)
116
                ->setCreator($adminUser)
117
                ->setParent($course)
118
                ->addCourseLink($course);
119
120
            $this->em->persist($document);
121
            $this->em->flush();
122
123
            $documentRepo = $this->em->getRepository(CDocument::class);
124
            $documentRepo->addFileFromPath($document, $basename, $filePath);
125
126
            // Step 4: Create LP item linked to the document
127
            // Ensure root item exists
128
            $lpItemRepo = $this->em->getRepository(CLpItem::class);
129
            $rootItem = $lpItemRepo->getRootItem((int) $lp->getIid());
130
131
            if (!$rootItem) {
132
                $rootItem = (new CLpItem())
133
                    ->setTitle('root')
134
                    ->setPath('root')
135
                    ->setLp($lp)
136
                    ->setItemType('root');
137
                $this->em->persist($rootItem);
138
                $this->em->flush();
139
            }
140
141
            $lpItem = (new CLpItem())
142
                ->setLp($lp)
143
                ->setTitle($basename)
144
                ->setItemType('document')
145
                ->setRef((string) $document->getIid())
146
                ->setPath((string) $document->getIid())
147
                ->setDisplayOrder(1)
148
                ->setLaunchData('')
149
                ->setMinScore(0)
150
                ->setMaxScore(100)
151
                ->setParent($rootItem)
152
                ->setLvl(1)
153
                ->setRoot($rootItem);
154
155
            $this->em->persist($lpItem);
156
            $this->em->flush();
157
158
            $io->success("Course '$courseCode' created with LP and document item '$basename'");
159
        }
160
161
        return Command::SUCCESS;
162
    }
163
164
    private function getFirstAdmin(): ?User
165
    {
166
        return $this->em->getRepository(User::class)
167
            ->createQueryBuilder('u')
168
            ->where('u.roles LIKE :role')
169
            ->setParameter('role', '%ROLE_ADMIN%')
170
            ->setMaxResults(1)
171
            ->getQuery()
172
            ->getOneOrNullResult();
173
    }
174
}
175