dao = $dao; } public function save(array $data): ?\plugin\article\app\model\Content { try { return $this->transaction(function () use ($data) { $payload = $this->normalizePayload($data); $tagIds = $payload['tag_ids'] ?? []; unset($payload['tag_ids']); $model = new Content(); PropertyCopier::copyProperties((object) $payload, $model); $model->save(); $this->syncTags($model, $tagIds); return $model->refresh()?->load(['category', 'tags', 'createds', 'updateds']); }); } catch (\Throwable $e) { throw new AdminException($e->getMessage()); } } public function update($id, $data): void { try { $this->transaction(function () use ($id, $data) { $model = $this->dao->get($id); if (!$model) { throw new AdminException('内容不存在'); } $payload = $this->normalizePayload($data, false); $tagIds = $payload['tag_ids'] ?? null; unset($payload['tag_ids']); PropertyCopier::copyProperties((object) $payload, $model); $model->save(); if ($tagIds !== null) { $this->syncTags($model, $tagIds); } }); } catch (\Throwable $e) { throw new AdminException($e->getMessage()); } } protected function normalizePayload(array $data, bool $isCreate = true): array { $payload = $data; $payload['content_type'] = $payload['content_type'] ?? 'article'; $payload['channel'] = $payload['channel'] ?? 'official'; $payload['visibility'] = isset($payload['visibility']) ? (int) $payload['visibility'] : 1; $payload['source'] = $payload['source'] ?? 'original'; $payload['status'] = isset($payload['status']) ? (int) $payload['status'] : 0; $payload['is_top'] = isset($payload['is_top']) ? (int) $payload['is_top'] : 0; $payload['is_recommend'] = isset($payload['is_recommend']) ? (int) $payload['is_recommend'] : 0; $payload['allow_comment'] = isset($payload['allow_comment']) ? (int) $payload['allow_comment'] : 1; $payload['sort'] = isset($payload['sort']) ? (int) $payload['sort'] : 100; $payload['view_count'] = isset($payload['view_count']) ? (int) $payload['view_count'] : 0; $payload['like_count'] = isset($payload['like_count']) ? (int) $payload['like_count'] : 0; $payload['comment_count'] = isset($payload['comment_count']) ? (int) $payload['comment_count'] : 0; $payload['favorite_count'] = isset($payload['favorite_count']) ? (int) $payload['favorite_count'] : 0; $payload['category_id'] = isset($payload['category_id']) ? (int) $payload['category_id'] : 0; if (!empty($payload['slug'])) { $payload['slug'] = trim((string) $payload['slug']); } elseif ($isCreate && !empty($payload['title'])) { $payload['slug'] = Str::slug((string) $payload['title']); } if (array_key_exists('tag_ids', $payload)) { $payload['tag_ids'] = collect($payload['tag_ids'] ?? []) ->filter(static fn($id) => $id !== null && $id !== '' && $id !== 0 && $id !== '0') ->map(static fn($id) => (int) $id) ->unique() ->values() ->all(); } return $payload; } protected function syncTags(Content $model, array $tagIds): void { $tableName = $model->tags()->getTable(); Db::table($tableName)->where('content_id', $model->id)->delete(); if (empty($tagIds)) { return; } $now = time(); $rows = []; foreach ($tagIds as $tagId) { $rows[] = [ 'id' => (string) Snowflake::generate(), 'content_id' => $model->id, 'tag_id' => (int) $tagId, 'created_at' => $now, ]; } Db::table($tableName)->insert($rows); } }