Skip to content

Commit 27b334a

Browse files
committed
Add user following
1 parent aaa5525 commit 27b334a

15 files changed

+326
-4
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use Illuminate\Http\Request;
6+
7+
use App\Http\Requests;
8+
use App\Http\Controllers\Controller;
9+
10+
use App\Models\User;
11+
use Auth;
12+
13+
class FollowersController extends Controller
14+
{
15+
public function __construct()
16+
{
17+
$this->middleware('auth', [
18+
'store', 'destroy'
19+
]);
20+
}
21+
22+
public function store($id)
23+
{
24+
$user = User::findOrFail($id);
25+
26+
if (Auth::user()->id === $user->id) {
27+
return redirect('/');
28+
}
29+
30+
if (!Auth::user()->isFollowing($id)) {
31+
Auth::user()->follow($id);
32+
}
33+
34+
return redirect()->route('users.show', $id);
35+
}
36+
37+
public function destroy($id)
38+
{
39+
$user = User::findOrFail($id);
40+
41+
if (Auth::user()->id === $user->id) {
42+
return redirect('/');
43+
}
44+
45+
if (Auth::user()->isFollowing($id)) {
46+
Auth::user()->unfollow($id);
47+
}
48+
49+
return redirect()->route('users.show', $id);
50+
}
51+
}

