where('collection_name', 'attachments') ->where('custom_properties->legacy_attachmentid', $legacyId) ->latest('id') ->first(); if ($existing && ! $existing->getCustomProperty('pending_sync')) { return $existing; } $post = Post::find($postId); // 游离附件(articleid=0 或对应文章不存在)统一挂到 id=0 占位文章上 if (! $post) { $post = new Post(['id' => 0]); } $properties = [ 'downloads' => (int) ($row['downloads'] ?? 0), 'isimage' => (bool) ($row['isimage'] ?? false), 'legacy_attachmentid' => (int) ($row['attachmentid'] ?? 0), 'legacy_filepath' => $row['filepath'] ?? null, 'legacy_thumb' => $row['thumb_filepath'] ?? null, 'legacy_articleid' => (int) ($row['articleid'] ?? 0), 'pending_sync' => true, ]; $source = $this->locateSource($row['filepath'] ?? null, $attachmentsDir); if ($source && $syncNow) { try { $media = $post->addMedia($source) ->preservingOriginal() ->withCustomProperties($properties) ->usingFileName(basename($row['filename']) ?: basename($source)) ->toMediaCollection('attachments', MediaDisk::name()); $media->setCustomProperty('pending_sync', false); $media->save(); return $media; } catch (\Throwable $e) { // addMedia 可能已插入记录并保存文件,仅缩略图生成失败:找回该记录标记完成 $existing = Media::query() ->where('collection_name', 'attachments') ->where('custom_properties->legacy_attachmentid', (int) ($row['attachmentid'] ?? 0)) ->latest('id') ->first(); if ($existing) { $existing->setCustomProperty('pending_sync', false); $existing->save(); return $existing; } // 文件损坏无法入库时降级为 pending,不中断整批导入 \Illuminate\Support\Facades\Log::warning('附件导入失败,已降级为待同步', [ 'attachment' => $row['attachmentid'] ?? null, 'file' => $source, 'error' => $e->getMessage(), ]); } } return $this->createPendingRecord($post->id, $row, $properties); } private function locateSource(?string $filepath, ?string $attachmentsDir): ?string { if (! $attachmentsDir || ! $filepath) { return null; } $candidate = rtrim($attachmentsDir, '/').'/'.ltrim($filepath, '/'); return is_file($candidate) ? $candidate : null; } private function createPendingRecord(int $postId, array $row, array $properties): Media { $disk = MediaDisk::name(); $media = new Media; $media->model_type = Post::class; $media->model_id = $postId; $media->uuid = (string) Str::uuid(); $media->collection_name = 'attachments'; $media->name = pathinfo($row['filename'] ?? 'attachment', PATHINFO_FILENAME) ?: 'attachment'; $media->file_name = $row['filename'] ?: basename($row['filepath'] ?? 'attachment.bin'); $media->mime_type = $row['filetype'] ?: null; $media->size = (int) ($row['filesize'] ?? 0); $media->disk = $disk; $media->conversions_disk = $disk; $media->manipulations = []; $media->custom_properties = $properties; $media->generated_conversions = []; $media->responsive_images = []; $media->save(); return $media; } }