blob: 43a52fab2002983b43d8ac5d09601f3413f6c401 [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 */
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010083 public function getDomains(): array
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020084 {
85 if (null === $this->domains) {
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010086 $domains = [];
87 foreach ([$this->source, $this->target] as $catalogue) {
88 foreach ($catalogue->getDomains() as $domain) {
89 $domains[$domain] = $domain;
90
91 if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) {
92 $domains[$domainIcu] = $domainIcu;
93 }
94 }
95 }
96
97 $this->domains = array_values($domains);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020098 }
99
100 return $this->domains;
101 }
102
103 /**
104 * {@inheritdoc}
105 */
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100106 public function getMessages(string $domain): array
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200107 {
108 if (!\in_array($domain, $this->getDomains())) {
109 throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
110 }
111
112 if (!isset($this->messages[$domain][self::ALL_BATCH])) {
113 $this->processDomain($domain);
114 }
115
116 return $this->messages[$domain][self::ALL_BATCH];
117 }
118
119 /**
120 * {@inheritdoc}
121 */
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100122 public function getNewMessages(string $domain): array
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200123 {
124 if (!\in_array($domain, $this->getDomains())) {
125 throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
126 }
127
128 if (!isset($this->messages[$domain][self::NEW_BATCH])) {
129 $this->processDomain($domain);
130 }
131
132 return $this->messages[$domain][self::NEW_BATCH];
133 }
134
135 /**
136 * {@inheritdoc}
137 */
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100138 public function getObsoleteMessages(string $domain): array
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200139 {
140 if (!\in_array($domain, $this->getDomains())) {
141 throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
142 }
143
144 if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) {
145 $this->processDomain($domain);
146 }
147
148 return $this->messages[$domain][self::OBSOLETE_BATCH];
149 }
150
151 /**
152 * {@inheritdoc}
153 */
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100154 public function getResult(): MessageCatalogueInterface
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200155 {
156 foreach ($this->getDomains() as $domain) {
157 if (!isset($this->messages[$domain])) {
158 $this->processDomain($domain);
159 }
160 }
161
162 return $this->result;
163 }
164
165 /**
166 * @param self::*_BATCH $batch
167 */
168 public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void
169 {
170 // If MessageFormatter class does not exists, intl domains are not supported.
171 if (!class_exists(\MessageFormatter::class)) {
172 return;
173 }
174
175 foreach ($this->getDomains() as $domain) {
176 $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
177 switch ($batch) {
178 case self::OBSOLETE_BATCH: $messages = $this->getObsoleteMessages($domain); break;
179 case self::NEW_BATCH: $messages = $this->getNewMessages($domain); break;
180 case self::ALL_BATCH: $messages = $this->getMessages($domain); break;
181 default: throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH));
182 }
183
184 if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {
185 continue;
186 }
187
188 $result = $this->getResult();
189 $allIntlMessages = $result->all($intlDomain);
190 $currentMessages = array_diff_key($messages, $result->all($domain));
191 $result->replace($currentMessages, $domain);
192 $result->replace($allIntlMessages + $messages, $intlDomain);
193 }
194 }
195
196 /**
197 * Performs operation on source and target catalogues for the given domain and
198 * stores the results.
199 *
200 * @param string $domain The domain which the operation will be performed for
201 */
202 abstract protected function processDomain(string $domain);
203}