Appearance
table
php
public function up() {
$table->text('content')
$table->foreignIn('user_id')->constrained()->onDelete('cascade')
$table->morphs('commentable')
$table->foreginIn('comment_id')->constrained()->onDelete('cascade')
$table->foreignIn('reply_user_id')->constrained('users','id')->onDelete('cascade')
}CommentFactory
php
[
'content'=>fake()->paragraph(),
'user_id'=>User::inRandomOrder()->first()->id,
'commentable_type'=>'App\model\Topic',
'commentable_id'=>1
]databaseSeeder
php
Comment::factory(2)->create();
Comment::find(2)->update([
'commentable_type'=>Comment::find(1)->commentable_type,
'commentable_id'=>Comment::find(1)->commentable_id,
'comment_id'=>1,
'reply_user_id'=>Comment::find(1)->user_id,
])Mode Comment
php
class Comment extends Model {
use HasFactory;
protected $fillable = ['content','user_id','comment_id','reply_user_id'];
protected $with = ['user','replyUser','comment'];
//与作者的关联
public function user(){
return $this->belongsTo(User::class);
}
//回复的用户
public function replyUser(){
return $this->belongsTo(User::class,'reply_user_id');
}
//回复了哪条评论
public function comment(){
return $this->belongsTo(Comment::class,'comment_id');
}
//获取评论的回复
public function replys(){
return $this->hasMany(Comment::class,'comment_id');
}
//这个评论是针对哪个帖子或新闻资讯的
public function model(){
return $this->morphTo('commentable');
}
}Helper.php
php
function modelClass($name) {
return 'App\Models\\'.ucfirst($name)
}
function model($name,$id) {
return modelClass($name)::findOrFail($id);
}Topic
php
class Topic extends Model
{
use HasFactory;
protected $fillable = ['title','content'];
public function user(){
return $this->belongsTo(User::class);
}
//获取评论
public function comments() {
return $this->morphMany(Comment::class,'commentable');
}
}Controller
php
class CommentController extends Controller {
public function __construct() {
$this->middleware(['auth:sanctum'])->except(['index','show']);
}
public function index(Request $request,$type,$id) {
$comments = model($type,$id)->comments()->whereNull('comment_id')->with('replys')->get();
return $this->success(data:CommentResource::collection($comments));
}
public function store(StoreCommentRequest $request,$type,$id) {
$model = model($type,$id);
$data = ['user_id'=>Auth::id()] + $request->input();
if($request->comment_id){
$data['reply_user_id'] = Comment::find($request->comment_id)->user_id;
}
if($request->isReply == 'yes' && $request->reply_user_id){
$data['reply_user_id'] = $request->reply_user_id;
}
//topic_id ,info_id
$comment = $model->comments()->create($data);
return $this->success('评论添加成功',new CommentResource($comment->fresh()));
}
public function destroy(Comment $comment) {
$this->authorize('delete',$comment);
$comment->delete();
return $this->success('评论添加成功');
}
}php
class CommentPolicy
{
use HandlesAuthorization;
public function before(){
if(isSuperAdmin()) return true;
}
public function create(User $user)
{
return true;
}
public function delete(User $user, Comment $comment)
{
return $user->id == $comment->user_id;
}
}php
Route::post('comment/{$type}/{$id}',[class,'store']) //写在下面会被覆盖
Route::get('comment/{$type}/{$id}',[class,'index'])
Route::ApiResource('comment',class)任务1:上传文件接口 #1 创建控制器 php artisan make:controller AttachmentController; #2 创建UploadService
#3 安装裁切包 composer require spatie/image; #4 创建软连接 php artisan storage:link public_path('attachments') => storage_path('app/attachments'),
controller
php
class AttachmentController extends Controller {
public function image(Request $request) {
$request->validate([
'file' => ['required', 'image', 'max:2048']
], [
'file.required' => '上传文件必选',
'file.max' => '文件不能超过2M',
'file.image' => '上传文件必须是图片格式'
]);
$url = app(UploadService::class)->image(request('file'));
return $this->success(data: ['url' => $url]);
}
public function video(Request $request) {
//<input name="video" />
$request->validate([
'video' => ['required', 'mimetypes:video/avi,video/mpeg,video/quicktime,video/mp4','max:20480']
], [
'video.required' => '上传文件必选',
'video.max' => '文件不能超过20M',
'video.mimetypes' => '上传文件必须是视频格式'
]);
$url = $request->file('video')->store('attachments');
return $this->success(data: ['url' => url($url)]);
}
}php
class UploadService{
public function image($file,$width=800,$height=800,$fit=Manipulations::FIT_CONTAIN){
//返回图片存储的相对路径 attachments/xxxxx.jpg
$filePath = $file->store('attachments');
//获取上传图片的绝对路径 $realPath = storage/app/attachments/xxxxx.jpg
$realPath = storage_path('app/'.$filePath);
//缩放裁切图片
Image::load($realPath)->fit($fit,$width,$height)->save();
return url($filePath);
}
}php
Route::post('upload/image',[class,'image'])config/filesystems.php
php
[
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('attachments') => storage_path('app/attachments'),
],
]跑命令
php artisan storage:link