$paragraph['id'], 'type' => $paragraph['type'], 'order' => $paragraph['order'], 'content' => $paragraph['content'] ?? [], ]; // 根據類型進行特殊格式化 switch ($paragraph['type']) { case 1: // 純文字 $formatted = $this->formatTextParagraphForForm($formatted); break; case 2: // 區塊文字 $formatted = $this->formatBlockParagraphForForm($formatted); break; case 3: // 表格 $formatted = $this->formatTableParagraphForForm($formatted); break; case 4: // 圖片 $formatted = $this->formatImageParagraphForForm($formatted); break; } // 確保有 item_key if (!isset($formatted['item_key'])) { $formatted['item_key'] = Str::random(); } $formattedParagraphs[] = $formatted; \Log::info("格式化完成:", $formatted); } return $formattedParagraphs; } /** * 格式化純文字段落(載入時) */ protected function formatTextParagraphForForm(array $paragraph): array { // 確保 text_content 結構正確 if (!isset($paragraph['content']['text_content'])) { $paragraph['content']['text_content'] = ['zh_TW' => '', 'en' => '']; } return $paragraph; } /** * 格式化區塊文字段落(載入時) */ protected function formatBlockParagraphForForm(array $paragraph): array { // 確保 text_blocks 結構正確 if (!isset($paragraph['content']['text_blocks'])) { $paragraph['content']['text_blocks'] = []; } // 為每個 text_block 添加必要的欄位 foreach ($paragraph['content']['text_blocks'] as $index => &$block) { if (!isset($block['block_item_key'])) { $block['block_item_key'] = Str::random(); } if (!isset($block['order'])) { $block['order'] = $index + 1; } } return $paragraph; } /** * 格式化表格段落(載入時) */ protected function formatTableParagraphForForm(array $paragraph): array { $content = $paragraph['content']; if (!isset($content['column_count'])) { $content['column_count'] = 2; } if (!isset($content['table_title'])) { $content['table_title'] = ['zh_TW' => '', 'en' => '']; } if (!isset($content['table_description'])) { $content['table_description'] = ['zh_TW' => '', 'en' => '']; } if (!isset($content['simple_table_rows'])) { $content['simple_table_rows'] = []; } // 確保表頭資料結構 $columnCount = $content['column_count']; for ($i = 1; $i <= $columnCount; $i++) { if (!isset($content["head{$i}"])) { $content["head{$i}"] = ['zh_TW' => '', 'en' => '']; } } $paragraph['content'] = $content; return $paragraph; } /** * 格式化圖片段落(載入時) */ protected function formatImageParagraphForForm(array $paragraph): array { // 確保 multiple_images 結構正確 if (!isset($paragraph['content']['multiple_images'])) { $paragraph['content']['multiple_images'] = []; } // 為每個圖片添加必要的欄位 foreach ($paragraph['content']['multiple_images'] as $index => &$image) { if (!isset($image['para_img_item_key'])) { $image['para_img_item_key'] = Str::random(); } if (!isset($image['order'])) { $image['order'] = $index + 1; } } return $paragraph; } /** * 預處理 paragraphs 資料(儲存前使用) */ protected function preprocessParagraphs(array $paragraphs): array { \Log::info("=== 開始預處理 Paragraphs ==="); foreach ($paragraphs as $index => &$paragraph) { \Log::info("處理段落 {$index}:", $paragraph); // 確保基本欄位存在 $paragraph['content'] = $paragraph['content'] ?? []; $paragraph['order'] = $paragraph['order'] ?? ($index + 1); // 根據類型進行特殊處理 switch ($paragraph['type']) { case 1: // 純文字 $paragraph = $this->preprocessTextParagraph($paragraph); break; case 2: // 區塊文字 $paragraph = $this->preprocessBlockParagraph($paragraph); break; case 3: // 表格 $paragraph = $this->preprocessTableParagraph($paragraph); break; case 4: // 圖片 $paragraph = $this->preprocessImageParagraph($paragraph); break; } // 添加處理時間戳 $paragraph['content']['processed_at'] = now()->toISOString(); \Log::info("段落 {$index} 處理完成:", $paragraph); } return $paragraphs; } /** * 處理純文字段落(儲存前) */ protected function preprocessTextParagraph(array $paragraph): array { \Log::info("處理純文字段落"); // 確保文字內容結構正確 if (!isset($paragraph['content']['text_content'])) { $paragraph['content']['text_content'] = ['zh_TW' => '', 'en' => '']; } // 清理 HTML 標籤(如果需要) foreach ($paragraph['content']['text_content'] as $locale => $content) { $paragraph['content']['text_content'][$locale] = $this->cleanHtml($content); } return $paragraph; } /** * 處理區塊文字段落(儲存前) */ protected function preprocessBlockParagraph(array $paragraph): array { \Log::info("處理區塊文字段落"); // 確保有 text_blocks if (!isset($paragraph['content']['text_blocks'])) { $paragraph['content']['text_blocks'] = []; } // 處理每個文字區塊 foreach ($paragraph['content']['text_blocks'] as $index => &$block) { // 確保區塊有必要的欄位 $block['block_item_key'] = $block['block_item_key'] ?? Str::random(); $block['order'] = $block['order'] ?? ($index + 1); // 清理區塊內容 if (isset($block['block_content'])) { foreach ($block['block_content'] as $locale => $content) { $block['block_content'][$locale] = $this->cleanHtml($content); } } } return $paragraph; } /** * 處理表格段落(儲存前) */ protected function preprocessTableParagraph(array $paragraph): array { \Log::info("處理表格段落"); // 確保欄數設定 $columnCount = $paragraph['content']['column_count'] ?? 2; // 確保表頭存在 if (!isset($paragraph['content']['headers'])) { $paragraph['content']['headers'] = ['zh_TW' => [], 'en' => []]; } // 確保表格資料存在 if (!isset($paragraph['content']['simple_table_rows'])) { $paragraph['content']['simple_table_rows'] = []; } // 處理表格資料,確保欄數一致 foreach ($paragraph['content']['simple_table_rows'] as $rowIndex => &$row) { foreach (['zh_TW', 'en'] as $locale) { if (!isset($row[$locale])) { $row[$locale] = []; } // 確保每行都有正確的欄數 for ($i = 1; $i <= $columnCount; $i++) { if (!isset($row[$locale]["col{$i}"])) { $row[$locale]["col{$i}"] = ''; } } // 移除多餘的欄位 for ($i = $columnCount + 1; $i <= 4; $i++) { unset($row[$locale]["col{$i}"]); } } } return $paragraph; } /** * 處理圖片段落(儲存前) */ protected function preprocessImageParagraph(array $paragraph): array { \Log::info("處理圖片段落"); // 確保圖片陣列存在 if (!isset($paragraph['content']['multiple_images'])) { $paragraph['content']['multiple_images'] = []; } // 處理每個圖片 foreach ($paragraph['content']['multiple_images'] as $index => &$image) { $image['para_img_item_key'] = $image['para_img_item_key'] ?? Str::random(); $image['order'] = $image['order'] ?? ($index + 1); // 驗證圖片檔案是否存在 if (isset($image['image_url'])) { // 這裡可以添加圖片驗證邏輯 } } return $paragraph; } /** * 更新 paragraphs 關聯(編輯時使用) */ protected function updateParagraphs(Model $record, array $paragraphs): void { \Log::info("=== 開始更新 Paragraphs 關聯 ==="); // 獲取現有的段落 IDs $existingIds = collect($paragraphs) ->pluck('id') ->filter() ->values() ->toArray(); // 刪除不在列表中的段落 $record->paragraphs() ->whereNotIn('id', $existingIds) ->delete(); \Log::info("已刪除不存在的段落"); // 更新或建立段落 foreach ($paragraphs as $paragraphData) { if (isset($paragraphData['id'])) { // 更新現有段落 $paragraph = $record->paragraphs()->find($paragraphData['id']); if ($paragraph) { $paragraph->update([ 'type' => $paragraphData['type'], 'order' => $paragraphData['order'], 'content' => $paragraphData['content'], ]); \Log::info("更新段落 ID: {$paragraphData['id']}"); } } else { // 建立新段落 $newParagraph = $record->paragraphs()->create([ 'type' => $paragraphData['type'], 'order' => $paragraphData['order'], 'content' => $paragraphData['content'], ]); \Log::info("建立新段落 ID: {$newParagraph->id}"); } } \Log::info("=== Paragraphs 關聯更新完成 ==="); } /** * 建立 paragraphs 關聯(新增時使用) */ protected function createParagraphs(Model $record, array $paragraphs): void { \Log::info("=== 開始建立 Paragraphs 關聯 ==="); foreach ($paragraphs as $paragraphData) { $newParagraph = $record->paragraphs()->create([ 'type' => $paragraphData['type'], 'order' => $paragraphData['order'], 'content' => $paragraphData['content'], ]); \Log::info("建立新段落 ID: {$newParagraph->id}"); } \Log::info("=== Paragraphs 關聯建立完成 ==="); } /** * 清理 HTML 內容 */ protected function cleanHtml(string $html): string { // 這裡可以根據需求自定義清理邏輯 // 例如:移除危險標籤、清理空白等 return trim($html); } /** * 後處理 paragraphs(儲存後使用) */ protected function postProcessParagraphs($paragraphs): void { foreach ($paragraphs as $paragraph) { \Log::info("後處理段落:", [ 'id' => $paragraph->id, 'type' => $paragraph->type, 'content_keys' => array_keys($paragraph->content ?? []) ]); // 這裡可以進行: // - 快取更新 // - 搜尋索引更新 // - 通知發送 // 等後續處理 } } /** * 獲取並格式化關聯資料(載入時的輔助方法) */ protected function loadAndFormatParagraphs(Model $record): array { $paragraphs = $record->paragraphs() ->orderBy('order') ->get() ->toArray(); return $this->formatParagraphsForForm($paragraphs); } /** * 處理表單狀態中的 paragraphs(儲存時的輔助方法) */ protected function processFormParagraphs(): ?array { $formState = $this->form->getState(); if (!isset($formState['paragraphs'])) { return null; } return $this->preprocessParagraphs($formState['paragraphs']); } }