四、用户注册

四、用户注册

一、开发目标

在我们成功为用户创建完模型之后,接下来就得开始着手用户注册功能的构建了。本章我们将为注册页面添加一个注册表单,允许用户在表单上填写个人信息并提交注册,提交之后用户数据将转由控制器进行处理。在控制器中首先会对用户提交的数据进行验证,验证通过后才能存入数据库。在用户注册成功之后,我们还需要提供一个个人页面来展示用户的基本信息。

接下来让我们按照惯例为本章节新建一个分支:

$ git checkout master
$ git checkout -b sign-up

二、显示用户的信息

1,用户资源

我们之前已使用 Tinker 成功创建了一个用户对象。运行下面命令使用 Tinker 来查询用户的信息,确保该用户对象在数据库中确实存在:

$ php artisan tinker

从数据库中获取第一号用户的个人信息:

>>> App\Models\User::first()
=> App\Models\User {#2909
     id: 1,
     name: "Summer",
     email: "summer@example.com",
     email_verified_at: null,
     created_at: "2018-12-12 09:09:53",
     updated_at: "2018-12-12 09:21:53",
   }

通过 Tinker 返回的信息可以看到,id 为 1,用户名为 Summer 的用户信息被成功返回。接下来让我们开始着手构建用户个人页面,并在此页面上对用户信息进行显示。

Laravel 遵从 RESTful 架构的设计原则,将数据看做一个资源,由 URI 来指定资源。对资源进行的获取、创建、修改和删除操作,分别对应 HTTP 协议提供的 GET、POST、PATCH 和 DELETE 方法。当我们要查看一个 id 为 1 的用户时,需要向 /users/1 地址发送一个 GET 请求,当 Laravel 的路由接收到该请求时,默认会把该请求传给控制器的 show方法进行处理。

Laravel 为我们提供了 resource 方法来定义用户资源路由。

routes/web.php

Route::get('/','StaticPagesController@home')->name('home');
Route::get('/help','StaticPagesController@help')->name('help');
Route::get('/about','StaticPagesController@about')->name('about');

Route::get('/signup','UsersController@create')->name('signup');
Route::resource('users','UsersController');

新增的 resource 方法将遵从 RESTful 架构为用户资源生成路由。该方法接收两个参数,第一个参数为资源名称,第二个参数为控制器名称。

Route::resource('users', 'UsersController');

上面代码将等同于:

Route::get('/users', 'UsersController@index')->name('users.index');
Route::get('/users/create', 'UsersController@create')->name('users.create');
Route::get('/users/{user}', 'UsersController@show')->name('users.show');
Route::post('/users', 'UsersController@store')->name('users.store');
Route::get('/users/{user}/edit', 'UsersController@edit')->name('users.edit');
Route::patch('/users/{user}', 'UsersController@update')->name('users.update');
Route::delete('/users/{user}', 'UsersController@destroy')->name('users.destroy');

可以看到使用 resource 方法让我们少写了很多代码,且严格按照了 RESTful 架构对路由进行设计。

生成的资源路由列表信息如下所示:

HTTP 请求URL动作作用
GET/usersUsersController@index显示所有用户列表的页面
GET/users/{user}UsersController@show显示用户个人信息的页面
GET/users/createUsersController@create创建用户的页面
POST/usersUsersController@store创建用户
GET/users/{user}/editUsersController@edit编辑用户个人资料的页面
PATCH/users/{user}UsersController@update更新用户
DELETE/users/{user}UsersController@destroy删除用户

这时我们访问 http://weibo.test/users/1 页面,会出现如下页面。这是因为该路由请求由 UsersController 里面的 show 方法来处理,但现在该方法还不存在,因此会导致报错:

image.png


UsersController 的 show 方法定义如下:

app/Http/Controllers/UsersController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UsersController extends Controller
{
    public function create()
    {
        return view('users.create');
    }

    public function show(User $user)
    {
        return view('users.show',compact('user'));
    }
}

