Passed
Pull Request — master (#5310)
by Yannick
39:37 queued 29:50
created

AbstractMigrationChamilo::addSettingCurrent()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 56
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 30
c 0
b 0
f 0
nc 2
nop 13
dl 0
loc 56
rs 9.1288

How to fix   Long Method    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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