'integer', ]; public function coursesAsCover(): HasMany { return $this->hasMany(Course::class, 'cover_media_id'); } public function coursesAsPromo(): HasMany { return $this->hasMany(Course::class, 'promo_media_id'); } /** public 磁盘下文件的浏览器绝对地址(与 APP_URL / ASSET_URL 一致,SPA 可从任意端口加载) */ public static function publicAssetUrl(?string $pathRelativeToPublicDisk): ?string { if ($pathRelativeToPublicDisk === null || $pathRelativeToPublicDisk === '') { return null; } $trimmed = ltrim($pathRelativeToPublicDisk, '/'); return URL::asset('storage/'.$trimmed); } /** * @return array */ public function toApiArray(): array { $resolvedUrl = self::publicAssetUrl($this->path); $legacy = $this->attributes['url'] ?? ''; return [ 'id' => $this->id, 'disk' => $this->disk, 'path' => $this->path, 'url' => $resolvedUrl ?? (string) $legacy, 'category' => $this->category, 'original_name' => $this->original_name, 'mime_type' => $this->mime_type, 'size_bytes' => $this->size_bytes, 'created_at' => $this->created_at?->toIso8601String(), ]; } }