Laravel 会自动解析定义在控制器方法(变量名匹配路由片段)中的 Eloquent 模型类型声明。在上面代码中,由于 show() 方法传参时声明了类型 —— Eloquent 模型 User,对应的变量名 $user 会匹配路由片段中的 {user},这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。

此功能称为 『隐性路由模型绑定』,是『约定优于配置』设计范式的体现,同时满足以下两种情况,此功能即会自动启用:

  1. 路由声明时必须使用 Eloquent 模型的单数小写格式来作为路由片段参数,User 对应 {user}

Route::get('/users/{user}', 'UsersController@show')->name('users.show');

在使用资源路由 Route::resource('users', 'UsersController'); 时,默认已经包含了上面的声明。

  1. 控制器方法传参中必须包含对应的 Eloquent 模型类型声明,并且是有序的:

public function show(User $user)
{
    return view('users.show',compact('user'));
}

当请求 http://weibo.test/users/1 并且满足以上两个条件时,Laravel 将会自动查找 ID 为 1 的用户并赋值到变量 $user中,如果数据库中找不到对应的模型实例,会自动生成 HTTP 404 响应。

return view('users.show', compact('user'));

我们将用户对象 $user 通过 compact 方法转化为一个关联数组,并作为第二个参数传递给 view 方法,将数据与视图进行绑定。

show 方法添加完成之后,我们便能在视图中使用 user 变量来访问通过 view 方法传递给视图的用户数据。

由于我们还没有创建用户个人页面,因此这时访问用户页面时会出现如下报错。

View [users.show] not found.

image.png


下面让我们来新建一个用户个人页面。

resources/views/users/show.blade.php

@extends('layouts.default')
@section('title',$user->name)

@section('content')
{{$user->name}} - {{$user->email}}
@stop

由于我们使用了 view('users.show', compact('user')) 将用户数据与视图进行绑定,因此在视图中可以直接使用 $user 来访问用户实例。

这时候我们再访问用户个人页面,便能够看到基本的数据展示。

image.png

3、Gravatar 头像和侧边栏

现在,我们要为用户的个人页面添加头像显示的功能。接下来的项目开发将使用 Gravatar 来为用户提供个人头像支持。Gravatar 为 “全球通用头像”,当你在 Gravatar 的服务器上放置了自己的头像后,可通过将自己的 Gravatar 登录邮箱进行 MD5 转码,并与 Gravatar 的 URL 进行拼接来获取到自己的 Gravatar 头像。

接下来让我们在用户模型中定义一个 gravatar 方法,用来生成用户的头像。

app/Models/User.php

<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $table = "users";

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function gravatar($size = '100')
    {
        $hash = md5(strtolower(trim($this->attributes['email'])));
        return "http://www.gravatar.com/avatar/$hash?s=$size";
    }
}

该方法主要做了以下几个操作:

  1. 为 gravatar 方法传递的参数 size 指定了默认值 100;

  2. 通过 $this->attributes['email'] 获取到用户的邮箱;

  3. 使用 trim 方法剔除邮箱的前后空白内容;

  4. 用 strtolower 方法将邮箱转换为小写;

  5. 将小写的邮箱使用 md5 方法进行转码;

  6. 将转码后的邮箱与链接、尺寸拼接成完整的 URL 并返回;

定义好 gravatar 方法之后,我们便可以在视图中通过以下方式进行调用:

使用默认尺寸来获取头像:

$user->gravatar();

为 gravatar 指定尺寸大小来获取头像:

$user->gravatar('140');

接下来让我们来构建一个全局通用的局部视图,用于展示用户的头像和用户名等基本信息。

resources/views/shared/_user_info.blade.php

<a href="{{route('users.show',$user->id)}}">
    <img src="{{$user->gravatar('140')}}" alt="{{$user->name}}" class="gravatar">
</a>
<h1>{{$user->name}}</h1>

