Completed
Push — master ( f76b3a...bd6f71 )
by Tobias
04:11
created

FileStorage::writeTranslations()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 6
cp 0.6667
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 3
crap 2.1481
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\SymfonyStorage;
13
14
use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader as SymfonyTranslationLoader;
15
use Symfony\Component\Translation\MessageCatalogue;
16
use Symfony\Component\Translation\MessageCatalogueInterface;
17
use Symfony\Component\Translation\Reader\TranslationReader;
18
use Symfony\Component\Translation\Writer\TranslationWriter;
19
use Translation\Common\Model\Message;
20
use Translation\Common\Storage;
21
use Translation\Common\TransferableStorage;
22
23
/**
24
 * This storage uses Symfony's writer and loader.
25
 *
26
 * @author Tobias Nyholm <[email protected]>
27
 */
28
final class FileStorage implements Storage, TransferableStorage
29
{
30
    /**
31
     * @var TranslationWriter
32
     */
33
    private $writer;
34
35
    /**
36
     * @var TranslationLoader|SymfonyTranslationLoader
37
     */
38
    private $loader;
39
40
    /**
41
     * @var array directory path
42
     */
43
    private $dir;
44
45
    /**
46
     * @var array with option to the dumper
47
     */
48
    private $options;
49
50
    /**
51
     * @var MessageCatalogue[] Fetched catalogies
52
     */
53
    private $catalogues;
54
55
    /**
56
     * @param TranslationWriter                                            $writer
57
     * @param SymfonyTranslationLoader|TranslationLoader|TranslationReader $loader
58
     * @param array                                                        $dir
59
     * @param array                                                        $options
60
     */
61 10
    public function __construct(TranslationWriter $writer, $loader, array $dir, array $options = [])
62
    {
63
        // Create a legacy loader which is a wrapper for TranslationReader
64 10
        if ($loader instanceof TranslationReader) {
65
            $loader = new LegacyTranslationLoader($loader);
66
        }
67 10
        if (!$loader instanceof SymfonyTranslationLoader && !$loader instanceof TranslationLoader) {
0 ignored issues
show
Bug introduced by
The class Symfony\Bundle\Framework...ation\TranslationLoader does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
68 1
            throw new \LogicException('Second parameter of FileStorage must be a Symfony translation loader or implement Translation\SymfonyStorage\TranslationLoader');
69
        }
70
71 9
        if (empty($dir)) {
72 1
            throw new \LogicException('Third parameter of FileStorage cannot be empty');
73
        }
74
75 8
        if (!array_key_exists('xliff_version', $options)) {
76
            // Set default value for xliff version.
77 8
            $options['xliff_version'] = '2.0';
78 8
        }
79
80 8
        $this->writer = $writer;
81 8
        $this->loader = $loader;
82 8
        $this->dir = $dir;
83 8
        $this->options = $options;
84 8
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 1
    public function get($locale, $domain, $key)
90
    {
91 1
        $catalogue = $this->getCatalogue($locale);
92 1
        $translation = $catalogue->get($key, $domain);
93
94 1
        return new Message($key, $domain, $locale, $translation);
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100 2
    public function create(Message $m)
101
    {
102 2
        $catalogue = $this->getCatalogue($m->getLocale());
103 2
        if (!$catalogue->defines($m->getKey(), $m->getDomain())) {
104 2
            $catalogue->set($m->getKey(), $m->getTranslation(), $m->getDomain());
105 2
            $this->writeCatalogue($catalogue, $m->getLocale(), $m->getDomain());
106 2
        }
107 2
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 1
    public function update(Message $m)
113
    {
114 1
        $catalogue = $this->getCatalogue($m->getLocale());
115 1
        $catalogue->set($m->getKey(), $m->getTranslation(), $m->getDomain());
116 1
        $this->writeCatalogue($catalogue, $m->getLocale(), $m->getDomain());
117 1
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122 1
    public function delete($locale, $domain, $key)
123
    {
124 1
        $catalogue = $this->getCatalogue($locale);
125 1
        $messages = $catalogue->all($domain);
126 1
        unset($messages[$key]);
127
128 1
        $catalogue->replace($messages, $domain);
129 1
        $this->writeCatalogue($catalogue, $locale, $domain);
130 1
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135 1
    public function export(MessageCatalogueInterface $catalogue)
136
    {
137 1
        $locale = $catalogue->getLocale();
138 1
        $catalogue->addCatalogue($this->getCatalogue($locale));
139 1
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 1
    public function import(MessageCatalogueInterface $catalogue)
145
    {
146 1
        $domains = $catalogue->getDomains();
147 1
        foreach ($domains as $domain) {
148 1
            $this->writeCatalogue($catalogue, $catalogue->getLocale(), $domain);
0 ignored issues
show
Compatibility introduced by
$catalogue of type object<Symfony\Component...sageCatalogueInterface> is not a sub-type of object<Symfony\Component...ation\MessageCatalogue>. It seems like you assume a concrete implementation of the interface Symfony\Component\Transl...ssageCatalogueInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
149 1
        }
150 1
    }
151
152
    /**
153
     * Save catalogue back to file.
154
     *
155
     * @param MessageCatalogue $catalogue
156
     * @param string           $domain
157
     */
158 5
    private function writeCatalogue(MessageCatalogue $catalogue, $locale, $domain)
159
    {
160 5
        $resources = $catalogue->getResources();
161 5
        $options = $this->options;
162 5
        $written = false;
163 5
        foreach ($resources as $resource) {
164 3
            $path = (string) $resource;
165 3
            if (preg_match('|/'.$domain.'\.'.$locale.'\.([a-z]+)$|', $path, $matches)) {
166 3
                $options['path'] = str_replace($matches[0], '', $path);
167 3
                $this->writeTranslations($catalogue, $matches[1], $options);
168 3
                $written = true;
169 3
            }
170 5
        }
171
172 5
        if ($written) {
173
            // We have written the translation to a file.
174 3
            return;
175
        }
176
177 2
        $options['path'] = reset($this->dir);
178 2
        $format = isset($options['default_output_format']) ? $options['default_output_format'] : 'xlf';
179 2
        $this->writeTranslations($catalogue, $format, $options);
180 2
    }
181
182
    /**
183
     * @param string $locale
184
     *
185
     * @return MessageCatalogue
186
     */
187 6
    private function getCatalogue($locale)
188
    {
189 6
        if (empty($this->catalogues[$locale])) {
190 6
            $this->loadCatalogue($locale, $this->dir);
191 6
        }
192
193 6
        return $this->catalogues[$locale];
194
    }
195
196
    /**
197
     * Load catalogue from files.
198
     *
199
     * @param string $locale
200
     * @param array  $dirs
201
     */
202 6
    private function loadCatalogue($locale, array $dirs)
203
    {
204 6
        $currentCatalogue = new MessageCatalogue($locale);
205 6
        foreach ($dirs as $path) {
206 6
            if (is_dir($path)) {
207 5
                $this->loader->loadMessages($path, $currentCatalogue);
208 5
            }
209 6
        }
210
211 6
        $this->catalogues[$locale] = $currentCatalogue;
212 6
    }
213
214
    /**
215
     * This method calls the new TranslationWriter::write() if exist,
216
     * otherwise fallback to TranslationWriter::writeTranslations() call
217
     * to avoid BC breaks.
218
     *
219
     * @param MessageCatalogue $catalogue
220
     * @param string           $format
221
     * @param array            $options
222
     */
223 5
    private function writeTranslations(MessageCatalogue $catalogue, $format, array $options)
224
    {
225 5
        if (method_exists($this->writer, 'write')) {
226
            $this->writer->write($catalogue, $format, $options);
227
        } else {
228
            // This method is deprecated since 3.4, maintained to avoid BC breaks
229 5
            $this->writer->writeTranslations($catalogue, $format, $options);
0 ignored issues
show
Bug introduced by
The method writeTranslations() does not seem to exist on object<Symfony\Component...iter\TranslationWriter>.

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...
230
        }
231 5
    }
232
}
233