blob: 9869fbb8bb34ec385b8d34880f6dd58586188ab1 [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Catalogue;
13
14use Symfony\Component\Translation\Exception\InvalidArgumentException;
15use Symfony\Component\Translation\Exception\LogicException;
16use Symfony\Component\Translation\MessageCatalogue;
17use Symfony\Component\Translation\MessageCatalogueInterface;
18
19/**
20 * Base catalogues binary operation class.
21 *
22 * A catalogue binary operation performs operation on
23 * source (the left argument) and target (the right argument) catalogues.
24 *
25 * @author Jean-François Simon <contact@jfsimon.fr>
26 */
27abstract class AbstractOperation implements OperationInterface
28{
29 public const OBSOLETE_BATCH = 'obsolete';
30 public const NEW_BATCH = 'new';
31 public const ALL_BATCH = 'all';
32
33 protected $source;
34 protected $target;
35 protected $result;
36
37 /**
38 * @var array|null The domains affected by this operation
39 */
40 private $domains;
41
42 /**
43 * This array stores 'all', 'new' and 'obsolete' messages for all valid domains.
44 *
45 * The data structure of this array is as follows:
46 *
47 * [
48 * 'domain 1' => [
49 * 'all' => [...],
50 * 'new' => [...],
51 * 'obsolete' => [...]
52 * ],
53 * 'domain 2' => [
54 * 'all' => [...],
55 * 'new' => [...],
56 * 'obsolete' => [...]
57 * ],
58 * ...
59 * ]
60 *
61 * @var array The array that stores 'all', 'new' and 'obsolete' messages
62 */
63 protected $messages;
64
65 /**
66 * @throws LogicException
67 */
68 public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
69 {
70 if ($source->getLocale() !== $target->getLocale()) {
71 throw new LogicException('Operated catalogues must belong to the same locale.');
72 }
73
74 $this->source = $source;
75 $this->target = $target;
76 $this->result = new MessageCatalogue($source->getLocale());
77 $this->messages = [];
78 }
79
80 /**
81 * {@inheritdoc}
82 */
83 public function getDomains()
84 {
85 if (null === $this->domains) {
86 $this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
87 }
88
89 return $this->domains;
90 }
91
92 /**
93 * {@inheritdoc}
94 */
95 public function getMessages(string $domain)
96 {
97 if (!\in_array($domain, $this->getDomains())) {
98 throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
99 }
100
101 if (!isset($this->messages[$domain][self::ALL_BATCH])) {
102 $this->processDomain($domain);
103 }
104
105 return $this->messages[$domain][self::ALL_BATCH];
106 }
107
108 /**
109 * {@inheritdoc}
110 */
111 public function getNewMessages(string $domain)
112 {
113 if (!\in_array($domain, $this->getDomains())) {
114 throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
115 }
116
117 if (!isset($this->messages[$domain][self::NEW_BATCH])) {
118 $this->processDomain($domain);
119 }
120
121 return $this->messages[$domain][self::NEW_BATCH];
122 }
123
124 /**
125 * {@inheritdoc}
126 */
127 public function getObsoleteMessages(string $domain)
128 {
129 if (!\in_array($domain, $this->getDomains())) {
130 throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
131 }
132
133 if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) {
134 $this->processDomain($domain);
135 }
136
137 return $this->messages[$domain][self::OBSOLETE_BATCH];
138 }
139
140 /**
141 * {@inheritdoc}
142 */
143 public function getResult()
144 {
145 foreach ($this->getDomains() as $domain) {
146 if (!isset($this->messages[$domain])) {
147 $this->processDomain($domain);
148 }
149 }
150
151 return $this->result;
152 }
153
154 /**
155 * @param self::*_BATCH $batch
156 */
157 public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void
158 {
159 // If MessageFormatter class does not exists, intl domains are not supported.
160 if (!class_exists(\MessageFormatter::class)) {
161 return;
162 }
163
164 foreach ($this->getDomains() as $domain) {
165 $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
166 switch ($batch) {
167 case self::OBSOLETE_BATCH: $messages = $this->getObsoleteMessages($domain); break;
168 case self::NEW_BATCH: $messages = $this->getNewMessages($domain); break;
169 case self::ALL_BATCH: $messages = $this->getMessages($domain); break;
170 default: throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH));
171 }
172
173 if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {
174 continue;
175 }
176
177 $result = $this->getResult();
178 $allIntlMessages = $result->all($intlDomain);
179 $currentMessages = array_diff_key($messages, $result->all($domain));
180 $result->replace($currentMessages, $domain);
181 $result->replace($allIntlMessages + $messages, $intlDomain);
182 }
183 }
184
185 /**
186 * Performs operation on source and target catalogues for the given domain and
187 * stores the results.
188 *
189 * @param string $domain The domain which the operation will be performed for
190 */
191 abstract protected function processDomain(string $domain);
192}