该视图将被嵌套在用户个人页面中进行使用,因此我们需要对用户个人页面进行更改,加入我们新创建的用户信息局部视图。

resources/views/users/show.blade.php

@extends('layouts.default')
@section('title',$user->name)

@section('content')
    <div class="row">
        <div class="offset-md-2 col-md-8">
            <div class="col-md-12">
                <div class="offset-md-2 col-md-8">
                    <section class="user_info">
                        @include('shared._user_info',['user'=>$user])
                    </section>
                </div>
            </div>
        </div>
    </div>
@stop

我们可以通过给 @include 方法传参,将用户数据以关联数组的形式传送到 _user_info 局部视图上。

@include('shared._user_info', ['user' => $user])

接下来对样式再进行优化。

resources/sass/app.scss

/* User gravatar */

section.user_info {
  padding-bottom: 10px;
  margin-top: 20px;
  text-align: center;
  .gravatar {
    float: none;
    max-width: 70px;
  }
  h1 {
    font-size: 1.4em;
    letter-spacing: -1px;
    margin-bottom: 3px;
    margin-top: 15px;
  }
}

.gravatar {
  float: left;
  max-width: 50px;
  border-radius: 50%;
}

现在再次访问个人页面,便可以看到用户头像了。

image.png

Git 代码版本控制

接着让我们将这些修改加入到版本控制中:

$ git add -A
$ git commit -m "用户显示页面"

三、注册表单

1、注册表单

在我们接下来要进行的用户注册功能开发中,第一个步骤即是构建注册表单。首先我们需要把之前在 Tinker 中创建的所有用户数据进行删除,将数据库重置。重置的方法很简单,只需借助 migrate:refresh 命令,即可完成数据库的重置操作。

$ php artisan migrate:refresh

refresh 的作用是重置数据库并重新运行所有迁移。

2、表单构建

现在让我们更改之前已创建的用户注册页面,加入表单元素。

resources/views/users/create.blade.php

@extends('layouts.default')
@section('title','注册')

@section('content')
    <div class="offset-md-2 col-md-8">
        <div class="card ">
            <div class="card-header">
                <h5>注册</h5>
            </div>
            <div class="card-body">
                <form method="POST" action="{{ route('users.store') }}">
                    <div class="form-group">
                        <label for="name">名称:</label>
                        <input type="text" name="name" class="form-control" value="{{ old('name') }}">
                    </div>

                    <div class="form-group">
                        <label for="email">邮箱:</label>
                        <input type="text" name="email" class="form-control" value="{{ old('email') }}">
                    </div>

                    <div class="form-group">
                        <label for="password">密码:</label>
                        <input type="password" name="password" class="form-control" value="{{ old('password') }}">
                    </div>

                    <div class="form-group">
                        <label for="password_confirmation">确认密码:</label>
                        <input type="password" name="password_confirmation" class="form-control" value="{{ old('password_confirmation') }}">
                    </div>

                    <button type="submit" class="btn btn-primary">注册</button>
                </form>
            </div>
        </div>
    </div>
@stop

Laravel 提供了全局辅助函数 old 来帮助我们在 Blade 模板中显示旧输入数据。这样当我们信息填写错误,页面进行重定向访问时,输入框将自动填写上最后一次输入过的数据。

{{ old('name') }}

刷新页面瞧一瞧:

image.png


Git 代码版本控制

接着让我们将本次修改加入到版本控制中:

$ git add -A
$ git commit -m "用户注册表单"


四、用户数据验证

1、用户数据验证

如果你现在填写注册表单并进行提交,则会出现报错,因为表单还不能真正使用。我们还需要在用户控制器中添加一个用于处理表单数据提交后的 store 方法,用于处理用户创建的相关逻辑。

