laravel微博系列02

这一篇主要是注册功能的实现

创建注册路由

routes/web.php

// 用户注册表单视图页面路由
Route::get('/signup', 'UsersController@create')->name('signup');

添加控制器

php artisan make:controller UsersController

// 用户注册表单页面
public function create() {
	return view('users.create');
}

修改home视图文件中的注册链接

<a class="btn btn-lg btn-success" href="{{ route('signup') }}" role="button">现在注册</a>

添加注册视图文件

resources/views/users/create.blade.php

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

@section('content')
    <h1>注册</h1>
@stop

数据迁移

不必再手动去数据库建表,建字段了,或者创建.sql文件了,而是通过laravel本身提供的数据迁移文件,来创建表,创建字段,或者删除表,删除数据。

迁移文件放在 database/migrations ,默认已经有了四个,分别是:

database/migrations/2014_10_12_000000_create_users_table.php   构建用户表
database/migrations/2014_10_12_100000_create_password_resets_table.php   构建密码重置表
database/migrations/2019_08_19_000000_create_failed_jobs_table.php   构建任务失败表
database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php  构建访问令牌的表

我们来看看用户表的迁移文件中的内容:

定义了一个匿名类,并继承 Migration ,这个类中,有两个方法 up,down

执行迁移时,up会被调用(创建表),执行回滚时,down会被调用(删除表)

创建表

Schema::create('users', function (Blueprint $table) {  // 参数1就是表名,参数2是一个接收Blueprint 实例的闭包
    // 字段 
});

定义字段

用Blueprint实例来定义,也就是上面的 $table

$table->id();    // bigint unsigned 自增 id

$table->string('name'); // 昵称

$table->string('email')->unique(); // 邮箱,具有唯一性

$table->timestamp('email_verified_at')->nullable();   // 邮箱的验证时间,允许空值

$table->string('password'); // 密码

$table->rememberToken();  // 记住我token

$table->timestamps(); // created_at,updated_at -> 创建时间和更新时间

更多说明见文档:https://learnku.com/docs/laravel/9.x/migrations/12248#creating-tables

执行迁移

php artisan migrate

之前在 .env 中配置了数据库,此时可以去看看有没有创建表。

执行迁移回滚

php artisan migrate:rollback

用户模型

app/Models/User.php 这个是默认带的,我们来看看里面的内容

<?php
namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;  // HasFactory 是模型工厂相关功能的引用
use Illuminate\Foundation\Auth\User as Authenticatable;   // Authenticatable 是授权相关功能的引用
use Illuminate\Notifications\Notifiable;   // Notifiable 是消息通知相关功能引用
use Laravel\Sanctum\HasApiTokens;  // HasApiTokens API 令牌修改功能

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * 在这里面的字段才能被更新
     * 防止批量字段更新时,被恶意更改了不应该变更的字段
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * 将表中查询到的某些字段隐藏
     * 比如我们返回json格式给客户端,但是password是不需要给的,就可以在这里隐藏
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * 字段在代码中的数据类型
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',  // email_verified_at在表中为时间戳,在项目代码中,变为datetime类型
    ];
}

演示创建一个Article模型文件

创建model文件

php artisan make:model Article  // 注意:按约定是单数命名

// 如果需要同时创建其对应的迁移文件
php artisan make:model Article -m

模型文件讲解

一个最小的模型文件

<?php

namespace App\Models;

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

class Article extends Model
{
    use HasFactory;
}

类名称 -> 表名称

比如: Article -> articles  , User  -> users  , BlogPost  -> blog_posts 

如果你想自定义表名称?

protected $table = 'my_articles';

体验创建,查找,更新 用户

我们已经有了User模型和users表,因此,可以先来体验一下操作用户数据。

可以在tinker交互环境中运行,我这里就简单的使用路由闭包来完成,因为我觉得tinker中写代码不方便。

创建一个用户

Routes/web.php

Route::get('/createUser', function () {
   $rs = \App\Models\User::create([
        'name' => 'junwind',
        'email' => 'junwind@qq.com',
        'password' => bcrypt('123123')
    ]);
   var_dump($rs);
});

请求 http://192.168.0.101:8000/createUser ,然后检查表。

查询用户对象

// 引入 User 模型类
use App\Models\User   // 提前引入后,该文件后续使用User,就不必都带上完整的命名空间了

User::find(1)   // 查找id为1的,如果不存在,则返回null

