Completed
Pull Request — master (#1)
by Sascha-Oliver
04:47
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
    /**
31
     * PhraseApp constructor.
32
     *
33
     * @param PhraseAppClient $client
34
     * @param string $projectId
35
     * @param string $acountId
0 ignored issues
show
Bug introduced by
There is no parameter named $acountId. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
36
     */
37
    public function __construct(PhraseAppClient $client, string $projectId, array $localeToIdMapping)
38
    {
39
        $this->client = $client;
40
        $this->projectId = $projectId;
41
        $this->localeToIdMapping = $localeToIdMapping;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function get($locale, $domain, $key)
48
    {
49
        $translations = $this->client->request('translation.indexLocale', [
50
            'project_id' => $this->projectId,
51
            'locale_id' => $this->getLocaleId($locale),
52
        ]);
53
54
        foreach ($translations as $translation) {
55
            if ($translation['key']['name'] === "$domain::$key") {
56
                return new Message($key, $domain, $locale, substr($translation['content'], strlen($domain) + 2));
57
            }
58
        }
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function create(Message $message)
65
    {
66
        try {
67
            $response = $this->client->request('key.search', [
68
                'project_id' => $this->projectId,
69
                'locale_id' => $this->getLocaleId($message->getLocale()),
70
                'q' => 'tags:' . $message->getDomain() . ' name:' . $message->getDomain() . '::' . $message->getKey(),
71
            ]);
72
73
            foreach ($response as $key) {
74
                if ($key['name'] === $message->getDomain() . '::' . $message->getKey()) {
75
                    $keyId = $key['id'];
76
                    break;
77
                }
78
            }
79
80
            if (! isset($keyId)) {
81
                $response = $this->client->request('key.create', [
82
                    'project_id' => $this->projectId,
83
                    'locale_id' => $this->getLocaleId($message->getLocale()),
84
                    'name' => $message->getDomain() . '::' . $message->getKey(),
85
                    'tags' => $message->getDomain(),
86
                ]);
87
88
                $keyId = $response['id'];
89
            }
90
91
            $response = $this->client->request('translation.indexKeys', [
92
                'project_id' => $this->projectId,
93
                'key_id' => $keyId
94
            ]);
95
96
            if (empty($response)) {
97
                $this->client->request('translation.create', [
98
                    'project_id' => $this->projectId,
99
                    'locale_id' => $this->getLocaleId($message->getLocale()),
100
                    'key_id' => $keyId,
101
                    'content' => $message->getDomain() . '::' . $message->getTranslation(),
102
                ]);
103
104
                return;
105
            }
106
107
            foreach ($response as $translation) {
108
                if ($translation['locale']['name'] === $message->getLocale()) {
109
                    $id = $translation['id'];
110
                }
111
                break;
112
            }
113
114
            if (! isset($id)) {
115
                throw new StorageException('Translation id not found.');
116
            }
117
118
            $this->client->request('translation.update', [
119
                'project_id' => $this->projectId,
120
                'id' => $id,
121
                'content' => $message->getDomain() . '::' . $message->getTranslation(),
122
            ]);
123
        } catch (\Throwable $e) {
124
            throw new StorageException($e->getMessage());
125
        }
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function update(Message $message)
132
    {
133
        $this->create($message);
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139
    public function delete($locale, $domain, $key)
140
    {
141
        try {
142
            $response = $this->client->request('key.search', [
143
                'project_id' => $this->projectId,
144
                'locale_id' => $this->getLocaleId($locale),
145
                'q' => $domain . '::' . $key,
146
            ]);
147
148
            foreach ($response as $keyName) {
149
                if ($keyName['name'] === $key) {
150
                    $keyId = $key['id'];
151
                    break;
152
                }
153
            }
154
155
            if (! isset($keyId)) {
156
                return;
157
            }
158
159
            $this->client->request('key.destroy', [
160
                'project_id' => $this->projectId,
161
                'id' => $keyId
162
163
            ]);
164
        } catch (\Throwable $e) {
165
            throw new StorageException($e->getMessage());
166
        }
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function export(MessageCatalogueInterface $catalogue)
173
    {
174
        $locale = $catalogue->getLocale();
175
176
        foreach ($catalogue->getDomains() as $domain) {
177
            try {
178
                $response = $this->client->request('locale.download', [
179
                    'project_id' => $this->projectId,
180
                    'id' => $this->getLocaleId($locale),
181
                    'tag' => $domain,
182
                    'file_format' => 'symfony_xliff'
183
                ]);
184
            } catch (\Throwable $e) {
185
                throw new StorageException($e->getMessage());
186
            }
187
188
            $data = $response['text'];
189
            /* @var \GuzzleHttp\Stream\Stream $data */
190
            $catalogue->addCatalogue(XliffConverter::contentToCatalogue($data->getContents(), $locale, $domain));
191
        }
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197
    public function import(MessageCatalogueInterface $catalogue)
198
    {
199
        foreach ($this->localeToIdMapping as $locale => $localeId) {
200
            foreach ($catalogue->getDomains() as $domain) {
201
                $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...
202
                $file = sys_get_temp_dir() . '/' . $domain . '_' . $locale . '.xlf';
203
                file_put_contents($file, $data);
204
205
                try {
206
                    /* 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...
207
                     *
208
                    $response = $this->client->request('upload.create', [
209
                        'project_id' => $this->projectId,
210
                        'locale_id' => $localeId,
211
                        'file' => '@'.$file,
212
                        'file_format' => 'symfony_xliff',
213
                        'tags' => $domain
214
                    ]);
215
                    */
216
217
                    $ch = curl_init();
218
219
                    curl_setopt($ch, \CURLOPT_URL, 'https://api.phraseapp.com/api/v2/projects/' . $this->projectId . '/uploads');
220
                    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...
221
                    curl_setopt($ch, \CURLOPT_HEADER, 0);
222
                    curl_setopt($ch, \CURLOPT_POST, 1);
223
                    curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);
224
                    curl_setopt($ch, CURLOPT_VERBOSE, 1);
225
                    curl_setopt($ch, \CURLOPT_POSTFIELDS, [
226
                        'file' => new \CURLFile($file),
227
                        'file_format' => 'symfony_xliff',
228
                        'tags' => $domain,
229
                        'locale_id' => $localeId
230
                    ]);
231
232
                    curl_exec($ch);
233
                    curl_close($ch);
234
                } catch (\Throwable $e) {
235
                    throw new StorageException($e->getMessage());
236
                } finally {
237
                    unlink($file);
238
                }
239
            }
240
        }
241
    }
242
243
    private function getLocaleId(string $locale): string
244
    {
245
        if (isset($this->localeToIdMapping[$locale])) {
246
            return $this->localeToIdMapping[$locale];
247
        }
248
249
        throw new StorageException(sprintf('Id for locale "%s" has not been configured.', $locale));
250
    }
251
}
252