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

declare(strict_types=1);

namespace 
AppTraits;

use 
AppClassesValidator;
use 
AppModelsComment;
use 
AppModelsFile;
use 
AppModelsFlood;
use 
AppModelsUser;
use 
IlluminateDatabaseEloquentModel;
use 
IlluminateDatabaseEloquentRelationsMorphMany;
use 
IlluminateDatabaseQueryJoinClause;
use 
IlluminateHttpJsonResponse;
use 
IlluminateHttpRedirectResponse;
use 
IlluminateHttpRequest;
use 
IlluminateSupportCollection;
use 
IlluminateSupportStr;

trait 
HandlesComments
{
    
/**
     * Связь комментариев модели (morph-имя relate единое по движку)
     *
     * @return MorphMany<Comment, Model>
     */
    
private function commentsRelation(Model $model): MorphMany
    
{
        return 
$model->morphMany(Comment::class, 'relate')->with('relate');
    }

    
/**
     * Возвращает [routeName, params] для редиректа на страницу модели
     */
    
protected function commentableViewRoute(Model $model): array
    {
        
$plural Str::plural(Str::snake(class_basename($this->commentableModelClass)));

        return [
$plural '.view', ['id' => $model->getKey()]];
    }

    
/**
     * Находит родительскую модель по id или прерывает с 404
     */
    
protected function findCommentParent(int $id): Model
    
{
        
$model = ($this->commentableModelClass)::query()->find($id);
        if (! 
$model) {
            
abort(404__('main.record_not_found'));
        }

        return 
$model;
    }

    
/**
     * Проверяет доступность модели (прерывает если active = false)
     */
    
protected function checkCommentableModel(Model $model): void
    
{
        if (
array_key_exists('active'$model->getAttributes()) && ! $model->getAttribute('active')) {
            
abort(200__('main.record_not_active'));
        }
    }

    
/**
     * Возвращает комментарии в виде дерева и файлы для передачи во вью
     */
    
protected function getCommentsData(Model $model): array
    {
        
$user getUser();

        
$files $user
            
File::query()
                ->
where('relate_type'Comment::$morphName)
                ->
where('relate_id'0)
                ->
where('user_id'$user->id)
                ->
orderBy('created_at')
                ->
get()
            : 
collect();

        
$allComments $this->commentsRelation($model)
            ->
withoutGlobalScope('active')
            ->
select('comments.*''polls.vote')
            ->
leftJoin('polls', static function (JoinClause $join) {
                
$join->on('comments.id''polls.relate_id')
                    ->
where('polls.relate_type'Comment::$morphName)
                    ->
where('polls.user_id'getUser('id'));
            })
            ->
orderBy('created_at')
            ->
with(['user''files'])
            ->
get();

        
$comments $this->buildCommentTree($allComments);

        return 
compact('comments''files');
    }

    
/**
     * Строит дерево комментариев из плоской коллекции
     */
    
protected function buildCommentTree(Collection $all, ?int $parentId null): Collection
    
{
        return 
$all
            
->where('parent_id'$parentId)
            ->
map(function (Comment $comment) use ($all) {
                
$comment->setRelation('children'$this->buildCommentTree($all$comment->id));

                return 
$comment;
            })
            ->
values();
    }

    
/**
     * Редирект на страницу с якорем на добавленный комментарий
     */
    
protected function redirectAfterCommentAdded(Model $modelint $commentId): RedirectResponse
    
{
        [
$route$params] = $this->commentableViewRoute($model);

        return 
redirect()
            ->
route($route$params)
            ->
withFragment('comment_' $commentId);
    }

    
/**
     * Добавление комментария (POST-обработчик)
     */
    
public function storeComment(int $idRequest $requestValidator $validatorFlood $flood): RedirectResponse|JsonResponse
    
{
        
$model $this->findCommentParent($id);

        [
$viewRoute$viewParams] = $this->commentableViewRoute($model);

        
$user getUser();
        
$msg $request->input('msg');

        
$validator
            
->true($user__('main.not_authorized'))
            ->
false($flood->isFlood(), ['msg' => __('validator.flood', ['sec' => $flood->getPeriod()])])
            ->
length($msgsetting('comment_text_min'), setting('comment_text_max'), ['msg' => __('validator.text')]);

        
$validator->empty($model->getAttribute('closed'), ['msg' => __('main.closed_comments')]);

        if (
$validator->isValid()) {
            
$msg antimat($msg);

            
$parentId null;
            
$depth 0;
            
$parentComment $request->input('parent_id')
                ? 
Comment::query()->find((int) $request->input('parent_id'))
                : 
null;

            if (
$parentComment && $parentComment->relate_id === $model->getKey()) {
                if (
$parentComment->depth >= setting('comment_depth')) {
                    
$parentId $parentComment->parent_id;
                    
$depth $parentComment->depth;
                } else {
                    
$parentId $parentComment->id;
                    
$depth $parentComment->depth 1;
                }
            }

            
$comment $this->commentsRelation($model)->create([
                
'text'      => $msg,
                
'user_id'   => $user->id,
                
'parent_id' => $parentId,
                
'depth'     => $depth,
                
'ip'        => getIp(),
                
'brow'      => getBrowser(),
            ]);

            
File::query()
                ->
where('relate_type'Comment::$morphName)
                ->
where('relate_id'0)
                ->
where('user_id'$user->id)
                ->
update(['relate_id' => $comment->id]);

            
$user->increment('point'setting('comment_point'));
            
$user->increment('money'setting('comment_money'));

            
$model->increment('count_comments');

            
$flood->saveState();

            
$this->notifyAfterComment($model$comment$msg$viewRoute$viewParams$parentComment);

            if (
$request->wantsJson()) {
                return 
response()->json(['redirect' => route($viewRoute$viewParams) . '#comment_' $comment->id]);
            }

            
setFlash('success'__('main.comment_added_success'));

            return 
$this->redirectAfterCommentAdded($model$comment->id);
        }

        if (
$request->wantsJson()) {
            return 
response()->json(['errors' => $validator->getErrors()], 422);
        }

        
setInput($request->all());
        
setFlash('danger'$validator->getErrors());

        return 
redirect()->route($viewRoute$viewParams);
    }

    
/**
     * Уведомление о добавлении комментария
     */
    
private function notifyAfterComment(Model $modelComment $commentstring $msgstring $viewRoute, array $viewParams, ?Comment $parentComment): void
    
{
        
$url route($viewRoute$viewParamsfalse) . '#comment_' $comment->id;
        
$title = (string) $model->getAttribute('title');
        
$skip = [];

        
$owner $model->getRelationValue('user');
        
$owner $owner instanceof User && $owner->exists $owner null;
        if (
$owner && $owner->notify_comment && $owner->id !== getUser('id') && $parentComment === null) {
            
$login getUser('login');
            
$owner->sendMessage(nulltextNotice('comment_added'compact('login''url''title') + ['text' => $msg]));
            
$skip[] = $owner->login;
        }

        
$replyUser $parentComment?->user?->exists $parentComment->user null;
        if (
$replyUser && ! in_array($replyUser->login$skiptrue) && $replyUser->notify_reply && $replyUser->id !== getUser('id')) {
            
$login getUser('login');
            
$replyUser->sendMessage(nulltextNotice('comment_reply'compact('login''url''title') + ['text' => $msg]));
            
$skip[] = $replyUser->login;
        }

        
sendNotify($msg$url$title$skip);
    }
}
Онлайн: 0
Реклама