Completed
Pull Request — develop (#455)
by Lucas
62:34 queued 56:30
created

I18nUtils   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 12
dl 0
loc 239
ccs 0
cts 120
cp 0
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A isTranslatableContext() 0 4 1
A getTranslatableDomain() 0 11 3
A getDefaultLanguage() 0 4 1
A getLanguages() 0 9 3
A getTranslatedField() 0 17 2
B findMatchingTranslatables() 0 33 2
A flushTranslatables() 0 4 1
B insertTranslatable() 0 40 4
1
<?php
2
/**
3
 * service for i18n stuff
4
 */
5
6
namespace Graviton\I18nBundle\Service;
7
8
use Graviton\DocumentBundle\Entity\ExtReference;
9
use Graviton\I18nBundle\Model\Translatable;
10
use Graviton\I18nBundle\Document\Translatable as TranslatableDocument;
11
use Graviton\I18nBundle\Document\TranslatableLanguage;
12
use Graviton\I18nBundle\Repository\LanguageRepository;
13
use Symfony\Component\HttpFoundation\Request;
14
use Symfony\Component\Translation\TranslatorInterface;
15
16
/**
17
 * A service (meaning symfony service) providing some convenience stuff when dealing with our RestController
18
 * based services (meaning rest services).
19
 *
20
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
21
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
22
 * @link     http://swisscom.ch
23
 */
24
class I18nUtils
25
{
26
27
    /**
28
     * @var string
29
     */
30
    protected $defaultLanguage;
31
32
    /**
33
     * @var \Symfony\Component\Translation\TranslatorInterface
34
     */
35
    protected $translator;
36
37
    /**
38
     * @var array
39
     */
40
    protected $languages = [];
41
42
    /**
43
     * @var \Graviton\I18nBundle\Model\Translatable
44
     */
45
    protected $translatable;
46
47
    /**
48
     * @var \Graviton\I18nBundle\Repository\LanguageRepository
49
     */
50
    protected $languageRepository;
51
52
    /**
53
     * @var \Symfony\Component\HttpFoundation\Request
54
     */
55
    protected $request;
56
57
    /**
58
     * Constructor
59
     *
60
     * @param string              $defaultLanguage    default language
61
     * @param TranslatorInterface $translator         Translator
62
     * @param Translatable        $translatable       translatable
63
     * @param LanguageRepository  $languageRepository lang repo
64
     * @param Request             $request            request
0 ignored issues
show
Documentation introduced by
Should the type for parameter $request not be null|Request?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
65
     */
66
    public function __construct(
67
        $defaultLanguage,
68
        TranslatorInterface $translator,
69
        Translatable $translatable,
70
        LanguageRepository $languageRepository,
71
        Request $request = null
72
    ) {
73
        $this->defaultLanguage = $defaultLanguage;
74
        $this->translator = $translator;
75
        $this->translatable = $translatable;
76
        $this->languageRepository = $languageRepository;
77
        $this->request = $request;
78
    }
79
80
    /**
81
     * Returns whether we are in a Translatable context. That means if we can determine a translation domain.
82
     *
83
     * @return bool true if yes, false if not
84
     */
85
    public function isTranslatableContext()
86
    {
87
        return (!is_null($this->getTranslatableDomain()));
88
    }
89
90
    /**
91
     * Returns the domain to use according to the current request.
92
     * If there is no valid request, null will be returned..
93
     *
94
     * @return string domain
95
     */
96
    public function getTranslatableDomain()
97
    {
98
        $ret = null;
99
        if ($this->request instanceof Request) {
100
            $uriParts = explode('/', substr($this->request->getRequestUri(), 1));
101
            if (isset($uriParts[0])) {
102
                $ret = $uriParts[0];
103
            }
104
        }
105
        return $ret;
106
    }
107
108
    /**
109
     * Returns the default/original language - is set by DIC param
110
     *
111
     * @return string default language
112
     */
113
    public function getDefaultLanguage()
114
    {
115
        return $this->defaultLanguage;
116
    }
117
118
    /**
119
     * Returns all languages as a simple flat array
120
     *
121
     * @return array array of language id's
122
     */
123
    public function getLanguages()
124
    {
125
        if (empty($this->languages)) {
126
            foreach ($this->languageRepository->findAll() as $lang) {
127
                $this->languages[] = $lang->getId();
128
            }
129
        }
130
        return $this->languages;
131
    }
132
133
    /**
134
     * build a complete translated field
135
     *
136
     * @param string $value     value to translate
137
     * @param bool   $forClient if true, we look at languages header, false we render all languages
138
     *
139
     * @return array array with translated strings
140
     */
141
    public function getTranslatedField($value, $forClient = true)
142
    {
143
        $domain = $this->getTranslatableDomain();
144
145
        if ($forClient) {
146
            $languages = $this->request->attributes->get('languages');
147
        } else {
148
            $languages = $this->getLanguages();
149
        }
150
151
        return array_map(
152
            function ($language) use ($value, $domain) {
153
                return $this->translator->trans($value, array(), $domain, $language);
154
            },
155
            $languages
156
        );
157
    }
158
159
    /**
160
     * This function allows to search for existing translations from a source
161
     * language, probably using a wildcard
162
     *
163
     * @param string  $value        the translated string
164
     * @param string  $sourceLocale a source locale
165
     * @param boolean $useWildCard  if we should search wildcard or not
166
     *
167
     * @return array matching Translatables
168
     */
169
    public function findMatchingTranslatables($value, $sourceLocale, $useWildCard = false)
170
    {
171
        // i need to use a queryBuilder as the repository doesn't let me do regex queries (i guess so..)
172
        $builder = $this->translatable->getRepository()->createQueryBuilder();
173
        $builder
174
            ->field('domain')->equals($this->getTranslatableDomain())
175
            ->field('locale')->equals($sourceLocale);
176
177
        if ($useWildCard === true) {
178
            $value = new \MongoRegex($value);
179
        }
180
181
        /*
182
         * we have 2 cases to match
183
         * - 'translated' is set and matches
184
         * - 'translated' is not present, so 'original' can match (as this is inserted 'virtually')
185
         */
186
        $builder->addAnd(
187
            $builder->expr()
188
                ->addOr(
189
                    $builder->expr()->field('translated')->equals($value)
190
                )
191
                ->addOr(
192
                    $builder->expr()
193
                        ->field('translated')->equals(null)
194
                        ->field('original')->equals($value)
195
                )
196
        );
197
198
        $query = $builder->getQuery();
199
200
        return $query->execute()->toArray();
201
    }
202
203
    /**
204
     * Flush the translatables if it hasn't been done yet
205
     *
206
     * @return void
207
     */
208
    public function flushTranslatables()
209
    {
210
        $this->translatable->flush();
211
    }
212
213
    /**
214
     * [In|Up]serts a Translatable object using an array with language strings.
215
     *
216
     * @param array $values  array with language strings; key should be language id
217
     * @param bool  $doFlush if we should flush after the insert or not
218
     * @throws \Exception
219
     *
220
     * @return void
221
     */
222
    public function insertTranslatable(array $values, $doFlush = true)
223
    {
224
        if (!isset($values[$this->getDefaultLanguage()])) {
225
            throw new \Exception(
226
                sprintf(
227
                    'Creating new Translatable without "%s" key is not support yet.',
228
                    $this->getDefaultLanguage()
229
                )
230
            );
231
        }
232
233
        $original = $values[$this->getDefaultLanguage()];
234
235
        if ($this->isTranslatableContext()) {
236
            $languages = $this->getLanguages();
237
            \array_walk(
238
                $languages,
239
                function ($locale) use ($original, $values, $doFlush) {
240
                    $isLocalized = false;
241
                    $translated = '';
242
                    $domain = $this->getTranslatableDomain();
243
                    if (array_key_exists($locale, $values)) {
244
                        $translated = $values[$locale];
245
                        $isLocalized = true;
246
                    }
247
                    $translatable = new TranslatableDocument();
248
                    $translatable->setId($domain . '-' . $locale . '-' . $original);
249
                    $translatable->setLocale($locale);
250
                    $translatable->setDomain($domain);
251
                    $translatable->setOriginal($original);
252
                    $translatable->setTranslated($translated);
253
                    $translatable->setIsLocalized($isLocalized);
254
                    $translatableLang = new TranslatableLanguage();
255
                    $translatableLang->setRef(ExtReference::create('Language', $locale));
256
                    $translatable->setLanguage($translatableLang);
257
                    $this->translatable->insertRecord($translatable, false, $doFlush);
258
                }
259
            );
260
        }
261
    }
262
}
263