UserController.php 5.71 KB
<?php

namespace App\Http\Container\AppSection\Controllers\Recommend;

use App\Enums\UserStatusEnum;
use App\Helpers\JsonResource;
use App\Models\User;
use App\Models\UserAction;
use App\Models\UserFollowRelation;
use App\Models\UserTagRelation;
use App\Support\Controller;
use Auth;
use Cache;
use Illuminate\Cache\TaggedCache;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Str;

class UserController extends Controller
{
    private TaggedCache $cache;

    protected ?User $user;

    public function __construct()
    {
        $this->middleware(['auth.check:app', 'emptyToNull']);
        $this->cache = Cache::tags('recommend_user');
    }

    /**
     * @return int
     */
    protected function getUserKey(): int
    {
        return $this->user?->getKey() ?? 0;
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \Random\RandomException
     */
    public function __invoke(Request $request): JsonResponse
    {
        $page       = $request->integer('page', 1);
        $pageSize   = $request->integer('size', 20);
        $identifier = $request->get('identifier') ?? Str::uuid()->toString();

        $this->user = Auth::user();
        $page === 1 && $this->cache->delete($identifier);
        $recommendIds = $this->getRecommendIds($identifier);
        $pageIds      = $recommendIds->forPage($page, $pageSize);
        $pageCount    = $recommendIds->count();


        return JsonResource::success(JsonResource::SUCCESS, [
            'data'       => $pageIds->isEmpty() ? [] : $this->get($pageIds->toArray()),
            'count'      => $pageCount,
            'identifier' => $identifier,
        ]);

    }

    /**
     * @param array $fieldIds
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function get(array $fieldIds): Collection
    {
        return User::orderByField('id', $fieldIds)
            ->select(['id', 'nick_name', 'avatar', 'identity', 'user_tag_id'])
            ->with(['authTags:id,name', 'userTag:id,name,icon,frame'])
            ->addSelect(['is_follow' => UserFollowRelation::selectRaw('IFNULL(COUNT(*),0)')->whereColumn('users.id', 'following_id')->where('follower_id', $this->getUserKey())])
            ->get();
    }


    /**
     * @throws \Random\RandomException
     */
    protected function getRecommendIds(string $key): Collection
    {
        $tagIds  = request()?->input('tag', []);
        $starIds = request()?->input('star', []);
        $type    = match (request()?->integer('type', 1)) {
            1 => [1, 3],
            2 => [2, 3],
            default => NULL
        };
        $search  = request()?->input('search', []);

        $tagLink = UserTagRelation::select('user_id')->where('type', 4)->whereIn('tag_id', $tagIds)->groupBy('user_id');

        $builder = User::select('id')
            ->when($search, fn(Builder $query) => $query->where('nick_name', 'like', '%' . $search . '%'))
            ->when($type, fn(Builder $builder) => $builder->whereIn('identity', $type))
            ->when(
                filled($tagIds) && filled($starIds),
                fn(Builder $query) => $query->leftJoinSub($tagLink, 't', 't.user_id', 'users.id')->where(fn(Builder $query) => $query->whereIn('user_tag_id', $starIds)->orWhereNotNull('t.user_id')),
                fn(Builder $query) => $query->when(filled($tagIds), fn(Builder $query) => $query->joinSub($tagLink, 't', 't.user_id', 'users.id'))->when(filled($starIds), fn(Builder $query) => $query->whereIn('user_tag_id', $starIds))
            )
            ->where('audit_status', 1)
            ->where('status', UserStatusEnum::ACTIVATE);

        if (!$this->cache->has($key)) {
            $this->cache->put($key, match (request('sort_field')) {
                'register' => $this->getRegisterIds($builder),
                'latest' => $this->getLastIds($builder),
                'activation' => $this->getActivationIds($builder),
                default => $this->getRandomIds($builder)
            });
        }

        return $this->cache->get($key);
    }

    /**
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \Illuminate\Support\Collection
     */
    protected function getRegisterIds(Builder $builder): Collection
    {
        return $builder->latest('id')->pluck('id');
    }

    /**
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \Illuminate\Support\Collection
     */
    protected function getLastIds(Builder $builder): Collection
    {
        return $builder->latest('audit_at')->pluck('id');
    }

    /**
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \Illuminate\Support\Collection
     */
    protected function getActivationIds(Builder $builder): Collection
    {
        return $builder->addSelect([
            'login_count' => UserAction::selectRaw('IFNULL(COUNT(DISTINCT DATE(actions.created_at)),0)')->whereColumn('users.id', 'actions.user_id')
                ->where('event_name', 'me_click')->where('actions.created_at', '>=', now()->subDays(30)->toDateString()),
        ])->latest('login_count')->pluck('id');
    }

    /**
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \Illuminate\Support\Collection
     * @throws \Random\RandomException
     */
    protected function getRandomIds(Builder $builder): Collection
    {
        return $builder->addSelect(['user_tag_id'])->with('userTag')->get()
            ->each(fn(User $user) => $user->setAttribute('score', $user->getRelation('userTag') ? random_int(100, 200) : random_int(80, 160)))
            ->sortByDesc('score')->values()->pluck('id');
    }
}