Вход Регистрация
Файл: app/Models/User.php
Строк: 530
<?php

declare(strict_types=1);

namespace 
AppModels;

use 
AppCastsHtmlCast;
use 
AppClassesRegistry;
use 
AppTraitsSearchableTrait;
use 
AppTraitsSortableTrait;
use 
AppTraitsUploadTrait;
use 
CarbonCarbonImmutable;
use 
IlluminateAuthAuthenticatable;
use 
IlluminateAuthMustVerifyEmail;
use 
IlluminateAuthPasswordsCanResetPassword;
use 
IlluminateContractsAuthAccessAuthorizable as AuthorizableContract;
use 
IlluminateContractsAuthAuthenticatable as AuthenticatableContract;
use 
IlluminateContractsAuthCanResetPassword as CanResetPasswordContract;
use 
IlluminateDatabaseEloquentCollection;
use 
IlluminateDatabaseEloquentFactoriesHasFactory;
use 
IlluminateDatabaseEloquentModel;
use 
IlluminateDatabaseEloquentRelationsBelongsTo;
use 
IlluminateDatabaseEloquentRelationsHasMany;
use 
IlluminateDatabaseEloquentRelationsHasOne;
use 
IlluminateDatabaseQueryJoinClause;
use 
IlluminateFoundationAuthAccessAuthorizable;
use 
IlluminateNotificationsNotifiable;
use 
IlluminateSupportFacadesCache;
use 
IlluminateSupportFacadesDB;
use 
IlluminateSupportHtmlString;
use 
IlluminateSupportStr;

/**
 * Class User
 *
 * @property int                  $id
 * @property string               $login
 * @property string               $password
 * @property string               $email
 * @property string               $level
 * @property string               $name
 * @property string               $country
 * @property string               $city
 * @property string               $language
 * @property string               $info
 * @property string               $site
 * @property string               $phone
 * @property string               $gender
 * @property string               $birthday
 * @property int                  $newprivat
 * @property string               $themes
 * @property string               $timezone
 * @property int                  $point
 * @property int                  $money
 * @property string               $status
 * @property string               $color
 * @property string               $avatar
 * @property string               $picture
 * @property int                  $rating
 * @property int                  $posrating
 * @property int                  $negrating
 * @property int                  $sendprivatmail
 * @property int                  $newchat
 * @property bool                 $notify_mention
 * @property bool                 $notify_reply
 * @property bool                 $notify_comment
 * @property string               $apikey
 * @property string|null          $subscribe
 * @property string               $remember_token
 * @property string               $confirm_token
 * @property CarbonImmutable|null $timeban
 * @property CarbonImmutable|null $timebonus
 * @property CarbonImmutable|null $updated_at
 * @property CarbonImmutable      $created_at
 * @property-read Collection<UserData> $data
 */
class User extends Model implements AuthenticatableContractAuthorizableContractCanResetPasswordContract
{
    use 
Authenticatable;
    use 
Authorizable;
    use 
CanResetPassword;

    
/** @use HasFactory<DatabaseFactoriesUserFactory> */
    
use HasFactory;
    use 
MustVerifyEmail;
    use 
Notifiable;
    use 
SearchableTrait;
    use 
SortableTrait;
    use 
UploadTrait;

    public const 
string BOSS 'boss';   // Владелец
    
public const string ADMIN 'admin';  // Админ
    
public const string MODER 'moder';  // Модератор
    
public const string EDITOR 'editor'// Редактор
    
public const string USER 'user';   // Пользователь
    
public const string PENDED 'pended'// Ожидающий
    
public const string BANNED 'banned'// Забаненный

