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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user