Passed
Push — dependabot/npm_and_yarn/microm... ( e84ba6...f2f212 )
by
unknown
10:03
created

Version20231022124700::getDescription()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
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\Migrations\AbstractMigrationChamilo;
10
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
11
use Chamilo\CourseBundle\Repository\CDocumentRepository;
12
use Doctrine\DBAL\Schema\Schema;
13
use Exception;
14
15
final class Version20231022124700 extends AbstractMigrationChamilo
16
{
17
    public function getDescription(): string
18
    {
19
        return 'Replace old cidReq URL path with the new version and handle updates for HTML files.';
20
    }
21
22
    public function up(Schema $schema): void
23
    {
24
        $this->entityManager->clear();
0 ignored issues
show
Bug introduced by
The method clear() 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

24
        $this->entityManager->/** @scrutinizer ignore-call */ 
25
                              clear();

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...
25
26
        // Configuration for content updates in the database
27
        $updateConfigurations = [
28
            ['table' => 'c_tool_intro', 'field' => 'intro_text'],
29
            ['table' => 'c_course_description', 'field' => 'content'],
30
            ['table' => 'c_quiz', 'fields' => ['description', 'text_when_finished']],
31
            ['table' => 'c_quiz_question', 'fields' => ['description', 'question']],
32
            ['table' => 'c_quiz_answer', 'fields' => ['answer', 'comment']],
33
            ['table' => 'c_student_publication', 'field' => 'description'],
34
            ['table' => 'c_student_publication_comment', 'field' => 'comment'],
35
            ['table' => 'c_forum_post', 'field' => 'post_text'],
36
            ['table' => 'c_glossary', 'field' => 'description'],
37
            ['table' => 'c_survey', 'fields' => ['title', 'subtitle']],
38
            ['table' => 'c_survey_question', 'fields' => ['survey_question', 'survey_question_comment']],
39
            ['table' => 'c_survey_question_option', 'field' => 'option_text'],
40
        ];
41
42
        foreach ($updateConfigurations as $config) {
43
            $this->updateContent($config);
44
        }
45
46
        $this->updateHtmlFiles();
47
    }
48
49
    private function updateContent(array $config): void
50
    {
51
        $fields = isset($config['field']) ? [$config['field']] : $config['fields'] ?? [];
52
53
        foreach ($fields as $field) {
54
            $sql = "SELECT iid, {$field} FROM {$config['table']}";
55
            $result = $this->connection->executeQuery($sql);
56
            $items = $result->fetchAllAssociative();
57
58
            foreach ($items as $item) {
59
                $originalText = $item[$field];
60
                if (is_string($originalText) && trim($originalText) !== '') {
61
                    $updatedText = $this->replaceURLParametersInContent($originalText);
62
                    if ($originalText !== $updatedText) {
63
                        $updateSql = "UPDATE {$config['table']} SET {$field} = :newText WHERE iid = :id";
64
                        $this->connection->executeQuery($updateSql, ['newText' => $updatedText, 'id' => $item['iid']]);
65
                    }
66
                }
67
            }
68
        }
69
    }
70
71
    private function updateHtmlFiles(): void
72
    {
73
        $sql = "SELECT iid, resource_node_id FROM c_document WHERE filetype = 'file'";
74
        $result = $this->connection->executeQuery($sql);
75
        $items = $result->fetchAllAssociative();
76
77
        $documentRepo = $this->container->get(CDocumentRepository::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

77
        /** @scrutinizer ignore-call */ 
78
        $documentRepo = $this->container->get(CDocumentRepository::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...
78
        $resourceNodeRepo = $this->container->get(ResourceNodeRepository::class);
79
80
        foreach ($items as $item) {
81
            $document = $documentRepo->find($item['iid']);
82
            if (!$document) {
83
                continue;
84
            }
85
86
            $resourceNode = $document->getResourceNode();
87
            if (!$resourceNode || !$resourceNode->hasResourceFile()) {
88
                continue;
89
            }
90
91
            $resourceFile = $resourceNode->getResourceFiles()->first();
92
            if (!$resourceFile || $resourceFile->getMimeType() !== 'text/html') {
93
                continue;
94
            }
95
96
            try {
97
                $content = $resourceNodeRepo->getResourceNodeFileContent($resourceNode);
98
                if (is_string($content) && trim($content) !== '') {
99
                    $updatedContent = $this->replaceURLParametersInContent($content);
100
                    if ($content !== $updatedContent) {
101
                        $documentRepo->updateResourceFileContent($document, $updatedContent);
102
                        $documentRepo->update($document);
103
                    }
104
                }
105
            } catch (Exception $e) {
106
                // Error handling for specific documents
107
                error_log("Error processing file for document ID {$item['iid']}: " . $e->getMessage());
108
            }
109
        }
110
    }
111
112
    private function replaceURLParametersInContent(string $content): string
113
    {
114
        // Pattern to find and replace cidReq, id_session, and gidReq
115
        $pattern = '/((https?:\/\/[^\/\s]*|)\/[^?\s]+?)\?(.*?)(cidReq=([a-zA-Z0-9_]+))((?:&|&amp;)id_session=([0-9]+))?((?:&|&amp;)gidReq=([0-9]+))?(.*)/i';
116
117
        $newContent = @preg_replace_callback(
118
            $pattern,
119
            function ($matches) {
120
                $code = $matches[5];
121
122
                $courseId = null;
123
                $sql = 'SELECT id FROM course WHERE code = :code ORDER BY id DESC LIMIT 1';
124
                $stmt = $this->connection->executeQuery($sql, ['code' => $code]);
125
                $course = $stmt->fetch();
126
127
                if ($course) {
128
                    $courseId = $course['id'];
129
                }
130
131
                if (null === $courseId) {
132
                    return $matches[0]; // If the courseId is not found, return the original URL.
133
                }
134
135
                // Ensure sid and gid are always populated
136
                $sessionId = isset($matches[7]) && !empty($matches[7]) ? $matches[7] : '0';
137
                $groupId = isset($matches[9]) && !empty($matches[9]) ? $matches[9] : '0';
138
                $remainingParams = isset($matches[10]) ? $matches[10] : '';
139
140
                // Prepare new URL with updated parameters
141
                $newParams = "cid=$courseId&sid=$sessionId&gid=$groupId";
142
                $beforeCidReqParams = isset($matches[3]) ? $matches[3] : '';
143
144
                // Ensure other parameters are maintained
145
                if (!empty($remainingParams)) {
146
                    $newParams .= '&' . ltrim($remainingParams, '&amp;');
147
                }
148
149
                $finalUrl = $matches[1] . '?' . $beforeCidReqParams . $newParams;
150
151
                return str_replace('&amp;', '&', $finalUrl); // Replace any remaining &amp; with &
152
            },
153
            $content
154
        );
155
156
        if (PREG_NO_ERROR !== preg_last_error()) {
157
            error_log('Error encountered in preg_replace_callback: ' . preg_last_error());
158
        }
159
160
        return $newContent;
161
    }
162
}
163