Passed
Push — master ( b349f1...7e5caa )
by Angel Fernando Quiroz
09:34
created

AbstractMigrationChamilo::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
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\Migrations;
8
9
use Chamilo\CoreBundle\Entity\AbstractResource;
10
use Chamilo\CoreBundle\Entity\AccessUrl;
11
use Chamilo\CoreBundle\Entity\Admin;
12
use Chamilo\CoreBundle\Entity\Course;
13
use Chamilo\CoreBundle\Entity\ResourceInterface;
14
use Chamilo\CoreBundle\Entity\ResourceLink;
15
use Chamilo\CoreBundle\Entity\ResourceType;
16
use Chamilo\CoreBundle\Entity\Session;
17
use Chamilo\CoreBundle\Entity\SettingsCurrent;
18
use Chamilo\CoreBundle\Entity\SettingsOptions;
19
use Chamilo\CoreBundle\Entity\User;
20
use Chamilo\CoreBundle\Repository\Node\UserRepository;
21
use Chamilo\CoreBundle\Repository\ResourceRepository;
22
use Chamilo\CoreBundle\Repository\SessionRepository;
23
use Chamilo\CourseBundle\Repository\CGroupRepository;
24
use DateTime;
25
use DateTimeZone;
26
use Doctrine\DBAL\Connection;
27
use Doctrine\Migrations\AbstractMigration;
28
use Doctrine\ORM\EntityManagerInterface;
29
use Psr\Log\LoggerInterface;
30
use Symfony\Component\DependencyInjection\ContainerInterface;
31
use Symfony\Component\Filesystem\Filesystem;
32
use Symfony\Component\Finder\Finder;
33
use Symfony\Component\HttpFoundation\File\UploadedFile;
34
35
abstract class AbstractMigrationChamilo extends AbstractMigration
36
{
37
    public const BATCH_SIZE = 20;
38
39
    protected ?EntityManagerInterface $entityManager = null;
40
    protected ?ContainerInterface $container = null;
41
42
    private LoggerInterface $logger;
43
44
    public function __construct(Connection $connection, LoggerInterface $logger)
45
    {
46
        parent::__construct($connection, $logger);
47
        $this->logger = $logger;
48
    }
49
50
    protected function getLogger(): LoggerInterface
51
    {
52
        return $this->logger;
53
    }
54
55
    public function setEntityManager(EntityManagerInterface $entityManager): void
56
    {
57
        $this->entityManager = $entityManager;
58
    }
59
60
    public function setContainer(?ContainerInterface $container = null): void
61
    {
62
        $this->container = $container;
63
    }
64
65
    public function adminExist(): bool
66
    {
67
        $sql = 'SELECT user_id FROM admin WHERE user_id IN (SELECT id FROM user) ORDER BY id LIMIT 1';
68
        $result = $this->connection->executeQuery($sql);
69
        $adminRow = $result->fetchAssociative();
70
71
        if (empty($adminRow)) {
72
            return false;
73
        }
74
75
        return true;
76
    }
77
78
    public function getAdmin(): User
79
    {
80
        $admin = $this->entityManager
81
            ->getRepository(Admin::class)
0 ignored issues
show
Bug introduced by
The method getRepository() does not exist on null. ( Ignorable by Annotation )

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

81
            ->/** @scrutinizer ignore-call */ getRepository(Admin::class)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
82
            ->findOneBy([], ['id' => 'ASC'])
83
        ;
84
85
        return $admin->getUser();
86
    }
87
88
    /**
89
     * Speeds up SettingsCurrent creation.
90
     *
91
     * @param string $variable            The variable itself
92
     * @param string $subKey              The subkey
93
     * @param string $type                The type of setting (text, radio, select, etc)
94
     * @param string $category            The category (Platform, User, etc)
95
     * @param string $selectedValue       The default value
96
     * @param string $title               The setting title string name
97
     * @param string $comment             The setting comment string name
98
     * @param string $scope               The scope
99
     * @param string $subKeyText          Text if there is a subKey
100
     * @param int    $accessUrl           What URL it is for
101
     * @param bool   $accessUrlChangeable Whether it can be changed on each url
102
     * @param bool   $accessUrlLocked     Whether the setting for the current URL is
103
     *                                    locked to the current value
104
     * @param array  $options             Optional array in case of a radio-type field,
105
     *                                    to insert options
106
     */
107
    public function addSettingCurrent(
108
        $variable,
109
        $subKey,
110
        $type,
111
        $category,
112
        $selectedValue,
113
        $title,
114
        $comment,
115
        $scope = '',
116
        $subKeyText = '',
117
        $accessUrl = 1,
118
        $accessUrlChangeable = false,
119
        $accessUrlLocked = true,
120
        $options = []
121
    ): void {
122
        $accessUrl = $this->entityManager->find(AccessUrl::class, $accessUrl);
123
124
        $setting = new SettingsCurrent();
125
        $setting
126
            ->setVariable($variable)
127
            ->setSubkey($subKey)
128
            ->setType($type)
129
            ->setCategory($category)
130
            ->setSelectedValue($selectedValue)
131
            ->setTitle($title)
132
            ->setComment($comment)
133
            ->setScope($scope)
134
            ->setSubkeytext($subKeyText)
135
            ->setUrl($accessUrl)
136
            ->setAccessUrlChangeable((int) $accessUrlChangeable)
137
            ->setAccessUrlLocked((int) $accessUrlLocked)
138
        ;
139
140
        $this->entityManager->persist($setting);
141
142
        if (\count($options) > 0) {
143
            foreach ($options as $option) {
144
                if (empty($option['text'])) {
145
                    if ('true' === $option['value']) {
146
                        $option['text'] = 'Yes';
147
                    } else {
148
                        $option['text'] = 'No';
149
                    }
150
                }
151
152
                $settingOption = new SettingsOptions();
153
                $settingOption
154
                    ->setVariable($variable)
155
                    ->setValue($option['value'])
156
                    ->setDisplayText($option['text'])
157
                ;
158
159
                $this->entityManager->persist($settingOption);
160
            }
161
        }
162
        $this->entityManager->flush();
163
    }
164
165
    /**
166
     * @param string     $variable
167
     * @param null|mixed $configuration
168
     */
169
    public function getConfigurationValue($variable, $configuration = null)
170
    {
171
        global $_configuration;
172
173
        if (isset($configuration)) {
174
            $_configuration = $configuration;
175
        }
176
177
        if (isset($_configuration[$variable])) {
178
            return $_configuration[$variable];
179
        }
180
181
        return false;
182
    }
183
184
    public function getMailConfigurationValue(string $variable, array $configuration = []): mixed
185
    {
186
        global $platform_email;
187
188
        if ($configuration) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $configuration of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
189
            $platform_email = $configuration;
190
        }
191
192
        if (isset($platform_email[$variable])) {
193
            return $platform_email[$variable];
194
        }
195
196
        return false;
197
    }
