Extractor   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 18
eloc 42
dl 0
loc 134
ccs 47
cts 47
cp 1
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A convert() 0 10 2
A addMessages() 0 6 1
A setOnly() 0 4 2
A process() 0 34 6
A applyRoot() 0 10 2
A setExcept() 0 4 2
A __construct() 0 8 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\TranslatorExtractor;
6
7
use Symfony\Component\Console\Output\OutputInterface;
8
use Yiisoft\Files\PathMatcher\PathMatcher;
9
use Yiisoft\Translator\Extractor\TranslationExtractor;
10
use Yiisoft\TranslatorExtractor\Exception\NoCategorySourceConfigException;
11
12
/**
13
 * Extracts translator IDs from files within a given path and writes them into message source given merging
14
 * results with what is already there.
15
 */
16
final class Extractor
17
{
18
    /** @var string[]|null */
19
    private ?array $except = ['./vendor/**'];
20
21
    /** @var string[]|null */
22
    private ?array $only = null;
23
24
    /**
25
     * @var CategorySource[] Array of category message sources indexed by category names.
26
     */
27
    private array $categorySources = [];
28
29
    /**
30
     * @param CategorySource[] $categories
31
     * @param string $translatorCall Translation call to look for.
32
     */
33 21
    public function __construct(array $categories, private string $translatorCall = '->translate')
34
    {
35 21
        if (empty($categories)) {
36 3
            throw new NoCategorySourceConfigException();
37
        }
38
39 18
        foreach ($categories as $category) {
40 18
            $this->categorySources[$category->getName()] = $category;
41
        }
42
    }
43
44
    /**
45
     * Set list of patterns that the files or directories should not match.
46
     *
47
     * @see PathMatcher
48
     *
49
     * @param string[] $except
50
     */
51 10
    public function setExcept(array $except): void
52
    {
53 10
        if (!empty($except)) {
54 3
            $this->except = $except;
55
        }
56
    }
57
58
    /**
59
     * Set list of patterns that the files or directories should match.
60
     *
61
     * @see PathMatcher
62
     *
63
     * @param string[] $only
64
     */
65 10
    public function setOnly(array $only): void
66
    {
67 10
        if (!empty($only)) {
68 3
            $this->only = $only;
69
        }
70
    }
71
72
    /**
73
     * @param string $filesPath Path to files to extract from.
74
     * @param string $defaultCategory Category to use if category isn't set in translation call.
75
     * @param string[] $languages Languages to write extracted IDs to.
76
     */
77 18
    public function process(string $filesPath, string $defaultCategory, array $languages, OutputInterface $output): void
78
    {
79 18
        if (!isset($this->categorySources[$defaultCategory])) {
80 1
            $output->writeln('<comment>Default category was not found in a list of Categories.</comment>');
81 1
            return;
82
        }
83
84 17
        $translationExtractor = new TranslationExtractor(
85 17
            $filesPath,
86 17
            $this->applyRoot($this->only, $filesPath),
87 17
            $this->applyRoot($this->except, $filesPath)
88 17
        );
89
90 17
        $messagesList = $translationExtractor->extract($defaultCategory, $this->translatorCall);
91
92 17
        if (empty($messagesList)) {
93 6
            $output->writeln('<comment>Messages not found</comment>');
94 6
            return;
95
        }
96
97 11
        $output->writeln('Languages: ' . implode(', ', $languages));
98
99
        /**
100
         * @var string $categoryName
101
         * @var array<array-key, array<string, string>|mixed> $messages
102
         */
103 11
        foreach ($messagesList as $categoryName => $messages) {
104 11
            $output->writeln('<info>Category: "' . $categoryName . '", messages found: ' . count($messages) . '.</info>');
105
106
            /** @var array<string, array<string, string>> $convertedMessages */
107 11
            $convertedMessages = $this->convert($messages);
108 11
            foreach ($languages as $language) {
109 11
                $extractCategory = isset($this->categorySources[$categoryName]) ? $categoryName : $defaultCategory;
110 11
                $this->addMessages($extractCategory, $language, $convertedMessages);
111
            }
112
        }
113
    }
114
115 11
    private function addMessages(string $categoryName, string $language, array $messages): void
116
    {
117 11
        $readMessages = $this->categorySources[$categoryName]->readMessages($categoryName, $language);
118
        /** @var array<string, array<string, string>> $convertedMessages */
119 11
        $convertedMessages = array_merge($messages, $readMessages);
120 11
        $this->categorySources[$categoryName]->writeMessages($categoryName, $language, $convertedMessages);
121
    }
122
123 11
    private function convert(array $messages): array
124
    {
125 11
        $returningMessages = [];
126
127
        /** @var array<string, string> $messages */
128 11
        foreach ($messages as $message) {
129 11
            $returningMessages[$message] = ['message' => $message];
130
        }
131
132 11
        return $returningMessages;
133
    }
134
135
    /**
136
     * @param string[]|null $list
137
     *
138
     * @return string[]|null
139
     */
140 17
    private function applyRoot(?array $list, string $rootFolder): ?array
141
    {
142 17
        if (is_array($list)) {
0 ignored issues
show
introduced by
The condition is_array($list) is always true.
Loading history...
143 17
            return array_map(
144 17
                static fn (string $except): string => preg_replace('#^\./#', $rootFolder . '/', $except),
145 17
                $list
146 17
            );
147
        }
148
149 14
        return $list;
150
    }
151
}
152