64. 测试头像上传(二)
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 64 小节:Testing Avatar Uploads: Part 2
本节内容
本节我们继续头像上传的功能。首先我们运行迁移,添加avatar_path
字段:
$ php artisan migrate:refresh
进入Tinker
环境:
$ php artisan tinker
填充数据:
>>> factory('App\Thread',30)->create();
注册用户 NoNo1,并新建话题:
我们使用授权策略来进行上传头像的权限控制。首先我们新建授权策略:
$ php artisan make:policy UserPolicy
接着注册策略:
app/Providers/AuthServiceProvider.php
.
.
protected $policies = [
'App\Thread' => 'App\Policies\ThreadPolicy',
'App\Reply' => 'App\Policies\ReplyPolicy',
'App\User' => 'App\Policies\UserPolicy',
];
.
.
然后修改内容:
forum\app\Policies\UserPolicy.php
<?php
namespace App\Policies;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function update(User $signedInUser, User $user)
{
return $signedInUser->id === $user->id;
}
}
接下来我们增加上传文件的表单,并选择一张图片上传:
forum\resources\views\profiles\show.blade.php
.
.
<div class="page-header">
<h1>
{{ $profileUser->name }}
</h1>
@can('update',$profileUser)
<form method="POST" action="{{ route('avatar',$profileUser) }}" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="file" name="avatar">
<button type="submit" class="btn btn-primary">Add Avatar</button>
</form>
@endcan
</div>
.
.
我们在数据库进行查看:
头像路径已经存到数据库中,但是我们的文件存放在 forum\storage\app\public\avatars 目录下,我们想在 public\avatars 目录下使用头像。我们运行以下命令:
$ php artisan storage:link
接着我们将头像显示出来:
.
.
<div class="page-header">
<h1>
{{ $profileUser->name }}
</h1>
@can('update',$profileUser)
<form method="POST" action="{{ route('avatar',$profileUser) }}" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="file" name="avatar">
<button type="submit" class="btn btn-primary">Add Avatar</button>
</form>
@endcan
<img src="/{{ $profileUser->avatar_path }}" width="200" height="200">
</div>
.
.
注:以上代码对我未生效,所以我使用的是以下代码:
<img src="/storage/{{ $profileUser->avatar_path }}" width="200" height="200">
我们在刷新页面:
我们在话题详情页面显示头像:
forum\resources\views\threads\show.blade.php
.
.
<div class="panel-heading">
<div class="level">
<img src="/storage/{{ $thread->creator->avatar_path }}" alt="{{ $thread->creator->name }}" width="25" height="25" class="mr-1">
<span class="flex">
<a href="{{ route('profile',$thread->creator) }}">{{ $thread->creator->name }}</a> posted:
{{ $thread->title }}
</span>
@can('update',$thread)
<form action="{{ $thread->path() }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="submit" class="btn btn-link">Delete Thread</button>
</form>
@endcan
</div>
</div>
.
.
页面效果:
但是与此同时,如果没有上传头像的用户无法显示头像:
我们更改一下处理逻辑,如果用户没有上传头像,我们就使用默认头像。如下:
$thread->creator->avatar();
为此我们先来新建一个测试:
forum\tests\Unit\UserTest.php
.
.
/** @test */
public function a_user_can_determine_their_avatar_path()
{
$user = create('App\User');
$this->assertEquals('avatars/default.jpg',$user->avatar());
$user->avatar_path = 'avatars/me.jpg';
$this->assertEquals('avatars/me.jpg',$user->avatar());
}
}
添加avatar()
方法:
forum\app\User.php
.
.
public function avatar()
{
return $this->avatar_path ?: 'avatars/default.jpg';
}
public function visitedThreadCacheKey($thread)
{
return $key = sprintf("users.%s.visits.%s",$this->id,$thread->id);
}
}
运行测试:
现在我们可以有默认的头像,如果用户没有上传头像的话。我们在个人页面和话题详情页面应用:
forum\resources\views\profiles\show.blade.php
.
.
<div class="page-header">
<h1>
{{ $profileUser->name }}
</h1>
@can('update',$profileUser)
<form method="POST" action="{{ route('avatar',$profileUser) }}" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="file" name="avatar">
<button type="submit" class="btn btn-primary">Add Avatar</button>
</form>
@endcan
<img src="/storage/{{ $profileUser->avatar() }}" width="200" height="200">
</div>
.
.
forum\resources\views\threads\show.blade.php*
.
.
<div class="panel-heading">
<div class="level">
<img src="/storage/{{ $thread->creator->avatar() }}" alt="{{ $thread->creator->name }}" width="25" height="25" class="mr-1">
<span class="flex">
<a href="{{ route('profile',$thread->creator) }}">{{ $thread->creator->name }}</a> posted:
{{ $thread->title }}
</span>
.
.
页面效果: