Passed
Pull Request — master (#6936)
by
unknown
09:00
created

Version20251024173200::processHtmlDocuments()   C

Complexity

Conditions 13
Paths 21

Size

Total Lines 59
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 33
c 1
b 0
f 0
nc 21
nop 4
dl 0
loc 59
rs 6.6166

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\ResourceNodeRepository;
11
use Chamilo\CourseBundle\Repository\CDocumentRepository;
12
use Doctrine\DBAL\Schema\Schema;
13
use Exception;
14
15
final class Version20251024173200 extends AbstractMigrationChamilo
16
{
17
    /** Enable this to log changes without writing them to the database. */
18
    private const DRY_RUN = false;
19
20
    public function getDescription(): string
21
    {
22
        return 'Rewrite legacy /main/img/* by /img/* in HTML documents (filetype=certificate).';
23
    }
24
25
    public function up(Schema $schema): void
26
    {
27
        $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

27
        $this->entityManager->/** @scrutinizer ignore-call */ 
28
                              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...
28
29
        /** @var CDocumentRepository $documentRepo */
30
        $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

30
        /** @scrutinizer ignore-call */ 
31
        $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...
31
        /** @var ResourceNodeRepository $resourceNodeRepo */
32
        $resourceNodeRepo = $this->container->get(ResourceNodeRepository::class);
33
34
        // Course certificates saved as documents
35
        $certSql   = "SELECT iid FROM c_document WHERE filetype = 'certificate'";
36
        $certItems = $this->connection->executeQuery($certSql)->fetchAllAssociative();
37
        $this->processHtmlDocuments($certItems, $documentRepo, $resourceNodeRepo, 'certificate');
38
    }
39
40
    /**
41
     * Iterate over candidate documents and update only those that are text/html,
42
     * replacing legacy asset paths in their HTML content.
43
     */
44
    private function processHtmlDocuments(
45
        array $items,
46
        CDocumentRepository $documentRepo,
47
        ResourceNodeRepository $resourceNodeRepo,
48
        string $context
49
    ): void {
50
        $total     = \count($items);
51
        $processed = 0;
52
        $changed   = 0;
53
54
        foreach ($items as $item) {
55
            $processed++;
56
            $iid = (int) $item['iid'];
57
58
            try {
59
                $document = $documentRepo->find($iid);
60
                if (!$document) {
61
                    continue;
62
                }
63
64
                $resourceNode = $document->getResourceNode();
65
                if (!$resourceNode || !$resourceNode->hasResourceFile()) {
66
                    continue;
67
                }
68
69
                $resourceFile = $resourceNode->getResourceFiles()->first();
70
                if (!$resourceFile) {
71
                    continue;
72
                }
73
74
                // Update HTML only (skip binaries and non-HTML text)
75
                $mime = $resourceFile->getMimeType();
76
                if (!\is_string($mime) || stripos($mime, 'text/html') === false) {
77
                    continue;
78
                }
79
80
                $content = $resourceNodeRepo->getResourceNodeFileContent($resourceNode);
81
                if (!\is_string($content) || trim($content) === '') {
82
                    continue;
83
                }
84
85
                $updatedContent = $this->normalizeLegacyImgPaths($content);
86
87
                if ($updatedContent !== $content) {
88
                    $changed++;
89
                    if (!self::DRY_RUN) {
90
                        $documentRepo->updateResourceFileContent($document, $updatedContent);
91
                        $documentRepo->update($document);
92
                    } else {
93
                        error_log("[MIGRATION][DRY_RUN][{$context}] Would update HTML for document iid={$iid}");
94
                    }
95
                }
96
            } catch (Exception $e) {
97
                error_log("[MIGRATION][{$context}] Error processing iid={$iid}: ".$e->getMessage());
98
                // Continue with the next item
99
            }
100
        }
101
102
        error_log(sprintf('[MIGRATION][%s] Processed=%d, Updated=%d (Total candidates=%d)', $context, $processed, $changed, $total));
103
    }
104
105
    /**
106
     * Normalize legacy C1 asset paths to C2:
107
     *  - /main/img/...  -> /img/...
108
     * Covers HTML attributes (src, href) and CSS url() references.
109
     */
110
    private function normalizeLegacyImgPaths(string $html): string
111
    {
112
        // Targeted replacements first, to cover common attribute and CSS forms
113
        $map = [
114
            'src="/main/img/'   => 'src="/img/',
115
            "src='/main/img/"   => "src='/img/",
116
            'href="/main/img/'  => 'href="/img/',
117
            "href='/main/img/"  => "href='/img/",
118
            'url(/main/img/'    => 'url(/img/',
119
            'url("/main/img/'   => 'url("/img/',
120
            "url('/main/img/"   => "url('/img/",
121
        ];
122
123
        $updated = strtr($html, $map);
124
125
        // Fallback replacement to catch any remaining occurrences (absolute local paths only)
126
        $updated = str_replace('/main/img/', '/img/', $updated);
127
128
        return $updated;
129
    }
130
131
    public function down(Schema $schema): void {}
132
}
133