app/Http/Controllers/UsersController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UsersController extends Controller
{
    public function create()
    {
        return view('users.create');
    }

    public function show(User $user)
    {
        return view('users.show',compact('user'));
    }

    public function store(Request $request)
    {
        $this->validate($request,[
            'name' => 'required|max:50',
            'email' => 'require|email|unique:users|max:255',
            'password'=>'required|confirmed|min:6'
        ]);
        return ;
    }
}

接下来让我来讲解下新增的 store 方法。

public function store(Request $request)
{
    $this->validate($request,[
        'name' => 'required|max:50',
        'email' => 'require|email|unique:users|max:255',
        'password'=>'required|confirmed|min:6'
    ]);
    return ;
}

在实际开发中,我们经常需要对用户输入的数据进行 验证,在验证成功后再将数据存入数据库。在 Laravel 开发中,提供了多种数据验证方式,在本教程中,我们使用其中一种对新手较为友好的验证方式 - validator 来进行讲解。validator 由 App\Http\Controllers\Controller 类中的 ValidatesRequests 进行定义,因此我们可以在所有的控制器中使用 validate 方法来进行数据验证。validate 方法接收两个参数,第一个参数为用户的输入数据,第二个参数为该输入数据的验证规则。

2、验证规则

下面来看下我们在验证用户数据时,都用到了哪几种验证规则。

(1)存在性验证

在用户填写表单的时候,我们会要求用户必须填写上自己的用户名,当用户名为空时将注册失败。

这时我们可以使用 required 来验证用户名是否为空。

'name' => 'required'

(2)长度验证

我们还可以使用 min 和 max 来限制用户名所填写的最小长度和最大长度。

'name' => 'min:3|max:50'

如果需要同时验证多个条件时,则可使用 | 对验证规则进行分割。

(3)格式验证

在其它的一些应用上,如果要对用户邮箱进行验证,则可能需要你写一段非常冗长且不易理解的 正则表达式 来匹配邮箱格式。但在 Laravel 中,我们只需简单的使用 email 便能够完成邮箱格式的验证。

'email' => 'email'

(4)唯一性验证

一般情况下,我们还需要验证用户使用的注册邮箱是否已被它人使用,这时我们可以使用唯一性验证,这里是针对于数据表 users 做验证。

'email' => 'unique:users'

但这种验证方式还是不够严谨,所以我们需要在一开始创建 用户数据表 时便设置邮箱字段的唯一属性。这个 Laravel 在默认给我们生成的用户表迁移文件中便已经默认设定好了。

(5)密码匹配验证

如果我们需要确保用户在输入密码时,保证两次输入的密码一致。这时候则可以使用 confirmed 来进行密码匹配验证。

'password' => 'confirmed'

3、表单提交

在我们为注册表单添加上验证规则之后,尝试点击注册会发现『页面过期』的报错异常:

image.png


出现该报错的原因是,在我们使用 POST 方法提交表单时,Laravel 为了安全考虑,会让我们提供一个 token(令牌)来防止我们的应用受到 CSRF(跨站请求伪造)的攻击。修复该异常的方法很简单,我们只需要在表单元素中添加 Blade 模板为我们提供的 csrf_field 方法即可。该方法在 Blade 模板中调用如下:

{{ csrf_field() }}

上面这段代码转换为 HTML 如下所示:

<input type="hidden" name="_token" value="fhcxqT67dNowMoWsAHGGPJOAWJn8x5R5ctSwZrAq">

由于输入框为 hidden 类型,因此该 input 元素在页面上是不可见的。现在让我们为注册表单添加 csrf_field 方法。

resources/views/users/create.blade.php

@extends('layouts.default')
@section('title','注册')

