Passed
Push — master ( f7af3b...d79566 )
by Angel Fernando Quiroz
16:52 queued 14s
created

AbstractMigrationChamilo::writeFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 6
rs 10
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\Session;
16
use Chamilo\CoreBundle\Entity\SettingsCurrent;
17
use Chamilo\CoreBundle\Entity\SettingsOptions;
18
use Chamilo\CoreBundle\Entity\User;
19
use Chamilo\CoreBundle\Repository\Node\UserRepository;
20
use Chamilo\CoreBundle\Repository\ResourceRepository;
21
use Chamilo\CoreBundle\Repository\SessionRepository;
22
use Chamilo\CourseBundle\Repository\CGroupRepository;
23
use DateTime;
24
use DateTimeZone;
25
use Doctrine\Migrations\AbstractMigration;
26
use Doctrine\ORM\EntityManagerInterface;
27
use Symfony\Component\DependencyInjection\ContainerInterface;
28
use Symfony\Component\Filesystem\Filesystem;
29
use Symfony\Component\HttpFoundation\File\UploadedFile;
30
31
abstract class AbstractMigrationChamilo extends AbstractMigration
32
{
33
    public const BATCH_SIZE = 20;
34
35
    protected ?EntityManagerInterface $entityManager = null;
36
    protected ?ContainerInterface $container = null;
37
38
    public function setEntityManager(EntityManagerInterface $entityManager): void
39
    {
40
        $this->entityManager = $entityManager;
41
    }
42
43
    public function setContainer(?ContainerInterface $container = null): void
44
    {
45
        $this->container = $container;
46
    }
47
48
    public function adminExist(): bool
49
    {
50
        $sql = 'SELECT user_id FROM admin WHERE user_id IN (SELECT id FROM user) ORDER BY id LIMIT 1';
51
        $result = $this->connection->executeQuery($sql);
52
        $adminRow = $result->fetchAssociative();
53
54
        if (empty($adminRow)) {
55
            return false;
56
        }
57
58
        return true;
59
    }
60
61
    public function getAdmin(): User
62
    {
63
        $admin = $this->entityManager
64
            ->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

64
            ->/** @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...
65
            ->findOneBy([], ['id' => 'ASC'])
66
        ;
67
68
        return $admin->getUser();
69
    }
70
71
    /**
72
     * Speeds up SettingsCurrent creation.
73
     *
74
     * @param string $variable            The variable itself
75
     * @param string $subKey              The subkey
76
     * @param string $type                The type of setting (text, radio, select, etc)
77
     * @param string $category            The category (Platform, User, etc)
78
     * @param string $selectedValue       The default value
79
     * @param string $title               The setting title string name
80
     * @param string $comment             The setting comment string name
81
     * @param string $scope               The scope
82
     * @param string $subKeyText          Text if there is a subKey
83
     * @param int    $accessUrl           What URL it is for
84
     * @param bool   $accessUrlChangeable Whether it can be changed on each url
85
     * @param bool   $accessUrlLocked     Whether the setting for the current URL is
86
     *                                    locked to the current value
87
     * @param array  $options             Optional array in case of a radio-type field,
88
     *                                    to insert options
89
     */
90
    public function addSettingCurrent(
91
        $variable,
92
        $subKey,
93
        $type,
94
        $category,
95
        $selectedValue,
96
        $title,
97
        $comment,
98
        $scope = '',
99
        $subKeyText = '',
100
        $accessUrl = 1,
101
        $accessUrlChangeable = false,
102
        $accessUrlLocked = true,
103
        $options = []
104
    ): void {
105
        $accessUrl = $this->entityManager->find(AccessUrl::class, $accessUrl);
106
107
        $setting = new SettingsCurrent();
108
        $setting
109
            ->setVariable($variable)
110
            ->setSubkey($subKey)
111
            ->setType($type)
112
            ->setCategory($category)
113
            ->setSelectedValue($selectedValue)
114
            ->setTitle($title)
115
            ->setComment($comment)
116
            ->setScope($scope)
117
            ->setSubkeytext($subKeyText)
118
            ->setUrl($accessUrl)
119
            ->setAccessUrlChangeable((int) $accessUrlChangeable)
120
            ->setAccessUrlLocked((int) $accessUrlLocked)
121
        ;
122
123
        $this->entityManager->persist($setting);
124
125
        if (\count($options) > 0) {
126
            foreach ($options as $option) {
127
                if (empty($option['text'])) {
128
                    if ('true' === $option['value']) {
129
                        $option['text'] = 'Yes';
130
                    } else {
131
                        $option['text'] = 'No';
132
                    }
133
                }
134
135
                $settingOption = new SettingsOptions();
136
                $settingOption
137
                    ->setVariable($variable)
138
                    ->setValue($option['value'])
139
                    ->setDisplayText($option['text'])
140
                ;
141
142
                $this->entityManager->persist($settingOption);
143
            }
144
        }
145
        $this->entityManager->flush();
146
    }
147
148
    /**
149
     * @param string     $variable
150
     * @param null|mixed $configuration
151
     */
152
    public function getConfigurationValue($variable, $configuration = null)
153
    {
154
        global $_configuration;
155
156
        if (isset($configuration)) {
157
            $_configuration = $configuration;
158
        }
159
160
        if (isset($_configuration[$variable])) {
161
            return $_configuration[$variable];
162
        }
163
164
        return false;
165
    }
166
167
    public function getMailConfigurationValue(string $variable, array $configuration = []): mixed
168
    {
169
        global $platform_email;
170
171
        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...
172
            $platform_email = $configuration;
173
        }
174
175
        if (isset($platform_email[$variable])) {
176
            return $platform_email[$variable];
177
        }
178
179
        return false;
180
    }
181
182
    /**
183
     * Remove a setting completely.
184
     *
185
     * @param string $variable The setting variable name
186
     */
187
    public function removeSettingCurrent($variable): void
188
    {
189
        // to be implemented
190
    }
191
192
    public function addLegacyFileToResource(
193
        string $filePath,
194
        ResourceRepository $repo,
195
        AbstractResource $resource,
196
        $id,
197
        $fileName = '',
198
        $description = ''
199
    ): bool {
200
        $class = $resource::class;
201
        $documentPath = basename($filePath);
202
203
        if (is_dir($filePath) || (!is_dir($filePath) && !file_exists($filePath))) {
204
            $this->warnIf(true, "Cannot migrate {$class} #'.{$id}.' file not found: {$documentPath}");
205
206
            return false;
207
        }
208
209
        $mimeType = mime_content_type($filePath);
210
        if (empty($fileName)) {
211
            $fileName = basename($documentPath);
212
        }
213
        $file = new UploadedFile($filePath, $fileName, $mimeType, null, true);
214
        $repo->addFile($resource, $file);
215
216
        return true;
217
    }
218
219
    public function fixItemProperty(
220
        $tool,
221
        ResourceRepository $repo,
222
        $course,
223
        $admin,
224
        ResourceInterface $resource,
225
        $parentResource,
226
        array $items = []
227
    ) {
228
        $courseId = $course->getId();
229
        $id = $resource->getResourceIdentifier();
230
231
        if (empty($items)) {
232
            $sql = "SELECT * FROM c_item_property
233
                    WHERE tool = '{$tool}' AND c_id = {$courseId} AND ref = {$id}";
234
            $result = $this->connection->executeQuery($sql);
235
            $items = $result->fetchAllAssociative();
236
        }
237
238
        // For some reason the resource doesn't have a c_item_property value.
239
        if (empty($items)) {
240
            return false;
241
        }
242
243
        $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

243
        /** @scrutinizer ignore-call */ 
244
        $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...
244
        $groupRepo = $this->container->get(CGroupRepository::class);
245
        $userRepo = $this->container->get(UserRepository::class);
246
247
        $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

247
        $resource->/** @scrutinizer ignore-call */ 
248
                   setParent($parentResource);
Loading history...
248
        $resourceNode = null;
249
        $userList = [];
250
        $groupList = [];
251
        $sessionList = [];
252
        foreach ($items as $item) {
253
            $visibility = (int) $item['visibility'];
254
            $userId = (int) $item['insert_user_id'];
255
            $sessionId = $item['session_id'] ?? 0;
256
            $groupId = $item['to_group_id'] ?? 0;
257
            if (empty($item['lastedit_date'])) {
258
                $lastUpdatedAt = new DateTime('now', new DateTimeZone('UTC'));
259
            } else {
260
                $lastUpdatedAt = new DateTime($item['lastedit_date'], new DateTimeZone('UTC'));
261
            }
262
            $newVisibility = ResourceLink::VISIBILITY_DRAFT;
263
264
            // Old 1.11.x visibility (item property) is based in this switch:
265
            switch ($visibility) {
266
                case 0:
267
                    $newVisibility = ResourceLink::VISIBILITY_DRAFT;
268
269
                    break;
270
271
                case 1:
272
                    $newVisibility = ResourceLink::VISIBILITY_PUBLISHED;
273
274
                    break;
275
            }
276
277
            // If c_item_property.insert_user_id doesn't exist we use the first admin id.
278
            $user = null;
279
            if (isset($userList[$userId])) {
280
                $user = $userList[$userId];
281
            } else {
282
                if (!empty($userId)) {
283
                    $userFound = $userRepo->find($userId);
284
                    if ($userFound) {
285
                        $user = $userList[$userId] = $userRepo->find($userId);
286
                    }
287
                }
288
            }
289
290
            if (null === $user) {
291
                $user = $admin;
292
            }
293
294
            $session = null;
295
            if (!empty($sessionId)) {
296
                if (isset($sessionList[$sessionId])) {
297
                    $session = $sessionList[$sessionId];
298
                } else {
299
                    $session = $sessionList[$sessionId] = $sessionRepo->find($sessionId);
300
                }
301
            }
302
303
            $group = null;
304
            if (!empty($groupId)) {
305
                if (isset($groupList[$groupId])) {
306
                    $group = $groupList[$groupId];
307
                } else {
308
                    $group = $groupList[$groupId] = $groupRepo->find($groupId);
309
                }
310
            }
311
312
            if (null === $resourceNode) {
313
                $resourceNode = $repo->addResourceNode($resource, $user, $parentResource);
314
                $this->entityManager->persist($resourceNode);
315
            }
316
            $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

316
            $resource->/** @scrutinizer ignore-call */ 
317
                       addCourseLink($course, $session, $group, $newVisibility);
Loading history...
317
318
            if (2 === $visibility) {
319
                $link = $resource->getResourceNode()->getResourceLinkByContext($course, $session, $group);
320
                $link->setDeletedAt($lastUpdatedAt);
321
            }
322
323
            $this->entityManager->persist($resource);
324
        }
325
326
        return true;
327
    }
328
329
    public function fileExists($filePath): bool
330
    {
331
        return file_exists($filePath) && !is_dir($filePath) && is_readable($filePath);
332
    }
333
334
    public function findCourse(int $id): ?Course
335
    {
336
        if (0 === $id) {
337
            return null;
338
        }
339
340
        return $this->entityManager->find(Course::class, $id);
341
    }
342
343
    public function findSession(int $id): ?Session
344
    {
345
        if (0 === $id) {
346
            return null;
347
        }
348
349
        return $this->entityManager->find(Session::class, $id);
350
    }
351
352
    public function getMailConfigurationValueFromFile(string $variable): ?string
353
    {
354
        global $platform_email;
355
356
        $rootPath = $this->container->get('kernel')->getProjectDir();
357
        $oldConfigPath = $rootPath.'/app/config/mail.conf.php';
358
359
        $configFileLoaded = \in_array($oldConfigPath, get_included_files(), true);
360
361
        if (!$configFileLoaded) {
362
            include_once $oldConfigPath;
363
        }
364
365
        $settingValue = $this->getConfigurationValue($variable, $platform_email);
366
367
        if (\is_bool($settingValue)) {
368
            $selectedValue = var_export($settingValue, true);
369
        } else {
370
            $selectedValue = (string) $settingValue;
371
        }
372
373
        return $selectedValue;
374
    }
375
376
    private function generateFilePath(string $filename): string
377
    {
378
        $cacheDir = $this->container->get('kernel')->getCacheDir();
379
380
        return $cacheDir.'/migration_'.$filename;
381
    }
382
383
    protected function writeFile(string $filename, string $content): void
384
    {
385
        $fullFilename = $this->generateFilePath($filename);
386
387
        $fs = new Filesystem();
388
        $fs->dumpFile($fullFilename, $content);
389
    }
390
391
    protected function readFile(string $filename): string
392
    {
393
        $fullFilename = $this->generateFilePath($filename);
394
395
        return file_get_contents($fullFilename);
396
    }
397
398
    protected function removeFile(string $filename): void
399
    {
400
        $fullFilename = $this->generateFilePath($filename);
401
402
        $fs = new Filesystem();
403
        $fs->remove($fullFilename);
404
    }
405
}
406