198
199
    /**
200
     * Remove a setting completely.
201
     *
202
     * @param string $variable The setting variable name
203
     */
204
    public function removeSettingCurrent($variable): void
205
    {
206
        // to be implemented
207
    }
208
209
    public function addLegacyFileToResource(
210
        string $filePath,
211
        ResourceRepository $repo,
212
        AbstractResource $resource,
213
        $id,
214
        $fileName = '',
215
        $description = ''
216
    ): bool {
217
        $class = $resource::class;
218
        $documentPath = basename($filePath);
219
220
        if (is_dir($filePath) || (!is_dir($filePath) && !file_exists($filePath))) {
221
            $this->warnIf(true, "Cannot migrate {$class} #'.{$id}.' file not found: {$documentPath}");
222
223
            return false;
224
        }
225
226
        $mimeType = mime_content_type($filePath);
227
        if (empty($fileName)) {
228
            $fileName = basename($documentPath);
229
        }
230
        $file = new UploadedFile($filePath, $fileName, $mimeType, null, true);
231
        $repo->addFile($resource, $file, $description);
232
233
        return true;
234
    }
235
236
    public function fixItemProperty(
237
        $tool,
238
        ResourceRepository $repo,
239
        $course,
240
        $admin,
241
        ResourceInterface $resource,
242
        $parentResource,
243
        array $items = [],
244
        ?ResourceType $resourceType = null,
245
    ) {
246
        $courseId = $course->getId();
247
        $id = $resource->getResourceIdentifier();
248
249
        if (empty($items)) {
250
            $sql = "SELECT * FROM c_item_property
251
                    WHERE tool = '{$tool}' AND c_id = {$courseId} AND ref = {$id}";
252
            $result = $this->connection->executeQuery($sql);
253
            $items = $result->fetchAllAssociative();
254
        }
255
256
        // For some reason the resource doesn't have a c_item_property value.
257
        if (empty($items)) {
258
            return false;
259
        }
260
261
        $sessionRepo = $this->container->get(SessionRepository::class);
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

261
        /** @scrutinizer ignore-call */ 
262
        $sessionRepo = $this->container->get(SessionRepository::class);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
262
        $groupRepo = $this->container->get(CGroupRepository::class);
263
        $userRepo = $this->container->get(UserRepository::class);
264
265
        $resourceType = $resourceType ?: $repo->getResourceType();
266
267
        $resource->setParent($parentResource);
0 ignored issues
show
Bug introduced by
The method setParent() does not exist on Chamilo\CoreBundle\Entity\ResourceInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Chamilo\CoreBundle\Entity\ResourceInterface. ( Ignorable by Annotation )

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

267
        $resource->/** @scrutinizer ignore-call */ 
268
                   setParent($parentResource);
Loading history...
268
        $resourceNode = null;
269
        $userList = [];
270
        $groupList = [];
271
        $sessionList = [];
272
        foreach ($items as $item) {
273
            $visibility = (int) $item['visibility'];
274
            $userId = (int) $item['insert_user_id'];
275
            $sessionId = $item['session_id'] ?? 0;
276
            $groupId = $item['to_group_id'] ?? 0;
277
            if (empty($item['lastedit_date'])) {
278
                $lastUpdatedAt = new DateTime('now', new DateTimeZone('UTC'));
279
            } else {
280
                $lastUpdatedAt = new DateTime($item['lastedit_date'], new DateTimeZone('UTC'));
281
            }
282
            $newVisibility = ResourceLink::VISIBILITY_DRAFT;
283
284
            // Old 1.11.x visibility (item property) is based in this switch:
285
            switch ($visibility) {
286
                case 0:
287
                    $newVisibility = ResourceLink::VISIBILITY_DRAFT;
288
289
                    break;
290
291
                case 1:
292
                    $newVisibility = ResourceLink::VISIBILITY_PUBLISHED;
293
294
                    break;
295
            }
296
297
            // If c_item_property.insert_user_id doesn't exist we use the first admin id.
298
            $user = $admin;
299
300
            if ($userId) {
301
                if (isset($userList[$userId])) {
302
                    $user = $userList[$userId];
303
                } elseif ($userFound = $userRepo->find($userId)) {
304
                    $user = $userList[$userId] = $userFound;
305
                }
306
            }
307
308
            $session = null;
309
            if (!empty($sessionId)) {
310
                if (isset($sessionList[$sessionId])) {
311
                    $session = $sessionList[$sessionId];
312
                } else {
313
                    $session = $sessionList[$sessionId] = $sessionRepo->find($sessionId);
314
                }
315
            }
316
317
            $group = null;
318
            if (!empty($groupId)) {
319
                if (isset($groupList[$groupId])) {
320
                    $group = $groupList[$groupId];
321
                } else {
322
                    $group = $groupList[$groupId] = $groupRepo->find($groupId);
323
                }
324
            }
325
326
            if (null === $resourceNode) {
327
                $resourceNode = $repo->addResourceNode(
328
                    $resource,
329
                    $user,
330
                    $parentResource,
331
                    $resourceType
332
                );
333
                $this->entityManager->persist($resourceNode);
334
            }
335
            $resource->addCourseLink($course, $session, $group, $newVisibility);
0 ignored issues
show
Bug introduced by
The method addCourseLink() does not exist on Chamilo\CoreBundle\Entity\ResourceInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Chamilo\CoreBundle\Entity\User. Are you sure you never get one of those? ( Ignorable by Annotation )

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

335
            $resource->/** @scrutinizer ignore-call */ 
336
                       addCourseLink($course, $session, $group, $newVisibility);
Loading history...
336
337
            if (2 === $visibility) {
338
                $link = $resource->getResourceNode()->getResourceLinkByContext($course, $session, $group);
339
                $link->setDeletedAt($lastUpdatedAt);
340
            }
341
342
            $this->entityManager->persist($resource);
343
        }
344
345
        return true;
346
    }
