*/ protected $fillable = [ 'package_name', 'slug', 'name', 'description', 'icon_url', 'latest_version', 'rating', 'downloads_count', 'views_count', 'os_requirement', 'category_id', 'developer', 'size', 'mod_info', 'screenshots', 'download_url', 'version_code', 'status', 'featured', ]; /** * Get the attributes that should be cast. * * @return array */ protected function casts(): array { return [ 'rating' => 'decimal:2', 'downloads_count' => 'integer', 'screenshots' => 'array', 'featured' => 'boolean', ]; } /** * The attributes that should be hidden for serialization. * * @var list */ protected $hidden = [ 'created_at', ]; // ---------------------------------------------------- // RELATIONS // ---------------------------------------------------- /** * Get the category that owns the app. */ public function category(): BelongsTo { return $this->belongsTo(Category::class); } /** * Get the versions for the app. */ public function versions(): HasMany { return $this->hasMany(Version::class)->orderBy('version_code', 'desc'); } /** * Get the latest version for the app. */ public function latestVersion(): HasMany { // استخدام ofMany لجلب آخر نسخة بناءً على version_code الأكبر return $this->versions()->one()->ofMany('version_code', 'max'); } // ---------------------------------------------------- // ACCESSORS (MODERN ATTRIBUTES) // ---------------------------------------------------- /** * Get the app's icon URL, providing a placeholder if none is set. */ protected function iconUrl(): Attribute { return Attribute::get(function ($value) { if (empty($value)) { return 'https://placehold.co/128x128/0f172a/ffffff?text=APP'; } if (Str::startsWith($value, ['http://', 'https://'])) { return $value; } return Storage::url($value); }); } /** * Get the app's download URL. */ protected function downloadUrl(): Attribute { return Attribute::get(function ($value) { if (empty($value)) { return '#'; } if (Str::startsWith($value, ['http://', 'https://'])) { return $value; } return Storage::url($value); }); } /** * Get formatted downloads count (e.g., 1.2M, 50K). */ protected function formattedDownloads(): Attribute { return Attribute::get(function () { $count = $this->downloads_count; if ($count >= 1000000) { return number_format($count / 1000000, 1) . 'M'; } elseif ($count >= 1000) { return number_format($count / 1000, 1) . 'K'; } return number_format($count); }); } /** * Get formatted size (e.g., 50.1 MB). */ protected function formattedSize(): Attribute { return Attribute::get(function () { if (!$this->size) { return 'Unknown'; } $bytes = $this->size; $units = ['B', 'KB', 'MB', 'GB']; for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) { $bytes /= 1024; } // ضمان أن يتم إرجاع القيمة حتى لو لم يدخل في الـ loop return round($bytes, 1) . ' ' . $units[$i]; }); } /** * Display updated_at in a human-friendly format. */ protected function formattedLastUpdated(): Attribute { return Attribute::get(function () { return $this->updated_at?->format('M d, Y') ?? __('Unknown'); }); } // ---------------------------------------------------- // SCOPES // ---------------------------------------------------- /** * Scope a query to only include active apps. */ public function scopeActive(Builder $query): Builder { return $query->where('status', 'active'); } /** * Scope a query to only include featured apps. */ public function scopeFeatured(Builder $query): Builder { return $query->where('featured', true); } /** * Scope a query to get latest apps. */ public function scopeLatest(Builder $query): Builder { return $query->orderBy('updated_at', 'desc'); } /** * Scope a query to get most downloaded apps. */ public function scopeMostDownloaded(Builder $query): Builder { return $query->orderBy('downloads_count', 'desc'); } /** * Scope a query to get top rated apps. */ public function scopeTopRated(Builder $query): Builder { return $query->orderBy('rating', 'desc'); } // ---------------------------------------------------- // MISC // ---------------------------------------------------- /** * Get the route key for the model. */ public function getRouteKeyName(): string { return 'slug'; } /** * Get translated name. */ public function getTranslatedName(): string { // استخدام عامل التجميع الصفري لضمان إرجاع نص return $this->name ?? ''; } /** * Get translated description. */ public function getTranslatedDescription(): string { return $this->description ?? ''; } /** * Boot the model, defining automatic slug generation on creation/update. */ protected static function boot(): void { parent::boot(); static::creating(function (self $app) { if (empty($app->slug)) { $app->slug = Str::slug($app->name); } }); static::updating(function (self $app) { // تحديث الـ slug إذا تم تغيير الاسم (حتى لو كان الـ slug موجودًا) if ($app->isDirty('name')) { $app->slug = Str::slug($app->name); } }); } }