'datetime', 'password' => 'hashed', 'two_factor_enabled' => 'boolean', ]; protected $appends = ['avatar_url', 'banner_url']; // Auto-generate a unique slug-based username when creating a user without one protected static function boot(): void { parent::boot(); static::creating(function (User $user) { if (empty($user->username)) { $user->username = static::generateUniqueUsername($user->name); } }); } public static function generateUniqueUsername(string $name): string { $base = substr(Str::slug(trim($name)), 0, 18); if ($base === '') { $base = 'user'; } do { $slug = $base . '-' . Str::lower(Str::random(6)); } while (static::where('username', $slug)->exists()); return $slug; } // Returns the channel URL slug — the username, auto-generated and saved if missing public function getChannelAttribute(): string { if (empty($this->username)) { $this->username = static::generateUniqueUsername($this->name); $this->saveQuietly(); } return $this->username; } // Relationships public function videos() { return $this->hasMany(Video::class); } public function likes() { return $this->belongsToMany(Video::class, 'video_likes')->withTimestamps(); } public function views() { return $this->belongsToMany(Video::class, 'video_views')->withTimestamps(); } public function comments() { return $this->hasMany(Comment::class); } public function playlists() { return $this->hasMany(Playlist::class); } public function posts() { return $this->hasMany(\App\Models\Post::class); } public function getAvatarUrlAttribute(): string { if ($this->avatar) { return route('media.avatar', $this->avatar); } return 'https://i.pravatar.cc/150?u='.$this->id; } public function getBannerUrlAttribute(): ?string { if ($this->banner) { return route('media.banner', $this->banner); } return null; } public function sendEmailVerificationNotification(): void { $this->notify(new VerifyEmail); } // Role helper methods public function isSuperAdmin() { return $this->role === 'super_admin'; } public function isAdmin() { return in_array($this->role, ['admin', 'super_admin']); } public function isUser() { return $this->role === 'user' || $this->role === null; } // Users who subscribe TO this channel public function subscribers() { return $this->belongsToMany( User::class, 'user_subscriptions', 'channel_id', 'subscriber_id' )->withPivot('created_at'); } // Channels this user subscribes to public function subscriptions() { return $this->belongsToMany( User::class, 'user_subscriptions', 'subscriber_id', 'channel_id' )->withPivot('created_at'); } public function isSubscribedTo(User $channel): bool { return $this->subscriptions()->where('channel_id', $channel->id)->exists(); } public function getSubscriberCountAttribute(): int { return $this->subscribers()->count(); } // Check if user has any social links public function socialLinks() { return $this->hasMany(UserSocialLink::class)->orderBy('sort_order'); } public function hasSocialLinks() { return $this->socialLinks()->exists(); } // Get formatted website URL public function getWebsiteUrlAttribute() { if (! $this->website) { return null; } // Add https:// if no protocol is specified if (! preg_match('/^https?:\/\//', $this->website)) { return 'https://'.$this->website; } return $this->website; } }