Completed
Pull Request — master (#1)
by Sascha-Oliver
07:20 queued 05:24
created

PhraseApp::getLocaleId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 7
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Translation\PlatformAdapter\PhraseApp;
4
5
use nediam\PhraseApp\PhraseAppClient;
6
use Symfony\Component\Translation\MessageCatalogueInterface;
7
use Translation\Common\Exception\StorageException;
8
use Translation\Common\Model\Message;
9
use Translation\Common\Storage;
10
use Translation\Common\TransferableStorage;
11
use Translation\PlatformAdapter\PhraseApp\Bridge\Symfony\XliffConverter;
12
13
class PhraseApp implements Storage, TransferableStorage
14
{
15
    /**
16
     * @var PhraseAppClient
17
     */
18
    private $client;
19
20
    /**
21
     * @var string
22
     */
23
    private $projectId;
24
25
    /**
26
     * @var array
27
     */
28
    private $localeToIdMapping;
29
30
    public function __construct(PhraseAppClient $client, string $projectId, array $localeToIdMapping)
31
    {
32
        $this->client = $client;
33
        $this->projectId = $projectId;
34
        $this->localeToIdMapping = $localeToIdMapping;
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40
    public function get($locale, $domain, $key)
41
    {
42
        $translations = $this->client->request('translation.indexLocale', [
43
            'project_id' => $this->projectId,
44
            'locale_id' => $this->getLocaleId($locale),
45
        ]);
46
47
        foreach ($translations as $translation) {
48
            if ($translation['key']['name'] === "$domain::$key") {
49
                return new Message($key, $domain, $locale, substr($translation['content'], strlen($domain) + 2));
50
            }
51
        }
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function create(Message $message)
58
    {
59
        try {
60
            $response = $this->client->request('key.search', [
61
                'project_id' => $this->projectId,
62
                'locale_id' => $this->getLocaleId($message->getLocale()),
63
                'q' => 'tags:' . $message->getDomain() . ' name:' . $message->getDomain() . '::' . $message->getKey(),
64
            ]);
65
66 View Code Duplication
            foreach ($response as $key) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
67
                if ($key['name'] === $message->getDomain() . '::' . $message->getKey()) {
68
                    $keyId = $key['id'];
69
                    break;
70
                }
71
            }
72
73 View Code Duplication
            if (!isset($keyId)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74
                $response = $this->client->request('key.create', [
75
                    'project_id' => $this->projectId,
76
                    'locale_id' => $this->getLocaleId($message->getLocale()),
77
                    'name' => $message->getDomain() . '::' . $message->getKey(),
78
                    'tags' => $message->getDomain(),
79
                ]);
80
81
                $keyId = $response['id'];
82
            }
83
84
            $response = $this->client->request('translation.indexKeys', [
85
                'project_id' => $this->projectId,
86
                'key_id' => $keyId
87
            ]);
88
89 View Code Duplication
            if (empty($response)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
                $this->client->request('translation.create', [
91
                    'project_id' => $this->projectId,
92
                    'locale_id' => $this->getLocaleId($message->getLocale()),
93
                    'key_id' => $keyId,
94
                    'content' => $message->getDomain() . '::' . $message->getTranslation(),
95
                ]);
96
97
                return;
98
            }
99
        } catch (\Throwable $e) {
100
            throw new StorageException($e->getMessage());
101
        }
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107
    public function update(Message $message)
108
    {
109
        try {
110
            $response = $this->client->request('key.search', [
111
                'project_id' => $this->projectId,
112
                'locale_id' => $this->getLocaleId($message->getLocale()),
113
                'q' => 'tags:' . $message->getDomain() . ' name:' . $message->getDomain() . '::' . $message->getKey(),
114
            ]);
115
116 View Code Duplication
            foreach ($response as $key) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117
                if ($key['name'] === $message->getDomain() . '::' . $message->getKey()) {
118
                    $keyId = $key['id'];
119
                    break;
120
                }
121
            }
122
123 View Code Duplication
            if (!isset($keyId)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
                $response = $this->client->request('key.create', [
125
                    'project_id' => $this->projectId,
126
                    'locale_id' => $this->getLocaleId($message->getLocale()),
127
                    'name' => $message->getDomain() . '::' . $message->getKey(),
128
                    'tags' => $message->getDomain(),
129
                ]);
130
131
                $keyId = $response['id'];
132
            }
133
134
            $response = $this->client->request('translation.indexKeys', [
135
                'project_id' => $this->projectId,
136
                'key_id' => $keyId
137
            ]);
138
139 View Code Duplication
            if (empty($response)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
140
                $this->client->request('translation.create', [
141
                    'project_id' => $this->projectId,
142
                    'locale_id' => $this->getLocaleId($message->getLocale()),
143
                    'key_id' => $keyId,
144
                    'content' => $message->getDomain() . '::' . $message->getTranslation(),
145
                ]);
146
147
                return;
148
            }
149
150
            foreach ($response as $translation) {
151
                if ($translation['locale']['name'] === $message->getLocale()) {
152
                    $id = $translation['id'];
153
                }
154
                break;
155
            }
156
157
            if (!isset($id)) {
158
                throw new StorageException('Translation id not found.');
159
            }
160
161
            $this->client->request('translation.update', [
162
                'project_id' => $this->projectId,
163
                'id' => $id,
164
                'content' => $message->getDomain() . '::' . $message->getTranslation(),
165
            ]);
166
        } catch (\Throwable $e) {
167
            throw new StorageException($e->getMessage());
168
        }
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    public function delete($locale, $domain, $key)
175
    {
176
        try {
177
            $response = $this->client->request('key.search', [
178
                'project_id' => $this->projectId,
179
                'locale_id' => $this->getLocaleId($locale),
180
                'q' => $domain . '::' . $key,
181
            ]);
182
183
            foreach ($response as $keyName) {
184
                if ($keyName['name'] === $key) {
185
                    $keyId = $key['id'];
186
                    break;
187
                }
188
            }
189
190
            if (!isset($keyId)) {
191
                return;
192
            }
193
194
            $this->client->request('key.destroy', [
195
                'project_id' => $this->projectId,
196
                'id' => $keyId
197
198
            ]);
199
        } catch (\Throwable $e) {
200
            throw new StorageException($e->getMessage());
201
        }
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    public function export(MessageCatalogueInterface $catalogue)
208
    {
209
        $locale = $catalogue->getLocale();
210
211
        foreach ($catalogue->getDomains() as $domain) {
212
            try {
213
                $response = $this->client->request('locale.download', [
214
                    'project_id' => $this->projectId,
215
                    'id' => $this->getLocaleId($locale),
216
                    'tag' => $domain,
217
                    'file_format' => 'symfony_xliff'
218
                ]);
219
            } catch (\Throwable $e) {
220
                throw new StorageException($e->getMessage());
221
            }
222
223
            /* @var \GuzzleHttp\Stream\Stream $data */
224
            $data = $response['text'];
225
            $catalogue->addCatalogue(XliffConverter::contentToCatalogue($data->getContents(), $locale, $domain));
226
        }
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232
    public function import(MessageCatalogueInterface $catalogue)
233
    {
234
        foreach ($this->localeToIdMapping as $locale => $localeId) {
235
            foreach ($catalogue->getDomains() as $domain) {
236
                $data = XliffConverter::catalogueToContent($catalogue, $domain);
0 ignored issues
show
Compatibility introduced by
$catalogue of type object<Symfony\Component...sageCatalogueInterface> is not a sub-type of object<Symfony\Component...ation\MessageCatalogue>. It seems like you assume a concrete implementation of the interface Symfony\Component\Transl...ssageCatalogueInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
237
                $file = sys_get_temp_dir() . '/' . $domain . '_' . $locale . '.xlf';
238
                file_put_contents($file, $data);
239
240
                try {
241
                    /* I could not get guzzle to work with this, so fallback to curl for now
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
242
                     *
243
                    $response = $this->client->request('upload.create', [
244
                        'project_id' => $this->projectId,
245
                        'locale_id' => $localeId,
246
                        'file' => '@'.$file,
247
                        'file_format' => 'symfony_xliff',
248
                        'tags' => $domain
249
                    ]);
250
                    */
251
252
                    $ch = curl_init();
253
254
                    curl_setopt($ch, \CURLOPT_URL, 'https://api.phraseapp.com/api/v2/projects/' . $this->projectId . '/uploads');
255
                    curl_setopt($ch, \CURLOPT_USERPWD, $this->client->getToken());
0 ignored issues
show
Bug introduced by
The method getToken() does not seem to exist on object<nediam\PhraseApp\PhraseAppClient>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
256
                    curl_setopt($ch, \CURLOPT_HEADER, 0);
257
                    curl_setopt($ch, \CURLOPT_POST, 1);
258
                    curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);
259
                    curl_setopt($ch, CURLOPT_VERBOSE, 1);
260
                    curl_setopt($ch, \CURLOPT_POSTFIELDS, [
261
                        'file' => new \CURLFile($file),
262
                        'file_format' => 'symfony_xliff',
263
                        'tags' => $domain,
264
                        'locale_id' => $localeId
265
                    ]);
266
267
                    curl_exec($ch);
268
                    curl_close($ch);
269
                } catch (\Throwable $e) {
270
                    throw new StorageException($e->getMessage());
271
                } finally {
272
                    unlink($file);
273
                }
274
            }
275
        }
276
    }
277
278
    private function getLocaleId(string $locale): string
279
    {
280
        if (isset($this->localeToIdMapping[$locale])) {
281
            return $this->localeToIdMapping[$locale];
282
        }
283
284
        throw new StorageException(sprintf('Id for locale "%s" has not been configured.', $locale));
285
    }
286
}
287