Passed
Pull Request — master (#6017)
by
unknown
08:15
created

Version20250106151300::processHtmlFiles()   B

Complexity

Conditions 11
Paths 23

Size

Total Lines 58
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 32
c 1
b 0
f 0
nc 23
nop 0
dl 0
loc 58
rs 7.3166

How to fix   Long Method    Complexity   

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:

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\Node\CourseRepository;
11
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
12
use Chamilo\CourseBundle\Repository\CDocumentRepository;
13
use Doctrine\DBAL\Schema\Schema;
14
use Exception;
15
16
final class Version20250106151300 extends AbstractMigrationChamilo
17
{
18
    public function getDescription(): string
19
    {
20
        return 'Fix incorrect resource links in HTML files already migrated.';
21
    }
22
23
    public function up(Schema $schema): void
24
    {
25
        $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

25
        $this->entityManager->/** @scrutinizer ignore-call */ 
26
                              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...
26
        $this->processHtmlFiles();
27
    }
28
29
    private function processHtmlFiles(): void
30
    {
31
        // Select only HTML files that are linked to resource links
32
        $sql = "
33
            SELECT rl.resource_node_id, rl.c_id
34
            FROM resource_link rl
35
            JOIN c_document cd ON rl.resource_node_id = cd.resource_node_id
36
            WHERE cd.filetype = 'file'
37
        ";
38
        $result = $this->connection->executeQuery($sql);
39
        $items = $result->fetchAllAssociative();
40
41
        $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

41
        /** @scrutinizer ignore-call */ 
42
        $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...
42
        $resourceNodeRepo = $this->container->get(ResourceNodeRepository::class);
43
44
        foreach ($items as $item) {
45
            try {
46
                // Find the document by resource node ID
47
                $document = $documentRepo->findOneBy(['resourceNode' => $item['resource_node_id']]);
48
                if (!$document) {
49
                    error_log("Document not found for resource node ID {$item['resource_node_id']}");
50
                    continue;
51
                }
52
53
                // Retrieve the resource node
54
                $resourceNode = $document->getResourceNode();
55
                if (!$resourceNode || !$resourceNode->hasResourceFile()) {
56
                    error_log("Resource node or file not found for document ID {$document->getIid()}");
57
                    continue;
58
                }
59
60
                // Get the first resource file and validate MIME type
61
                $resourceFile = $resourceNode->getResourceFiles()->first();
62
                if (!$resourceFile || 'text/html' !== $resourceFile->getMimeType()) {
63
                    error_log("Invalid or missing HTML file for document ID {$document->getIid()}");
64
                    continue;
65
                }
66
67
                // Fetch content of the HTML file
68
                $content = $resourceNodeRepo->getResourceNodeFileContent($resourceNode);
69
                if (!is_string($content) || '' === trim($content)) {
70
                    error_log("Empty or invalid content for resource node ID {$item['resource_node_id']}");
71
                    continue;
72
                }
73
74
                // Update the content with fixed links
75
                $updatedContent = $this->fixHtmlLinks($content, $document->getIid(), $item['resource_node_id'], $item['c_id']);
76
                if ($content !== $updatedContent) {
77
                    // Save the updated content back
78
                    $documentRepo->updateResourceFileContent($document, $updatedContent);
79
                    $documentRepo->update($document);
80
                    error_log("Updated content for document ID {$document->getIid()}");
81
                } else {
82
                    error_log("No changes required for document ID {$document->getIid()}");
83
                }
84
            } catch (Exception $e) {
85
                // Log errors for debugging purposes
86
                error_log("Error processing document with resource node ID {$item['resource_node_id']}: " . $e->getMessage());
87
            }
88
        }
89
    }
90
91
    private function fixHtmlLinks(string $content, int $documentId, int $resourceNodeId, int $currentCourseId): string
92
    {
93
        // Define the pattern to find resource links
94
        $pattern = '/\/r\/document\/files\/([a-f0-9\-]+)\/view/';
95
96
        return preg_replace_callback($pattern, function ($matches) use ($documentId, $resourceNodeId, $currentCourseId) {
97
            $uuid = $matches[1];
98
99
            // Normalize UUID by removing dashes and converting to binary
100
            $cleanUuid = strtoupper(str_replace('-', '', $uuid));
101
            $uuidBinary = pack('H*', $cleanUuid);
102
103
            // Check the resource link for the given UUID and fetch title
104
                $query = '
105
                SELECT rl.resource_node_id, rl.c_id, rn.title
106
                FROM resource_link rl
107
                JOIN resource_node rn ON rl.resource_node_id = rn.id
108
                WHERE rn.uuid = UNHEX(:uuid)
109
            ';
110
            $resourceData = $this->connection->fetchAssociative($query, ['uuid' => $cleanUuid]);
111
112
            if ($resourceData && $resourceData['c_id'] === $currentCourseId) {
113
                // Log debugging information
114
                error_log("Document ID $documentId, Resource Node $resourceNodeId: Valid resource found for UUID $uuid in the correct course $currentCourseId");
115
116
                // Return the corrected link with original UUID format
117
                return "/r/document/files/$uuid/view";
118
            } elseif ($resourceData) {
119
                // If the course ID doesn't match, find the correct file in the current course
120
                error_log("Document ID $documentId, Resource Node $resourceNodeId: UUID $uuid does not belong to course $currentCourseId. Searching for the correct file...");
121
122
                $documentRepo = $this->container->get(CDocumentRepository::class);
123
                $courseRepo = $this->container->get(CourseRepository::class);
124
                $title = $resourceData['title'];
125
126
                // Load the Course object
127
                $course = $courseRepo->find($currentCourseId);
128
                if (!$course) {
129
                    error_log("Document ID $documentId, Resource Node $resourceNodeId: Course with ID $currentCourseId not found.");
130
                    return $matches[0]; // Return original link if course not found
131
                }
132
133
                // Search for a document in the current course by title
134
                $correctDocument = $documentRepo->findResourceByTitleInCourse($title, $course);
135
136
                if ($correctDocument) {
137
                    $newUrl = $documentRepo->getResourceFileUrl($correctDocument);
138
                    error_log("Document ID $documentId: Correct URL found: $newUrl");
139
140
                    return $newUrl;
141
                } else {
142
                    error_log("Document ID $documentId, Resource Node $resourceNodeId: No document found for title $title in course $currentCourseId.");
143
                }
144
            }
145
146
            // Log missing resource data
147
            error_log("Document ID $documentId, Resource Node $resourceNodeId: Resource link for UUID $uuid not found.");
148
            return $matches[0]; // Return original link if no match found
149
        }, $content);
150
    }
151
152
153
    public function down(Schema $schema): void
154
    {
155
        $this->abortIf(true, 'This migration cannot be rolled back.');
156
    }
157
}
158