diff --git a/database/factories/TranslationValueFactory.php b/database/factories/TranslationValueFactory.php deleted file mode 100644 index 12bbf631..00000000 --- a/database/factories/TranslationValueFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - - */ - protected $model = TranslationValue::class; - - /** - * Define the model's default state. - */ - public function definition(): array - { - return [ - // - ]; - } -} diff --git a/database/migrations/2024_11_07_195330_create_root_translations_table.php b/database/migrations/2024_11_07_195330_create_root_translations_table.php index 34c3cfaa..8d097988 100644 --- a/database/migrations/2024_11_07_195330_create_root_translations_table.php +++ b/database/migrations/2024_11_07_195330_create_root_translations_table.php @@ -15,9 +15,10 @@ public function up(): void $table->id(); $table->morphs('translatable'); $table->string('language', 8); + $table->json('values')->nullable(); $table->timestamps(); - $table->unique(['translatable_id', 'translatable_type', 'language']); + $table->unique(['translatable_id', 'translatable_type', 'language'], 'root_translatable_language'); }); } diff --git a/database/migrations/2024_11_07_200801_create_root_translation_values_table.php b/database/migrations/2024_11_07_200801_create_root_translation_values_table.php deleted file mode 100644 index 295d3fd4..00000000 --- a/database/migrations/2024_11_07_200801_create_root_translation_values_table.php +++ /dev/null @@ -1,32 +0,0 @@ -id(); - $table->foreignId('translation_id')->constrained('root_translations')->cascadeOnDelete(); - $table->string('key'); - $table->text('value')->nullable(); - $table->timestamps(); - - $table->unique(['translation_id', 'key']); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('root_translation_values'); - } -}; diff --git a/src/Fields/Field.php b/src/Fields/Field.php index 8ba751f7..8782c4bd 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -451,7 +451,12 @@ public function withoutOldValue(): mixed */ public function getValue(Model $model): mixed { - return $model->getAttribute($this->getModelAttribute()); + $attribute = $this->getModelAttribute(); + + return match (true) { + str_contains($attribute, '->') => data_get($model, str_replace('->', '.', $attribute)), + default => $model->getAttribute($this->getModelAttribute()), + }; } /** diff --git a/src/Fields/Translations.php b/src/Fields/Translations.php index f1bd0239..f58a41c6 100644 --- a/src/Fields/Translations.php +++ b/src/Fields/Translations.php @@ -3,8 +3,6 @@ namespace Cone\Root\Fields; use Closure; -use Cone\Root\Models\TranslationValue; -use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; use Illuminate\Validation\Rule; @@ -81,63 +79,6 @@ public function resolveDisplay(Model $related): ?string return parent::resolveDisplay($related); } - /** - * {@inheritdoc} - */ - public function persist(Request $request, Model $model, mixed $value): void - { - $this->resolveHydrate($request, $model, $value); - - $model->saved(static function (Model $model): void { - $model->values->each(function (TranslationValue $value) use ($model): void { - $value->translation()->associate($model)->save(); - }); - }); - } - - /** - * {@inheritdoc} - */ - public function resolveHydrate(Request $request, Model $model, mixed $value): void - { - if (is_null($this->hydrateResolver)) { - $this->hydrateResolver = function (Request $request, Model $model, array $value): void { - foreach ($value as $key => $attr) { - if ($key === 'language') { - $model->setAttribute($key, $attr); - } else { - $related = $model->values->firstWhere('key', $key) ?: $model->values()->make(); - - $cast = $model->related->getCasts()[$key] ?? 'string'; - - $related->mergeCasts(['value' => $cast])->fill(['key' => $key, 'value' => $attr]); - - $model->values->when( - ! $related->exists, - fn (Collection $collection): Collection => $collection->push($related) - ); - } - } - }; - } - - parent::resolveHydrate($request, $model, $value); - } - - /** - * {@inheritdoc} - */ - public function getValueForHydrate(Request $request): mixed - { - return $this->resolveFields($request) - ->mapWithKeys(static function (Field $field) use ($request): mixed { - return [ - $field->getModelAttribute() => $field->getValueForHydrate($request), - ]; - }) - ->all(); - } - /** * {@inheritdoc} */ @@ -153,9 +94,11 @@ public function fields(Request $request): array $model->related->translations->pluck('language')->all() ); - return is_null($model->language) + $options = is_null($model->language) ? $options : array_unique(array_merge([$model->language], $options)); + + return array_combine($options, $options); }) ->required() ->rules(['required', 'string', Rule::in($this->getLanguages())]), diff --git a/src/Interfaces/Models/Translation.php b/src/Interfaces/Models/Translation.php index 6e1bdbed..b44b6f5f 100644 --- a/src/Interfaces/Models/Translation.php +++ b/src/Interfaces/Models/Translation.php @@ -2,7 +2,12 @@ namespace Cone\Root\Interfaces\Models; +use Illuminate\Database\Eloquent\Relations\MorphTo; + interface Translation { - // + /** + * Get the translatable model for the translation. + */ + public function translatable(): MorphTo; } diff --git a/src/Interfaces/Models/TranslationValue.php b/src/Interfaces/Models/TranslationValue.php deleted file mode 100644 index 57e4ca88..00000000 --- a/src/Interfaces/Models/TranslationValue.php +++ /dev/null @@ -1,8 +0,0 @@ - */ - protected $casts = []; + protected $casts = [ + 'values' => 'json', + ]; /** * The attributes that are mass assignable. * * @var array */ - protected $fillable = []; + protected $fillable = [ + 'language', + 'values', + ]; /** * The table associated with the model. @@ -60,12 +64,4 @@ public function translatable(): MorphTo { return $this->morphTo(); } - - /** - * Get the translation values for the translation. - */ - public function values(): HasMany - { - return $this->hasMany(TranslationValue::getProxiedClass()); - } } diff --git a/src/Models/TranslationValue.php b/src/Models/TranslationValue.php deleted file mode 100644 index 9980754f..00000000 --- a/src/Models/TranslationValue.php +++ /dev/null @@ -1,65 +0,0 @@ - - */ - protected $casts = []; - - /** - * The attributes that are mass assignable. - * - * @var array - */ - protected $fillable = [ - 'key', - 'value', - ]; - - /** - * The table associated with the model. - * - * @var string - */ - protected $table = 'root_translation_values'; - - /** - * Get the proxied interface. - */ - public static function getProxiedInterface(): string - { - return Contact::class; - } - - /** - * Create a new factory instance for the model. - */ - protected static function newFactory(): TranslationValueFactory - { - return TranslationValueFactory::new(); - } - - /** - * Get the translation for the translation value. - */ - public function translation(): BelongsTo - { - return $this->belongsTo(Translation::getProxiedClass()); - } -} diff --git a/src/Resources/Resource.php b/src/Resources/Resource.php index 23b2e63d..b2d1e919 100644 --- a/src/Resources/Resource.php +++ b/src/Resources/Resource.php @@ -344,19 +344,11 @@ public function resolveTranslationsField(Request $request): ?Translations return $this->resolveFields($request) ->translatable() ->map(static function (Field $field): Field { - $field = clone $field; - - $field->translatable(false); - - return $field->value(static function (Request $request, Model $model) use ($field): mixed { - $key = $field->getModelAttribute(); - - $cast = $model->related->getCasts()[$key] ?? 'string'; - - return $model->values->firstWhere('key', $key) - ?->mergeCasts(['value' => $cast]) - ?->value; - }); + return (clone $field) + ->translatable(false) + ->setModelAttribute($key = 'values->'.$field->getModelAttribute()) + ->name($key) + ->id($key); }) ->all(); }) diff --git a/src/RootServiceProvider.php b/src/RootServiceProvider.php index a51c0654..176e0093 100644 --- a/src/RootServiceProvider.php +++ b/src/RootServiceProvider.php @@ -41,7 +41,6 @@ class RootServiceProvider extends ServiceProvider Interfaces\Models\Notification::class => Models\Notification::class, Interfaces\Models\Setting::class => Models\Setting::class, Interfaces\Models\Translation::class => Models\Translation::class, - Interfaces\Models\TranslationValue::class => Models\TranslationValue::class, Interfaces\Models\User::class => Models\User::class, Interfaces\Navigation\Registry::class => Navigation\Registry::class, Interfaces\Settings\Registry::class => Settings\Registry::class, diff --git a/src/Traits/Translatable.php b/src/Traits/Translatable.php index 452ea15e..952b41b1 100644 --- a/src/Traits/Translatable.php +++ b/src/Traits/Translatable.php @@ -3,8 +3,6 @@ namespace Cone\Root\Traits; use Cone\Root\Models\Translation; -use Cone\Root\Models\TranslationValue; -use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Support\Facades\App; @@ -18,16 +16,6 @@ public function translations(): MorphMany return $this->morphMany(Translation::getProxiedClass(), 'translatable'); } - /** - * Get the translation values for the model. - */ - public function translationValues(): HasManyThrough - { - return $this->hasManyThrough(TranslationValue::getProxiedClass(), Translation::getProxiedClass(), 'translatable_id') - ->where('root_translations.translatable_type', static::class) - ->select(['*', 'root_translations.language as language']); - } - /** * Translate the value of the given key. */ @@ -35,14 +23,8 @@ public function translate(string $key, ?string $language = null): mixed { $language ??= App::getLocale(); - $value = $this->translationValues->first(function (TranslationValue $value) use ($key, $language): bool { - return $value->key === $key && $value->language === $language; - }); - - if (is_null($value)) { - return $this->getAttribute($key); - } + $translation = $this->translations->firstWhere('language', $language); - return $value->mergeCasts(['key' => $this->getCasts()[$key] ?? 'string'])->value; + return $translation?->values[$key] ?? null; } }