User::findOrFail(2)  // 查询id为2的,如果不存在,则会报错。
 Illuminate\Database\Eloquent\ModelNotFoundException with message 'No query results for model [App\Models\User] 2'

User::first()  // 表中的第一个

User::all()  // 所有

// 为了方便我测试,我直接在web.php路由文件中写model了
Route::get('queryUser', function () {
    $user = \App\Models\User::find(1);
    dd($user, $user->name);
});

变更用户对象数据

1、先对User对象的属性赋值,再save保存

$user = User::find(1);
$user->name = 'kevin';
$user->save();

2、直接update

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

添加users资源路由

// users资源路由  php artisan route:list
Route::resource('users', 'UsersController');

添加个人信息展示页面

我们知道,这个路由实际是 Route::get(‘/users/{user}’, ‘UsersController@show’)

当我们访问 http://192.168.0.101:8000/users/1 时,其实就是显示id为1的用户信息。

当然,此时我们访问,会报错,因为还没有对应的show()方法。

添加show方法:app/Http/Controllers/UsersController.php

public function show(User $user) { // 这里具有 『隐性路由模型绑定』 ,当然需要符合某种约定才行。
	return view('users.show', compact('user'));  // 参数1是视图页面,参数2是将$user数据传递给视图页面
}

$user 为 User模型对象,这个对象的查询条件为id,id的值就是路由中的 {user} 值,这里laravel会自动注入{user}的值给$user的。能这么用,是要按一种约定:

  1. {user} 和 User模型名称一致,只不过是小写的。当然了,资源路由本身就是这种。
  2. 控制器方法中,必须有模型类的声明。 show(User $user)
  3. 请求的方式是 http://xx/users/1 这种

创建用户的个人信息页面:

resources/views/users/show.blade.php

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

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

再次访问 http://192.168.0.101/users/1 页面试试看。

生成用户头像

我们先来创建一个自己的助手函数文件,然后在里面添加生成图片的方法。

注意:里面都是静态方法,这是为了方便调用,并且性能也更好。

// 生成首字母base64图片
public static function letter_avatar($text)
{
	$total = unpack('L', hash('adler32', $text, true))[1];
	$hue = $total % 360;
	list($r, $g, $b) = self::hsv2rgb($hue / 360, 0.3, 0.9);
	$bg = "rgb({$r},{$g},{$b})";
	$color = "#ffffff";
	$first = mb_strtoupper(mb_substr($text, 0, 1));
	$src = base64_encode('<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="100" width="100"><rect fill="' . $bg . '" x="0" y="0" width="100" height="100"></rect><text x="50" y="50" font-size="50" text-copy="fast" fill="' . $color . '" text-anchor="middle" text-rights="admin" alignment-baseline="central">' . $first . '</text></svg>');
	return 'data:image/svg+xml;base64,' . $src;
}

// 生成字母对应的RGB颜色码
public static function hsv2rgb($h, $s, $v)
{
	$r = $g = $b = 0;
	$i = floor($h * 6);
	$f = $h * 6 - $i;
	$p = $v * (1 - $s);
	$q = $v * (1 - $f * $s);
	$t = $v * (1 - (1 - $f) * $s);
	switch ($i % 6) {
		case 0:
			$r = $v;
			$g = $t;
			$b = $p;
			break;
		case 1:
			$r = $q;
			$g = $v;
			$b = $p;
			break;
		case 2:
			$r = $p;
			$g = $v;
			$b = $t;
			break;
		case 3:
			$r = $p;
			$g = $q;
			$b = $v;
			break;
		case 4:
			$r = $t;
			$g = $p;
			$b = $v;
			break;
		case 5:
			$r = $v;
			$g = $p;
			$b = $q;
			break;
	}
	return [
		floor($r * 255),
		floor($g * 255),
		floor($b * 255)
	];
}

调用时,和其它类一样

use App\Helpers\Helpers;
...
print_r( Helpers::letter_avatar("xqw") );

添加用户头像局部视图文件

resources/views/layouts/_user_info.blade.php

<a href="{{ route('users.show', $user->id) }}">
    <img src="{{ $gravatar }}" 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('layouts._user_info', ['user' => $user, 'gravatar' => $gravatar])
                    </section>
                </div>
            </div>
        </div>
    </div>
@stop

控制器中 app/Http/Controllers/UsersController.php :

