Completed
Push — 1.2-symfony-4.0-application ( 618605 )
by Kamil
58:56
created

Translator::provideMessageFormatter()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
rs 9.2
cc 4
eloc 11
nc 3
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
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
declare(strict_types=1);
13
14
namespace Sylius\Bundle\ThemeBundle\Translation;
15
16
use Sylius\Bundle\ThemeBundle\Translation\Provider\Loader\TranslatorLoaderProviderInterface;
17
use Sylius\Bundle\ThemeBundle\Translation\Provider\Resource\TranslatorResourceProviderInterface;
18
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
19
use Symfony\Component\Translation\Formatter\MessageFormatter;
20
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;
21
use Symfony\Component\Translation\MessageSelector;
22
use Symfony\Component\Translation\Translator as BaseTranslator;
23
24
final class Translator extends BaseTranslator implements WarmableInterface
25
{
26
    /**
27
     * @var array
28
     */
29
    protected $options = [
30
        'cache_dir' => null,
31
        'debug' => false,
32
    ];
33
34
    /**
35
     * @var TranslatorLoaderProviderInterface
36
     */
37
    private $loaderProvider;
38
39
    /**
40
     * @var TranslatorResourceProviderInterface
41
     */
42
    private $resourceProvider;
43
44
    /**
45
     * @var bool
46
     */
47
    private $resourcesLoaded = false;
48
49
    /**
50
     * @param TranslatorLoaderProviderInterface $loaderProvider
51
     * @param TranslatorResourceProviderInterface $resourceProvider
52
     * @param MessageSelector|MessageFormatterInterface $messageFormatterOrSelector
53
     * @param string $locale
54
     * @param array $options
55
     */
56
    public function __construct(
57
        TranslatorLoaderProviderInterface $loaderProvider,
58
        TranslatorResourceProviderInterface $resourceProvider,
59
        $messageFormatterOrSelector,
60
        string $locale,
61
        array $options = []
62
    ) {
63
        $this->assertOptionsAreKnown($options);
64
65
        $this->loaderProvider = $loaderProvider;
66
        $this->resourceProvider = $resourceProvider;
67
68
        $this->options = array_merge($this->options, $options);
69
        if (null !== $this->options['cache_dir'] && $this->options['debug']) {
70
            $this->addResources();
71
        }
72
73
        parent::__construct($locale, $this->provideMessageFormatter($messageFormatterOrSelector), $this->options['cache_dir'], $this->options['debug']);
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function warmUp($cacheDir): void
80
    {
81
        // skip warmUp when translator doesn't use cache
82
        if (null === $this->options['cache_dir']) {
83
            return;
84
        }
85
86
        $locales = array_merge(
87
            $this->getFallbackLocales(),
88
            [$this->getLocale()],
89
            $this->resourceProvider->getResourcesLocales()
90
        );
91
        foreach (array_unique($locales) as $locale) {
92
            // reset catalogue in case it's already loaded during the dump of the other locales.
93
            if (isset($this->catalogues[$locale])) {
94
                unset($this->catalogues[$locale]);
95
            }
96
97
            $this->loadCatalogue($locale);
98
        }
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    protected function initializeCatalogue($locale): void
105
    {
106
        $this->initialize();
107
108
        parent::initializeCatalogue($locale);
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    protected function computeFallbackLocales($locale): array
115
    {
116
        $themeModifier = $this->getLocaleModifier($locale);
117
        $localeWithoutModifier = $this->getLocaleWithoutModifier($locale, $themeModifier);
118
119
        $computedFallbackLocales = parent::computeFallbackLocales($locale);
120
        array_unshift($computedFallbackLocales, $localeWithoutModifier);
121
122
        $fallbackLocales = [];
123
        foreach (array_diff($computedFallbackLocales, [$locale]) as $computedFallback) {
124
            $fallback = $computedFallback . $themeModifier;
125
            if (null !== $themeModifier && $locale !== $fallback) {
126
                $fallbackLocales[] = $fallback;
127
            }
128
129
            $fallbackLocales[] = $computedFallback;
130
        }
131
132
        return array_unique($fallbackLocales);
133
    }
134
135
    /**
136
     * @param string $locale
137
     *
138
     * @return string
139
     */
140
    private function getLocaleModifier(string $locale): string
141
    {
142
        $modifier = strrchr($locale, '@');
143
144
        return $modifier ?: '';
145
    }
146
147
    /**
148
     * @param string $locale
149
     * @param string $modifier
150
     *
151
     * @return string
152
     */
153
    private function getLocaleWithoutModifier(string $locale, string $modifier): string
154
    {
155
        return str_replace($modifier, '', $locale);
156
    }
157
158
    private function initialize(): void
159
    {
160
        $this->addResources();
161
        $this->addLoaders();
162
    }
163
164
    private function addResources(): void
165
    {
166
        if ($this->resourcesLoaded) {
167
            return;
168
        }
169
170
        $resources = $this->resourceProvider->getResources();
171
        foreach ($resources as $resource) {
172
            $this->addResource(
173
                $resource->getFormat(),
174
                $resource->getName(),
175
                $resource->getLocale(),
176
                $resource->getDomain()
177
            );
178
        }
179
180
        $this->resourcesLoaded = true;
181
    }
182
183
    private function addLoaders(): void
184
    {
185
        $loaders = $this->loaderProvider->getLoaders();
186
        foreach ($loaders as $alias => $loader) {
187
            $this->addLoader($alias, $loader);
188
        }
189
    }
190
191
    /**
192
     * @param array $options
193
     */
194
    private function assertOptionsAreKnown(array $options): void
195
    {
196
        if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
197
            throw new \InvalidArgumentException(sprintf('The Translator does not support the following options: \'%s\'.', implode('\', \'', $diff)));
198
        }
199
    }
200
201
    private function provideMessageFormatter($messageFormatterOrSelector): MessageFormatterInterface
202
    {
203
        if ($messageFormatterOrSelector instanceof MessageSelector) {
204
            @trigger_error(sprintf('Passing a "%s" instance into the "%s" as a third argument is deprecated since Sylius 1.2 and will be removed in 2.0. Inject a "%s" implementation instead.', MessageSelector::class, __METHOD__, MessageFormatterInterface::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
205
206
            return new MessageFormatter($messageFormatterOrSelector);
207
        }
208
209
        if ($messageFormatterOrSelector instanceof MessageFormatterInterface) {
210
            return $messageFormatterOrSelector;
211
        }
212
213
        throw new \UnexpectedValueException(sprintf(
214
            'Expected an instance of "%s" or "%s", got "%s"!',
215
            MessageFormatterInterface::class,
216
            MessageSelector::class,
217
            is_object($messageFormatterOrSelector) ? get_class($messageFormatterOrSelector) : gettype($messageFormatterOrSelector)
218
        ));
219
    }
220
}
221