Laravel 项目:使用 TDD 构建论坛 Chapter 22

0.写在前面

  • 本系列文章为laracasts.com 的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版
  • 视频源码地址:https://github.com/laracasts/Lets-Build-a-Forum-in-Laravel
  • *本项目为一个 forum(论坛)项目,与本站的第二本实战教程 Laravel 教程 - Web 开发实战进阶 ( Laravel 5.5 ) 类似,可互相参照
  • 项目开发模式为TDD开发,教程简介为:

    A forum is a deceptively complex thing. Sure, it's made up of threads and replies, but what else might exist as part of a forum? What about profiles, or thread subscriptions, or filtering, or real-time notifications? As it turns out, a forum is the perfect project to stretch your programming muscles. In this series, we'll work together to build one with tests from A to Z.

  • 项目版本为 laravel 5.4,教程后面会进行升级到 laravel 5.5 的教学
  • 视频教程共计 102 个小节,笔记章节与视频教程一一对应

1.本节说明

  • 对应视频第 22 小节:A User Has A Profile

2.本节内容

本节我们来建立用户的 profile 功能。首先新建测试文件:
forum\tests\Feature\ProfilesTest.php

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class ProfilesTest extends TestCase
{
    use DatabaseMigrations;

    /** @test */
    public function a_user_has_a_profile()
    {
        $user = create('App\User');

        $this->get("/profiles/{$user->name}")
            ->assertSee($user->name);
    }
}

运行测试显然会失败:
file
先来增加路由:
forum\routes\web.php

.
.
Route::get('/profiles/{user}','ProfilesController@show');

再来新建控制器并增加show()方法:

$  php artisan make:controller ProfilesController

forum\app\Http\Controllers\ProfilesController.php

<?php

namespace App\Http\Controllers;

class ProfilesController extends Controller
{
    public function show()
    {

    }
}

再次运行测试:
file
仍然失败,所以我们要补充完整控制器内容:

.
public function show()
{
    return view('profiles.show',[
        'profileUser'=> $user
    ]);
}
.

并且新建视图文件:
forum\resources\views\profiles\show.blade.php

@extends('layouts.app')

@section('content')
    {{ $profileUser->name }}
@endsection

再次运行测试:
file
由于隐性路由模型绑定的缘故:

Route::get('/profiles/{user}','ProfilesController@show');

我们期望的路由片段类似于:/profiles/1{user}片段对应的是$userid属性,但我们期望的是$username属性。所以我们仿照Channel模型改变默认路由片段对应的属性值,改变User对应的默认属性值为name
forum\app\User.php

.
.
    public function getRouteKeyName()
    {
        return 'name';
    }
}

再次测试,测试通过:
file
这意味着我们访问 http://forum.test/profiles/NoNo1 会看到如下页面:
file
可以看到页面十分简陋,让我们略微丰富一下:
forum\resources\views\profiles\show.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="page-header">
            <h1>
                {{ $profileUser->name }}
                <small>注册于{{ $profileUser->created_at->diffForHumans() }}</small>
            </h1>
        </div>
    </div>
@endsection

略微好了点:
file
测试仍然是通过的:
file
接下来我们想把用户相关的Thread显示出来。按照惯例,先建立测试:
forum\tests\Feature\ProfilesTest.php

.
.
/** @test */
public function profiles_display_all_threads_created_by_the_associated_user()
{
    $user = create('App\User');

    $thread = create('App\Thread',['user_id' => $user->id]);

    $this->get("/profiles/{$user->name}")
        ->assertSee($thread->title)
        ->assertSee($thread->body);
}
.

补充完视图:
forum\resources\views\profiles\show.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="page-header">
            <h1>
                {{ $profileUser->name }}
                <small>注册于{{ $profileUser->created_at->diffForHumans() }}</small>
            </h1>
        </div>

        @foreach($profileUser->threads as $thread)
            <div class="panel panel-default">
                <div class="panel-heading">
                    <div class="level">
                        <span class="flex">
                            <a href="#">{{ $thread->creator->name }}</a> 发表于
                            {{ $thread->title }}
                        </span>

                        <span>{{ $thread->created_at->diffForHumans() }}</span>
                    </div>
                </div>

                <div class="panel-body">
                    {{ $thread->body }}
                </div>
            </div>
        @endforeach
    </div>
@endsection

我们使用了threads模型关联关系,但此时关联关系还未建立。前往建立:
forum\app\User.php

.
.
    public function threads()
    {
        return $this->hasMany(Thread::class)->latest();
    }
}

运行测试,测试通过:
file
刷新页面:
file
现在我们还有一个地方需要处理,那就是给页面加上分页:
forum\resources\views\profiles\show.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="page-header">
            <h1>
                {{ $profileUser->name }}
                <small>注册于{{ $profileUser->created_at->diffForHumans() }}</small>
            </h1>
        </div>

        @f oreach($threads as $thread)  -->此处修改
            <div class="panel panel-default">
                <div class="panel-heading">
                    <div class="level">
                        <span class="flex">
                            <a href="#">{{ $thread->creator->name }}</a> 发表于
                            {{ $thread->title }}
                        </span>

                        <span>{{ $thread->created_at->diffForHumans() }}</span>
                    </div>
                </div>

                <div class="panel-body">
                    {{ $thread->body }}
                </div>
            </div>
        @endforeach

        {{ $threads->links() }}   -->此处加上分页链接
    </div>
@endsection

修改控制器:
forum\app\Http\Controllers\ProfilesController.php

<?php

namespace App\Http\Controllers;

use App\User;

class ProfilesController extends Controller
{
    public function show(User $user)
    {
        return view('profiles.show',[
            'profileUser'=> $user,
            'threads' => $user->threads()->paginate(10)
        ]);
    }
}

最后,我们需要在出现用户名的页面给用户名加上链接,跳转到用户的profile页面。我们先为profile路由定义别名:
forum\routes\web.php

.
.
Route::get('/profiles/{user}','ProfilesController@show')->name('profile');

为页面加上链接:
forum\resources\views\profiles\show.blade.php

.
.
<span class="flex">
    <a href="{{ route('profile',$thread->creator) }}">{{ $thread->creator->name }}</a> 发表于
    {{ $thread->title }}
</span>
.
.

forum\resources\views\threads\reply.blade.php

.
.
<h5 class="flex">
    <a href="{{ route('profile',$reply->owner) }}"> {{ $reply->owner->name }}</a>
    回复于
    {{ $reply->created_at->diffForHumans() }}
</h5>
.
.

forum\resources\views\threads\show.blade.php

.
.
<div class="panel-heading">
    <a href="{{ route('profile',$thread->creator) }}">{{ $thread->creator->name }}</a>
    {{ $thread->title }}
</div>
.
.

最后运行一下全部测试:
file

3.写在后面

  • 如有建议或意见,欢迎指出~
  • 如果觉得文章写的不错,请点赞鼓励下哈,你的鼓励将是我的动力!
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!