@section('content')
    <div class="offset-md-2 col-md-8">
        <div class="card ">
            <div class="card-header">
                <h5>注册</h5>
            </div>
            <div class="card-body">
                <form method="POST" action="{{ route('users.store') }}">
                    {{ csrf_field() }}
                    <div class="form-group">
                        <label for="name">名称:</label>
                        <input type="text" name="name" class="form-control" value="{{ old('name') }}">
                    </div>

                    <div class="form-group">
                        <label for="email">邮箱:</label>
                        <input type="text" name="email" class="form-control" value="{{ old('email') }}">
                    </div>

                    <div class="form-group">
                        <label for="password">密码:</label>
                        <input type="password" name="password" class="form-control" value="{{ old('password') }}">
                    </div>

                    <div class="form-group">
                        <label for="password_confirmation">确认密码:</label>
                        <input type="password" name="password_confirmation" class="form-control" value="{{ old('password_confirmation') }}">
                    </div>

                    <button type="submit" class="btn btn-primary">注册</button>
                </form>
            </div>
        </div>
    </div>
@stop

这时候如果你再次填写注册表单并进行提交,你会发现表单依旧处于不可用状态,这是因为:

  1. 在表单信息验证失败时,在页面上没有给出错误提示;

  2. 在表单信息验证通过后,页面没有重定向跳转到其它页面,并给出注册成功的提示;

下面让我们针对上面两种情况继续完善注册表单。

Git 代码版本控制

开始之前先让我们将本次修改加入到版本控制中:

$ git add -A
$ git commit -m "增加 CSRF 验证"

五、注册失败错误消息

1、显示表单错误信息

目前是我们尝试填写完表单,如果表单信息填写有误并提交,页面不会展示报错信息。Laravel 默认给我们提供了一种非常好的展示错误信息的方法,现在让我们来为应用加上提交失败时的错误信息展示。

resources/views/shared/_errors.blade.php

@if (count($errors) > 0)
    <div class="alert alert-danger">
        <ul>
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

通过上面代码我们可以看到 Blade 模板还为我们提供了一些其它的便利方法,如:

@if (count($errors) > 0)
    {{ count($errors) }}
@endif

在解析成 PHP 代码后为:

if (count($errors) > 0) {
    {{ count($errors) }}
}

Blade 支持所有的循环语句和条件判断语句,如 @if, @elseif, @else, @for, @foreach, @while 等等,应用在 Blade 中的表达式都需要以 @ 开头。

Laravel 默认会将所有的验证错误信息进行闪存。当检测到错误存在时,Laravel 会自动将这些错误消息绑定到视图上,因此我们可以在所有的视图上使用 errors 变量来显示错误信息。需要注意的是,在我们对 errors 进行使用时,要先使用 count($errors) 检查其值是否为空。

定义好错误消息局部视图,便可以在用户的注册表单中对该视图进行引用。

resources/views/users/create.blade.php

@extends('layouts.default')
@section('title','注册')

@section('content')
    <div class="offset-md-2 col-md-8">
        <div class="card ">
            <div class="card-header">
                <h5>注册</h5>
            </div>
            <div class="card-body">

                @include('shared._errors')

                <form method="POST" action="{{ route('users.store') }}">
                    {{ csrf_field() }}
                    <div class="form-group">
                        <label for="name">名称:</label>
                        <input type="text" name="name" class="form-control" value="{{ old('name') }}">
                    </div>

                    <div class="form-group">
                        <label for="email">邮箱:</label>
                        <input type="text" name="email" class="form-control" value="{{ old('email') }}">
                    </div>

                    <div class="form-group">
                        <label for="password">密码:</label>
                        <input type="password" name="password" class="form-control" value="{{ old('password') }}">
                    </div>

                    <div class="form-group">
                        <label for="password_confirmation">确认密码:</label>
                        <input type="password" name="password_confirmation" class="form-control" value="{{ old('password_confirmation') }}">
                    </div>

                    <button type="submit" class="btn btn-primary">注册</button>
                </form>
            </div>
        </div>
    </div>
@stop

这时,如果再次尝试填写一些验证无法通过的信息并进行表单提交,便能够在页面上看到错误消息提示。

image.png




2、添加语言包

