Completed
Push — master ( dd41bc...0f9cdd )
by Tobias
02:09
created

WebUIController::createAction()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 0
cts 25
cp 0
rs 8.8177
c 0
b 0
f 0
cc 6
nc 8
nop 4
crap 42
1
<?php
2
3
/*
4
 * This file is part of the PHP Translation package.
5
 *
6
 * (c) PHP Translation team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Translation\Bundle\Controller;
13
14
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15
use Symfony\Component\HttpFoundation\Request;
16
use Symfony\Component\HttpFoundation\Response;
17
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
18
use Symfony\Component\Intl\Intl;
19
use Symfony\Component\Intl\Locales;
20
use Symfony\Component\Translation\MessageCatalogue;
21
use Symfony\Component\Validator\Validator\ValidatorInterface;
22
use Translation\Bundle\Catalogue\CatalogueFetcher;
23
use Translation\Bundle\Catalogue\CatalogueManager;
24
use Translation\Bundle\Exception\MessageValidationException;
25
use Translation\Bundle\Model\CatalogueMessage;
26
use Translation\Bundle\Service\ConfigurationManager;
27
use Translation\Bundle\Service\StorageManager;
28
use Translation\Bundle\Service\StorageService;
29
use Translation\Common\Exception\StorageException;
30
use Translation\Common\Model\Message;
31
use Translation\Common\Model\MessageInterface;
32
33
/**
34
 * @author Tobias Nyholm <[email protected]>
35
 */
