Passed
Pull Request — master (#59)
by
unknown
10:39
created

TranslatableTrait::matchTranslation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 16
rs 10
c 0
b 0
f 0
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
12
/**
13
 * @see TranslatableInterface
14
 *
15
 * @author Gonzalo Vilaseca <[email protected]>
16
 */
17
trait TranslatableTrait
18
{
19
    /**
20
     * Protected to allow access in classes using this Trait or extending provided AbstractTranslatable
21
     * @var Collection<TranslationInterface>
22
     */
23
    protected Collection $translations;
24
    /**
25
     * @var array|TranslationInterface[]
26
     */
27
    protected array $translationsCache = [];
28
    protected ?string $currentLocale = null;
29
    protected ?string $fallbackLocale = null;
30
31
    /**
32
     * @codeCoverageIgnore
33
     */
34
    public function __construct()
35
    {
36
        $this->translations = new ArrayCollection();
37
    }
38
39
    /**
40
     * {@inheritdoc}
41
     *
42
     * @throws \RuntimeException
43
     */
44
    public function getTranslation(?string $locale = null): TranslationInterface
45
    {
46
        $locale = $locale ?: $this->currentLocale;
47
        if (null === $locale) {
48
            throw new \RuntimeException('No locale has been set and current locale is undefined.');
49
        }
50
51
        $translation = $this->matchTranslation($locale);
52
        if (null !== $translation) {
53
            return $translation;
54
        }
55
56
        if ($locale !== $this->fallbackLocale) {
57
            $fallbackTranslation = $this->matchTranslation($this->fallbackLocale);
0 ignored issues
show
Bug introduced by
It seems like $this->fallbackLocale can also be of type null; however, parameter $locale of Locastic\ApiPlatformTran...ait::matchTranslation() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

57
            $fallbackTranslation = $this->matchTranslation(/** @scrutinizer ignore-type */ $this->fallbackLocale);
Loading history...
58
            if (null !== $fallbackTranslation) {
59
                return $fallbackTranslation;
60
            }
61
        }
62
63
        $translation = $this->createTranslation();
64
        $translation->setLocale($locale);
65
66
        $this->addTranslation($translation);
67
68
        $this->translationsCache[$locale] = $translation;
69
70
        return $translation;
71
    }
72
73
    private function matchTranslation(string $locale): ?TranslationInterface
74
    {
75
        if (isset($this->translationsCache[$locale])) {
76
            return $this->translationsCache[$locale];
77
        }
78
79
        $expr = new Comparison('locale', '=', $locale);
80
        $translation = $this->translations->matching(new Criteria($expr))->first();
0 ignored issues
show
Bug introduced by
The method matching() does not exist on Doctrine\Common\Collections\Collection. It seems like you code against a sub-type of said class. However, the method does not exist in Doctrine\Common\Collections\AbstractLazyCollection. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

80
        $translation = $this->translations->/** @scrutinizer ignore-call */ matching(new Criteria($expr))->first();
Loading history...
81
82
        if ($translation instanceof TranslationInterface) {
83
            $this->translationsCache[$locale] = $translation;
84
85
            return $translation;
86
        }
87
88
        return null;
89
    }
90
91
    /**
92
     * @return string[]
93
     */
94
    public function getTranslationLocales(): array
95
    {
96
        $locales = [];
97
98
        foreach ($this->getTranslations() as $translation) {
99
            $locales[] = $translation->getLocale();
100
        }
101
102
        return $locales;
103
    }
104
105
    /**
106
     * @param string $locale
107
     */
108
    public function removeTranslationWithLocale(string $locale): void
109
    {
110
        $translations = $this->getTranslations();
111
112
        foreach ($translations as $translation) {
113
            if ($translation->getLocale() === $locale) {
114
                $this->removeTranslation($translation);
115
116
                $translation->setTranslatable(null);
117
            }
118
        }
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     * @return Collection<TranslationInterface>
124
     */
125
    public function getTranslations(): Collection
126
    {
127
        return $this->translations;
128
    }
129
130
    public function hasTranslation(TranslationInterface $translation): bool
131
    {
132
        return isset($this->translationsCache[$translation->getLocale()])
133
               || $this->translations->containsKey($translation->getLocale());
134
    }
135
136
    public function addTranslation(TranslationInterface $translation): void
137
    {
138
        if (!$this->hasTranslation($translation)) {
139
            $this->translationsCache[$translation->getLocale()] = $translation;
140
141
            $this->translations->set($translation->getLocale(), $translation);
142
            $translation->setTranslatable($this);
0 ignored issues
show
Bug introduced by
$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 ignore-type  annotation

142
            $translation->setTranslatable(/** @scrutinizer ignore-type */ $this);
Loading history...
143
        }
144
    }
145
146
    public function removeTranslation(TranslationInterface $translation): void
147
    {
148
        if ($this->translations->removeElement($translation)) {
149
            unset($this->translationsCache[$translation->getLocale()]);
150
151
            $translation->setTranslatable(null);
152
        }
153
    }
154
155
    public function setCurrentLocale(?string $currentLocale): void
156
    {
157
        $this->currentLocale = $currentLocale;
158
    }
159
160
    public function setFallbackLocale(?string $fallbackLocale): void
161
    {
162
        $this->fallbackLocale = $fallbackLocale;
163
    }
164
165
    /**
166
     * Create resource translation model.
167
     */
168
    abstract protected function createTranslation(): TranslationInterface;
169
}
170