通过页面显示我们可以看到,这时的报错信息显示的还是英文。Laravel 为消息验证的多语言提供了一种非常简便的方法进行支持。我们可以通过添加一个如 resources/lang/xx/validation.php 语言包,并在语言包的 custom 数组中对翻译语言进行设定。如:

'custom' => [
    'email' => [
        'required' => '邮箱地址不能为空!',
    ],
],

这是非常通用的功能,所以在 GitHub 上有人专门为此写了一个扩展包 - overtrue/laravel-lang 来对 Laravel 提供默认提示信息添加多语言版本翻译。

接下来让我们使用 Composer 来安装 laravel-lang

$ composer require "overtrue/laravel-lang:~3.0"

由于该包已经配置了包的自动注册 (Package Auto-Discovery),所以不需要你在配置文件去注册服务提供器即可使用。

最后,我们还需要将项目语言设置为中文。

config/app.php

<?phpreturn [
    .
    .
    .
    'locale' => 'zh-CN',
    .
    .
    .
];

现在再次提交验证不通过的信息,能看到错误提示已变成中文。

image.png



如果你需要对属性或者验证消息改写,直接在 resources/lang/xx/validation.php 中编写你需要定制的部分即可,更多使用方式请参考overtrue/laravel-lang 中文使用说明

Git 代码版本控制

接着让我们将本次更改加入到版本控制中:

$ git add -A
$ git commit -m "中文的错误提示信息"

六、注册成功

1、注册成功

目前用户注册失败的逻辑已经处理完成,让我们接着完善用户注册成功后的处理逻辑。

当用户注册完成,且表单信息验证通过后,我们需要做以下两个操作:

  1. 将用户提交的信息存储到数据库,并重定向到其个人页面;

  2. 在网页顶部位置显示注册成功的提示信息;

让我们针对这两个操作来写具体的逻辑实现代码。

2、保存用户并重定向

app/Http/Controllers/UsersController.php

store 方法接受一个 Illuminate\Http\Request 实例参数,我们可以使用该参数来获得用户的所有输入数据。如果我们的表单中包含一个 name 字段,则可以借助 Request 使用下面的这种方式来获取 name 的值:

$name = $request->name;

如果需要获取用户输入的所有数据,可使用:

$data = $request->all();

用户模型 User::create() 创建成功后会返回一个用户对象,并包含新注册用户的所有信息。我们将新注册用户的所有信息赋值给变量 $user,并通过路由跳转来进行数据绑定。

redirect()->route('users.show', [$user]);

注意这里是一个『约定优于配置』的体现,此时 $user 是 User 模型对象的实例。route() 方法会自动获取 Model 的主键,也就是数据表 users 的主键 id,以上代码等同于:

redirect()->route('users.show', [$user->id]);

3、消息提示

现在验证通过的注册用户已经能够成功创建,并进行重定向跳转了。接下来我们要做的就是,用户注册成功后,在页面顶部位置显示注册成功的提示信息。

app/Http/Controllers/UsersController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UsersController extends Controller
{
    public function create()
    {
        return view('users.create');
    }

    public function show(User $user)
    {
        return view('users.show',compact('user'));
    }

    public function store(Request $request)
    {
        $this->validate($request,[
            'name' => 'required|max:50',
            'email' => 'required|email|unique:users|max:255',
            'password'=>'required|confirmed|min:6'
        ]);

        $user = User::created([
            'name'=>$request->name,
            'email'=>$request->email,
            'password'=>bcrypt($request->password),
        ]);
        session()->flash('success','欢迎,您将在这里开启一段新的旅程~');
        return redirect()->route('users.show',[$user]);
    }
}

由于 HTTP 协议是无状态的,所以 Laravel 提供了一种用于临时保存用户数据的方法 - 会话(Session),并附带支持多种会话后端驱动,可通过统一的 API 进行使用。

我们可以使用 session() 方法来访问会话实例。而当我们想存入一条缓存的数据,让它只在下一次的请求内有效时,则可以使用 flash 方法。flash 方法接收两个参数,第一个为会话的键,第二个为会话的值,我们可以通过下面这行代码的为会话赋值。