36
class WebUIController extends AbstractController
37
{
38
    private $configurationManager;
39
    private $catalogueFetcher;
40
    private $catalogueManager;
41
    private $storageManager;
42
    private $validator;
43
    private $locales;
44
    private $isWebUIEnabled;
45
    private $isWebUIAllowCreate;
46
    private $isWebUIAllowDelete;
47
    private $fileBasePath;
48
49
    public function __construct(
50
        ConfigurationManager $configurationManager,
51
        CatalogueFetcher $catalogueFetcher,
52
        CatalogueManager $catalogueManager,
53
        StorageManager $storageManager,
54
        ValidatorInterface $validator,
55
        array $locales,
56
        bool $isWebUIEnabled,
57
        bool $isWebUIAllowCreate,
58
        bool $isWebUIAllowDelete,
59
        string $fileBasePath
60
    ) {
61
        $this->configurationManager = $configurationManager;
62
        $this->catalogueFetcher = $catalogueFetcher;
63
        $this->catalogueManager = $catalogueManager;
64
        $this->storageManager = $storageManager;
65
        $this->validator = $validator;
66
        $this->locales = $locales;
67
        $this->isWebUIEnabled = $isWebUIEnabled;
68
        $this->isWebUIAllowCreate = $isWebUIAllowCreate;
69
        $this->isWebUIAllowDelete = $isWebUIAllowDelete;
70
        $this->fileBasePath = $fileBasePath;
71
    }
72
73
    /**
74
     * Show a dashboard for the configuration.
75
     */
76
    public function indexAction(?string $configName = null): Response
77
    {
78
        if (!$this->isWebUIEnabled) {
79
            return new Response('You are not allowed here. Check your config.', Response::HTTP_BAD_REQUEST);
80
        }
81
82
        $config = $this->configurationManager->getConfiguration($configName);
83
        $localeMap = $this->getLocale2LanguageMap();
84
        $catalogues = $this->catalogueFetcher->getCatalogues($config);
85
86
        $catalogueSize = [];
87
        $maxDomainSize = [];
88
        $maxCatalogueSize = 1;
89
90
        // For each catalogue (or locale)
91
        /** @var MessageCatalogue $catalogue */
92
        foreach ($catalogues as $catalogue) {
93
            $locale = $catalogue->getLocale();
94
            $domains = $catalogue->all();
95
            \ksort($domains);
96
            $catalogueSize[$locale] = 0;
97
            foreach ($domains as $domain => $messages) {
98
                $count = \count($messages);
99
                $catalogueSize[$locale] += $count;
100
                if (!isset($maxDomainSize[$domain]) || $count > $maxDomainSize[$domain]) {
101
                    $maxDomainSize[$domain] = $count;
102
                }
103
            }
104
105
            if ($catalogueSize[$locale] > $maxCatalogueSize) {
106
                $maxCatalogueSize = $catalogueSize[$locale];
107
            }
108
        }
109
110
        return $this->render('@Translation/WebUI/index.html.twig', [
111
            'catalogues' => $catalogues,
112
            'catalogueSize' => $catalogueSize,
113
            'maxDomainSize' => $maxDomainSize,
114
            'maxCatalogueSize' => $maxCatalogueSize,
115
            'localeMap' => $localeMap,
116
            'configName' => $config->getName(),
117
            'configNames' => $this->configurationManager->getNames(),
118
        ]);
119
    }
120
121
    /**
122
     * Show a catalogue.
123
     */
124
    public function showAction(string $configName, string $locale, string $domain): Response
125
    {
126
        if (!$this->isWebUIEnabled) {
127
            return new Response('You are not allowed here. Check your config.', Response::HTTP_BAD_REQUEST);
128
        }
129
        $config = $this->configurationManager->getConfiguration($configName);
130
131
        // Get a catalogue manager and load it with all the catalogues
132
        $this->catalogueManager->load($this->catalogueFetcher->getCatalogues($config));
133
134
        /** @var CatalogueMessage[] $messages */
135
        $messages = $this->catalogueManager->getMessages($locale, $domain);
136
        \usort($messages, function (CatalogueMessage $a, CatalogueMessage $b) {
137
            return \strcmp($a->getKey(), $b->getKey());
138
        });
139
140
        return $this->render('@Translation/WebUI/show.html.twig', [
141
            'messages' => $messages,
142
            'domains' => $this->catalogueManager->getDomains(),
143
            'currentDomain' => $domain,
144
            'locales' => $this->locales,
145
            'currentLocale' => $locale,
146
            'configName' => $config->getName(),
147
            'configNames' => $this->configurationManager->getNames(),
148
            'allow_create' => $this->isWebUIAllowCreate,
149
            'allow_delete' => $this->isWebUIAllowDelete,
150
            'file_base_path' => $this->fileBasePath,
151
        ]);
152
    }
153
154
    public function createAction(Request $request, string $configName, string $locale, string $domain): Response
155
    {
156
        if (!$this->isWebUIEnabled || !$this->isWebUIAllowCreate) {
157
            return new Response('You are not allowed to create. Check your config.', Response::HTTP_BAD_REQUEST);
158
        }
159
160
        /** @var StorageService $storage */
161
        $storage = $this->storageManager->getStorage($configName);
162
163
        try {
164
            $message = $this->getMessageFromRequest($request);
165
            $message = $message->withDomain($domain);
166
            $message = $message->withLocale($locale);
167
            $this->validateMessage($message, ['Create']);
168
        } catch (MessageValidationException $e) {
169
            return new Response($e->getMessage(), Response::HTTP_BAD_REQUEST);
170
        }
171
172
        try {
173
            $storage->create($message);
174
        } catch (StorageException $e) {
175
            throw new BadRequestHttpException(\sprintf('Key "%s" does already exist for "%s" on domain "%s".', $message->getKey(), $locale, $domain), $e);
176
        } catch (\Exception $e) {
177
            return new Response($e->getMessage(), Response::HTTP_BAD_REQUEST);
178
        }
179
180
        return $this->render('@Translation/WebUI/create.html.twig', [
181
            'message' => $message,
182
        ]);
183
    }
184
185
    public function editAction(Request $request, string $configName, string $locale, string $domain): Response
186
    {
187
        if (!$this->isWebUIEnabled) {
188
            return new Response('You are not allowed here. Check your config.', Response::HTTP_BAD_REQUEST);
189
        }
190
191
        try {
192
            $message = $this->getMessageFromRequest($request);
193
            $message = $message->withDomain($domain);
194
            $message = $message->withLocale($locale);
195
            $this->validateMessage($message, ['Edit']);
196
        } catch (MessageValidationException $e) {
197
            return new Response($e->getMessage(), Response::HTTP_BAD_REQUEST);
198
        }
199
200
        /** @var StorageService $storage */
201
        $storage = $this->storageManager->getStorage($configName);
202
        try {
203
            $storage->update($message);
204
        } catch (\Exception $e) {
205
            return new Response($e->getMessage(), Response::HTTP_BAD_REQUEST);
206
        }
207
208
        return new Response('Translation updated');
209
    }
210
211
    public function deleteAction(Request $request, string $configName, string $locale, string $domain): Response
212
    {
213
        if (!$this->isWebUIEnabled || !$this->isWebUIAllowDelete) {
214
            return new Response('You are not allowed to create. Check your config.', Response::HTTP_BAD_REQUEST);
215
        }
216
217
        try {
218
            $message = $this->getMessageFromRequest($request);
219
            $message = $message->withLocale($locale);
220
            $message = $message->withDomain($domain);
221
            $this->validateMessage($message, ['Delete']);
222
        } catch (MessageValidationException $e) {
223
            return new Response($e->getMessage(), Response::HTTP_BAD_REQUEST);
224
        }
225
226
        /** @var StorageService $storage */
227
        $storage = $this->storageManager->getStorage($configName);
228
        try {
229
            $storage->delete($locale, $domain, $message->getKey());
230
        } catch (\Exception $e) {
231
            return new Response($e->getMessage(), Response::HTTP_BAD_REQUEST);
232
        }
233
234
        return new Response('Message was deleted');
235
    }
236
237
    private function getMessageFromRequest(Request $request): Message
238
    {
239
        $json = $request->getContent();
240
        $data = \json_decode($json, true);
241
        $message = new Message($data['key']);
242
        if (isset($data['message'])) {
243
            $message = $message->withTranslation($data['message']);
244
        }
245
246
        return $message;
247
    }
248
249
    /**
250
     * This will return a map of our configured locales and their language name.
251
     *
252
     * @return array locale => language
253
     */
254
    private function getLocale2LanguageMap(): array
255
    {
256
        $names = \class_exists(Locales::class)
257
            ? Locales::getNames('en')
258
            : Intl::getLocaleBundle()->getLocaleNames('en');
0 ignored issues
show
Bug introduced by
The method getLocaleBundle() does not seem to exist on object<Symfony\Component\Intl\Intl>.

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...
259
        $map = [];
260
        foreach ($this->locales as $l) {
261
            $map[$l] = $names[$l] ?? $l;
262
        }
263
264
        return $map;
265
    }
266
267
    /**
268
     * @throws MessageValidationException
269
     */
270
    private function validateMessage(MessageInterface $message, array $validationGroups): void
271
    {
272
        $errors = $this->validator->validate($message, null, $validationGroups);
273
        if (\count($errors) > 0) {
274
            throw  MessageValidationException::create();
275
        }
276
    }
277
}
278