Completed
Push — master ( 14b645...5c8609 )
by Simonas
63:34
created

ImportManager::cleanTranslations()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[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 ONGR\TranslationsBundle\Service\Import;
13
14
use ONGR\ElasticsearchBundle\Service\Manager;
15
use ONGR\ElasticsearchBundle\Service\Repository;
16
use ONGR\ElasticsearchDSL\Query\FullText\MatchQuery;
17
use ONGR\TranslationsBundle\Document\Message;
18
use ONGR\TranslationsBundle\Document\Translation;
19
use Symfony\Component\Finder\Finder;
20
use Symfony\Component\Finder\SplFileInfo;
21
use Symfony\Component\Translation\Exception\InvalidResourceException;
22
use Symfony\Component\Translation\Loader\YamlFileLoader;
23
use Symfony\Component\Yaml\Exception\ParseException;
24
use Symfony\Component\Yaml\Parser as YamlParser;
25
26
/**
27
 * Collects translations.
28
 */
29
class ImportManager
30
{
31
    /**
32
     * @var array
33
     */
34
    private $locales;
35
36
    /**
37
     * @var Repository
38
     */
39
    private $repository;
40
41
    /**
42
     * @var Manager
43
     */
44
    private $manager;
45
46
    /**
47
     * @var YamlFileLoader
48
     */
49
    private $parser;
50
51
    /**
52
     * @var string
53
     */
54
    private $kernelRoot;
55
56
    /**
57
     * @param Repository $repository
58
     */
59
    public function __construct(
60
        Repository $repository,
61
        $kernelRoot
62
    )
63
    {
64
        $this->parser = new YamlParser();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Symfony\Component\Yaml\Parser() of type object<Symfony\Component\Yaml\Parser> is incompatible with the declared type object<Symfony\Component...\Loader\YamlFileLoader> of property $parser.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
65
        $this->repository = $repository;
66
        $this->manager = $repository->getManager();
67
        $this->kernelRoot = $kernelRoot;
68
    }
69
70
    /**
71
     * @return array
72
     */
73
    public function getLocales()
74
    {
75
        return $this->locales;
76
    }
77
78
    /**
79
     * @param array $locales
80
     */
81
    public function setLocales(array $locales)
82
    {
83
        $this->locales = $locales;
84
    }
85
86
    /**
87
     * Write translations to storage.
88
     *
89
     * @param $translations
90
     */
91
    public function writeToStorage($domain, $translations)
92
    {
93
        foreach ($translations as $keys) {
94
            foreach ($keys as $key => $transMeta) {
95
                $search = $this->repository->createSearch();
96
                $search->addQuery(new MatchQuery('key', $key));
97
                $results = $this->repository->findDocuments($search);
98
                if (count($results)) {
99
                    continue;
100
                }
101
102
                $document = new Translation();
103
                $document->setDomain($domain);
104
                $document->setKey($key);
105
                $document->setPath($transMeta['path']);
106
                $document->setFormat($transMeta['format']);
107
                foreach ($transMeta['messages'] as $locale => $text) {
108
                    $message = new Message();
109
                    $message->setLocale($locale);
110
                    $message->setMessage($text);
111
                    $document->addMessage($message);
112
                }
113
                $this->manager->persist($document);
114
            }
115
        }
116
117
        $this->manager->commit();
118
    }
119
120
    /**
121
     * @param array $translations
122
     */
123
    public function cleanTranslations(array $translations)
124
    {
125
        $translationKeys    = array_keys($translations);
126
        $storedTranslations = $this->repository->findBy([]);
127
128
        foreach ($storedTranslations as $document) {
129
            if (!in_array($document->getKey(), $translationKeys)) {
130
                $this->repository->remove($document->getId());
131
            }
132
        }
133
    }
134
135
    /**
136
     * Imports translation files from a directory.
137
     * @param string $dir
138
     */
139
    public function importTranslationFiles($domain, $dir)
140
    {
141
        $translations = $this->getTranslationsFromFiles($domain, $dir);
142
        $this->writeToStorage($domain, $translations);
143
    }
144
145
    /**
146
     * Return a Finder object if $path has a Resources/translations folder.
147
     *
148
     * @param string $domain
149
     * @param string $path
150
     * @param array $directories
151
     *
152
     * @return array
153
     */
154
    public function getTranslationsFromFiles($domain, $path, array $directories = [])
155
    {
156
        if (!$directories) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $directories of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
157
            $directories = [
158
                $path . 'Resources' . DIRECTORY_SEPARATOR . 'translations',
159
                $this->kernelRoot . DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . $domain . DIRECTORY_SEPARATOR . 'translations',
160
            ];
161
        }
162
163
        $finder = new Finder();
164
        $translations = [];
165
166
        foreach ($directories as $directory) {
167
            if (is_dir($directory)) {
168
                $finder->files()
169
                    ->name($this->getFileNamePattern())
170
                    ->in($directory);
171
172
                foreach ($finder as $file) {
173
                    $translations = array_replace_recursive($this->getFileTranslationMessages($file, $domain), $translations);
174
                }
175
            }
176
        }
177
178
        return $translations;
179
    }
180
181
    /**
182
     * @param SplFileInfo $file
183
     * @param string      $domain
184
     *
185
     * @return array
186
     */
187
    public function getFileTranslationMessages(SplFileInfo $file, $domain)
188
    {
189
        $locale = explode('.', $file->getFilename())[1];
190
191
        if (!in_array($locale, $this->getLocales())) {
192
            return [];
193
        }
194
195
        $translations = [];
196
197
        try {
198
            $domainMessages = $this->parser->parse(file_get_contents($file->getPath().DIRECTORY_SEPARATOR.$file->getFilename()));
0 ignored issues
show
Bug introduced by
The method parse() does not seem to exist on object<Symfony\Component...\Loader\YamlFileLoader>.

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...
199
        } catch (ParseException $e) {
200
            throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $file->getPath()), 0, $e);
201
        }
202
203
        $path = substr(pathinfo($file->getPathname(), PATHINFO_DIRNAME), strlen(getcwd()) + 1);
204
        foreach ($domainMessages as $key => $content) {
205
            $translations[$domain][$key]['messages'][$locale] = $content;
206
            $translations[$domain][$key]['path'] = $path;
207
            $translations[$domain][$key]['format'] = $file->getExtension();
208
        }
209
210
        return $translations;
211
    }
212
213
    /**
214
     * @return string
215
     */
216
    private function getFileNamePattern()
217
    {
218
        $regex = sprintf(
219
            '/(.*\.(%s)\.(%s))/',
220
            implode('|', $this->getLocales()),
221
            'yml$'
222
        );
223
        return $regex;
224
    }
225
}
226