session()->flash('success', '欢迎,您将在这里开启一段新的旅程~');

之后我们可以使用 session()->get('success') 通过键名来取出对应会话中的数据,取出的结果为 欢迎,您将在这里开启一段新的旅程~

接下来的消息提示我们会用会话进行闪存,并分别为其设定好指定的键。dangerwarningsuccessinfo 这四个键名在 Bootstrap 分别具有不同样式展现效果,因此后面我们将使用这几个键名作为消息提示的专有设定。

现在让我们加入消息提醒视图,让会话消息在视图上进行展示。

resources/views/shared/_messages.blade.php

@foreach(['danger','warning','success','info'] as $msg) 
    @if(session()->has($msg)) 
        <div class="flash-message">
            <p class="alert alert-{{$msg}}">
                {{session()->get($msg)}}
            </p>
        </div>
    @endif
@endforeach

session()->has($msg) 可用于判断会话中 $msg 键对应的值是否为空,若为空则在页面上不进行显示。最后,我们通过 session()->get($msg) 来取出对应的值并在页面上进行显示。

现在,让我们在全局通用视图中加入消息提醒视图。

resources/views/layouts/default.blade.php

<!DOCTYPE html>
<html>
  <head>
    <title>@yield('title', 'Weibo App') - Laravel 入门教程</title>
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
  </head>
  <body>
    @include('layouts._header')

    <div class="container">
      <div class="offset-md-1 col-md-10">
          @include('shared._messages')
          @yield('content')
          @include('layouts._footer')
      </div>
    </div>
  </body>
</html>

当我们再次注册一个验证通过的用户时,能够看到消息提醒在页面上成功展示。

image.png


Git 代码版本控制

接下来让我们将改动的代码进行提交,并切回到主分支中进行合并。

image.png


使用上面的链接打开我们的 Heroku 应用,并进入注册页面:

image.png

七、在Heroku 上使用PostgreSQL

Heroku 为 Laravel 应用提供了数据存储的功能,我们可以在 Heroku 上使用 MySQL 或 PostgreSQL 来进行数据存储。由于 Heroku 对 PostgreSQL 的支持比 MySQL 更好,因此本教程中将在 Heroku 上使用 PostgreSQL 来作为我们应用的数据库。

要在 Heroku 上使用 PostgreSQL,我们需要先安装 PostgreSQL 扩展。

$ heroku addons:add heroku-postgresql:hobby-dev

安装完成之后,Heroku 将为我们生成一个唯一的数据库 URL - DATABASE_URL,我们可以通过下面命令查看 Heroku 的所有配置信息:

$ heroku config

在本地开发中,我们使用了 MySQL 来作为数据库储存,但在 Heroku 环境上我们要改为使用 PostgreSQL 来作为数据库储存。因此在进行数据库设置时,我们需要对当前环境进行判断。如果环境为本地环境,则使用 MySQL 数据库,若为 Heroku 环境,则使用 PostgreSQL 数据库。我们可以通过为 Heroku 新增一个 IS_IN_HEROKU 配置项来判断应用是否运行在 Heroku 上。

$ heroku config:set IS_IN_HEROKU=true

一般来说,应用的数据库都在 config/database.php 中进行配置,因此我们需要针对该配置文件,来为不同环境的数据库连接方式定义一个帮助方法,以便根据应用不同的运行环境来指定数据库配置信息,我们需要新建一个 helpers.php 文件并写入以下内容:

app/helpers.php

<?php
/**
 * Created by PhpStorm.
 * User: SEELE
 * Date: 2019/1/17
 * Time: 17:21
 */
