create([ 'type' => $data['type'], 'slug' => $data['slug'], 'name' => $data['name'], 'summary' => $data['summary'] ?? '', 'description' => $data['description'] ?? '', 'author' => $data['author'] ?? '', 'homepage' => $data['homepage'] ?? '', 'icon_url' => $data['icon_url'] ?? '', 'license' => $data['license'] ?? '', 'status' => $data['status'] ?? 'draft', 'is_featured' => (bool) ($data['is_featured'] ?? false), 'sort_order' => (int) ($data['sort_order'] ?? 0), 'download_count' => 0, 'latest_version' => '', ]); $this->syncCategories($package, Arr::get($data, 'categories', [])); return $package->load(['categories', 'latestStableVersion']); }); } public function updatePackage(Package $package, array $data): Package { return DB::transaction(function () use ($package, $data) { $package->fill([ 'name' => $data['name'] ?? $package->name, 'summary' => $data['summary'] ?? $package->summary, 'description' => $data['description'] ?? $package->description, 'author' => $data['author'] ?? $package->author, 'homepage' => $data['homepage'] ?? $package->homepage, 'icon_url' => $data['icon_url'] ?? $package->icon_url, 'license' => $data['license'] ?? $package->license, 'status' => $data['status'] ?? $package->status, 'is_featured' => array_key_exists('is_featured', $data) ? (bool) $data['is_featured'] : $package->is_featured, 'sort_order' => array_key_exists('sort_order', $data) ? (int) $data['sort_order'] : $package->sort_order, ]); $package->save(); if (array_key_exists('categories', $data)) { $this->syncCategories($package, Arr::get($data, 'categories', [])); } $this->refreshLatestVersion($package->fresh()); return $package->fresh(['categories', 'latestStableVersion']); }); } public function updateStatus(Package $package, string $status): Package { $package->status = $status; $package->save(); return $package->fresh(['categories', 'latestStableVersion']); } public function createVersion(Package $package, array $data): Version { return DB::transaction(function () use ($package, $data) { $markAsLatest = array_key_exists('mark_as_latest', $data) ? (bool) $data['mark_as_latest'] : true; if ($markAsLatest) { $package->versions()->update(['is_latest' => false]); } $version = $package->versions()->create([ 'version' => $data['version'], 'changelog' => $data['changelog'] ?? '', 'typecho_min' => $data['typecho_min'] ?? '1.2.0', 'typecho_max' => $data['typecho_max'] ?? '', 'php_min' => $data['php_min'] ?? '7.4', 'php_max' => $data['php_max'] ?? '', 'php_extensions' => json_encode($data['php_extensions'] ?? [], JSON_UNESCAPED_UNICODE), 'package_url' => $data['package_url'], 'package_size' => (int) ($data['package_size'] ?? 0), 'sha256' => strtolower($data['sha256']), 'is_stable' => array_key_exists('is_stable', $data) ? (bool) $data['is_stable'] : true, 'is_latest' => $markAsLatest, 'download_count' => 0, 'published_at' => $data['published_at'] ?? now(), ]); $this->refreshLatestVersion($package->fresh()); return $version->fresh(); }); } public function deleteVersion(Version $version): void { DB::transaction(function () use ($version) { $package = $version->package; $version->delete(); if ($package) { $this->refreshLatestVersion($package->fresh()); } }); } public function refreshLatestVersion(Package $package): void { $latestStable = $package->versions() ->where('is_stable', true) ->orderByDesc('is_latest') ->orderByDesc('published_at') ->orderByDesc('id') ->first(); if ($latestStable) { $package->latest_version = $latestStable->version; $package->save(); return; } $latestAny = $package->versions() ->orderByDesc('is_latest') ->orderByDesc('published_at') ->orderByDesc('id') ->first(); $package->latest_version = $latestAny?->version ?: ''; $package->save(); } private function syncCategories(Package $package, array $categorySlugs): void { $categorySlugs = array_values(array_unique(array_filter(array_map('strval', $categorySlugs)))); if (empty($categorySlugs)) { $package->categories()->sync([]); return; } $categoryIds = Category::query() ->where('type', $package->type) ->whereIn('slug', $categorySlugs) ->pluck('id') ->all(); $package->categories()->sync($categoryIds); } }