php-translation /
symfony-bundle
| 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 delete. 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
|
|||
| 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 |
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.