Skip to content

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

Lucking