Enhance translation handling in EditPage and TranslationTabs: Implemented eager loading for translations to optimize performance and avoid N+1 query issues. Updated the EditPage mount method to load translations, and modified the fillFromRecord method in TranslationTabs to utilize eager-loaded translations. Disabled old format conversion in mutateFormDataBeforeFill to prevent memory exhaustion with nested arrays, ensuring data integrity while maintaining original format.

This commit is contained in:
Ümit Tunç
2025-11-01 16:40:20 -03:00
parent 5fb74384ce
commit af0d7964ca
3 changed files with 27 additions and 57 deletions
@@ -167,10 +167,20 @@ class TranslationTabs
$languages = Language::active()->ordered()->get();
$fields = $record->getTranslatableFields();
// Eager load all translations to avoid N+1 queries
$allTranslations = $record->translations()
->whereIn('language_code', $languages->pluck('code'))
->whereIn('field_name', $fields)
->get()
->groupBy('language_code');
foreach ($languages as $language) {
$data['translations'][$language->code] = [];
$languageTranslations = $allTranslations->get($language->code) ?? collect();
$translationsByField = $languageTranslations->keyBy('field_name');
foreach ($fields as $field) {
$translation = $record->getTranslation($field, $language->code, false);
$translation = $translationsByField->get($field);
if ($translation) {
$data['translations'][$language->code][$field] = $translation->field_value;
}
@@ -21,6 +21,14 @@ class EditPage extends EditRecord
public bool $autoSaveEnabled = false;
public ?string $lastAutoSaveTime = null;
public function mount($record): void
{
parent::mount($record);
// Eager load translations to avoid N+1 queries
$this->record->load('translations');
}
public function getTitle(): string
{
return __('pages.edit');
@@ -88,60 +96,12 @@ class EditPage extends EditRecord
protected function mutateFormDataBeforeFill(array $data): array
{
// Load existing translations
// Load existing translations with eager loading
$translationData = TranslationTabs::fillFromRecord($this->record);
// Convert old format sections to new format
if (isset($data['sections']) && is_array($data['sections'])) {
$data['sections'] = array_map(function ($section) {
if (!isset($section['data']) || !is_array($section['data'])) {
return $section;
}
// Check if already in new format
$firstKey = array_key_first($section['data']);
if (is_numeric($firstKey) && isset($section['data'][$firstKey]['key'])) {
return $section;
}
// Convert old format to new format
$newData = [];
foreach ($section['data'] as $key => $value) {
$type = 'text'; // Default
// Auto-detect type based on key name and value
if (str_contains($key, 'image') || str_contains($key, 'photo')) {
$type = 'image';
} elseif (str_contains($key, 'icon') && is_string($value) && str_starts_with($value, 'assets/')) {
$type = 'image';
} elseif (str_contains($key, 'color')) {
$type = 'color';
} elseif (str_contains($key, 'url') || str_contains($key, 'link')) {
$type = 'url';
} elseif (is_string($value) && (str_contains($key, 'subtitle') || str_contains($key, 'description'))) {
$type = 'textarea';
} elseif (is_string($value) && str_contains($value, '<') && str_contains($value, '>') && strlen($value) > 200) {
$type = 'html'; // Long HTML content
} elseif (is_string($value) && strlen($value) > 100) {
$type = 'textarea';
} elseif (is_array($value)) {
$type = 'array';
} elseif (is_bool($value)) {
$type = 'boolean';
}
// 'title' gibi kısa HTML snippet'leri 'text' olarak kalır
$newData[] = [
'key' => $key,
'type' => $type,
'value' => $value,
];
}
$section['data'] = $newData;
return $section;
}, $data['sections']);
}
// DISABLED: Old format conversion causes memory exhaustion with nested arrays
// Leave sections as-is; they work fine in their original format
// If needed, conversion can be done manually or in a separate migration
return array_merge($data, $translationData);
}
@@ -526,12 +526,13 @@ class PageForm
->addActionLabel(__('pages.section_add'))
->reorderable()
->collapsible()
->collapsed()
->itemLabel(fn (array $state): ?string => isset($state['type']) ? __('pages.section_type_' . $state['type']) : 'Bölüm')
->columnSpanFull(),
])
->columnSpanFull()
->collapsible(true)
->collapsed(false),
->collapsed(true),
// Dynamic Template System
Section::make(__('pages.form_section_header_template'))
@@ -746,9 +747,8 @@ class PageForm
->addActionLabel(__('pages.add_template_section'))
->reorderable()
->collapsible()
->itemLabel(fn (array $state): ?string =>
SectionTemplate::find($state['section_template_id'] ?? null)?->title ?? __('pages.template_section')
)
->collapsed()
->itemLabel(__('pages.template_section'))
->columnSpanFull(),
])
->columnSpanFull()