function get_db_config()
{
    if (getenv('IS_IN_HEROKU')) {
        $url = parse_url(getenv("DATABASE_URL"));

        return $db_config = [
            'connection' => 'pgsql',
            'host' => $url["host"],
            'database'  => substr($url["path"], 1),
            'username'  => $url["user"],
            'password'  => $url["pass"],
        ];
    } else {
        return $db_config = [
            'connection' => env('DB_CONNECTION', 'mysql'),
            'host' => env('DB_HOST', 'localhost'),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
        ];
    }
}

可以看到,我们定义了 get_db_config 方法来根据数据库的不同运行环境获取不同的配置信息。通过 Heroku 生成的 DATABASE_URL 包含了一切与数据库相关的配置信息,如主机、用户名、密码、数据库等,因此我们需要使用 parse_url 方法对其进行解析,来获取到指定的值。当运行环境为 Heroku 时,我们使用 DATABASE_URL 提供的数据库配置信息,如果为其它环境,则使用默认的数据库配置信息。

在我们新增 helpers.php 文件之后,还需要在项目根目录下 composer.json 文件中的 autoload 选项里 files 字段加入该文件:

composer.json

"autoload": {
    "psr-4": {
        "App\\": "app/"
    },
    "classmap": [
        "database/seeds",
        "database/factories"
    ],
    "files":[
        "app/helpers.php"
    ]
},

修改保存后运行以下命令进行重新加载文件即可:

$ composer dump-autoload

现在,让我们使用刚刚定义好的 get_db_config 方法对数据库进行配置。

config/database.php

<?php

$db_config = get_db_config();

return [
    'default' => env('DB_CONNECTION', 'mysql'),

    'connections' => [

        'sqlite' => [
            'driver' => 'sqlite',
            'database' => env('DB_DATABASE', database_path('database.sqlite')),
            'prefix' => '',
            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
        ],

        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
        ],

        'pgsql' => [
            'driver' => 'pgsql',
            'host' => $db_config['host'],
            'port' => env('DB_PORT', '5432'),
            'database' => $db_config['database'],
            'username' => $db_config['username'],
            'password' => $db_config['password'],
            'charset' => 'utf8',
            'prefix' => '',
            'prefix_indexes' => true,
            'schema' => 'public',
            'sslmode' => 'prefer',
        ],

        'sqlsrv' => [
            'driver' => 'sqlsrv',
            'host' => env('DB_HOST', 'localhost'),
            'port' => env('DB_PORT', '1433'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'charset' => 'utf8',
            'prefix' => '',
            'prefix_indexes' => true,
        ],

    ],

    'redis' => [

        'client' => 'predis',

        'default' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => env('REDIS_DB', 0),
        ],

        'cache' => [
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => env('REDIS_CACHE_DB', 1),
        ],

    ],

];

现在整个用户注册功能到此已开发完毕。让我们将改动的代码进行提交,并推送到 GitHub 和 Heroku 上。

先把 .env 文件的3306端口注释掉

#DB_PORT=3306
$ git add -A
$ git commit -m "Updated database configuration"$ git push
$ git push heroku master

我们可以使用 heroku run 在 Heroku 运行 Laravel 的指定命令。现在我们需要在 Heroku 上执行迁移,生成用户表,可通过下面命令来完成:

$ heroku run php artisan migrate

若提示是否要在生产环境上运行此命令,请输入 yes 或者 y


image.png

数据库迁移执行完后,即可尝试注册一个新用户:

image.png

如果你要在 Heroku 上重置 PostgreSQL 数据库,可以使用以下命令(知晓即可,你不需要执行):

$ heroku pg:reset DATABASE
$ heroku run php artisan migrate

八、小结

经过本章节的学习,我们学到了以下内容:

  • 使用 RESTful 来构建用户资源;

  • Gravatar 头像的实现;

  • 通过表单与控制器协同处理数据;

  • 验证表单提交的数据,验证失败给出错误提示;

  • 利用 Composer 安装扩展包(中文错误提示);

  • 使用闪存来展示提醒信息;

  • 在 Heroku 上使用数据库;






回复列表



回复操作

正在加载验证码......

请先拖动验证码到相应位置