    /**
     * Администраторы
     */
    
public const array ADMIN_GROUPS = [
        
self::EDITOR,
        
self::MODER,
        
self::ADMIN,
        
self::BOSS,
    ];

    
/**
     * Участники
     */
    
public const array USER_GROUPS = [
        
self::USER,
        
self::EDITOR,
        
self::MODER,
        
self::ADMIN,
        
self::BOSS,
    ];

    
/**
     * Все пользователи
     */
    
public const array ALL_GROUPS = [
        
self::BANNED,
        
self::PENDED,
        
self::USER,
        
self::EDITOR,
        
self::MODER,
        
self::ADMIN,
        
self::BOSS,
    ];

    
/**
     * Genders
     */
    
public const string MALE 'male';
    public const 
string FEMALE 'female';

    
/**
     * The name of the "updated at" column.
     *
     * updated_at управляется вручную (время последнего визита, пишет Metrika),
     * поэтому Eloquent не должен трогать его на каждом update()
     */
    
public const ?string UPDATED_AT null;

    
/**
     * The attributes that aren't mass assignable.
     */
    
protected $guarded = [];

    
/**
     * The attributes that should be hidden for arrays.
     */
    
protected $hidden = [
        
'password',
        
'remember_token',
    ];

    
/**
     * Директория загрузки файлов
     */
    
public string $uploadPath '/uploads/pictures';

    
/**
     * Директория загрузки аватаров
     */
    
public string $uploadAvatarPath '/uploads/avatars';

    
/**
     * Morph name
     */
    
public static string $morphName 'users';

    
/**
     * Get the attributes that should be cast.
     */
    
protected function casts(): array
    {
        return [
            
'info'       => HtmlCast::class,
            
'updated_at' => 'datetime',
            
'timeban'    => 'datetime',
            
'timebonus'  => 'datetime',
        ];
    }

    
/**
     * Возвращает поля участвующие в поиске
     */
    
public function searchableFields(): array
    {
        return [
'login''name''info''site''status'];
    }

    
/**
     * Get info
     */
    
public function getInfo(): HtmlString
    
{
        return 
renderHtml($this->info);
    }

    
/**
     * Возвращает список сортируемых полей
     */
    
protected static function sortableFields(): array
    {
        return [
            
'point'   => ['field' => 'point''label' => __('users.assets')],
            
'rating'  => ['field' => 'rating''label' => __('users.reputation')],
            
'money'   => ['field' => 'money''label' => __('users.moneys')],
            
'created' => ['field' => 'created_at''label' => __('main.registration_date')],
            
'updated' => ['field' => 'updated_at''label' => __('users.last_visit')],
        ];
    }

    
/**
     * Is admin
     */
    
public function isAdmin(?string $level null): bool
    
{
        
$level $level ?? self::EDITOR;
        
$levels array_flip(self::ADMIN_GROUPS);

        return isset(
$levels[$this->level], $levels[$level])
            && 
$levels[$this->level] >= $levels[$level];
    }

    
/**
     * Связь с таблицей online
     */
    
public function online(): BelongsTo
    
{
        return 
$this->belongsTo(Online::class, 'id''user_id')->withDefault();
    }

    
/**
     * Возвращает последний бан
     */
    
public function lastBan(): HasOne
    
{
        return 
$this->hasOne(Banhist::class, 'user_id''id')
            ->
whereIn('type', ['ban''change'])
            ->
orderByDesc('created_at')
            ->
withDefault();
    }

    
/**
     * Возвращает дополнительные поля
     */
    
public function data(): HasMany
    
{
        return 
$this->hasMany(UserData::class, 'user_id');
    }

    
/**
     * Возвращает имя или логин пользователя
     */
    
public function getName(): string
    
{
        if (
$this->exists) {
            return 
$this->name ?: $this->login;
        }

        return 
setting('deleted_user');
    }

    
/**
     * Возвращает ссылку на профиль пользователя
     */
    
public function getProfile(): HtmlString
    
{
        if (
$this->id) {
            
$admin null;
            
$name check($this->getName());

            if (
$this->color) {
                
$name '<span style="color:' $this->color '">' $name '</span>';
            }

            if (
in_array($this->levelself::ADMIN_GROUPStrue)) {
                
$admin ' <i class="fas fa-xs fa-star text-info" title="' $this->getLevel() . '"></i>';
            }

            
$html '<a class="section-author fw-bold" href="/users/' $this->login '" data-login="' $this->login '">' $name '</a>';

            return new 
HtmlString($html $admin);
        }

        
$html '<span class="section-author fw-bold" data-login="' setting('deleted_user') . '">' setting('deleted_user') . '</span>';

        return new 
HtmlString($html);
    }

    
/**
     * Возвращает пол пользователя
     */
    
public function getGender(): HtmlString
    
{
        if (
$this->gender === 'female') {
            return new 
HtmlString('<i class="fa fa-female fa-lg"></i>');
        }

        return new 
HtmlString('<i class="fa fa-male fa-lg"></i>');
    }

    
/**
     * Возвращает название уровня по ключу
     */
    
public static function getLevelByKey(string $level): string
    
{
        return 
match ($level) {
            
self::BOSS   => __('main.boss'),
            
self::ADMIN  => __('main.admin'),
            
self::MODER  => __('main.moder'),
            
self::EDITOR => __('main.editor'),
            
self::USER   => __('main.user'),
            
self::PENDED => __('main.pended'),
            
self::BANNED => __('main.banned'),
            default      => 
setting('statusdef'),
        };
    }

    
/**
     * Возвращает уровень пользователя
     */
    
public function getLevel(): string
    
{
        return 
self::getLevelByKey($this->level);
    }

    
/**
     * Возвращает карту login => name для резолва упоминаний
     *
     * @return array<string, string>
     */
    
public static function names(): array
    {
        static 
$names null;

        return 
$names ??= Cache::rememberForever('users', static fn () => self::query()
            ->
whereNotNull('name')
            ->
where('name''!=''')
            ->
pluck('name''login')
            ->
all());
    }

    
/**
     * Is user online
     */
    
public function isOnline(): bool
    
{
        if (! 
$this->id) {
            return 
false;
        }

        static 
$visits;

        if (! 
$visits) {
            
$visits Cache::remember('visit'10, static function () {
                return 
Online::query()
                    ->
whereNotNull('user_id')
                    ->
pluck('user_id''user_id')
                    ->
all();
            });
        }

        return isset(
$visits[$this->id]);
    }

    
/**
     * User online status
     */
    
public function getOnline(): HtmlString
    
{
        
$online '';

        if (
$this->isOnline()) {
            
$online '<div class="user-status bg-success" title="' __('main.online') . '"></div>';
        }

        return new 
HtmlString($online);
    }

    
/**
     * Get last visit
     */
    
public function getVisit(): string
    
{
        if (
$this->isOnline()) {
            
$visit __('main.online');
        } else {
            
$visit dateFixed($this->updated_at);
        }

        return 
$visit;
    }

    
/**
     * Возвращает статус пользователя
     */
    
public function getStatus(): HtmlString|string
    
{
        static 
$status;

        if (! 
$this->id) {
            return 
setting('statusdef');
        }

        if (! 
$status) {
            
$status $this->getStatuses(3600);
        }

        if (isset(
$status[$this->id])) {
            return new 
HtmlString($status[$this->id]);
        }

        return 
setting('statusdef');
    }

    
/**
     * Возвращает аватар пользователя
     */
    
public function getAvatar(): HtmlString
    
{
        if (! 
$this->id) {
            return 
$this->getAvatarGuest();
        }

        if (
$this->avatar && file_exists(public_path($this->avatar))) {
            
$avatar $this->getAvatarImage();
        } else {
            
$avatar $this->getAvatarDefault();
        }

        return new 
HtmlString('<a href="/users/' $this->login '">' $avatar '</a> ');
    }

    
/**
     * Возвращает изображение аватара
     */
    
public function getAvatarImage(): HtmlString
    
{
        if (! 
$this->id) {
            return 
$this->getAvatarGuest();
        }

        if (
$this->avatar && file_exists(public_path($this->avatar))) {
            return new 
HtmlString('<img class="avatar-default rounded-circle" src="' $this->avatar '" alt="">');
        }

        return 
$this->getAvatarDefault();
    }

    
/**
     * Get guest avatar
     */
    
public function getAvatarGuest(): HtmlString
    
{
        return new 
HtmlString('<span class="avatar-default avatar-guest rounded-circle"><i class="fas fa-user"></i></span> ');
    }

    
/**
     * Возвращает аватар для пользователя по умолчанию
     */
    
private function getAvatarDefault(): HtmlString
    
{
        
$name $this->getName();
        
$color '#' substr(dechex(crc32($this->login)), 06);
        
$letter mb_strtoupper(Str::substr($name01), 'utf-8');

        return new 
HtmlString('<span class="avatar-default rounded-circle" style="background:' $color '">' $letter '</span>');
    }

    
/**
     * Кеширует статусы пользователей
     */
    
public function getStatuses(int $seconds): array
    {
        return 
Cache::remember('status'$seconds, static function () {
            
$users self::query()
                ->
select('users.id''users.status''status.name''status.color')
                ->
leftJoin('status', static function (JoinClause $join) {
                    
$join->whereRaw('users.point between status.topoint and status.point');
                })
                ->
where('users.point''>'0)
                ->
toBase()
                ->
get();

            
$statuses = [];
            foreach (
$users as $user) {
                if (
$user->status) {
                    
$statuses[$user->id] = '<span style="color:#ff0000">' check($user->status) . '</span>';
                    continue;
                }

                if (
$user->color) {
                    
$statuses[$user->id] = '<span style="color:' $user->color '">' check($user->name) . '</span>';
                    continue;
                }

                
$statuses[$user->id] = check($user->name);
            }

            return 
$statuses;
        });
    }

    
/**
     * Отправляет приватное сообщение
     */
    
public function sendMessage(?self $authorstring $textbool $withAuthor true): Message
    
{
        return (new 
Message())->createDialogue($this$author$text$withAuthor);
    }

    
/**
     * Возвращает количество писем пользователя
     */
    
public function getCountMessages(): int
    
{
        return 
Dialogue::query()->where('user_id'$this->id)->count();
    }

    
/**
     * Удаляет записи пользователя из всех таблиц
     */
    
public function delete(): ?bool
    
{
        return 
DB::transaction(function () {
            
deleteFile(public_path($this->picture));
            
deleteFile(public_path($this->avatar));

            
Message::query()->where('user_id'$this->id)->delete();
            
Dialogue::query()->where('user_id'$this->id)->delete();
            
Rating::query()->where('user_id'$this->id)->delete();
            
Banhist::query()->where('user_id'$this->id)->delete();

            foreach (
Registry::$onDeleteUser as $callback) {
                
$callback($this);
            }

            return 
parent::delete();
        });
    }

    
/**
     * Updates count messages
     */
    
public function updatePrivate(): void
    
{
        if (
$this->newprivat) {
            
$countDialogues Dialogue::query()
                ->
where('user_id'$this->id)
                ->
where('reading'0)
                ->
count();

            if (
$countDialogues !== $this->newprivat) {
                
$this->update([
                    
'newprivat'      => $countDialogues,
                    
'sendprivatmail' => 0,
                ]);
            }
        }
    }

    
/**
     * Check user banned
     */
    
public function isBanned(): bool
    
{
        return 
$this->level === self::BANNED;
    }

    
/**
     * Check user pended
     */
    
public function isPended(): bool
    
{
        return 
setting('regkeys') && $this->level === self::PENDED;
    }

    
/**
     * Check user active
     */
    
public function isActive(): bool
    
{
        return 
in_array($this->levelself::USER_GROUPStrue);
    }

    
/**
     * Getting daily bonus
     */
    
public function gettingBonus(): void
    
{
        if (
$this->isActive() && (! $this->timebonus || $this->timebonus->lt(now()->subHours(23)))) {
            
$this->increment('money'setting('bonusmoney'));
            
$this->update(['timebonus' => now()]);

            
setFlash('success'__('main.daily_bonus', ['money' => plural(setting('bonusmoney'), setting('moneyname'))]));
        }
    }
}
Онлайн: 0
Реклама