Completed
Push — master ( 6695d4...9bc3b7 )
by Harry
04:41
created

ReplaceText::modify()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.4285
cc 2
eloc 9
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Graze\DataFile\Modify;
4
5
use Graze\DataFile\Helper\GetOptionTrait;
6
use Graze\DataFile\Helper\OptionalLoggerTrait;
7
use Graze\DataFile\Helper\Process\ProcessFactoryAwareInterface;
8
use Graze\DataFile\Helper\Process\ProcessTrait;
9
use Graze\DataFile\Node\FileNodeInterface;
10
use Graze\DataFile\Node\LocalFile;
11
use InvalidArgumentException;
12
use Psr\Log\LoggerAwareInterface;
13
use Psr\Log\LogLevel;
14
use Symfony\Component\Process\Exception\ProcessFailedException;
15
16
class ReplaceText implements FileModifierInterface, LoggerAwareInterface, ProcessFactoryAwareInterface
17
{
18
    use OptionalLoggerTrait;
19
    use FileProcessTrait;
20
    use GetOptionTrait;
21
22
    /**
23
     * Can this file be modified by this modifier
24
     *
25
     * @param FileNodeInterface $file
26
     *
27
     * @return bool
28
     */
29 1
    public function canModify(FileNodeInterface $file)
30
    {
31
        return (
32 1
            ($file instanceof localFile) &&
33 1
            ($file->exists())
34
        );
35
    }
36
37
    /**
38
     * Modify the file
39
     *
40
     * @param FileNodeInterface $file
41
     * @param array             $options List of options:
42
     *                                   -fromText <string|array> Text to be replace
43
     *                                   -toText <string|array> Text to replace
44
     *                                   -postifx <string> (Default: replace) Set this to blank to replace inline
45
     *                                   -keepOldFile <bool> (Default: true)
46
     *
47
     * @return FileNodeInterface
48
     */
49 5
    public function modify(FileNodeInterface $file, array $options = [])
50
    {
51 5
        $this->options = $options;
52 5
        $fromText = $this->requireOption('fromText');
53 4
        $toText = $this->requireOption('toText');
54
55 3
        unset($options['fromText']);
56 3
        unset($options['toText']);
57
58 3
        if (!($file instanceof LocalFile)) {
59 1
            throw new InvalidArgumentException("Supplied: $file is not a LocalFile");
60
        }
61
62 2
        return $this->replaceText($file, $fromText, $toText, $options);
63
    }
64
65
    /**
66
     * @extend Graze\DataFile\Node\File\LocalFile
67
     *
68
     * @param LocalFile       $file
69
     * @param string|string[] $fromText
70
     * @param string|string[] $toText
71
     * @param array           $options List of options:
72
     *                                 -postfix <string> (Default: replace) Set this to blank to replace inline
73
     *                                 -keepOldFile <bool> (Default: true)
74
     *
75
     * @throws InvalidArgumentException
76
     * @throws ProcessFailedException
77
     * @return LocalFile
78
     */
79 11
    public function replaceText(LocalFile $file, $fromText, $toText, array $options = [])
80
    {
81 11
        $this->options = $options;
82 11
        $postfix = $this->getOption('postfix', 'replace');
83 11
        if (strlen($postfix) > 0) {
84 10
            $postfix = '-' . $postfix;
85
        }
86
87 11
        $pathInfo = pathinfo($file->getPath());
88 11
        $outputFileName = $pathInfo['filename'] . $postfix;
89 11
        if (isset($pathInfo['extension'])) {
90 10
            $outputFileName .= '.' . $pathInfo['extension'];
91
        }
92 11
        $outputFilePath = $pathInfo['dirname'] . '/' . $outputFileName;
93
94 11
        $output = $file->getClone()
95 11
                       ->setPath($outputFilePath);
96
97 11
        if (is_array($fromText)) {
98 3
            if (is_array($toText) &&
99 3
                count($fromText) == count($toText)
100
            ) {
101 2
                $sedStrings = [];
102 2
                for ($i = 0; $i < count($fromText); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
103 2
                    $sedStrings[] = $this->getReplacementCommand($fromText[$i], $toText[$i]);
104
                }
105 2
                $replacementString = implode(';', $sedStrings);
106
            } else {
107 3
                throw new InvalidArgumentException("Number of items in 'fromText' (" . count($fromText) . ") is different to 'toText' (" . count($toText) . ")");
108
            }
109
        } else {
110 8
            $replacementString = $this->getReplacementCommand($fromText, $toText);
111
        }
112
113 10
        if ($file->getFilename() == $output->getFilename()) {
114 1
            $cmd = sprintf(
115 1
                "perl -p -i -e '%s' %s",
116
                $replacementString,
117 1
                $file->getPath()
118
            );
119
        } else {
120 9
            $cmd = sprintf(
121 9
                "perl -p -e '%s' %s > %s",
122
                $replacementString,
123 9
                $file->getPath(),
124 9
                $output->getPath()
125
            );
126
        }
127
128 10
        $this->log(LogLevel::INFO, "Replacing the text: {from} to {to} in file: '{file}'", [
129 10
            'from' => json_encode($fromText),
130 10
            'to'   => json_encode($toText),
131 10
            'file' => $file,
132
        ]);
133
134 10
        return $this->processFile($file, $output, $cmd, $this->getOption('keepOldFile', true));
135
    }
136
137
    /**
138
     * Get the string replacement command for a single item
139
     *
140
     * @param $fromText
141
     * @param $toText
142
     *
143
     * @return string
144
     */
145 10
    private function getReplacementCommand($fromText, $toText)
146
    {
147 10
        return sprintf(
148 10
            's/%s/%s/g',
149 10
            str_replace(["'", ";", "\\"], ["\\'", "\\;", "\\\\"], $fromText),
150 10
            str_replace(["'", ";", "\\"], ["\\'", "\\;", "\\\\"], $toText)
151
        );
152
    }
153
}
154