Passed
Push — main ( 6eca2e...a5dcf9 )
by Alex
01:24
created

TraitTranslate::replacePlaceholders()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 10
rs 10
cc 3
nc 4
nop 2
1
<?php
2
3
namespace Erykai\Translate;
4
5
/**
6
 *
7
 */
8
trait TraitTranslate
9
{
10
    /**
11
     * @param string $dir
12
     * create dir
13
     */
14
    private function create(string $dir): void
15
    {
16
        if (!is_dir($dir) && !mkdir($dir, 0755, true) && !is_dir($dir)) {
17
            throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir));
18
        }
19
    }
20
21
    /**
22
     * create dir defaults
23
     */
24
    protected function dir($module): void
25
    {
26
        $this->create($this->getPath());
0 ignored issues
show
Bug introduced by
It seems like getPath() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

26
        $this->create($this->/** @scrutinizer ignore-call */ getPath());
Loading history...
27
        $this->create("{$this->getPath()}/{$this->getSource()}");
0 ignored issues
show
Bug introduced by
It seems like getSource() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( 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->create("{$this->getPath()}/{$this->/** @scrutinizer ignore-call */ getSource()}");
Loading history...
28
        if ($module) {
29
            $this->create("{$this->getPath()}/{$this->getSource()}/public");
30
        }
31
32
        $this->create("{$this->getPath()}/{$this->getTarget()}");
0 ignored issues
show
Bug introduced by
It seems like getTarget() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
        $this->create("{$this->getPath()}/{$this->/** @scrutinizer ignore-call */ getTarget()}");
Loading history...
33
        if ($module) {
34
            $this->create("{$this->getPath()}/{$this->getTarget()}/public");
35
        }
36
    }
37
38
    /**
39
     * create files .translate
40
     */
41
    protected function file(string $module = null, ?string $keyArray = null): void
42
    {
43
        if ($module) {
44
            $modulePath = dirname(__DIR__, 4) . "/modules/{$module}/translate";
45
            $this->create("{$modulePath}/{$this->getSource()}");
46
            $this->create("{$modulePath}/{$this->getSource()}/public");
47
            $this->create("{$modulePath}/{$this->getTarget()}");
48
            $this->create("{$modulePath}/{$this->getTarget()}/public");
49
            $this->setSourceFile("{$modulePath}/{$this->getSource()}/{$this->getData()->file}." . TRANSLATE_EXT);
0 ignored issues
show
Bug introduced by
It seems like setSourceFile() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

49
            $this->/** @scrutinizer ignore-call */ 
50
                   setSourceFile("{$modulePath}/{$this->getSource()}/{$this->getData()->file}." . TRANSLATE_EXT);
Loading history...
Bug introduced by
It seems like getData() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

49
            $this->setSourceFile("{$modulePath}/{$this->getSource()}/{$this->/** @scrutinizer ignore-call */ getData()->file}." . TRANSLATE_EXT);
Loading history...
50
            $this->setTargetFile("{$modulePath}/{$this->getTarget()}/{$this->getData()->file}." . TRANSLATE_EXT);
0 ignored issues
show
Bug introduced by
It seems like setTargetFile() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

50
            $this->/** @scrutinizer ignore-call */ 
51
                   setTargetFile("{$modulePath}/{$this->getTarget()}/{$this->getData()->file}." . TRANSLATE_EXT);
Loading history...
51
        } else {
52
            $this->setSourceFile("{$this->getPath()}/{$this->getSource()}/{$this->getData()->file}." . TRANSLATE_EXT);
53
            $this->setTargetFile("{$this->getPath()}/{$this->getTarget()}/{$this->getData()->file}." . TRANSLATE_EXT);
54
        }
55
        if ($keyArray) {
56
            $this->array($keyArray);
57
        } else {
58
            $this->line();
59
        }
60
61
    }
62
63
    /**
64
     * @return void
65
     */
66
    protected function line(): void
67
    {
68
        if (!is_file($this->getSourceFile())) {
0 ignored issues
show
Bug introduced by
It seems like getSourceFile() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

68
        if (!is_file($this->/** @scrutinizer ignore-call */ getSourceFile())) {
Loading history...
69
            file_put_contents($this->getSourceFile(), $this->getData()->text . PHP_EOL);
70
        } else if (!in_array($this->getData()->text . PHP_EOL, array_filter(file($this->getSourceFile())), true)) {
71
            file_put_contents($this->getSourceFile(), $this->getData()->text . PHP_EOL, FILE_APPEND);
72
        }
73
74
        if (!is_file($this->getTargetFile())) {
0 ignored issues
show
Bug introduced by
It seems like getTargetFile() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

74
        if (!is_file($this->/** @scrutinizer ignore-call */ getTargetFile())) {
Loading history...
75
            file_put_contents($this->getTargetFile(), $this->translate(file_get_contents($this->getSourceFile())) . PHP_EOL);
76
        } else {
77
            $source = array_filter(file($this->getSourceFile()));
78
            $target = array_filter(file($this->getTargetFile()));
79
            $result = array_diff_key($source, $target);
80
            $implode = implode("", $result);
81
            if (count(array_filter(file($this->getSourceFile()))) > count(array_filter(file($this->getTargetFile())))) {
82
                file_put_contents($this->getTargetFile(), $this->translate($implode) . PHP_EOL, FILE_APPEND);
83
            }
84
85
        }
86
    }
87
88
    /**
89
     * @param string $keyArray
90
     * @return void
91
     */
92
    protected function array(string $keyArray): void
93
    {
94
        $text = $this->getData()->text;
95
        $sourceFile = $this->getSourceFile();
96
97
        $contentSource = [];
98
        if (is_file($sourceFile)) {
99
            $contentSource = include $sourceFile;
100
        }
101
        if (!preg_match("/'$keyArray'\s*=>/", var_export($contentSource, true))) {
102
            $this->insertNestedArrayValue($contentSource, $keyArray, $text);
103
            $sourceContent = "<?php\n\nreturn " . $this->formatArraySyntax(var_export($contentSource, true)) . ";\n";
104
            file_put_contents($sourceFile, $sourceContent);
105
        }
106
107
        $targetFile = $this->getTargetFile();
108
        $contentTarget = [];
109
        if (is_file($targetFile)) {
110
            $contentTarget = include $targetFile;
111
        }
112
        if (!preg_match("/'$keyArray'\s*=>/", var_export($contentTarget, true))) {
113
            $translatedText = $this->translate($text);
114
            $this->insertNestedArrayValue($contentTarget, $keyArray, $translatedText);
115
            $targetContent = "<?php\n\nreturn " . $this->formatArraySyntax(var_export($contentTarget, true)) . ";\n";
116
            file_put_contents($targetFile, $targetContent);
117
        }
118
    }
119
120
    /**
121
     * @param $array
122
     * @param $path
123
     * @param $value
124
     * @return void
125
     */
126
    private function insertNestedArrayValue(&$array, $path, $value): void
127
    {
128
        $keys = explode('.', $path);
129
        while (count($keys) > 1) {
130
            $key = array_shift($keys);
131
            if (!isset($array[$key]) || !is_array($array[$key])) {
132
                $array[$key] = [];
133
            }
134
            $array = &$array[$key];
135
        }
136
        $array[array_shift($keys)] = $value;
137
    }
138
139
    /**
140
     * @param $content
141
     * @return array|string
142
     */
143
    private function formatArraySyntax($content): array|string
144
    {
145
        return str_replace(['array (', ')'], ['[', ']'], $content);
146
    }
147
148
    private function replacePlaceholders($template, $values): string
149
    {
150
        if (!is_array($values)) {
151
            $values = [$values];
152
        }
153
154
        foreach ($values as $value) {
155
            $template = preg_replace('/<#>/', $value, $template, 1);
156
        }
157
        return $template;
158
    }
159
160
    /**
161
     * @param string $text
162
     * @return mixed
163
     * send server translate
164
     */
165
    private function translate(string $text): mixed
166
    {
167
        $url = TRANSLATE_API_URL;
168
        $ch = curl_init($url);
169
        curl_setopt_array($ch, [
170
            CURLOPT_FOLLOWLOCATION => 1,
171
            CURLOPT_RETURNTRANSFER => 1,
172
            CURLOPT_POSTFIELDS => http_build_query([
173
                "key" => TRANSLATE_API_KEY,
174
                "source" => "en",
175
                "target" => $this->getTarget(),
176
                "text" => $text,
177
                "route" => $this->getData()->file
178
            ])
179
        ]);
180
        $response = curl_exec($ch);
181
        curl_close($ch);
182
        if (!$response) {
183
            return $text;
184
        }
185
        $data = json_decode($response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

185
        $data = json_decode(/** @scrutinizer ignore-type */ $response);
Loading history...
186
        if ($data->status === "success") {
187
            return trim($this->replacePlaceholders($data->translate, $this->getDynamic()));
0 ignored issues
show
Bug introduced by
It seems like getDynamic() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

187
            return trim($this->replacePlaceholders($data->translate, $this->/** @scrutinizer ignore-call */ getDynamic()));
Loading history...
188
        }
189
        return trim($this->replacePlaceholders($text, $this->getDynamic()));
190
    }
191
192
}