Laravel Vuejs 实战:开发知乎 (23)用户关注之组件化开发

开发vue的时候最好在开始的时候执行:

  1 npm install && npm run watch-poll

这样每次编辑了vue都会后台自动生成一下,方便查看效果。

1.生成一个控制器:

php artisan make:controller FollowerController

代码:

  1 <?php
  2 
  3 namespace App\Http\Controllers;
  4 
  5 use App\User;
  6 use Illuminate\Http\Request;
  7 
  8 class FollowerController extends Controller
  9 {
 10     //
 11     public function __construct()
 12     {
 13         $this->middleware('auth')
 14             ->except(
 15                 [
 16                     'getFollowStats',
 17                     'followThroughApi',
 18                 ]
 19             );
 20     }
 21 
 22 
 23     public function getFollowStats(Request $request)
 24     {
 25         //解析出用户
 26         $user = User::find($request->get('user'));
 27         //解析出当前登录用户
 28         $currentUser = auth()->user();
 29         //返回能否关注的状态 [follow是FollowPolicy中的follow方法,FollowPolicy已经在AuthServiceProvider中注册]
 30         return response()->json(['followable' => $currentUser->can('follow', $user),
 31             'self' => $user->id === $currentUser->id,]);
 32     }
 33 
 34 
 35     public function followThroughApi(Request $request)
 36     {
 37         //解析出用户
 38         $user = User::find($request->get('user'));
 39 
 40         //解析出当前登录用户
 41         $currentUser = auth()->user();
 42 
 43         //执行关注/取关操作 [不能关注自己]
 44         if ($user->id !== $currentUser->id) {
 45             $currentUser->followings()->toggle($user->id);
 46         }
 47 
 48         //返回新能否关注的状态 [follow是FollowPolicy中的follow方法,FollowPolicy已经在AuthServiceProvider中注册]
 49         return response()->json(
 50             [
 51                 'followable' => $currentUser->can('follow', $user),
 52                 'self' => $user->id === $currentUser->id,
 53             ]
 54         );
 55     }
 56 }
 57 
 58 
FollowerController.php

1.2 添加一个授权策略

php artisan make:policy FollowPolicy

  1 <?php
  2 
  3 namespace App\Policies;
  4 
  5 use App\User;
  6 use Illuminate\Auth\Access\HandlesAuthorization;
  7 
  8 class FollowPolicy
  9 {
 10     use HandlesAuthorization;
 11 
 12     /**
 13      * Create a new policy instance.
 14      *
 15      * @return void
 16      */
 17     public function __construct()
 18     {
 19         //
 20     }
 21 
 22     public function follow(User $currentUser, User $user)
 23     {
 24         //用户不能关注自己,也不能关注已经关注的用户
 25         return $currentUser->id !== $user->id && !($currentUser->followings->contains('id', $user->id));
 26     }
 27 }
 28 
 29 
FollowPolicy.php

Lightning记得添加到AuthServiceProvider的 $policies中

代码:

  1 <?php
  2 
  3 namespace App\Providers;
  4 
  5 use App\Models\Question;
  6 use App\Policies\FollowPolicy;
  7 use App\Policies\QuestionPolicy;
  8 use App\User;
  9 use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
 10 use Illuminate\Support\Facades\Gate;
 11 
 12 class AuthServiceProvider extends ServiceProvider
 13 {
 14     /**
 15      * The policy mappings for the application.
 16      *
 17      * @var array
 18      */
 19     protected $policies = [
 20         // 'App\Model' => 'App\Policies\ModelPolicy',
 21         //添加授权映射关系
 22         Question::class => QuestionPolicy::class,
 23         User::class => FollowPolicy::class,
 24     ];
 25 
 26     /**
 27      * Register any authentication / authorization services.
 28      *
 29      * @return void
 30      */
 31     public function boot()
 32     {
 33         $this->registerPolicies();
 34 
 35         //
 36     }
 37 }
 38 
 39 
AuthServiceProvider.php

2.添加api route:

  1 
  2 #region 用户关注
  3 //加载页面时取关注状态
  4 Route::middleware('auth:api')->post('/users/follow/stats', 'FollowerController@getFollowStats');
  5 //执行关注/取关操作
  6 Route::middleware('auth:api')->post('/users/follow', 'FollowerController@followThroughApi');
  7 
  8 #endregion
  9 
 10 
  1 <?php
  2 
  3 use Illuminate\Http\Request;
  4 
  5 /*
  6 |--------------------------------------------------------------------------
  7 | API Routes
  8 |--------------------------------------------------------------------------
  9 |
 10 | Here is where you can register API routes for your application. These
 11 | routes are loaded by the RouteServiceProvider within a group which
 12 | is assigned the "api" middleware group. Enjoy building your API!
 13 |
 14 */
 15 
 16 Route::middleware('auth:api')->get('/user', function (Request $request) {
 17     return $request->user();
 18 });
 19 
 20 Route::middleware('api')->get('/topics', function (Request $request) {
 21     $query = $request->query('q');
 22     return \App\Topic::query()->where('name', 'like', '%' . $query . '%')->get();
 23 });
 24 #region 问题关注
 25 //加载页面时取关注状态
 26 Route::middleware('auth:api')->post('/questions/follow/stats', 'QuestionController@getFollowStats');
 27 //执行关注/取关操作
 28 Route::middleware('auth:api')->post('/questions/follow', 'QuestionController@followThroughApi');
 29 #endregion
 30 
 31 #region 用户关注
 32 //加载页面时取关注状态
 33 Route::middleware('auth:api')->post('/users/follow/stats', 'FollowerController@getFollowStats');
 34 //执行关注/取关操作
 35 Route::middleware('auth:api')->post('/users/follow', 'FollowerController@followThroughApi');
 36 
 37 #endregion
 38 
 39 
