Completed
Pull Request — master (#4)
by Harry
04:07
created

ReplaceText::replaceText()   C

Complexity

Conditions 8
Paths 6

Size

Total Lines 47
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 8

Importance

Changes 6
Bugs 2 Features 0
Metric Value
c 6
b 2
f 0
dl 0
loc 47
ccs 36
cts 36
cp 1
rs 5.7377
cc 8
eloc 33
nc 6
nop 4
crap 8
1
<?php
2
/**
3
 * This file is part of graze/data-file
4
 *
5
 * Copyright (c) 2016 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/data-file/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/data-file
12
 */
13
14
namespace Graze\DataFile\Modify;
15
16
use Graze\DataFile\Helper\GetOptionTrait;
17
use Graze\DataFile\Helper\OptionalLoggerTrait;
18
use Graze\DataFile\Helper\Process\ProcessFactoryAwareInterface;
19
use Graze\DataFile\Node\FileNodeInterface;
20
use Graze\DataFile\Node\LocalFile;
21
use InvalidArgumentException;
22
use Psr\Log\LoggerAwareInterface;
23
use Psr\Log\LogLevel;
24
use Symfony\Component\Process\Exception\ProcessFailedException;
25
26
class ReplaceText implements FileModifierInterface, LoggerAwareInterface, ProcessFactoryAwareInterface
27
{
28
    use OptionalLoggerTrait;
29
    use FileProcessTrait;
30
    use GetOptionTrait;
31
32
    /**
33
     * Can this file be modified by this modifier
34
     *
35
     * @param FileNodeInterface $file
36
     *
37
     * @return bool
38
     */
39 1
    public function canModify(FileNodeInterface $file)
40
    {
41
        return (
42 1
            ($file instanceof localFile) &&
43 1
            ($file->exists())
44 1
        );
45
    }
46
47
    /**
48
     * Modify the file
49
     *
50
     * @param FileNodeInterface $file
51
     * @param array             $options List of options:
52
     *                                   -fromText <string|array> Text to be replace
53
     *                                   -toText <string|array> Text to replace
54
     *                                   -postifx <string> (Default: replace) Set this to blank to replace inline
55
     *                                   -keepOldFile <bool> (Default: true)
56
     *
57
     * @return FileNodeInterface
58
     */
59 5
    public function modify(FileNodeInterface $file, array $options = [])
60
    {
61 5
        $this->options = $options;
62 5
        $fromText = $this->requireOption('fromText');
63 4
        $toText = $this->requireOption('toText');
64
65 3
        unset($options['fromText']);
66 3
        unset($options['toText']);
67
68 3
        if (!($file instanceof LocalFile)) {
69 1
            throw new InvalidArgumentException("Supplied: $file is not a LocalFile");
70
        }
71
72 2
        return $this->replaceText($file, $fromText, $toText, $options);
73
    }
74
75
    /**
76
     * @extend Graze\DataFile\Node\File\LocalFile
77
     *
78
     * @param LocalFile       $file
79
     * @param string|string[] $fromText
80
     * @param string|string[] $toText
81
     * @param array           $options List of options:
82
     *                                 -postfix <string> (Default: replace) Set this to blank to replace inline
83
     *                                 -keepOldFile <bool> (Default: true)
84
     *
85
     * @throws InvalidArgumentException
86
     * @throws ProcessFailedException
87
     * @return LocalFile
88
     */
89 12
    public function replaceText(LocalFile $file, $fromText, $toText, array $options = [])
90
    {
91 12
        $this->options = $options;
92
93 12
        $postfix = $this->getOption('postfix', 'replace');
94 12
        $output = $this->getTargetFile($file, $postfix);
95
96 12
        if (is_array($fromText) && is_array($toText)) {
97 3
            if (count($fromText) == count($toText)) {
98 2
                $sedStrings = [];
99 2
                $fromSize = count($fromText);
100 2
                for ($i = 0; $i < $fromSize; $i++) {
101 2
                    $sedStrings[] = $this->getReplacementCommand($fromText[$i], $toText[$i]);
102 2
                }
103 2
                $replacementString = implode(';', $sedStrings);
104 2
            } else {
105 1
                throw new InvalidArgumentException("Number of items in 'fromText' (" . count($fromText) . ") is different to 'toText' (" . count($toText) . ")");
106
            }
107 11
        } elseif (is_array($fromText) || is_array($toText)) {
108 1
            throw new InvalidArgumentException("Only one of fromText or toText in an array, both should be arrays or string");
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 1
                $replacementString,
117 1
                $file->getPath()
118 1
            );
119 1
        } else {
120 9
            $cmd = sprintf(
121 9
                "perl -p -e '%s' %s > %s",
122 9
                $replacementString,
123 9
                $file->getPath(),
124 9
                $output->getPath()
125 9
            );
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 10
        ]);
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 string $fromText
141
     * @param string $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 10
        );
152
    }
153
}
154