347
348
    public function fileExists($filePath): bool
349
    {
350
        return file_exists($filePath) && !is_dir($filePath) && is_readable($filePath);
351
    }
352
353
    public function findCourse(int $id): ?Course
354
    {
355
        if (0 === $id) {
356
            return null;
357
        }
358
359
        return $this->entityManager->find(Course::class, $id);
360
    }
361
362
    public function findSession(int $id): ?Session
363
    {
364
        if (0 === $id) {
365
            return null;
366
        }
367
368
        return $this->entityManager->find(Session::class, $id);
369
    }
370
371
    public function getMailConfigurationValueFromFile(string $variable): ?string
372
    {
373
        global $platform_email;
374
375
        $rootPath = $this->container->get('kernel')->getProjectDir();
376
        $oldConfigPath = $this->getUpdateRootPath().'/app/config/mail.conf.php';
377
378
        $configFileLoaded = \in_array($oldConfigPath, get_included_files(), true);
379
380
        if (!$configFileLoaded) {
381
            include_once $oldConfigPath;
382
        }
383
384
        $settingValue = $this->getConfigurationValue($variable, $platform_email);
385
386
        if (\is_bool($settingValue)) {
387
            $selectedValue = var_export($settingValue, true);
388
        } else {
389
            $selectedValue = (string) $settingValue;
390
        }
391
392
        return $selectedValue;
393
    }
