Completed
Push — master ( cc7cf3...f7d42d )
by Kamil
19s
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
dl 0
loc 19
rs 9.2
c 0
b 0
f 0
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);
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