api.php

3.添加用户关注按钮vue组件:

  1 <template>
  2     <button :class="classObject"
  3             @click="follow"
  4             v-text="text">
  5     </button>
  6 </template>
  7 
  8 <script>
  9     export default {
 10         props: ['user'],
 11         name: "UserFollowButton",
 12         data() {
 13             return {
 14                 followable: true,
 15                 self: true,
 16             }
 17         },
 18         computed: {
 19             text() {
 20                 return this.followable ? "关注" : "取关";
 21             },
 22             classObject() {
 23                 if (this.self) {
 24                     return "d-none"
 25                 }
 26                 return this.followable ? "btn btn-sm btn-secondary" : "btn btn-sm btn-danger";
 27             },
 28         },
 29         mounted: function () {
 30             let currentObj = this;
 31             axios.post('/api/users/follow/stats', {'user': this.user})
 32                 .then(function (response) {
 33                     currentObj.followable = response.data.followable;
 34                     currentObj.self = response.data.self;
 35                 })
 36                 .catch(function (e) {
 37                     console.log(e);
 38                 });
 39         },
 40         methods: {
 41             follow() {
 42                 let currentObj = this;
 43                 axios.post('/api/users/follow', {'user': this.user})
 44                     .then(function (response) {
 45                             currentObj.followable = response.data.followable;
 46                             currentObj.self = response.data.self;
 47                         }
 48                     )
 49                     .catch(function (e) {
 50                         console.log(e);
 51                     });
 52             },
 53         }
 54     }
 55 </script>
 56 
 57 <style scoped>
 58 
 59 </style>
 60 
 61 
UserFollowButton.vue
  1 <div class="card-footer float">
  2     <div class="text-center float-left mr-4">
  3         <div class="text">提问数</div>
  4         <div class="number">{{ $question->user->questions_count }}</div>
  5     </div>
  6     <div class="text-center float-left mr-4">
  7         <div class="text">回答数</div>
  8         <div class="number">{{ $question->user->answers->count() }}</div>
  9     </div>
 10     <div class="text-center float-left ">
 11         <div class="text">粉丝数</div>
 12         <div class="number">{{ $question->user->followers->count() }}</div>
 13     </div>
 14 </div>
 15 
 16 
_user_stats.blade.php

补充:之前User模型中 外键设置理解错误了Crying face,参考:

数据库(外键及其约束理解)

Laravel学习记录--Model

修改后Thumbs up

  1 <?php
  2 
  3 namespace App;
  4 
  5 use App\Models\Question;
  6 use Illuminate\Contracts\Auth\MustVerifyEmail;
  7 use Illuminate\Database\Eloquent\SoftDeletes;
  8 use Illuminate\Foundation\Auth\User as Authenticatable;
  9 use Illuminate\Notifications\Notifiable;
 10 
 11 class User extends Authenticatable implements MustVerifyEmail
 12 {
 13     use Notifiable;
 14     #region 支持软删除
 15     use SoftDeletes;
 16     protected $dates = ['deleted_at'];
 17     #endregion
 18     /**
 19      * The attributes that are mass assignable.
 20      *
 21      * @var array
 22      */
 23     protected $fillable = [
 24         'name', 'email', 'password', 'avatar', 'activation_token', 'api_token'
 25     ];
 26 
 27     /**
 28      * The attributes that should be hidden for arrays.
 29      *
 30      * @var array
 31      */
 32     protected $hidden = [
 33         'password', 'remember_token',
 34     ];
 35 
 36     /**
 37      * The attributes that should be cast to native types.
 38      *
 39      * @var array
 40      */
 41     protected $casts = [
 42         'email_verified_at' => 'datetime',
 43     ];
 44 
 45 
 46     /**添加用户模型和问题模型的模型关联
 47      * @return \Illuminate\Database\Eloquent\Relations\HasMany
 48      */
 49     public function questions()
 50     {
 51         return $this->hasMany(Question::class);
 52     }
 53 
 54 
 55     /** 添加用户模型和回答模型的模型关联 一个用户可以有多个回答
 56      * @return \Illuminate\Database\Eloquent\Relations\HasMany
 57      */
 58     public function answers()
 59     {
 60         return $this->hasMany(Answer::class);
 61     }
 62 
 63 
 64     public function followQuestions()
 65     {
 66         //默认表名 可以不设置后面三个参数,自定义表名需要设置
 67         return $this->belongsToMany(Question::class, 'users_questions', 'question_id', 'user_id')->withTimestamps();
 68     }
 69 
 70 
 71     /** 用户的粉丝
 72      * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 73      */
 74     public function followers()
 75     {
 76 
 77         return $this->belongsToMany
 78         (
 79             self::class,
 80             'followers',
 81             'user_id', //foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是leader】的外键id
 82             'follower_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键)
 83         )->withTimestamps();
 84     }
 85 
 86 
 87     /** 用户关注的作者
 88      * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 89      */
 90     public function followings()
 91     {
 92         return $this->belongsToMany
 93         (
 94             self::class,
 95             'followers',
 96             'follower_id',//foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是粉丝】的外键id
 97             'user_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键)
 98         )
 99             ->withTimestamps();
100     }
101 }
102 
103 
User.php
posted @ 2020-03-02 16:01  dzkjz  阅读(249)  评论(0编辑  收藏  举报