This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace WeAreNeopix\LaravelModelTranslation\Drivers; |
||
4 | |||
5 | use Illuminate\Support\Str; |
||
6 | use Illuminate\Support\Collection; |
||
7 | use Illuminate\Database\Eloquent\Model; |
||
8 | use Illuminate\Filesystem\FilesystemAdapter as StorageDisk; |
||
9 | use WeAreNeopix\LaravelModelTranslation\Contracts\TranslationDriver; |
||
10 | use WeAreNeopix\LaravelModelTranslation\Jobs\SyncModelLanguageMapping; |
||
11 | use WeAreNeopix\LaravelModelTranslation\Jobs\RemoveModelFromLanguageModelMap; |
||
12 | |||
13 | class JSONTranslationDriver implements TranslationDriver |
||
14 | { |
||
15 | /** @var StorageDisk */ |
||
16 | protected $disk; |
||
17 | |||
18 | public function __construct(StorageDisk $disk) |
||
19 | { |
||
20 | $this->disk = $disk; |
||
21 | } |
||
22 | |||
23 | public function storeTranslationsForModel(Model $model, string $language, array $translations): bool |
||
24 | { |
||
25 | $pathFromDiskRoot = $this->getJsonPathForModel($model, $language); |
||
26 | |||
27 | $content = json_encode($translations); |
||
28 | |||
29 | if (config('translation.json.cache')) { |
||
30 | SyncModelLanguageMapping::dispatch($model, $language); |
||
31 | } |
||
32 | |||
33 | return $this->disk->put($pathFromDiskRoot, $content); |
||
34 | } |
||
35 | |||
36 | public function getTranslationsForModel(Model $model, string $language): array |
||
37 | { |
||
38 | $path = $this->getJsonPathForModel($model, $language); |
||
39 | |||
40 | if (! $this->disk->exists($path)) { |
||
41 | return []; |
||
42 | } |
||
43 | |||
44 | $contents = $this->disk->get($this->getJsonPathForModel($model, $language)); |
||
45 | |||
46 | return json_decode($contents, true); |
||
47 | } |
||
48 | |||
49 | public function getTranslationsForModels(Collection $models, string $language): Collection |
||
50 | { |
||
51 | return $models->mapWithKeys(function (Model $model) use ($language) { |
||
52 | $path = $this->getJsonPathForModel($model, $language); |
||
53 | $translationArray = []; |
||
54 | |||
55 | if ($this->disk->exists($path)) { |
||
56 | $translationsJson = $this->disk->get($this->getJsonPathForModel($model, $language)); |
||
57 | $translationArray = json_decode($translationsJson, true); |
||
58 | } |
||
59 | |||
60 | return [ |
||
61 | $model->getInstanceIdentifier() => $translationArray, |
||
62 | ]; |
||
63 | }); |
||
64 | } |
||
65 | |||
66 | public function getAvailableLanguagesForModel(Model $model): array |
||
67 | { |
||
68 | $path = $this->getJsonPathForModel($model); |
||
69 | |||
70 | return array_map(function ($jsonFile) { |
||
71 | return basename($jsonFile, '.json'); |
||
72 | }, $this->disk->files($path)); |
||
73 | } |
||
74 | |||
75 | public function getModelsAvailableInLanguage(string $modelIdentifier, string $language): array |
||
76 | { |
||
77 | return (config('translation.json.cache')) |
||
78 | ? $this->getModelsAvailableInLanguageFromMap($modelIdentifier, $language) |
||
79 | : $this->parseModelsAvailableInLanguage($modelIdentifier, $language); |
||
80 | } |
||
81 | |||
82 | protected function getModelsAvailableInLanguageFromMap(string $modelIdentifier, string $language): array |
||
83 | { |
||
84 | $map = $this->getLanguageModelMap($language); |
||
85 | |||
86 | return $map[$modelIdentifier] ?? []; |
||
87 | } |
||
88 | |||
89 | protected function parseModelsAvailableInLanguage(string $modelIdentifier, string $language): array |
||
90 | { |
||
91 | $modelDirectory = $this->normalizeModelIdentifier($modelIdentifier); |
||
92 | $existingInstances = collect($this->disk->directories($modelDirectory)); |
||
93 | |||
94 | $language .= '.json'; |
||
95 | |||
96 | $instancesInLanguage = $existingInstances->filter(function ($instanceDirectoryPath) use ($language) { |
||
97 | $path = $instanceDirectoryPath.DIRECTORY_SEPARATOR.$language; |
||
98 | return $this->disk->exists($path); |
||
99 | }); |
||
100 | |||
101 | return $instancesInLanguage->map(function ($instanceDirectory) { |
||
102 | return basename($instanceDirectory); |
||
103 | })->toArray(); |
||
104 | } |
||
105 | |||
106 | public function putTranslationsForModel(Model $model, string $language, array $translations): bool |
||
107 | { |
||
108 | return $this->storeTranslationsForModel($model, $language, $translations); |
||
109 | } |
||
110 | |||
111 | public function patchTranslationsForModel(Model $model, string $language, array $translations): bool |
||
112 | { |
||
113 | $existingTranslations = $this->getTranslationsForModel($model, $language); |
||
114 | |||
115 | $newTranslations = array_merge($existingTranslations, $translations); |
||
116 | |||
117 | return $this->storeTranslationsForModel($model, $language, $newTranslations); |
||
118 | } |
||
119 | |||
120 | public function deleteAllTranslationsForModel(Model $model): bool |
||
121 | { |
||
122 | $path = $this->getJsonPathForModel($model); |
||
123 | |||
124 | if (config('translation.json.cache')) { |
||
125 | RemoveModelFromLanguageModelMap::dispatch($model); |
||
126 | } |
||
127 | |||
128 | return $this->disk->deleteDirectory($path); |
||
129 | } |
||
130 | |||
131 | public function deleteLanguagesForModel(Model $model, array $languages): bool |
||
132 | { |
||
133 | $modelDir = $this->getJsonPathForModel($model).DIRECTORY_SEPARATOR; |
||
134 | foreach ($languages as $language) { |
||
135 | $this->disk->delete($modelDir."{$language}.json"); |
||
136 | |||
137 | if (config('translation.json.cache')) { |
||
138 | SyncModelLanguageMapping::dispatch($model, $language); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | return true; |
||
143 | } |
||
144 | |||
145 | public function deleteAttributesForModel(Model $model, array $attributes, string $language = null): bool |
||
146 | { |
||
147 | $modelDir = $this->getJsonPathForModel($model); |
||
148 | if ($language !== null) { |
||
149 | $paths = [$modelDir.DIRECTORY_SEPARATOR."{$language}.json"]; |
||
150 | if (! $this->disk->exists($paths[0])) { |
||
151 | return true; |
||
152 | } |
||
153 | } else { |
||
154 | $paths = $this->disk->files($modelDir); |
||
155 | } |
||
156 | |||
157 | foreach ($paths as $filePath) { |
||
158 | $translations = json_decode($this->disk->get($filePath), true); |
||
159 | $newTranslations = array_diff_key($translations, array_flip($attributes)); |
||
160 | |||
161 | if (empty($newTranslations)) { |
||
162 | $this->disk->delete($filePath); |
||
163 | } else { |
||
164 | $this->disk->put($filePath, json_encode($newTranslations)); |
||
165 | } |
||
166 | |||
167 | $language = pathinfo($filePath)['filename']; |
||
168 | if (config('translation.json.cache')) { |
||
169 | SyncModelLanguageMapping::dispatch($model, $language); |
||
170 | } |
||
171 | } |
||
172 | |||
173 | return true; |
||
174 | } |
||
175 | |||
176 | |||
177 | public function syncModelsForLanguage(string $language, Model $model) |
||
178 | { |
||
179 | if (in_array($language, $this->getAvailableLanguagesForModel($model))) { |
||
180 | $this->addModelToLanguageMap($model, $language); |
||
181 | } else { |
||
182 | $this->removeModelFromLanguageMap($model, $language); |
||
183 | } |
||
184 | } |
||
185 | |||
186 | protected function addModelToLanguageMap(Model $model, string $language) |
||
187 | { |
||
188 | $modelIdentifier = $model->getModelIdentifier(); |
||
189 | $instanceIdentifier = $model->getInstanceIdentifier(); |
||
190 | $map = $this->getLanguageModelMap($language); |
||
191 | |||
192 | if (!array_key_exists($modelIdentifier, $map)) { |
||
193 | $map[$modelIdentifier] = [$instanceIdentifier]; |
||
194 | $this->saveMap($map, $language); |
||
195 | } elseif (!in_array($instanceIdentifier, $map[$modelIdentifier])) { |
||
196 | $map[$modelIdentifier][] = $instanceIdentifier; |
||
197 | $this->saveMap($map, $language); |
||
198 | } |
||
199 | } |
||
200 | |||
201 | protected function removeModelFromLanguageMap(Model $model, string $language) |
||
202 | { |
||
203 | $modelIdentifier = $model->getModelIdentifier(); |
||
204 | $modelInstanceIdentifier = $model->getInstanceIdentifier(); |
||
205 | $map = $this->getLanguageModelMap($language); |
||
206 | |||
207 | $instances = collect($map[$modelIdentifier] ?? [])->filter(function ($instanceIdentifier) use ($modelInstanceIdentifier) { |
||
208 | return $instanceIdentifier != $modelInstanceIdentifier; |
||
209 | })->values(); |
||
210 | |||
211 | $map[$modelIdentifier] = $instances->toArray(); |
||
212 | |||
213 | $map = $this->removeRedundancyFromMap($map, $language); |
||
0 ignored issues
–
show
|
|||
214 | |||
215 | (empty($map)) ? $this->removeMap($language) : $this->saveMap($map, $language); |
||
216 | } |
||
217 | |||
218 | public function removeModelFromAllLanguages(Model $model) |
||
219 | { |
||
220 | $languages = $this->getAvailableLanguagesForModel($model); |
||
221 | foreach ($languages as $language) { |
||
222 | $this->removeModelFromLanguageMap($model, $language); |
||
223 | } |
||
224 | } |
||
225 | |||
226 | |||
227 | protected function initializeMap(string $language) |
||
228 | { |
||
229 | $this->disk->put($this->mapName($language), json_encode([])); |
||
230 | } |
||
231 | |||
232 | protected function mapName(string $language) |
||
233 | { |
||
234 | return "meta" . DIRECTORY_SEPARATOR . "{$language}.json"; |
||
235 | } |
||
236 | |||
237 | protected function getLanguageModelMap($language) |
||
238 | { |
||
239 | if (!$this->disk->has($this->mapName($language))) { |
||
240 | $this->initializeMap($language); |
||
241 | return []; |
||
242 | } |
||
243 | |||
244 | return json_decode($this->disk->get($this->mapName($language)), true); |
||
245 | } |
||
246 | |||
247 | protected function removeRedundancyFromMap(array $map) { |
||
248 | foreach ($map as $modelIdentifier => $instances) { |
||
249 | if (empty($instances)) { |
||
250 | unset($map[$modelIdentifier]); |
||
251 | } |
||
252 | } |
||
253 | return $map; |
||
254 | } |
||
255 | |||
256 | protected function saveMap(array $map, string $language) |
||
257 | { |
||
258 | $this->disk->put($this->mapName($language), json_encode($map)); |
||
259 | } |
||
260 | |||
261 | protected function removeMap(string $language) |
||
262 | { |
||
263 | $this->disk->delete($this->mapName($language)); |
||
264 | } |
||
265 | |||
266 | |||
267 | protected function getJsonPathForModel(Model $model, string $language = null) |
||
268 | { |
||
269 | $instanceIdentifier = $model->getInstanceIdentifier(); |
||
270 | $modelIdentifier = $this->normalizeModelIdentifier($model->getModelIdentifier()); |
||
271 | |||
272 | $path = $modelIdentifier.DIRECTORY_SEPARATOR.$instanceIdentifier; |
||
273 | if ($language !== null) { |
||
274 | $path .= DIRECTORY_SEPARATOR."{$language}.json"; |
||
275 | } |
||
276 | |||
277 | return $path; |
||
278 | } |
||
279 | |||
280 | protected function normalizeModelIdentifier($modelIdentifier) |
||
281 | { |
||
282 | $modelIdentifier = str_replace('\\', '_', $modelIdentifier); |
||
283 | |||
284 | return Str::slug($modelIdentifier); |
||
285 | } |
||
286 | } |
||
287 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.