Completed
Push — master ( 7062b3...1c7f62 )
by
unknown
01:56 queued 39s
created

Version20201216110722   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 79
c 0
b 0
f 0
dl 0
loc 135
rs 10
wmc 13

2 Methods

Rating   Name   Duplication   Size   Complexity  
A getDescription() 0 3 1
C up() 0 128 12
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
8
9
use Chamilo\CoreBundle\Command\DoctrineMigrationsMigrateCommandDecorator;
10
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
11
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
12
use Chamilo\CourseBundle\Entity\CAttendance;
13
use Chamilo\CourseBundle\Repository\CAttendanceRepository;
14
use Database;
15
use Doctrine\DBAL\Schema\Schema;
16
17
final class Version20201216110722 extends AbstractMigrationChamilo
18
{
19
    public function getDescription(): string
20
    {
21
        return 'Migrate c_attendance';
22
    }
23
24
    public function up(Schema $schema): void
25
    {
26
        $attendanceRepo = $this->container->get(CAttendanceRepository::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

26
        /** @scrutinizer ignore-call */ 
27
        $attendanceRepo = $this->container->get(CAttendanceRepository::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...
27
        $courseRepo = $this->container->get(CourseRepository::class);
28
        $attendanceResourceType = $attendanceRepo->getResourceType();
29
        $admin = $this->getAdmin();
30
31
        $skipAttendances = (bool) getenv(DoctrineMigrationsMigrateCommandDecorator::SKIP_ATTENDANCES_FLAG);
32
33
        // IDs linked to gradebook (type=7) -> normalized to attendance.iid
34
        $gradebookIds = [];
35
        if ($skipAttendances) {
36
            $ids = $this->connection->fetchFirstColumn(
37
                'SELECT DISTINCT a.iid
38
         FROM gradebook_link gl
39
         INNER JOIN c_attendance a ON (a.iid = gl.ref_id OR a.id = gl.ref_id)
40
         WHERE gl.type = 7'
41
            );
42
43
            $ids = array_map('intval', $ids);
44
            $gradebookIds = array_fill_keys($ids, true);
45
        }
46
47
        /*
48
         * Title/slug performance hack:
49
         * Backup titles, temporarily make titles unique, migrate, then restore titles.
50
         * We do it only for the attendances that WILL be migrated when skip is enabled.
51
         */
52
        if ($skipAttendances) {
53
            $attendancesBackup = $this->connection->fetchAllAssociative(
54
                'SELECT a.iid, a.title
55
                 FROM c_attendance a
56
                 WHERE a.iid IN (SELECT ref_id FROM gradebook_link WHERE type = 7)'
57
            );
58
59
            $this->connection->executeStatement(
60
                "UPDATE c_attendance
61
                 SET title = CONCAT(title, '-', iid)
62
                 WHERE iid IN (SELECT ref_id FROM gradebook_link WHERE type = 7)"
63
            );
64
        } else {
65
            $attendancesBackup = $this->connection->fetchAllAssociative('SELECT iid, title FROM c_attendance');
66
            $this->connection->executeStatement("UPDATE c_attendance SET title = CONCAT(title, '-', iid)");
67
        }
68
69
        /**
70
         * Instead of iterating ALL courses and relying on c_attendance.c_id,
71
         * we iterate only course ids that have attendances through c_item_property.
72
         */
73
        $courseIds = $this->connection->fetchFirstColumn(
74
            "SELECT DISTINCT c_id
75
             FROM c_item_property
76
             WHERE tool = 'attendance'
77
             ORDER BY c_id"
78
        );
79
80
        foreach ($courseIds as $courseId) {
81
            $courseId = (int) $courseId;
82
            $course = $courseRepo->find($courseId);
83
84
            if (null === $course) {
85
                $this->write(sprintf('Course %s not found - skipping attendances migration', $courseId));
86
                continue;
87
            }
88
89
            // Fetch attendance IDs belonging to this course via c_item_property
90
            $rows = $this->connection->fetchAllAssociative(
91
                "SELECT a.iid
92
                 FROM c_attendance a
93
                 INNER JOIN c_item_property ip
94
                    ON ip.tool = 'attendance'
95
                   AND ip.ref = a.iid
96
                   AND ip.c_id = :courseId
97
                 ORDER BY a.iid",
98
                ['courseId' => $courseId]
99
            );
100
101
            foreach ($rows as $row) {
102
                $id = (int) $row['iid'];
103
104
                // If skip enabled, we only migrate gradebook-linked attendances
105
                if ($skipAttendances && !isset($gradebookIds[$id])) {
106
                    $this->write(sprintf('Attendance %s is not linked to gradebook - skipping', $id));
107
                    continue;
108
                }
109
110
                /** @var CAttendance|null $resource */
111
                $resource = $attendanceRepo->find($id);
112
                if (null === $resource || $resource->hasResourceNode()) {
113
                    continue;
114
                }
115
116
                $ok = $this->fixItemProperty(
117
                    'attendance',
118
                    $attendanceRepo,
119
                    $course,
120
                    $admin,
121
                    $resource,
122
                    $course,
123
                    [],
124
                    $attendanceResourceType
125
                );
126
127
                if (false === $ok) {
128
                    continue;
129
                }
130
131
                $this->entityManager->persist($resource);
0 ignored issues
show
Bug introduced by
The method persist() 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

131
                $this->entityManager->/** @scrutinizer ignore-call */ 
132
                                      persist($resource);

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...
132
                $this->entityManager->flush();
133
            }
134
        }
135
136
        // Restore attendance title and resource_node title
137
        $db = new Database();
138
        $db->setManager($this->entityManager);
139
140
        foreach ($attendancesBackup as $attendance) {
141
            $iid = (int) $attendance['iid'];
142
            $titleForDatabase = $db->escape_string((string) $attendance['title']);
143
144
            $this->connection->executeStatement(
145
                "UPDATE c_attendance SET title = '{$titleForDatabase}' WHERE iid = {$iid}"
146
            );
147
148
            $this->connection->executeStatement(
149
                "UPDATE resource_node
150
                 SET title = '{$titleForDatabase}'
151
                 WHERE id IN (SELECT resource_node_id FROM c_attendance WHERE iid = {$iid})"
152
            );
153
        }
154
    }
155
}
156