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

ReplaceText::replaceText()   B

Complexity

Conditions 8
Paths 20

Size

Total Lines 57
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 8

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 57
ccs 34
cts 34
cp 1
rs 7.2648
cc 8
eloc 39
nc 20
nop 4
crap 8

How to fix   Long Method   

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
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