ldc-groupe/app/Helpers/TranslationHelper.php

112 lines
4.7 KiB
PHP
Raw Permalink Normal View History

<?php
namespace App\Helpers;
use App\Contracts\TranslatableModel;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class TranslationHelper
{
/**
* Get all cached translations.
*
* @param string|null $locale
* @return array
*/
public static function getCachedTranslations(?string $locale = null): array
{
if (is_null($locale)) {
$locale = app()->getLocale();
}
return Cache::remember(sprintf('translations_%s', app()->getLocale()), 86400, function () {
$translator = App::make('translator');
$property = (new \ReflectionClass($translator))->getProperty('loaded');
$property->setAccessible(true);
return $property->getValue($translator);
});
}
/**
* Assert fallback locale translation is present.
*
* @param \App\Contracts\TranslatableModel $model
2026-02-10 15:43:47 +01:00
* @param array $excludeKeys Key of the model we need to keep nullable.
* @return void
* @throws \Illuminate\Validation\ValidationException Translations missing.
*/
public static function validateFallbackTranslations(TranslatableModel $model, array $excludeKeys = []): void
{
$localeFallback = config('app.fallback_locale');
$missingTranslations = [];
2026-02-10 15:43:47 +01:00
$excludeFields = array_merge(['slug'], $excludeKeys);
foreach (Arr::except($model->getTranslations(), $excludeFields) as $key => $value) {
if (!is_null($model->{$key}) && !$model->hasTranslation($key, $localeFallback)) {
$validationTranslations = self::getCachedTranslations()['validation'];
$field = (array_key_exists($key, $validationTranslations['attributes']))
? trans("validation.attributes.$key")
: trans("validation.custom.$key");
$missingTranslations = array_merge($missingTranslations, [
$key => trans_choice('back.missing_translations', 1, [
'field' => $field,
'locales' => Str::upper($localeFallback),
]),
]);
}
}
if ($missingTranslations) {
throw ValidationException::withMessages($missingTranslations);
}
}
/**
2026-02-19 14:06:28 +01:00
* Assert that a value is unique inside a JSON translation field.
*
* The uniqueness can optionally be scoped to another attribute/value pair.
* If $anotherDbAttribute and $anotherValue are provided, the uniqueness
* will be checked only within that scope. Otherwise, the value must be
* globally unique.
*
* @param \Illuminate\Database\Eloquent\Model $model The model instance being validated.
* @param string $value The translated value to check.
* @param string $dbAttribute The JSON column containing translations.
* @param string|null $anotherValue Optional value used to scope uniqueness.
* @param string|null $anotherDbAttribute Optional database column used to scope uniqueness.
* @param string|null $errorAttribute Optional attribute name used in the validation error.
* @param string|null $errorTranslation Optional translated attribute label for the error message.
*
* @return void
2026-02-19 14:06:28 +01:00
*
* @throws \Illuminate\Validation\ValidationException If the value is already used.
*/
public static function assertTranslationFieldIsUnique(
Model $model,
string $value,
string $dbAttribute,
2026-02-19 14:06:28 +01:00
?string $anotherValue = null,
?string $anotherDbAttribute = null,
?string $errorAttribute = null,
?string $errorTranslation = null,
): void {
$modelClass = get_class($model);
2026-02-19 14:06:28 +01:00
$query = $modelClass::query()
->whereKeyNot($model->getKey())
2026-02-19 14:06:28 +01:00
->whereRaw("JSON_SEARCH(`{$dbAttribute}`, 'one', ?) IS NOT NULL", [$value]);
if ($anotherDbAttribute !== null) {
2026-02-19 14:06:28 +01:00
$query->where($anotherDbAttribute, $anotherValue);
}
if ($query->exists()) {
throw ValidationException::withMessages([
$errorAttribute ?? $dbAttribute => trans("validation.unique", [
'attribute' => $errorTranslation ?? trans("validation.attributes.$dbAttribute"),
])
]);
}
}
}