Completed
Push — master ( e218e8...7593ae )
by Iman
02:08
created

FileManipulator::applyToEachLine()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 2
dl 0
loc 31
rs 9.424
c 0
b 0
f 0
1
<?php
2
3
namespace Imanghafoori\LaravelMicroscope\Analyzers;
4
5
use Imanghafoori\LaravelMicroscope\Psr4Classes;
6
7
class FileManipulator
8
{
9
    public static function removeLine($file, $_line = null)
10
    {
11
        $lineChanger = function ($lineNum) use ($_line) {
12
            // Replace only the first occurrence in the file
13
            if ($lineNum == $_line) {
14
                return '';
15
            }
16
        };
17
18
        return self::applyToEachLine($file, $lineChanger);
19
    }
20
21
    public static function replaceFirst($absPath, $search, $replace = '', $_line = null)
22
    {
23
        $lineChanger = function ($lineNum, $line, $isReplaced) use ($search, $replace, $_line) {
24
            // Replace only the first occurrence in the file
25
            if (! $isReplaced && strstr($line, $search)) {
26
                if (! $_line || $lineNum == $_line) {
27
                    return \str_replace($search, $replace, $line);
28
                }
29
            }
30
        };
31
32
        return self::applyToEachLine($absPath, $lineChanger);
33
    }
34
35
    public static function insertAtLine($absPath, $newLine, $atLine)
36
    {
37
        $lineChanger = function ($lineNum, $currentLine) use ($newLine, $atLine) {
38
            if ($lineNum == $atLine) {
39
                return $newLine.PHP_EOL.$currentLine;
40
            }
41
42
            return $currentLine;
43
        };
44
45
        return self::applyToEachLine($absPath, $lineChanger);
46
    }
47
48
    public static function fixReference($absPath, $class, $lineNum, $prefix = '', $isUsed = false)
49
    {
50
        if (config('microscope.no_fix')) {
51
            return [false, []];
52
        }
53
54
        $class_list = Psr4Classes::classList();
55
        $cls = \explode('\\', $class);
56
        $className = array_pop($cls);
57
        $correct = $class_list[$className] ?? [];
58
59
        $contextClassNamespace = NamespaceCorrector::getNamespaceFromRelativePath($absPath);
60
61
        if (\count($correct) !== 1) {
62
            return [false, $correct];
63
        }
64
65
        // We just remove the wrong import if import is not needed.
66
        if (NamespaceCorrector::haveSameNamespace($contextClassNamespace, $correct[0])) {
67
            if ($isUsed) {
68
                return [self::removeLine($absPath, $lineNum), [' Deleted!']];
69
            }
70
71
            $correct[0] = trim(class_basename($correct[0]), '\\');
72
            $prefix = '';
73
        }
74
75
        $uses = ParseUseStatement::parseUseStatements(token_get_all(file_get_contents($absPath)))[1];
76
77
        // if there is any use statement at the top of the file
78
        if (count($uses) && ! isset($uses[$className])) {
79
            foreach ($uses as $use) {
80
                self::replaceFirst($absPath, $class, $className, $lineNum);
81
                $lineNum = $use[1];
82
                $fullClassPath = trim($prefix, '\\').$correct[0];
83
84
                return [self::insertAtLine($absPath, "use $fullClassPath;", $lineNum), $correct];
85
            }
86
        }
87
        $uses = ParseUseStatement::parseUseStatements(token_get_all(file_get_contents($absPath)))[1];
88
89
        if (isset($uses[$className])) {
90
            return [self::replaceFirst($absPath, $class, $className, $lineNum), $correct];
91
        }
92
93
        return [self::replaceFirst($absPath, $class, $prefix.$correct[0], $lineNum), $correct];
94
    }
95
96
    private static function applyToEachLine($absPath, $lineChanger)
97
    {
98
        $reading = fopen($absPath, 'r');
99
        $tmpFile = fopen($absPath.'._tmp', 'w');
100
101
        $isReplaced = false;
102
103
        $lineNum = 0;
104
        while (! feof($reading)) {
105
            $lineNum++;
106
            $line = fgets($reading);
107
108
            $newLine = $lineChanger($lineNum, $line, $isReplaced);
109
            if (is_string($newLine)) {
110
                $line = $newLine;
111
                $isReplaced = true;
112
            }
113
            // Copy the entire file to the end
114
            fwrite($tmpFile, $line);
115
        }
116
        fclose($reading);
117
        fclose($tmpFile);
118
        // Might as well not overwrite the file if we didn't replace anything
119
        if ($isReplaced) {
120
            rename($absPath.'._tmp', $absPath);
121
        } else {
122
            unlink($absPath.'._tmp');
123
        }
124
125
        return $isReplaced;
126
    }
127
}
128