Laravel Vuejs 实战:开发知乎 (45-47)用户设置
45节的重置密码省略:默认已经带得有。
因为用户个人信息等可能在后面会随时增加,比如增加一个字段存储用户的电话号码,增加一个字段存储用户的某社交账户的地址,
如果每次都用migration的方式,会比较不方便;建议采取如下方式。【如果这些信息需要排序,筛选,分类的情况另当别论,还是用字段的方式更快捷】
用户设置:
1.路由添加:
1 #region 2 3 Route::get('setting', 'SettingController@index')->name('setting.index'); 4 5 Route::post('setting', 'SettingController@store')->name('setting.store'); 6 #endregion 7 8
路由代码
1 <?php 2 3 /* 4 |-------------------------------------------------------------------------- 5 | Web Routes 6 |-------------------------------------------------------------------------- 7 | 8 | Here is where you can register web routes for your application. These 9 | routes are loaded by the RouteServiceProvider within a group which 10 | contains the "web" middleware group. Now create something great! 11 | 12 */ 13 14 Route::get('/', function () { 15 return view('welcome'); 16 }); 17 18 Auth::routes(['verify' => true]); 19 20 Route::get('/home', 'HomeController@index')->name('home'); 21 22 Route::resource('questions', 'QuestionController'); 23 24 25 #region 回答路由CRUD 26 27 //查看回答 以及 回答的form 都是在questions详细内容页面 28 29 //提交回答 30 Route::post('questions/{question}/answers', 'AnswerController@store')->name('answers.store'); 31 32 //更新回答 33 34 35 //删除回答 36 37 38 #endregion 39 40 41 #region 42 //用户关注 取消关注问题 43 Route::get('questions/{question}/follow', 'QuestionController@follow')->name('questions.follow'); 44 #endregion 45 46 47 #region 48 49 //用户通知消息路由 50 Route::get('/notifications', 'NotificationController@index')->name('notification.index'); 51 #endregion 52 53 #region 54 //用户查看短消息 55 Route::get('/inbox', 'InboxController@index')->name('inbox.index'); 56 57 //展示用户间私信对话具体内容页 58 Route::get('/inbox/{userId}', 'InboxController@show')->name('inbox.show'); 59 60 //用户回信息 61 Route::post('/inbox/{userId}/send', 'InboxController@store')->name('inbox.store'); 62 #endregion 63 64 65 #region 66 //访问用户详细页面 67 68 Route::get('/avatar', 'UserController@avatar')->name('users.avatar'); 69 70 Route::post('/avatar/upload', 'UserController@avatarStore'); 71 72 #endregion 73 74 75 #region 76 77 Route::get('setting', 'SettingController@index')->name('setting.index'); 78 79 Route::post('setting', 'SettingController@store')->name('setting.store'); 80 #endregion 81 82
2.执行:
1 php artisan make:model Setting –c
控制器SettingController.php:
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use Illuminate\Http\Request; 6 7 class SettingController extends Controller 8 { 9 // 10 public function __construct() 11 { 12 $this->middleware('auth'); 13 } 14 15 public function index() 16 { 17 $settings = auth()->user()->settings; 18 return view('users.setting', compact('settings')); 19 } 20 21 public function store(Request $request) 22 { 23 $settings = auth()->user()->settings; 24 if (!is_array($settings)) { 25 $settings = []; 26 } 27 $settings = array_merge( 28 $settings, 29 array_only( 30 $request->all(), 31 [ 32 'city', 33 'info' 34 ] 35 ) 36 ); 37 38 auth()->user()->update( 39 [ 40 'settings' => $settings, 41 ] 42 ); 43 return redirect()->back()->with('success', '更新成功!'); 44 } 45 46 } 47 48
3.view视图:
setting.blade.php文件:
1 @extends('layouts.app') 2 3 @section('content') 4 5 <div class="container"> 6 <div class="row"> 7 <div class="col-md-8 offset-2"> 8 <div class="card"> 9 <div class="card-header"> 10 设置个人信息 11 </div> 12 <div class="card-body"> 13 <form action="{{ route('setting.store') }}" method="post"> 14 @csrf 15 <div class="form-group"> 16 <label for="city">现居城市</label> 17 <input type="text" name="city" id="city" class="form-control" 18 value="{{ $settings['city'] }}"> 19 @error('city') <span class="alert alert-danger">{{ $message }}</span>@enderror 20 </div> 21 22 23 <div class="form-group"> 24 <label for="info">个人简介</label> 25 <textarea type="text" name="info" id="info" 26 class="form-control">{{ $settings['info'] }}</textarea> 27 @error('info') <span class="alert alert-danger">{{ $message }} </span>@enderror 28 </div> 29 30 31 <div class="form-group"> 32 <button type="submit" class="btn btn-success btn-block form-control">更新资料</button> 33 </div> 34 </form> 35 </div> 36 </div> 37 </div> 38 </div> 39 </div> 40 41 @endsection 42 43
settings字段采用的是: Eloquent: Mutators
参考:Eloquent: 修改器 有点类似WPF中的IValueConverter
4.User.php中的cast属性修改以及fillable属性修改:
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', 'settings', 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 'settings' => 'array', 44 ]; 45 46 47 /**添加用户模型和问题模型的模型关联 48 * @return \Illuminate\Database\Eloquent\Relations\HasMany 49 */ 50 public function questions() 51 { 52 return $this->hasMany(Question::class); 53 } 54 55 56 /** 添加用户模型和回答模型的模型关联 一个用户可以有多个回答 57 * @return \Illuminate\Database\Eloquent\Relations\HasMany 58 */ 59 public function answers() 60 { 61 return $this->hasMany(Answer::class); 62 } 63 64 65 public function followQuestions() 66 { 67 //默认表名 可以不设置后面三个参数,自定义表名需要设置 68 return $this->belongsToMany(Question::class, 'users_questions', 'question_id', 'user_id')->withTimestamps(); 69 } 70 71 72 /** 用户的粉丝 73 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 74 */ 75 public function followers() 76 { 77 78 return $this->belongsToMany 79 ( 80 self::class, 81 'followers', 82 'user_id', //foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是leader】的外键id 83 'follower_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键) 84 )->withTimestamps(); 85 } 86 87 88 /** 用户关注的作者 89 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 90 */ 91 public function followings() 92 { 93 return $this->belongsToMany 94 ( 95 self::class, 96 'followers', 97 'follower_id',//foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是粉丝】的外键id 98 'user_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键) 99 ) 100 ->withTimestamps(); 101 } 102 103 104 /** 105 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 106 */ 107 public function votes() 108 { 109 return $this->belongsToMany(Answer::class, 'votes')->withTimestamps(); 110 } 111 112 113 /** 114 * @param $answer_id 115 * @return array 116 */ 117 public function voteAnswer($answer_id) 118 { 119 return $this->votes()->toggle($answer_id); 120 } 121 122 123 public function messages() 124 { 125 return $this->hasMany(Message::class, 'to_user_id'); 126 } 127 128 public function comments() 129 { 130 return $this->hasMany(Comment::class); 131 } 132 133 } 134 135
5.RegisterController.php修改:
1 <?php 2 3 namespace App\Http\Controllers\Auth; 4 5 use App\Http\Controllers\Controller; 6 use App\Providers\RouteServiceProvider; 7 use App\User; 8 use Illuminate\Foundation\Auth\RegistersUsers; 9 use Illuminate\Support\Facades\Hash; 10 use Illuminate\Support\Facades\Validator; 11 12 class RegisterController extends Controller 13 { 14 /* 15 |-------------------------------------------------------------------------- 16 | Register Controller 17 |-------------------------------------------------------------------------- 18 | 19 | This controller handles the registration of new users as well as their 20 | validation and creation. By default this controller uses a trait to 21 | provide this functionality without requiring any additional code. 22 | 23 */ 24 25 use RegistersUsers; 26 27 /** 28 * Where to redirect users after registration. 29 * 30 * @var string 31 */ 32 protected $redirectTo = RouteServiceProvider::HOME; 33 34 /** 35 * Create a new controller instance. 36 * 37 * @return void 38 */ 39 public function __construct() 40 { 41 $this->middleware('guest'); 42 } 43 44 /** 45 * Get a validator for an incoming registration request. 46 * 47 * @param array $data 48 * @return \Illuminate\Contracts\Validation\Validator 49 */ 50 protected function validator(array $data) 51 { 52 return Validator::make($data, [ 53 'name' => ['required', 'string', 'max:255'], 54 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 55 'password' => ['required', 'string', 'min:8', 'confirmed'], 56 ]); 57 } 58 59 /** 60 * Create a new user instance after a valid registration. 61 * 62 * @param array $data 63 * @return \App\User 64 */ 65 protected function create(array $data) 66 { 67 return User::create([ 68 'name' => $data['name'], 69 'email' => $data['email'], 70 'avatar' => '/image/avatars/default.png', 71 //这里其实不需要再设置activation_token的值,也不需要再在验证后设置activated=1 采用Laravel提供的新功能验证用户邮箱即可 默认带一个email_verified_at字段,且更加完善具有过期时间戳和签名 72 'activation_token' => str_random(40),//通过composer require laravel/helpers安装扩展包 73 'password' => Hash::make($data['password']), 74 'api_token' => str_random(64), 75 'settings' => ['city' => '', 'info' => ''], 76 ]); 77 } 78 } 79 80
效果图:
6.重构SettingController的store方法:
新建一个Setting.php文件:
代码:
1 <?php 2 3 namespace App; 4 5 6 class Setting 7 { 8 protected $allowedAttribute = [ 9 'city', 10 'info' 11 ]; 12 /** 13 * @var User 14 */ 15 private $user; 16 17 public function __construct(User $user) 18 { 19 20 $this->user = $user; 21 } 22 23 // 24 public function merge(array $attributes) 25 { 26 $settings = $this->user->settings; 27 28 if (!is_array($settings)) { 29 $settings = []; 30 } 31 32 $settings = array_merge( 33 $settings, 34 array_only( 35 $attributes, 36 $this->allowedAttribute 37 ) 38 ); 39 40 $this->user->update([ 41 'settings' => $settings, 42 ]); 43 } 44 } 45 46
User.php中添加一个方法:
1 public function settings() 2 { 3 return new Setting($this); 4 } 5
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', 'settings', 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 'settings' => 'array', 44 ]; 45 46 47 /**添加用户模型和问题模型的模型关联 48 * @return \Illuminate\Database\Eloquent\Relations\HasMany 49 */ 50 public function questions() 51 { 52 return $this->hasMany(Question::class); 53 } 54 55 56 /** 添加用户模型和回答模型的模型关联 一个用户可以有多个回答 57 * @return \Illuminate\Database\Eloquent\Relations\HasMany 58 */ 59 public function answers() 60 { 61 return $this->hasMany(Answer::class); 62 } 63 64 65 public function followQuestions() 66 { 67 //默认表名 可以不设置后面三个参数,自定义表名需要设置 68 return $this->belongsToMany(Question::class, 'users_questions', 'question_id', 'user_id')->withTimestamps(); 69 } 70 71 72 /** 用户的粉丝 73 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 74 */ 75 public function followers() 76 { 77 78 return $this->belongsToMany 79 ( 80 self::class, 81 'followers', 82 'user_id', //foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是leader】的外键id 83 'follower_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键) 84 )->withTimestamps(); 85 } 86 87 88 /** 用户关注的作者 89 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 90 */ 91 public function followings() 92 { 93 return $this->belongsToMany 94 ( 95 self::class, 96 'followers', 97 'follower_id',//foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是粉丝】的外键id 98 'user_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键) 99 ) 100 ->withTimestamps(); 101 } 102 103 104 /** 105 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 106 */ 107 public function votes() 108 { 109 return $this->belongsToMany(Answer::class, 'votes')->withTimestamps(); 110 } 111 112 113 /** 114 * @param $answer_id 115 * @return array 116 */ 117 public function voteAnswer($answer_id) 118 { 119 return $this->votes()->toggle($answer_id); 120 } 121 122 123 public function messages() 124 { 125 return $this->hasMany(Message::class, 'to_user_id'); 126 } 127 128 public function comments() 129 { 130 return $this->hasMany(Comment::class); 131 } 132 133 public function settings() 134 { 135 return new Setting($this); 136 } 137 } 138 139
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use Illuminate\Http\Request; 6 7 class SettingController extends Controller 8 { 9 // 10 public function __construct() 11 { 12 $this->middleware('auth'); 13 } 14 15 public function index() 16 { 17 $settings = auth()->user()->settings; 18 return view('users.setting', compact('settings')); 19 } 20 21 public function store(Request $request) 22 { 23 // $settings = auth()->user()->settings; 24 // if (!is_array($settings)) { 25 // $settings = []; 26 // } 27 // $settings = array_merge( 28 // $settings, 29 // array_only( 30 // $request->all(), 31 // [ 32 // 'city', 33 // 'info' 34 // ] 35 // ) 36 // ); 37 // 38 // auth()->user()->update( 39 // [ 40 // 'settings' => $settings, 41 // ] 42 // ); 43 44 auth()->user()->settings()->merge($request->all()); 45 46 47 return redirect()->back()->with('success', '更新成功!'); 48 } 49 } 50 51
最后: