Completed
Push — master ( 4e8bc9...f46df8 )
by Tobias
13:01 queued 05:03
created

Importer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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\Bundle\Service;
13
14
use Symfony\Component\Finder\Finder;
15
use Symfony\Component\Translation\MessageCatalogue;
16
use Translation\Bundle\Model\ImportResult;
17
use Translation\Bundle\Model\Metadata;
18
use Translation\Extractor\Extractor;
19
use Translation\Extractor\Model\SourceCollection;
20
use Translation\Extractor\Model\SourceLocation;
21
use Translation\Bundle\Catalogue\Operation\ReplaceOperation;
22
23
/**
24
 * Use extractors to import translations to message catalogues.
25
 *
26
 * @author Tobias Nyholm <[email protected]>
27
 */
28
final class Importer
29
{
30
    /**
31
     * @var Extractor
32
     */
33
    private $extractor;
34
35
    /**
36
     * @var array
37
     */
38
    private $config;
39
40
    /**
41
     * @param Extractor $extractor
42
     */
43 1
    public function __construct(Extractor $extractor)
44
    {
45 1
        $this->extractor = $extractor;
46 1
    }
47
48
    /**
49
     * @param Finder             $finder
50
     * @param MessageCatalogue[] $catalogues
51
     * @param array              $config     {
52
     *
53
     *     @var array $blacklist_domains Blacklist the domains we should exclude. Cannot be used with whitelist.
54
     *     @var array $whitelist_domains Whitelist the domains we should include. Cannot be used with blacklist.
55
     *     @var string $project_root The project root will be removed from the source location.
56
     * }
57
     *
58
     * @return ImportResult
59
     */
60 1
    public function extractToCatalogues(Finder $finder, array $catalogues, array $config = [])
61
    {
62 1
        $this->processConfig($config);
63 1
        $sourceCollection = $this->extractor->extract($finder);
64 1
        $results = [];
65 1
        foreach ($catalogues as $catalogue) {
66 1
            $target = new MessageCatalogue($catalogue->getLocale());
67 1
            $this->convertSourceLocationsToMessages($target, $sourceCollection);
68
69
            // Remove all SourceLocation and State form catalogue.
70 1
            foreach ($catalogue->getDomains() as $domain) {
71 1
                foreach ($catalogue->all($domain) as $key => $translation) {
72 1
                    $meta = $this->getMetadata($catalogue, $key, $domain);
73 1
                    $meta->removeAllInCategory('file-source');
74 1
                    $meta->removeAllInCategory('state');
75 1
                    $this->setMetadata($catalogue, $key, $domain, $meta);
76 1
                }
77 1
            }
78
79 1
            $merge = new ReplaceOperation($target, $catalogue);
80 1
            $result = $merge->getResult();
81 1
            $domains = $merge->getDomains();
82
83
            // Mark new messages as new/obsolete
84 1
            foreach ($domains as $domain) {
85 1
                foreach ($merge->getNewMessages($domain) as $key => $translation) {
86 1
                    $meta = $this->getMetadata($result, $key, $domain);
0 ignored issues
show
Compatibility introduced by
$result 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...
87 1
                    $meta->setState('new');
88 1
                    $this->setMetadata($result, $key, $domain, $meta);
0 ignored issues
show
Compatibility introduced by
$result 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...
89 1
                }
90 1
                foreach ($merge->getObsoleteMessages($domain) as $key => $translation) {
91 1
                    $meta = $this->getMetadata($result, $key, $domain);
0 ignored issues
show
Compatibility introduced by
$result 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...
92 1
                    $meta->setState('obsolete');
93 1
                    $this->setMetadata($result, $key, $domain, $meta);
0 ignored issues
show
Compatibility introduced by
$result 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...
94 1
                }
95 1
            }
96 1
            $results[] = $result;
97 1
        }
98
99 1
        return new ImportResult($results, $sourceCollection->getErrors());
100
    }
101
102
    /**
103
     * @param MessageCatalogue $catalogue
104
     * @param SourceCollection $collection
105
     */
106 1
    private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, SourceCollection $collection)
107
    {
108
        /** @var SourceLocation $sourceLocation */
109 1
        foreach ($collection as $sourceLocation) {
110 1
            $context = $sourceLocation->getContext();
111 1
            $domain = isset($context['domain']) ? $context['domain'] : 'messages';
112
            // Check with white/black list
113 1
            if (!$this->isValidDomain($domain)) {
114
                continue;
115
            }
116
117 1
            $key = $sourceLocation->getMessage();
118 1
            $catalogue->set($key, null, $domain);
119 1
            $trimLength = 1 + strlen($this->config['project_root']);
120
121 1
            $meta = $this->getMetadata($catalogue, $key, $domain);
122 1
            $meta->addCategory('file-source', sprintf('%s:%s', substr($sourceLocation->getPath(), $trimLength), $sourceLocation->getLine()));
123 1
            $this->setMetadata($catalogue, $key, $domain, $meta);
124 1
        }
125 1
    }
126
127
    /**
128
     * @param MessageCatalogue $catalogue
129
     * @param $key
130
     * @param $domain
131
     *
132
     * @return Metadata
133
     */
134 1
    private function getMetadata(MessageCatalogue $catalogue, $key, $domain)
135
    {
136 1
        return new Metadata($catalogue->getMetadata($key, $domain));
137
    }
138
139
    /**
140
     * @param MessageCatalogue $catalogue
141
     * @param $key
142
     * @param $domain
143
     * @param Metadata $metadata
144
     */
145 1
    private function setMetadata(MessageCatalogue $catalogue, $key, $domain, Metadata $metadata)
146
    {
147 1
        $catalogue->setMetadata($key, $metadata->toArray(), $domain);
148 1
    }
149
150
    /**
151
     * @param string $domain
152
     *
153
     * @return bool
154
     */
155 1
    private function isValidDomain($domain)
156
    {
157 1 View Code Duplication
        if (!empty($this->config['blacklist_domains']) && in_array($domain, $this->config['blacklist_domains'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
158
            return false;
159
        }
160 1 View Code Duplication
        if (!empty($this->config['whitelist_domains']) && !in_array($domain, $this->config['whitelist_domains'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
161
            return false;
162
        }
163
164 1
        return true;
165
    }
166
167
    /**
168
     * Make sure the configuration is valid.
169
     *
170
     * @param array $config
171
     */
172 1
    private function processConfig($config)
173
    {
174
        $default = [
175 1
            'project_root' => '',
176 1
            'blacklist_domains' => [],
177 1
            'whitelist_domains' => [],
178 1
        ];
179
180 1
        $config = array_merge($default, $config);
181
182 1 View Code Duplication
        if (!empty($config['blacklist_domains']) && !empty($config['whitelist_domains'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183
            throw new \InvalidArgumentException('Cannot use "blacklist_domains" and "whitelist_domains" at the same time');
184
        }
185
186 1 View Code Duplication
        if (!empty($config['blacklist_domains']) && !is_array($config['blacklist_domains'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
            throw new \InvalidArgumentException('Config parameter "blacklist_domains" must be an array');
188
        }
189
190 1 View Code Duplication
        if (!empty($config['whitelist_domains']) && !is_array($config['whitelist_domains'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
            throw new \InvalidArgumentException('Config parameter "whitelist_domains" must be an array');
192
        }
193
194 1
        $this->config = $config;
195 1
    }
196
}
197