-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
init comment system #7
Changes from all commits
5dcad48
8a447ed
39340ba
47ce187
af1da2d
6c2d774
b7810c6
9fd7d05
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
<?php | ||
|
||
namespace App\Http\Controllers; | ||
|
||
use App\Models\Comment; | ||
use App\Models\Post; | ||
use Illuminate\Http\Request; | ||
|
||
class CommentsController extends Controller | ||
{ | ||
/** | ||
* @param \App\Models\Post $post | ||
* @param array $data | ||
* | ||
* @return string | ||
*/ | ||
public function show(Post $post, array $data = []) | ||
{ | ||
return view('components.comments', array_merge($data, [ | ||
'model' => $post, | ||
])) | ||
->fragmentIf(!request()->isMethod('GET'), 'comments'); | ||
} | ||
|
||
/** | ||
* @param \Illuminate\Http\Request $request | ||
* | ||
* @return string | ||
*/ | ||
public function store(Request $request) | ||
{ | ||
$this->authorize('create', Comment::class); | ||
|
||
$request->validate([ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В Form Request? |
||
'commentable_type' => 'required|sometimes|string', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Я предпочитаю везде массив для единообразия, потому что часто, надо Rule или кастом добавлять, что думаете? |
||
'commentable_id' => 'required|string|min:1', | ||
'message' => 'required|string', | ||
]); | ||
|
||
$model = $request->commentable_type::findOrFail($request->commentable_id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Я конечно такую магию не особо люблю, тут комментариями хотя бы примеры добавить что может содержать |
||
|
||
$comment = new Comment(); | ||
|
||
$comment->commenter()->associate($request->user()); | ||
|
||
$comment->commentable()->associate($model); | ||
|
||
$comment->fill([ | ||
'comment' => $request->input('message'), | ||
'approved' => true, | ||
])->save(); | ||
|
||
return $this->show($model); | ||
} | ||
|
||
/** | ||
* @param \App\Models\Comment $comment | ||
* | ||
* @return string | ||
*/ | ||
public function showReply(Comment $comment) | ||
{ | ||
return $this->show($comment->commentable, [ | ||
'reply' => $comment->getKey(), | ||
]); | ||
} | ||
|
||
/** | ||
* @param \App\Models\Comment $comment | ||
* | ||
* @return string | ||
*/ | ||
public function showEdit(Comment $comment) | ||
{ | ||
return $this->show($comment->commentable, [ | ||
'edit' => $comment->getKey(), | ||
]); | ||
} | ||
|
||
/** | ||
* @param \Illuminate\Http\Request $request | ||
* @param \App\Models\Comment $comment | ||
* | ||
* @return string | ||
*/ | ||
public function reply(Request $request, Comment $comment) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :Comment |
||
{ | ||
$this->authorize('reply', $comment); | ||
|
||
$request->validate([ | ||
'message' => 'required|string', | ||
]); | ||
|
||
$reply = new Comment([ | ||
'comment' => $request->input('message'), | ||
'approved' => true, | ||
]); | ||
|
||
$reply->commenter()->associate($request->user()); | ||
$reply->commentable()->associate($comment->commentable); | ||
$reply->parent()->associate($comment); | ||
$reply->save(); | ||
|
||
return $this->show($comment->commentable); | ||
} | ||
|
||
/** | ||
* @param \Illuminate\Http\Request $request | ||
* @param \App\Models\Comment $comment | ||
* | ||
* @return string | ||
*/ | ||
public function update(Request $request, Comment $comment) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :Comment |
||
{ | ||
$this->authorize('update', $comment); | ||
|
||
$request->validate([ | ||
'message' => 'required|string', | ||
]); | ||
|
||
$comment->update([ | ||
'comment' => $request->message, | ||
]); | ||
|
||
return $this->show($comment->commentable); | ||
} | ||
|
||
/** | ||
* @param \App\Models\Comment $comment | ||
* | ||
* @return string | ||
*/ | ||
public function delete(Comment $comment) | ||
{ | ||
$this->authorize('delete', $comment); | ||
|
||
$comment->children()->exists() | ||
? $comment->delete() | ||
: $comment->forceDelete(); | ||
|
||
return $this->show($comment->commentable); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ class PostController extends Controller | |
*/ | ||
public function show(Post $post) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :View |
||
{ | ||
$post->with('comments'); | ||
|
||
return view('post.show', [ | ||
'post' => $post, | ||
]); | ||
|
@@ -59,7 +61,8 @@ public function update(Request $request, Post $post) | |
*/ | ||
public function list(Request $request) | ||
{ | ||
$posts = Post::with('user') | ||
$posts = Post::with(['user']) | ||
->withCount('comments') | ||
->orderBy('id', 'desc') | ||
->simplePaginate(5); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<?php | ||
|
||
namespace App\Models; | ||
|
||
use App\Docs; | ||
use Illuminate\Database\Eloquent\Concerns\HasUuids; | ||
use Illuminate\Database\Eloquent\Factories\HasFactory; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Database\Eloquent\SoftDeletes; | ||
use Illuminate\Support\Str; | ||
|
||
class Comment extends Model | ||
{ | ||
use HasFactory, SoftDeletes; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Будем хранить эти комментарии? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Да, для всей цепочки. Посмотрим на сколько это будет востребовано. Как вариант будем удалять если нет дочерних элементов |
||
|
||
/** | ||
* @var string[] | ||
*/ | ||
protected $attributes = [ | ||
'commentable_type' => Post::class, | ||
'commenter_type' => User::class, | ||
]; | ||
|
||
/** | ||
* The relations to eager load on every query. | ||
* | ||
* @var array | ||
*/ | ||
protected $with = [ | ||
'commenter', | ||
]; | ||
|
||
/** | ||
* The attributes that are mass assignable. | ||
* | ||
* @var array | ||
*/ | ||
protected $fillable = [ | ||
'comment', | ||
'approved', | ||
]; | ||
|
||
/** | ||
* The attributes that should be cast to native types. | ||
* | ||
* @var array | ||
*/ | ||
protected $casts = [ | ||
'approved' => 'boolean', | ||
]; | ||
|
||
/** | ||
* The user who posted the comment. | ||
*/ | ||
public function commenter() | ||
{ | ||
return $this->morphTo(); | ||
} | ||
|
||
/** | ||
* The model that was commented upon. | ||
*/ | ||
public function commentable() | ||
{ | ||
return $this->morphTo(); | ||
} | ||
|
||
/** | ||
* Returns all comments that this comment is the parent of. | ||
*/ | ||
public function children() | ||
{ | ||
return $this->hasMany(static::class, 'child_id'); | ||
} | ||
|
||
/** | ||
* Returns the comment to which this comment belongs to. | ||
*/ | ||
public function parent() | ||
{ | ||
return $this->belongsTo(static::class, 'child_id'); | ||
} | ||
|
||
|
||
/** | ||
* @param string|null $text | ||
* | ||
* @return string | ||
*/ | ||
protected function urlFromTextToHtmlUrl(string $text = null): string | ||
{ | ||
return Str::of($text) | ||
->replaceMatches('/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/u', fn ($url) => "<a href='$url[0]' target='_blank'>$url[0]</a> "); | ||
} | ||
|
||
/** | ||
* @param string|null $text | ||
* | ||
* @return string | ||
*/ | ||
protected function mentionedUserToHtmlUrl(string $text = null): string | ||
{ | ||
return Str::of($text) | ||
->replaceMatches('/\@([a-zA-Z0-9_]+)/u', function ($mention) { | ||
$href = route('user.show', $mention[1]); | ||
$name = Str::of($mention[0])->trim(); | ||
|
||
return "<a href='$href' class='text-decoration-none'>$name</a>"; | ||
}); | ||
} | ||
|
||
/** | ||
* @param string|null $text | ||
* | ||
* @return string | ||
*/ | ||
protected function nl2br(string $text = null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :string |
||
{ | ||
return nl2br($text); | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function prettyComment(): string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. хочется куда нибудь вынести все эти методы со строкой в отдельный класс |
||
{ | ||
$safe = htmlspecialchars($this->comment ?? '', ENT_NOQUOTES, 'UTF-8'); | ||
|
||
$withLinks = $this->urlFromTextToHtmlUrl($safe); | ||
$withMention = $this->mentionedUserToHtmlUrl($withLinks); | ||
|
||
return $this->nl2br($withMention); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
namespace App\Models\Concerns; | ||
|
||
use App\Models\Comment; | ||
|
||
/** | ||
* Add this trait to any model that you want to be able to | ||
* comment upon or get comments for. | ||
*/ | ||
trait HasComments | ||
{ | ||
/** | ||
* This static method does voodoo magic to | ||
* delete leftover comments once the commentable | ||
* model is deleted. | ||
*/ | ||
protected static function bootHasComments() | ||
{ | ||
/* | ||
static::deleted(function ($commentable) { | ||
$commentable->comments->every->delete(); | ||
/* | ||
foreach ($commentable->comments as $comment) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Забыл удалить? |
||
$comment->delete(); | ||
} | ||
}); | ||
*/ | ||
} | ||
|
||
/** | ||
* Returns all comments for this model. | ||
*/ | ||
public function comments() | ||
{ | ||
return $this->morphMany(Comment::class, 'commentable')->withTrashed(); | ||
} | ||
|
||
/** | ||
* Returns only approved comments for this model. | ||
*/ | ||
public function approvedComments() | ||
{ | ||
return $this->morphMany(Comment::class, 'commentable')->where('approved', true); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:View