Passed
Pull Request — master (#5310)
by Yannick
39:37 queued 29:50
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\EntityManager;
27
use ReflectionClass;
28
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
29
use Doctrine\ORM\EntityManagerInterface;
30
use Symfony\Component\DependencyInjection\ContainerInterface;
31
use Symfony\Component\Filesystem\Filesystem;
32
use Symfony\Component\HttpFoundation\File\UploadedFile;
33
34
abstract class AbstractMigrationChamilo extends AbstractMigration
35
{
36
    public const BATCH_SIZE = 20;
37
38
    protected ?EntityManagerInterface $entityManager = null;
39
    protected ?ContainerInterface $container = null;
40
41
    public function setEntityManager(EntityManagerInterface $entityManager): void
42
    {
43
        $this->entityManager = $entityManager;
44
    }
45
46
    public function setContainer(?ContainerInterface $container = null): void
47
    {
48
        $this->container = $container;
49
    }
50
51
    public function adminExist(): bool
52
    {
53
        $sql = 'SELECT user_id FROM admin WHERE user_id IN (SELECT id FROM user) ORDER BY id LIMIT 1';
54
        $result = $this->connection->executeQuery($sql);
55
        $adminRow = $result->fetchAssociative();
56
57
        if (empty($adminRow)) {
58
            return false;
59
        }
60
61
        return true;
62
    }
63
64
    public function getAdmin(): User
65
    {
66
        $admin = $this->entityManager
67
            ->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

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

231
        /** @scrutinizer ignore-call */ 
232
        $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...
232
        $groupRepo = $this->container->get(CGroupRepository::class);
233
        $userRepo = $this->container->get(UserRepository::class);
234
235
        $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

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

304
            $resource->/** @scrutinizer ignore-call */ 
305
                       addCourseLink($course, $session, $group, $newVisibility);
Loading history...
305
306
            if (2 === $visibility) {
307
                $link = $resource->getResourceNode()->getResourceLinkByContext($course, $session, $group);
308
                $link->setDeletedAt($lastUpdatedAt);
309
            }
310
311
            $this->entityManager->persist($resource);
312
        }
313
314
        return true;
315
    }
316
317
    public function fileExists($filePath): bool
318
    {
319
        return file_exists($filePath) && !is_dir($filePath) && is_readable($filePath);
320
    }
321
322
    public function findCourse(int $id): ?Course
323
    {
324
        if (0 === $id) {
325
            return null;
326
        }
327
328
        return $this->entityManager->find(Course::class, $id);
329
    }
330
331
    public function findSession(int $id): ?Session
332
    {
333
        if (0 === $id) {
334
            return null;
335
        }
336
337
        return $this->entityManager->find(Session::class, $id);
338
    }
339
340
    private function generateFilePath(string $filename): string
341
    {
342
        $cacheDir = $this->getContainer()->get('kernel')->getCacheDir();
343
344
        return $cacheDir.'/migration_'.$filename;
345
    }
346
347
    protected function writeFile(string $filename, string $content): void
348
    {
349
        $fullFilename = $this->generateFilePath($filename);
350
351
        $fs = new Filesystem();
352
        $fs->dumpFile($fullFilename, $content);
353
    }
354
355
    protected function readFile(string $filename): string
356
    {
357
        $fullFilename = $this->generateFilePath($filename);
358
359
        return file_get_contents($fullFilename);
360
    }
361
362
    protected function removeFile(string $filename): string
363
    {
364
        $fullFilename = $this->generateFilePath($filename);
365
366
        $fs = new Filesystem();
367
        $fs->remove($fullFilename);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
368
    }
369
}
370