1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Locastic\ApiPlatformTranslationBundle\Model; |
||||
6 | |||||
7 | use Doctrine\Common\Collections\ArrayCollection; |
||||
8 | use Doctrine\Common\Collections\Collection; |
||||
9 | use Doctrine\Common\Collections\Criteria; |
||||
10 | use Doctrine\Common\Collections\Expr\Comparison; |
||||
11 | use Doctrine\Persistence\Proxy; |
||||
12 | |||||
13 | /** |
||||
14 | * @see TranslatableInterface |
||||
15 | * |
||||
16 | * @author Gonzalo Vilaseca <[email protected]> |
||||
17 | * @template T of TranslationInterface |
||||
18 | */ |
||||
19 | trait TranslatableTrait |
||||
20 | { |
||||
21 | /** |
||||
22 | * Protected to allow access in classes using this Trait or extending provided AbstractTranslatable |
||||
23 | * @var Collection<string, TranslationInterface> |
||||
24 | * @psalm-var Collection<string, T> |
||||
25 | */ |
||||
26 | protected Collection $translations; |
||||
27 | |||||
28 | /** |
||||
29 | * @var array|TranslationInterface[] |
||||
30 | * @psalm-var array<string, T> |
||||
31 | */ |
||||
32 | protected array $translationsCache = []; |
||||
33 | protected ?string $currentLocale = null; |
||||
34 | protected ?string $fallbackLocale = null; |
||||
35 | |||||
36 | /** |
||||
37 | * @codeCoverageIgnore |
||||
38 | */ |
||||
39 | public function __construct() |
||||
40 | { |
||||
41 | $this->translations = new ArrayCollection(); |
||||
42 | } |
||||
43 | |||||
44 | /** |
||||
45 | * {@inheritdoc} |
||||
46 | * |
||||
47 | * @return TranslationInterface |
||||
48 | * @psalm-return T |
||||
49 | * |
||||
50 | * @throws \RuntimeException |
||||
51 | */ |
||||
52 | public function getTranslation(?string $locale = null): TranslationInterface |
||||
53 | { |
||||
54 | if ($this instanceof Proxy && !$this->__isInitialized()) { |
||||
55 | $this->__load(); |
||||
56 | } |
||||
57 | |||||
58 | $locale = $locale ?: $this->currentLocale; |
||||
59 | if (null === $locale) { |
||||
60 | throw new \RuntimeException('No locale has been set and current locale is undefined.'); |
||||
61 | } |
||||
62 | |||||
63 | $translation = $this->matchTranslation($locale); |
||||
64 | if (null !== $translation) { |
||||
65 | return $translation; |
||||
66 | } |
||||
67 | |||||
68 | if ($locale !== $this->fallbackLocale && null !== $this->fallbackLocale) { |
||||
69 | $fallbackTranslation = $this->matchTranslation($this->fallbackLocale); |
||||
70 | if (null !== $fallbackTranslation) { |
||||
71 | return $fallbackTranslation; |
||||
72 | } |
||||
73 | } |
||||
74 | |||||
75 | $translation = $this->createTranslation(); |
||||
76 | $translation->setLocale($locale); |
||||
77 | |||||
78 | $this->addTranslation($translation); |
||||
79 | |||||
80 | $this->translationsCache[$locale] = $translation; |
||||
81 | |||||
82 | return $translation; |
||||
83 | } |
||||
84 | |||||
85 | /** |
||||
86 | * @param string $locale |
||||
87 | * @return TranslationInterface|null |
||||
88 | * @psalm-return T|null |
||||
89 | */ |
||||
90 | private function matchTranslation(string $locale): ?TranslationInterface |
||||
91 | { |
||||
92 | if (isset($this->translationsCache[$locale])) { |
||||
93 | return $this->translationsCache[$locale]; |
||||
94 | } |
||||
95 | |||||
96 | $expr = new Comparison('locale', '=', $locale); |
||||
97 | $translation = $this->translations->matching(new Criteria($expr))->first(); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
98 | |||||
99 | if ($translation instanceof TranslationInterface) { |
||||
100 | $this->translationsCache[$locale] = $translation; |
||||
101 | |||||
102 | return $translation; |
||||
103 | } |
||||
104 | |||||
105 | return null; |
||||
106 | } |
||||
107 | |||||
108 | /** |
||||
109 | * @return string[] |
||||
110 | */ |
||||
111 | public function getTranslationLocales(): array |
||||
112 | { |
||||
113 | $locales = []; |
||||
114 | |||||
115 | foreach ($this->getTranslations() as $translation) { |
||||
116 | $locales[] = $translation->getLocale(); |
||||
117 | } |
||||
118 | |||||
119 | return $locales; |
||||
120 | } |
||||
121 | |||||
122 | /** |
||||
123 | * @param string $locale |
||||
124 | */ |
||||
125 | public function removeTranslationWithLocale(string $locale): void |
||||
126 | { |
||||
127 | $translations = $this->getTranslations(); |
||||
128 | |||||
129 | foreach ($translations as $translation) { |
||||
130 | if ($translation->getLocale() === $locale) { |
||||
131 | $this->removeTranslation($translation); |
||||
132 | } |
||||
133 | } |
||||
134 | } |
||||
135 | |||||
136 | /** |
||||
137 | * @return Collection<string, TranslationInterface> |
||||
138 | * @psalm-return Collection<string, T> |
||||
139 | */ |
||||
140 | public function getTranslations(): Collection |
||||
141 | { |
||||
142 | return $this->translations; |
||||
143 | } |
||||
144 | |||||
145 | /** |
||||
146 | * @param TranslationInterface $translation |
||||
147 | * @psalm-param T $translation |
||||
148 | * @return bool |
||||
149 | */ |
||||
150 | public function hasTranslation(TranslationInterface $translation): bool |
||||
151 | { |
||||
152 | return null !== $translation->getLocale() |
||||
153 | && ( |
||||
154 | isset($this->translationsCache[$translation->getLocale()]) |
||||
155 | || $this->translations->containsKey($translation->getLocale()) |
||||
156 | ); |
||||
157 | } |
||||
158 | |||||
159 | /** |
||||
160 | * @param TranslationInterface $translation |
||||
161 | * @psalm-param T $translation |
||||
162 | * @return void |
||||
163 | */ |
||||
164 | public function addTranslation(TranslationInterface $translation): void |
||||
165 | { |
||||
166 | if (!$this->hasTranslation($translation) && null !== $translation->getLocale()) { |
||||
167 | $this->translationsCache[$translation->getLocale()] = $translation; |
||||
168 | |||||
169 | $this->translations->set($translation->getLocale(), $translation); |
||||
170 | $translation->setTranslatable($this); |
||||
0 ignored issues
–
show
$this of type Locastic\ApiPlatformTran...Model\TranslatableTrait is incompatible with the type Locastic\ApiPlatformTran...nslatableInterface|null expected by parameter $translatable of Locastic\ApiPlatformTran...face::setTranslatable() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
171 | } |
||||
172 | } |
||||
173 | |||||
174 | /** |
||||
175 | * @param TranslationInterface $translation |
||||
176 | * @psalm-param T $translation |
||||
177 | * @return void |
||||
178 | */ |
||||
179 | public function removeTranslation(TranslationInterface $translation): void |
||||
180 | { |
||||
181 | if ($this->translations->removeElement($translation) && null !== $translation->getLocale()) { |
||||
182 | unset($this->translationsCache[$translation->getLocale()]); |
||||
183 | |||||
184 | $translation->setTranslatable(null); |
||||
185 | } |
||||
186 | } |
||||
187 | |||||
188 | public function setCurrentLocale(?string $currentLocale): void |
||||
189 | { |
||||
190 | $this->currentLocale = $currentLocale; |
||||
191 | } |
||||
192 | |||||
193 | public function setFallbackLocale(?string $fallbackLocale): void |
||||
194 | { |
||||
195 | $this->fallbackLocale = $fallbackLocale; |
||||
196 | } |
||||
197 | |||||
198 | /** |
||||
199 | * Create resource translation model. |
||||
200 | * |
||||
201 | * @return TranslationInterface $translation |
||||
202 | * @psalm-return T $translation |
||||
203 | */ |
||||
204 | abstract protected function createTranslation(): TranslationInterface; |
||||
205 | } |
||||
206 |