app/Http/Controllers/UsersController.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class UsersController extends Controller
1717
public function __construct()
1818
{
1919
$this->middleware('auth', [
20-
'only' => ['edit', 'update', 'destroy']
20+
'only' => ['edit', 'update', 'destroy', 'followings', 'followers']
2121
]);
2222

2323
$this->middleware('guest', [
@@ -127,4 +127,20 @@ public function confirmEmail($token)
127127
session()->flash('success', '恭喜你,激活成功!');
128128
return redirect()->route('users.show', [$user]);
129129
}
130+
131+
public function followings($id)
132+
{
133+
$user = User::findOrFail($id);
134+
$users = $user->followings()->paginate(30);
135+
$title = '关注的人';
136+
return view('users.show_follow', compact('users', 'title'));
137+
}
138+
139+
public function followers($id)
140+
{
141+
$user = User::findOrFail($id);
142+
$users = $user->followers()->paginate(30);
143+
$title = '粉丝';
144+
return view('users.show_follow', compact('users', 'title'));
145+
}
130146
}

app/Http/routes.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@
1919
post('password/reset', 'Auth\PasswordController@postReset')->name('password.update');
2020

2121
resource('statuses', 'StatusesController', ['only' => ['store', 'destroy']]);
22+
23+
get('/users/{id}/followings', 'UsersController@followings')->name('users.followings');
24+
get('/users/{id}/followers', 'UsersController@followers')->name('users.followers');
25+
post('/users/followers/{id}', 'FollowersController@store')->name('followers.store');
26+
delete('/users/followers/{id}', 'FollowersController@destroy')->name('followers.destroy');

app/Models/User.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
1111
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
1212

13+
use Auth;
14+
1315
class User extends Model implements AuthenticatableContract,
1416
AuthorizableContract,
1517
CanResetPasswordContract
@@ -64,7 +66,41 @@ public function statuses()
6466

6567
public function feed()
6668
{
67-
return $this->statuses()
68-
->orderBy('created_at', 'desc');
69+
$user_ids = Auth::user()->followings->pluck('id')->toArray();
70+
array_push($user_ids, Auth::user()->id);
71+
return Status::whereIn('user_id', $user_ids)
72+
->with('user')
73+
->orderBy('created_at', 'desc');
74+
}
75+
76+
public function followers()
77+
{
78+
return $this->belongsToMany(User::Class, 'followers', 'user_id', 'follower_id');
79+
}
80+
81+
public function followings()
82+
{
83+
return $this->belongsToMany(User::Class, 'followers', 'follower_id', 'user_id');
84+
}
85+
86+
public function follow($user_ids)
87+
{
88+
if (!is_array($user_ids)) {
89+
$user_ids = compact('user_ids');
90+
}
91+
$this->followings()->sync($user_ids, false);
92+
}
93+
94+
public function unfollow($user_ids)
95+
{
96+
if (!is_array($user_ids)) {
97+
$user_ids = compact('user_ids');
98+
}
99+
$this->followings()->detach($user_ids);
100+
}
101+
102+
public function isFollowing($user_id)
103+
{
104+
return $this->followings->contains($user_id);
69105
}
70106
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Database\Schema\Blueprint;
4+
use Illuminate\Database\Migrations\Migration;
5+
6+
class CreateFollowersTable extends Migration
7+
{
8+
/**
9+
* Run the migrations.
10+
*
11+
* @return void
12+
*/
13+
public function up()
14+
{
15+
Schema::create('followers', function (Blueprint $table) {
16+
$table->increments('id');
17+
$table->integer('user_id')->index();
18+
$table->integer('follower_id')->index();
19+
$table->timestamps();
20+
});
21+
}
22+
23+
/**
24+
* Reverse the migrations.
25+
*
26+
* @return void
27+
*/
28+
public function down()
29+
{
30+
Schema::drop('followers');
31+
}
32+
}

database/seeds/DatabaseSeeder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function run()
1616

1717
$this->call('UsersTableSeeder');
1818
$this->call('StatusesTableSeeder');
19+
$this->call('FollowersTableSeeder');
1920

2021
Model::reguard();
2122
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Seeder;
4+
use App\Models\User;
5+
6+
class FollowersTableSeeder extends Seeder
7+
{
8+
/**
9+
* Run the database seeds.
10+
*
11+
* @return void
12+
*/
13+
public function run()
14+
{
15+
$users = User::all();
16+
$user = $users->first();
17+
$user_id = $user->id;
18+
19+
// 获取去除掉 ID 为 1 的所有用户 ID 数组
20+
$followers = $users->slice(1);
21+
$follower_ids = $followers->pluck('id')->toArray();
22+
23+
// 关注除了 1 号用户以外的所有用户
24+
$user->follow($follower_ids);
25+
26+
// 除了 1 号用户以外的所有用户都来关注 1 号用户
27+
foreach ($followers as $follower) {
28+
$follower->follow($user_id);
29+
}
30+
}
31+
}

public/css/app.css

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/css/app.css.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/assets/sass/app.scss

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,56 @@ section.user_info {
160160
border-radius: 50%;
161161
}
162162

163+
.stats {
164+
overflow: auto;
165+
margin-top: 0;
166+
padding: 0;
167+
a {
168+
float: left;
169+
padding: 0 10px;
170+
text-align: center;
171+
width: 33%;
172+
border-left: 1px solid $gray-lighter;
173+
color: gray;
174+
&:first-child {
175+
padding-left: 0;
176+
border: 0;
177+
}
178+
&:hover {
179+
text-decoration: none;
180+
color: #337ab7;
181+
}
182+
}
183+
strong {
184+
display: block;
185+
font-size: 1.2em;
186+
color: black;
187+
}
188+
}
189+
190+
.user_avatars {
191+
overflow: auto;
192+
margin-top: 10px;
193+
.gravatar {
194+
margin: 1px 1px;
195+
}
196+
a {
197+
padding: 0;
198+
}
199+
}
200+
201+
.users.follow {
202+
padding: 0;
203+
}
204+
163205
/* forms */
164206

207+
#follow_form button {
208+
margin: 0 auto;
209+
display: block;
210+
margin-top: 25px;
211+
}
212+
165213
input, textarea, select, .uneditable-input {
166214
border: 1px solid #bbb;
167215
width: 100%;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<div class="stats">
2+
<a href="{{ route('users.followings', $user->id) }}">
3+
<strong id="following" class="stat">
4+
{{ count($user->followings) }}
5+
</strong>
6+
关注
7+
</a>
8+
<a href="{{ route('users.followers', $user->id) }}">
9+
<strong id="followers" class="stat">
10+
{{ count($user->followers) }}
11+
</strong>
12+
粉丝
13+
</a>
14+
<a href="{{ route('users.show', $user->id) }}">
15+
<strong id="statuses" class="stat">
16+
{{ $user->statuses()->count() }}
17+
</strong>
18+
微博
19+
</a>
20+
</div>

resources/views/static_pages/home.blade.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
<section class="user_info">
1515
@include('shared.user_info', ['user' => Auth::user()])
1616
</section>
17+
<section class="stats">
18+
@include('shared.stats', ['user' => Auth::user()])
19+
</section>
1720
</aside>
1821
</div>
1922
@else
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@if ($user->id !== Auth::user()->id)
2+
<div id="follow_form">
3+
@if (Auth::user()->isFollowing($user->id))
4+
<form action="{{ route('followers.destroy', $user->id) }}" method="post">
5+
{{ csrf_field() }}
6+
{{ method_field('DELETE') }}
7+
<button type="submit" class="btn btn-sm">取消关注</button>
8+
</form>
9+
@else
10+
<form action="{{ route('followers.store', $user->id) }}" method="post">
11+
{{ csrf_field() }}
12+
<button type="submit" class="btn btn-sm btn-primary">关注</button>
13+
</form>
14+
@endif
15+
</div>
16+
@endif

resources/views/users/show.blade.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,16 @@
88
<section class="user_info">
99
@include('shared.user_info', ['user' => $user])
1010
</section>
11+
<section class="stats">
12+
@include('shared.stats', ['user' => $user])
13+
</section>
1114
</div>
1215
</div>
1316
<div class="col-md-12">
17+
@if (Auth::check())
18+
@include('users._follow_form')
19+
@endif
20+
1421
@if (count($statuses) > 0)
1522
<ol class="statuses">
1623
@foreach ($statuses as $status)

0 commit comments

Comments
 (0)