用户模块

用户迁移

php artisan migrate

会创建迁移内的表到数据库

用户模型

Laravel 默认为我们生成了用户模型文件

app/Models/User.php

创建Article 模型

php artisan make:model Article

同时创建迁移文件

如果需要在创建模型的同时顺便创建数据库迁移,则可以使用 --migration 或 -m 选项,让我们将刚刚生成的模型进行删除,尝试生成迁移文件:

rm app/Models/Article.php
php artisan make:model Article -m
Model created successfully.
Created Migration: 2020_07_29_234536_create_articles_table

可看到模型文件和迁移文件都一并生成了

Eloquent 表命名约定

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;

    protected $table = 'my_articles';
}

创建用户对象

我们使用此命令进入 Tinker 环境:

php artisan tinker

如果中途想要退出 Tinker,可使用 ctrl + c 快捷键。
通过下面命令我们可以很轻松的创建一个用户对象:

App\Models\User::create(['name'=> 'Summer', 'email'=>'summer@example.com','password'=>bcrypt('password')])

查找用户对象

php artisan tinker
User::find(1)

当你传给 find 方法的 id 不存在时,Tinker 将会返回 null:

更新用户对象

$user = User::first()
$user->name = 'Monkey'

调用save保存

$user->save()

通过 update 方法更新

$user->update(['name'=>'Summer'])

添加用户模块路由

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 架构对路由进行设计。

修改用户控制器

<?php

namespace App\Http\Controllers;

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

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

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

新建一个用户个人页面

# resources/views/users/show.blade.php
@extends('layouts.default')
@section('title', $user->name)

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

访问 /users/1 即可看到展示用户名的页面

设置用户头像和侧边栏

# app/Models/User.php
.
.
.
    public function gravatar($size = '100')
    {
        $hash = md5(strtolower(trim($this->attributes['email'])));
        return "https://cdn.v2ex.com/gravatar/$hash?s=$size";
    }
}    

定义好后我们可以调用用户头像了

$user->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])

再次 访问 /users/1页面查看效果

 

用户注册表单

重置数据库并重新运行所有迁移,我们之前创建的 1 号用户将会被删除。

php artisan migrate:refresh

表单构建

# 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="mb-3">
            <label for="name">名称:</label>
            <input type="text" name="name" class="form-control" value="{{ old('name') }}">
          </div>

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

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

          <div class="mb-3">
            <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') }}

用户数据验证

# app/Http/Controllers/UsersController.php

<?php

namespace App\Http\Controllers;

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

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|unique:users|max:50',
            'email' => 'required|email|unique:users|max:255',
            'password' => 'required|confirmed|min:6'
        ]);
        return;
    }
}

此时提交数据会被拦截,我们在form 表单中加入一个csrf令牌即可

{{ csrf_field() }}

注册失败错误消息

# 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

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

# 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="mb-3">
          <label for="name">名称:</label>
          <input type="text" name="name" class="form-control" value="{{ old('name') }}">
        </div>

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

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

        <div class="mb-3">
          <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

添加语言包

配置中文

# config/app.php
<?php

return [
    .
    .
    .
    'locale' => 'zh_CN',
    .
    .
    .
];    

发布 语言包

php artisan lang:publish
# lang/zh_CN/validation.php
'custom' => [
    'email' => [
        'required' => '邮箱地址不能为空!',
    ],
],

保存用户并重定向

# app/Http/Controllers/UsersController.php

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

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password),
        ]);

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

消息提示

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

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password),
        ]);

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

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

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

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

在视图上展示

# 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>