394
395
    private function generateFilePath(string $filename): string
396
    {
397
        $cacheDir = $this->container->get('kernel')->getCacheDir();
398
399
        return $cacheDir.'/migration_'.$filename;
400
    }
401
402
    protected function writeFile(string $filename, string $content): void
403
    {
404
        $fullFilename = $this->generateFilePath($filename);
405
406
        $fs = new Filesystem();
407
        $fs->dumpFile($fullFilename, $content);
408
    }
409
410
    protected function readFile(string $filename): string
411
    {
412
        $fullFilename = $this->generateFilePath($filename);
413
414
        if ($this->fileExists($fullFilename)) {
415
            return file_get_contents($fullFilename);
416
        }
417
418
        return '';
419
    }
420
421
    protected function removeFile(string $filename): void
422
    {
423
        $fullFilename = $this->generateFilePath($filename);
424
425
        $fs = new Filesystem();
426
        $fs->remove($fullFilename);
427
    }
428
429
    protected function getUpdateRootPath(): string
430
    {
431
        $updateRootPath = getenv('UPDATE_PATH');
432
433
        if (!empty($updateRootPath)) {
434
            error_log('getUpdateRootPath ::: '.$updateRootPath);
435
436
            return rtrim($updateRootPath, '/');
437
        }
438
439
        return $this->container->getParameter('kernel.project_dir');
440
    }
441
442
    protected static function pluginNameReplacements(): array
443
    {
444
        return [
445
            'bbb' => 'Bbb',
446
            'before_login' => 'BeforeLogin',
447
            'buycourses' => 'BuyCourses',
448
            'card_game' => 'CardGame',
449
            'check_extra_field_author_company' => 'CheckExtraFieldAuthorCompany',
450
            'cleandeletedfiles' => 'CleanDeletedFiles',
451
            'courseblock' => 'CourseBlock',
452
            'coursehomenotify' => 'CourseHomeNotify',
453
            'courselegal' => 'CourseLegal',
454
            'customcertificate' => 'CustomCertificate',
455
            'customfooter' => 'CustomFooter',
456
            'dashboard' => 'Dashboard',
457
            'dictionary' => 'Dictionary',
458
            'embedregistry' => 'EmbedRegistry',
459
            'exercise_signature' => 'ExerciseSignature',
460
            'ext_auth_chamilo_logout_button_behaviour' => 'ExtAuthChamiloLogoutButtonBehaviour',
461
            'externalnotificationconnect' => 'ExternalNotificationConnect',
462
            'extramenufromwebservice' => 'ExtraMenuFromWebservice',
463
            'google_maps' => 'GoogleMaps',
464
            'grading_electronic' => 'GradingElectronic',
465
            'h5pimport' => 'H5pImport',
466
            'hello_world' => 'HelloWorld',
467
            'ims_lti' => 'ImsLti',
468
            'justification' => 'Justification',
469
            'learning_calendar' => 'LearningCalendar',
470
            'lti_provider' => 'LtiProvider',
471
            'maintenancemode' => 'MaintenanceMode',
472
            'migrationmoodle' => 'MigrationMoodle',
473
            'nosearchindex' => 'NoSearchIndex',
474
            'notebookteacher' => 'NotebookTeacher',
475
            'onlyoffice' => 'Onlyoffice',
476
            'pausetraining' => 'PauseTraining',
477
            'pens' => 'Pens',
478
            'positioning' => 'Positioning',
479
            'questionoptionsevaluation' => 'QuestionOptionsEvaluation',
480
            'redirection' => 'Redirection',
481
            'resubscription' => 'Resubscription',
482
            'rss' => 'Rss',
483
            'search_course' => 'SearchCourse',
484
            'show_regions' => 'ShowRegions',
485
            'show_user_info' => 'ShowUserInfo',
486
            'static' => 'Static',
487
            'studentfollowup' => 'StudentFollowUp',
488
            'surveyexportcsv' => 'SurveyExportCsv',
489
            'surveyexporttxt' => 'SurveyExportTxt',
490
            'test2pdf' => 'Test2Pdf',
491
            'toplinks' => 'TopLinks',
492
            'tour' => 'Tour',
493
            'userremoteservice' => 'UserRemoteService',
494
            'xapi' => 'XApi',
495
            'zoom' => 'Zoom',
496
        ];
497
    }
498
}
499