// 用户信息页面
public function show(User $user) { // 这里具有 『隐性路由模型绑定』 ,当然需要符合某种约定才行。
	$gravatar = Helpers::letter_avatar($user->name);
	return view('users.show', compact('user', 'gravatar'));
}

最后,再次访问 http://192.168.0.101:8000/users/1、查看效果。

构建注册视图页面

清理数据库数据,其实就是删除users表中的旧数据

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
// 用户注册表单页面
public function create() {
	return view('users.create');
}

验证注册表单提交的数据

根据资源路由规则,我们知道,处理新增用户业务的是 UserController@store ,并且是Post方式

因此是在store方法里,接收表单提交的参数,先验证,然后新增到库中。

public function store(Request $request)
{
	$this->validate($request, [   // 参数1为用户输入的数据,参数2为对应数据的验证规则
		'name' => 'required|unique:users|max:50',  // required必填项   unique:users字段唯一性,并且针对的是users表   max:50字段最大长度
		'email' => 'required|email|unique:users|max:255',  // email邮箱验证
		'password' => 'required|confirmed|min:6'  // confirmed两次输入的密码必须一致
	]);
	return;
}

给表单添加csrf_field

为了防止网站被 CSRF(跨站请求伪造)的攻击 ,在表单中,我们应该添加

{{ csrf_field() }}

// 等同于
<input type="hidden" name="_token" value="fhcxqT67dNowMoWsAHGGPJOAWJn8x5R5ctSwZrAq">

这个token值,是基于session的,在config/session.php中的lifetime中配置了过期时间,默认2小时。

显示注册表单提交失败信息

注册提交后,可能会失败,此时应该在页面给出提示。

创建一个失败消息的局部视图文件 : resources/views/layouts/_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

laravel本身会将验证中的错误闪存到$errors变量中,当有错误存在时,laravel还会自动将错误 $errors 绑定到视图中,所以在视图文件中,可以直接使用 $errors。

在注册表单视图文件中引用错误提示局部视图:resources/views/users/create.blade.php

...
@include('layouts._errors')
<form method="POST" action="{{ route('users.store') }}">
...

使用语言包

我们的错误消息提示默认是英文的,我们使用语言包,将其改为中文的。

方式1:可以自定义语言包。

创建文件 : lang/zh_CN/validation.php

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

方式2:使用第三方库:

composer require overtrue/laravel-lang:~6.0

设置本地化:

config/app.php

'locale' => 'zh_CN',

如果字段名称还是英文的,我们创建语言包文件来解决:lang/zh_CN/validation.php

<?php
return [
    'attributes' => [
        'name' => '名称',
        'email' => '邮箱',
        'password' => '密码',
    ],
];

注册成功的处理

也就是经过了参数验证后,我们还需要处理:

1、用户数据落地,并重定向到个人页面。

public function store(Request $request)
{
	$this->validate($request, [   // 参数1为用户输入的数据,参数2为对应数据的验证规则
		'name' => 'required|unique:users|max:50',  // required必填项   unique:users字段唯一性,并且针对的是users表   max:50字段最大长度
		'email' => 'required|email|unique:users|max:255',  // email邮箱验证
		'password' => 'required|confirmed|min:6'  // confirmed两次输入的密码必须一致
	]);

	$user = User::create([   // 创建成功后返回一个User对象实例
		'name' => $request->name,
		'email' => $request->email,
		'password' => bcrypt($request->password),
	]);

	return redirect()->route('users.show', [$user]);  // route() 方法会自动获取 Model 的主键,也就是数据表 users 的主键 id, 所以 [$user] 等于 [$user->id]
}

2、跳转到个人页面后,显示注册成功的提示信息。

我们可以在注册成功后,加一个闪存,跳转页面后,读取这个闪存。

public function store(Request $request)
{
	...
	session()->flash('success', '注册成功');  // 参数1是key,参数2是值,读取一次后,数据就失效了  , 读数据  session()->get('success') , session()->has(key)是否存在key
	return redirect()->route('users.show', [$user]);
}

因为http协议是无状态的,我们可以用session来保存客户端上一次的状态,当然现在主流是用 Redis

添加消息提示局部视图: resources/views/layouts/_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

在全局默认视图中引入消息视图:resources/views/layouts/default.blade.php

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

<body>
    @include('layouts._header')

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

现在来测试一下注册功能,可以创建用户成功了,可以跳转到用户个人信息页面了,并且也有注册成功的提示消息了。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