最近一直在忙于毕业设计(的写代码和改 bug 工作),目前开发任务暂时告一段落。在毕设项目的信息系统开发中,后端的 PHP 框架选用了目前最成熟的 Laravel,从实现情况来看,其功能确实相当强大,不仅能实现 MVC 架构的基本操作,还可以通过安装扩展包实现诸如数据库批量填充假数据等功能,也能够使用 Voyager 这样强大的后台管理插件来快速生成网站的后台管理面板。当然整个过程中也踩了不少奇奇怪怪的坑,并且最终用各种奇奇怪的方式解决了,哎自己选的框架含着泪也要用下去……总而言之打算在这里记录一下项目开工以来,用到的各种技术方法和相关教程笔记。(不定期更新中)
毕设项目开发技术总结
前端:
- Bootstrap 3
- Valine - 前端评论系统
- jQuery File Upload - 文件上传插件
- taggle.js - 用于添加标签的表单控件
- holmes.js - 根据搜索框输入的关键词显示页面中的特定内容
- Font Awesome
后端:
- Laravel 5.5
- Laravel 的一些扩展包,如 Faker
- Voyager - Laravel 后台管理框架
- MAMP 集成开发环境
编辑器:
- Atom
《Laravel 教程 - Web 开发实战入门(Laravel 5.5)》学习笔记
原教程参阅 Laravel 教程 - Web 开发实战入门 ( Laravel 5.5 ),由 Laravel 中国社区提供。
MVC
MVC 是 Model(模型)、View(视图)和 Controller(控制器)三个单词的首字母缩写,是一种软件架构设计模式。
- 最上面的一层,是直接面向最终用户的『视图层』(View)。它是提供给用户的操作界面,是程序的外壳。
- 最底下的一层,是核心的『数据层』(Model),也就是程序需要操作的数据或信息。
- 中间的一层,就是『控制层』(Controller),它负责根据用户从『视图层』输入的指令,选取『数据层』中的数据,然后对其进行相应的操作,产生最终结果。
Laravel 开发说明
- 实际应用的开发过程中,应用一般会运行在以下几种环境中:
- 本地开发环境
- 测试环境
- 生产环境
- 在完成对
.env
文件的设置后,我们可以通过传递参数给getenv
方法来获取到.env
文件中指定的属性值,如调用getenv('APP_ENV')
将返回local
。
构建页面
配置路由
当用户在查看一个网页时,一个完整的访问过程如下:
- 打开浏览器在地址栏输入 URL 并访问;
- 路由将 URL 请求映射到指定控制器上;
- 控制器收到请求,开始进行处理。如果视图需要动态数据进行渲染,则控制器会开始从模型中读取数据;
- 数据读取完毕,将数据传送给视图进行渲染;
- 视图渲染完成,在浏览器上呈现出完整页面;
在 Laravel 开发中,使用路由来定义 URL 和 URL 的请求方式,再将该 URL 分配到相对应的控制器动作中进行处理。接下来要构建三个静态页面分别是主页、帮助页、关于页。因此我们需要为路由指定好三个不同的 URL。
进入
routes/web.php
文件,添加代码Route::get('/', 'StaticPagesController@home');
为 get 方法传递了两个参数,第一个参数指明了 URL,第二个参数指明了处理该 URL 的控制器动作。get 表明这个路由将会响应 GET 请求,并将请求映射到指定的控制器动作上。例如我们向 http://sample.test/ 发出了一个请求,则该请求将会由StaticPagesController
的home
方法进行处理。在 Laravel 中较为常用的几个基本的 HTTP 操作分别为 GET、POST、PATCH、DELETE。
- GET 常用于页面读取
- POST 常用于数据提交
- PATCH 常用于数据更新
- DELETE 常用于数据删除
在这四个动作中,PATCH 和 DELETE 是不被浏览器所支持的,但我们可以通过在提交表单中做一些手脚,让服务器以为这两个动作是从浏览器中发出的一样。
生成控制器
$ php artisan make:controller controller_name |
控制器的路径:app/Http/Controllers/。
控制器文件的内容:
namespace
是命名空间。使用
use
来引用在 PHP 文件中要使用的类,引用之后便可以对其进行调用。在静态页面控制器中定义了一个
StaticPagesController
类,这个类继承了父类App\Http\Controllers\Controller
,这意味着你可以在StaticPagesController
类中任意使用父类中除私密方法外的其它方法。
添加静态页面视图
要在控制器中指定渲染某个视图,则需要使用到 view
方法,view
方法接收两个参数,第一个参数是视图的路径名称,第二个参数是与视图绑定的数据,第二个参数为可选参数。
默认情况下,所有的视图文件都存放在 resources/views 文件夹下。
在控制器中指定渲染的视图之后,接下来便是对视图进行构建了,我们需要在 resources/views
中新增三个视图。
Blade 模板:
Blade 是 Laravel 中提供的一套模板引擎,在 Blade 视图中我们可以使用 Laravel 为这套引擎定义的一些默认方法,并且完全兼容 PHP 语法。在项目运行时,Laravel 会把所有的 Blade 视图进行编译缓存成普通的 PHP 代码。
通用视图:
我们给应用创建了一个 default 视图,并将其放在
layouts
文件夹中,default 视图将作为整个应用的基础视图。实际上你只要保证视图文件被放置在resources/views
目录下即可,Laravel 对视图的文件夹和文件命名并没有限制,将 default 文件放在layouts
文件下,只是为了让应用的目录结构让人更好理解。@yield('content')
表示占位区块content
,content
区块的内容将由继承自 default 视图的子视图定义。@yield()
可以有两个参数,第一个参数是区块名称,第二个参数是默认值。Laravel 的 Blade 模板支持继承,这意味多个子视图可以共用父视图提供的视图模板。
@extends('layouts.default')
@section('content')
<h1>主页</h1>
@stop使用
@extends
并通过传参来继承父视图layouts/default.blade.php
的视图模板。使用@section
和@stop
代码来填充父视图的content
区块,所有包含在@section
和@stop
中的代码都将被插入到父视图的content
区块。@section()
可以有两个参数,第一个参数是区块名称,第二个参数是区块内容,当第二个参数被制定时,不需要通过@stop
定界。
Artisan 命令
Artisan 是 Laravel 的命令行接口,它提供了非常多的命令来帮助我们开发 Laravel 应用。前面我们已使用过 Artisan 命令来生成应用的 App Key 和控制器。在本教程中,我们会用到以下 Artisan 命令。
使用 $ php artisan list
来查看所有可用的 Artisan 命令。使用 $ php artisan help command_name
来查看各个 Artisan 命令的帮助界面。
命令 | 说明 |
---|---|
php artisan key:generate | 生成 App Key |
php artisan make:controller | 生成控制器 |
php artisan make:model | 生成模型 |
php artisan make:policy | 生成授权策略 |
php artisan make:seeder | 生成 Seeder 文件 |
php artisan migrate | 执行迁移 |
php artisan migrate:rollback | 回滚迁移 |
php artisan migrate:refresh | 重置数据库 |
php artisan db:seed | 填充数据库 |
php artisan tinker | 进入 tinker 环境 |
php artisan route:list | 查看路由列表 |
优化页面
样式美化
Laravel 在运行时是以
public
文件夹为根目录。Laravel 项目默认集成了 Bootstrap 前端框架,但是还需要做一定配置之后才能够正常使用。Bootstrap 是以 NPM 扩展包的形式集成到 Laravel 项目中的,NPM 是 Node.js(一个基于 Google V8 引擎的 JavaScript 运行环境)的包管理和分发工具。
Laravel 默认集成了一些 NPM 扩展包,这些扩展包,为 Laravel 提供了一套完整的前端工作流。重点看以下几个:
- bootstrap-sass —— Bootstrap NPM 扩展包;
- jquery —— jQuery NPM 扩展包;
- laravel-mix —— 由 Laravel 官方提供的静态资源管理工具;
- vue —— VUE.js 前端框架;
使用Yarn https://yarnpkg.com/en/docs/install 安装bootstrap扩展包:(未使用)在项目根目录下运行以下命令进行安装:
$ yarn install --no-bin-links
$ yarn add cross-env
安装淘宝提供的 cnpm。之后进入项目根目录,使用
cnpm install
命令安装bootstrap扩展包。对 Laravel 默认生成的
app.scss
文件进行编辑,删除此文件里的所有内容,只留下面一行,导入 Bootstrap:resources/assets/sass/app.scss
// Bootstrap
@import "~bootstrap-sass/assets/stylesheets/bootstrap";将 Bootstrap 导入成功之后,需要使用以下命令来将
.scss
文件编译为.css
才能正常使用,在项目根目录运行编译命令如下:$ npm run dev
也可以通过下面的命令,在每次检测到
.scss
文件发生更改时,自动将其编译为.css
文件:$ npm run watch-poll
所有编译后的资源文件都被存放在
public
文件夹中,可以在public/css
文件夹中看到刚刚编译成功之后的文件。也可以直接在
<link>
元素中引入 CSS 文件。
Laravel 前端工作流
Sass 是一种可用于编写 CSS 的语言。可使用
@import
来导入其它的样式文件,支持变量,选择器嵌套,引用父选择器。Laravel Mix 是一款前端任务自动化管理工具,使用了工作流的模式对制定好的任务依次执行。Mix 提供了简洁流畅的 API,让你能够为你的 Laravel 应用定义 Webpack 编译任务。Mix 支持许多常见的 CSS 与 JavaScript 预处理器,通过简单的调用可以管理前端资源。我们可以在 webpack.mix.js 文件中制定一些如资源文件的编译、压缩等任务。Laravel 已默认为我们生成了 webpack.mix.js 文件,并集成了
laravel-mix
模块。要使用 Mix,需要运行命令:
$ npm run watch-poll
watch-poll
会在你的终端里持续运行,监控resources
文件夹下的资源文件是否有发生改变。在watch-poll
命令运行的情况下,一旦资源文件发生变化,Webpack 会自动重新编译。
局部视图
- 局部视图文件名一般以下划线 _ 开头。一般将网页的头部和底部设置为局部视图。
- 在完成头部视图和底部视图的定义后,接下来便可以在 default 视图中引用这两个视图,使用
@include
命令引入视图文件。@include
是 Blade 提供的视图引用方法,可通过传参一个具体的文件路径名称来引用视图。
布局中的链接
是在 HTML 中嵌入 PHP 代码的 Blade 语法标识符,表示包含在该区块内的代码都将使用 PHP 来编译运行。
route()
方法由 Laravel 提供,通过传递一个具体的路由名称来生成完整的 URL。- 在 Laravel 中,我们可以通过在路由后面链式调用
name
方法来为路由指定名称。 route('name')
为我们生成了完整的 URL 地址,这样当我们需要对生成的 URL 进行更改时,我们只需要改动路由文件即可。
创建用户注册页面
- 定义
signup
路由,把 signup 的路由请求交给用户控制器UsersController
来处理。Route::get('/signup', 'UsersController@create')->name('signup');
- 生成用户控制器:
php artisan make:controller UsersController
。将用户注册页面的请求处理指定给用户控制器的create
方法进行处理,返回值为 create 视图。 - 创建注册页面视图
users/create.blade.php
。
用户模型
Model(模型)与数据库交互。本章我们将构建一个基本的用户模型来实现用户数据的存储,并了解 Laravel 如何对模型对象进行增删改查操作。后面我们还会在此用户模型基础上添加用户注册和登录功能,并对用户身份进行权限认证,让管理员用户可以对用户进行删除操作。接着我们还会构建一套用户账号激活和密码找回系统,只有成功进行邮箱激活的用户才能在网站上进行登录,激活成功后的用户如果出现密码丢失的情况,可以使用已认证的邮箱进行密码找回。
准备
- Eloquent ORM:在接下来几章要实现的用户注册功能需要用到数据库来进行数据存储,用于放置用户的基本信息。在这期间,还需要用到数据模型- Model,利用 Laravel 提供的 Eloquent ORM 跟数据库进行交互,实现用户数据的增删改查操作。Eloquent 提供了简洁优雅的 ActiveRecord 实现来跟数据库进行交互。Active Record 是一种领域模型模式,其特点是一个模型类对应关系型数据库中的一个表,模型类的一个实例对应表中的一行记录。Active Record 最大优点是允许我们简单, 直观地操作数据层。
数据库迁移
Laravel 使用 数据库迁移 来管理数据库表结构,迁移就像是数据库中的版本控制,它让团队成员之间能够轻松的修改跟共享应用程序的数据库结构,而不用担心并行更新数据结构而造成冲突等问题。同时也让 Laravel 项目的部署变得很方便。不仅如此,Migration 建表要比直接手动创建表或者
.sql
文件具备额外的管理数据库的功能,如:回滚/重置/更新等。Migration 的建表方法大部分情况下能兼容 MySQL, PostgreSQL, SQLite 甚至是 Oracle 等主流数据库系统。所有创建的迁移文件都被放在
database/migrations
文件夹里。创建用户迁移文件里(database/migrations/2014_10_12_000000_create_users_table.php)包含的内容:定义了一个
CreateUsersTable
类,并继承自Migration
基类。CreateUsersTable 有两个方法up
和down
:- 当我们运行迁移时,
up
方法会被调用; - 当我们回滚迁移时,
down
方法会被调用。
- 当我们运行迁移时,
在
up
方法里面,我们通过调用Schema
类的create
方法来创建users
表。create
方法会接收两个参数:一个是数据表的名称,另一个则是接收$table
(Blueprint 实例)的闭包。若要了解更多 $table 的可用方法,可查阅 官方文档。
删除 migration 迁移文件后,建议执行以下命令,以免 migrate 运行迁移时报错:
composer dump-autoload
composer update
查看数据库表
MAMP/XAMPP 运行
php artisan migrate
报错。解决方法:在 config/database.php 中添加 unix_socket 路径,MAMP为/Applications/MAMP/tmp/mysql/mysql.sock
。另外,.env 和 database.php 文件中的”host” 设置为 localhost。MAMP/XAMPP 运行
php artisan migrate
报错:字符串过长。解决方法:edit yourAppServiceProvider.php
file and inside the boot method set a default string length:use Illuminate\Support\Facades\Schema;
function boot()
{
Schema::defaultStringLength(191);
}MAMP/XAMPP 运行
php artisan migrate
报错:MySQL 执行安全模式检查的问题。解决方法:在 laravel的 config/database.php 的mysql选项配置了严格模式默认为true,修改为false。数据库迁移:
运行
php artisan migrate
命令。注:我们一开始在创建sample
项目时,已经为其创建了数据库,并在.env
文件中做了配置,所以这里会直接使用这些数据库设置。生成的
migrations
表是在我们在第一次执行artisan migrate
命令时生成的,其作用是用来做迁移版本的记录。数据库回滚:
运行
php artisan migrate:rollback
命令。
模型文件
用户模型:app/User.php
用户模型中,
Notifiable
是消息通知相关功能引用,Authenticatable
是授权相关功能的引用。接下来我们主要将精力放在用户模型中定义的三个属性table
,fillable
,hidden
上。需要在 Eloquent 模型中借助对table
属性的定义,来指明要进行数据库交互的数据库表名称,在用户模型中,我们对应要交互的数据库表为users
。Article (文章)模型的例子:
模型文件可通过多种方式进行创建,一般情况下,如果要自己手动创建一个模型文件,最简单的方式是通过
make:model
来创建。模型类名称使用 单数形式来命名:php artisan make:model Article
。同时创建迁移文件:如果需要在创建模型的同时顺便创建数据库迁移,可以使用
--migration
或-m
选项。Laravel 使用 Eloquent 模型与数据库交互。一般每个模型对应一个数据库迁移文件。
Eloquent 数据模型:
在该文件中,Eloquent Article 模型默认情况下会使用类的「下划线命名法」与「复数形式名称」来作为数据表的名称生成规则。因此 Eloquent 将会假设 Article 模型被存储记录在 articles 数据表中。如果你需要指定自己的数据表,则可以通过
table
属性来定义:protected $table = 'my_articles';
。
创建用户对象
- 使用 Eloquent 模型来创建一个用户对象,并将该用户对象存储到数据库。虽然我们现在还没有用户注册表单,但是通过 Laravel 提供的 Tinker 环境可以让我们完成对用户对象创建。Tinker 是一个 REPL (read-eval-print-loop),REPL 指的是一个简单的、可交互式的编程环境,通过执行用户输入的命令,并将执行结果直接打印到命令行界面上来完成整个操作。
- 进入Tinker 环境:
php artisan tinker
。 - 创建一个用户对象:
>>> App\User::create(['name'=>'Aufree', 'email'=>'aufree@yousails.com','password'=>bcrypt('password')])
- 使用 Eloquent 模型提供的
create
方法,通过传入一个关联数组来新建一个用户对象。在我们对用户的password
进行赋值时,调用了一个叫bcrypt
的方法,将password
的值进行加密。
查找用户对象
示例:
当我们要查找一个 id 为 1 的用户时,可以使用下面这种方法:
>>> User::find(1)
用 all 方法取出所有的用户数据:
>>> User::all()
更新用户对象
有两种方式可以完成用户的更新操作:第一种是通过给用户对象属性进行赋值,赋值成功后再调用 save
方法进行保存更新;第二种则是直接调用 update
方法进行更新。较为常用的是第二种更新方式。
通过 update 方法更新:
>>> $user->update(['name'=>'PlusXu'])
Eloquent 除 create
,update
之外还提供了很多其它的方法来方便我们跟数据库进行交互,后面的教程中会讲到更多关于 Eloquent 模型的基本使用,也可以通过查阅 相关文档 来进行深入学习。
用户注册
Laravel 遵从 RESTful 架构的设计原则,将数据看做一个资源,由 URI 来指定资源。对资源进行的获取、创建、修改和删除操作,分别对应 HTTP 协议提供的 GET、POST、PATCH 和 DELETE 方法。当我们要查看一个 id 为 1 的用户时,需要向
/users/1
地址发送一个 GET 请求,当 Laravel 的路由接收到该请求时,默认会把该请求传给控制器的show
方法进行处理。Laravel 为我们提供了
resource
方法来定义用户资源路由。resource
方法遵从 RESTful 架构为用户资源生成路由。该方法接收两个参数,第一个参数为资源名称,第二个参数为控制器名称。Laravel 会自动解析定义在控制器方法(变量名匹配路由片段)中的 Eloquent 模型类型声明。在上面代码中,由于
show()
方法传参时声明了类型 —— Eloquent 模型User
,对应的变量名$user
会匹配路由片段中的{user}
,这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。同时满足以下两种情况,此功能即会自动启用:- 路由声明时必须使用 Eloquent 模型的单数小写格式来作为路由片段参数,User 对应
{user}
。 - 控制器方法传参中必须包含对应的 Eloquent 模型类型声明,并且是有序的。
- 路由声明时必须使用 Eloquent 模型的单数小写格式来作为路由片段参数,User 对应
模型类对应数据表,模型类的实例对应表中的一行记录。
用户对象
$user
通过compact
方法转化为一个关联数组,并作为第二个参数传递给view
方法,将数据与视图进行绑定。show
方法添加完成之后,我们便能在视图中使用user
变量来访问通过view
方法传递给视图的用户数据。laravel资源加载路径设置 bug:在路由中定义URL后,CSS/JS 等静态资源文件的相对路径的根目录也会发生改变,导致无法找到相应的资源(404)。解决方法:在相对路径的最前边加上”/“,表示与
public
目录下的index.php
处于同一路径。数据库重置:运行
migrate:refresh
命令,即可完成数据库的重置操作。$ php artisan migrate:refresh
refresh
的作用是重置数据库并重新运行所有迁移。
资源控制器
Laravel 资源路由将典型的「CRUD」路由分配给具有单行代码的控制器。比如,创建一个控制器来处理应用保存的「照片」的所有 HTTP 请求。使用 Artisan 命令 make:controller
来快速创建控制器:
php artisan make:controller PhotoController --resource |
这个命令会生成一个控制器 app/Http/Controllers/PhotoController.php
。其中包含了每个可用资源的操作方法。
接下来,你可以给控制器注册一个资源路由:
Route::resource('photos', 'PhotoController'); |
这个路由声明创建多个路由来处理资源上的各种行为。生成的控制器为每个行为保留了方法,同时还包括了 处理 HTTP 动作和 URI 的声明注释。
- 资源控制器操作处理:
动作 | URI | 行为 | 路由名称 |
---|---|---|---|
GET | /photos |
index | photos.index |
GET | /photos/create |
create | photos.create |
POST | /photos |
store | photos.store |
GET | /photos/{photo} |
show | photos.show |
GET | /photos/{photo}/edit |
edit | photos.edit |
PUT/PATCH | /photos/{photo} |
update | photos.update |
DELETE | /photos/{photo} |
destroy | photos.destroy |
- 指定资源模型:
如果你使用了路由模型绑定,并且想在资源控制器的方法中使用类型提示,你可以在生成控制器的时候使用 --model
选项:
php artisan make:controller PhotoController --resource --model=Photo |
- 伪造表单方法:
因为 HTML 表单不能生成 PUT
、 PATCH
或者 DELETE
请求,所以你需要添加一个隐藏的 _method
输入字段来伪造这些 HTTP 动作。辅助函数 method_field
可以帮你创建这个字段:
{{ method_field('PUT') }} |
- 部分资源路由:
声明资源路由时,你可以指定控制器处理的部分行为,而不是所有默认的行为:
Route::resource('photo', 'PhotoController', ['only' => [ |
- API资源路由:
当声明用于 APIs 的资源路由时,通常需要排除显示 HTML 模板的路由(如 create
和 edit
)。为了方便起见,你可以使用 apiResource
方法自动排除这两个路由:
Route::apiResource('photo', 'PhotoController'); |
你可以传递一个数组给 apiResources
方法来注册多个API资源控制器:
Route::apiResources([ |
- 命名资源路由:
默认情况下,所有的资源控制器行为都有一个路由名称。你可以传入 names
数组来覆盖这些名称:
Route::resource('photo', 'PhotoController', ['names' => [ |
- 命名资源路由参数:
默认情况下,Route::resource
会根据资源名称的「单数」形式创建资源路由的路由参数。你可以在选项数组中传入 parameters
参数来轻松地覆盖每个资源。parameters
数组应该是资源名称和参数名称的关联数组:
Route::resource('user', 'AdminUserController', ['parameters' => [ |
上例将会为资源的 show
路由生成如下的 URI :
/user/{admin_user} |
用户数据验证
- 在实际开发中,我们经常需要对用户输入的数据进行 验证,在验证成功后再将数据存入数据库。在 Laravel 开发中,提供了多种数据验证方式,在本教程中,我们使用其中一种对新手较为友好的验证方式 -
validator
来进行讲解。validator
由App\Http\Controllers\Controller
类中的ValidatesRequests
进行定义,因此我们可以在所有的控制器中使用validate
方法来进行数据验证。validate
方法接收两个参数,第一个参数为用户的提交数据,第二个参数为数据的验证规则。 - validate 方法的验证规则:`required(存在性)|min:3|max:50(长度)|email(电子邮件格式)|unique:users(唯一性验证,针对“users”表)|confirmed(密码匹配验证)
- 多语言支持:在项目根目录中运行
composer require caouecs/laravel-lang:~3.0
命令。可参考 GitHub 项目地址 https://github.com/caouecs/Laravel-lang。
注册成功
当用户注册完成,且表单信息验证通过后,我们需要做以下两个操作:
- 将用户提交的信息存储到数据库,并重定向到其个人页面;
- 在网页顶部位置显示注册成功的提示信息;
Illuminate\Http\Request
实例参数,我们可以使用该参数来获得用户的所有输入数据。如果我们的表单中包含一个name
字段,则可以借助Request
使用下面的这种方式来获取name
的值:$name = $request->name;
如果需要获取用户输入的所有数据,可使用:
$data = $request->all();
用户模型
User::create()
创建成功后会返回一个用户对象,并包含新注册用户的所有信息。我们将新注册用户的所有信息赋值给变量$user
,并通过路由跳转来进行数据绑定。由于 HTTP 协议是无状态的,所以 Laravel 提供了一种用于临时保存用户数据的方法 - 会话(Session),并附带支持多种会话后端驱动,可通过统一的 API 进行使用。
我们可以使用
session()
方法来访问会话实例。而当我们想存入一条缓存的数据,让它只在下一次的请求内有效时,则可以使用flash
方法。flash
方法接收两个参数,第一个为会话的键,第二个为会话的值,我们可以通过下面这行代码的为会话赋值。session()->flash('success', '欢迎,您将在这里开启一段新的旅程~');
之后我们可以使用
session()->get('success')
通过键名来取出对应会话中的数据。
会话管理
会话控制器
新建一个会话控制器,该控制器将用于处理用户登录退出相关的操作。当用户登录成功时创建会话,当用户退出登录时销毁会话。会话保存在浏览器上。
可以使用 Laravel 提供的
route:list
命令来查看已添加的路由。$ php artisan route:list
身份认证
借助 Laravel 提供的 Auth
的 attempt
方法可以让我们很方便的完成用户的身份认证操作,如下所示:
if (Auth::attempt(['email' => $email, 'password' => $password])) { |
attempt
方法会接收一个数组来作为第一个参数,该参数提供的值将用于寻找数据库中的用户数据。因此在上面的例子中,attempt
方法执行的代码逻辑如下:
- 使用
email
字段的值在数据库中查找; - 如果用户被找到:
1). 先将传参的password
值进行哈希加密,然后与数据库中password
字段中已加密的密码进行匹配;
2). 如果匹配后两个值完全一致,会创建一个『会话』给通过认证的用户。会话在创建的同时,也会种下一个名为laravel_session
的 HTTP Cookie,以此 Cookie 来记录用户登录状态,最终返回true
;
3). 如果匹配后两个值不一致,则返回false
; - 如果用户未找到,则返回
false
。
注册后自动登录
现在的注册功能已经可以正常使用,但我们希望在用户注册成功后能够自动登录,这样的应用用户体验会更棒。在 Laravel 中,如果要让一个已认证通过的用户实例进行登录,可以使用以下方法:
Auth::login($user); |
可以通过调用 Laravel 默认提供的 Auth::logout()
方法来实现用户的退出功能。
用户 CRUD
修改用户个人信息
edit 动作主要做了以下几个操作:
- 利用了 Laravel 的『隐性路由模型绑定』功能,直接读取对应 ID 的用户实例
$user
,未找到则报错; - 将查找到的用户实例
$user
与编辑视图进行绑定;
- 利用了 Laravel 的『隐性路由模型绑定』功能,直接读取对应 ID 的用户实例
在我们提交用户更新表单之后,将由用户控制器的
update
动作来做处理,因此我们需要把表单提交的请求地址指向用户更新的 URL 上。<form method="POST" action="{{ route('users.update', $user->id )}}">
上面代码转为 HTML 后如下所示:
<form method="POST" action="http://sample.test/users/1">
在 RESTful 架构中,我们使用 PATCH 动作来更新资源,但由于浏览器不支持发送 PATCH 动作,因此我们需要在表单中添加一个隐藏域来伪造 PATCH 请求。
{{ method_field('PATCH') }}
转换为 HTML 代码如下所示:
<input type="hidden" name="_method" value="PATCH">
表单对应视图,表单的数据提交到相应的控制器
在用户控制器加上
update
方法来处理用户提交的个人信息。update
方法接收两个参数,第一个为自动解析用户 id 对应的用户实例对象,第二个则为更新用户表单的输入数据。在我们接收到用户提交的信息时,需要先对用户提交的信息进行验证,最终调用update
方法对用户对象进行更新。在用户个人资料更新成功后,我们还需要将用户重定向到个人页面,方便用户第一时间查看到自己更改后的个人信息。
权限系统
Laravel 中间件 (Middleware) 为我们提供了一种非常棒的过滤机制来过滤进入应用的 HTTP 请求,例如,当我们使用 Auth 中间件来验证用户的身份时,如果用户未通过身份验证,则 Auth 中间件会把用户重定向到登录页面。如果用户通过了身份验证,则 Auth 中间件会通过此请求并接着往下执行。Laravel 框架默认为我们内置了一些中间件,例如身份验证、CSRF 保护等。所有的中间件文件都被放在项目的
app/Http/Middleware
文件夹中。限制未登录用户的权限。用户通过身份认证(登录)后才可以访问:
__construct
是 PHP 的构造器方法,当一个类对象被创建之前该方法将会被调用。在__construct
方法中调用了middleware
方法,该方法接收两个参数,第一个为中间件的名称,第二个为要进行过滤的动作。通过except
方法来设定指定动作不使用 Auth 中间件进行过滤,意为除了此处指定的动作以外,所有其他动作都必须通过身份认证用户才能访问。相反的还有only
方法,将只过滤指定动作。我们提倡在控制器 Auth 中间件使用中,首选except
方法,这样的话,当你新增一个控制器方法时,默认是安全的,此为最佳实践。Laravel 提供的 Auth 中间件在过滤指定动作时,如该用户未通过身份验证(未登录用户),默认将会被重定向到
/login
登录页面。限制已登录用户的权限。用户登录后只能编辑自己的个人信息:
在完成对未登录用户的限制之后,接下来我们要限制的是已登录用户的操作。当 id 为 1 的用户去尝试更新 id 为 2 的用户信息时,我们应该返回一个 403 禁止访问的异常。在 Laravel 中可以使用 授权策略 (Policy) 来对用户的操作权限进行验证,在用户未经授权进行操作时将返回 403 禁止访问的异常。
我们可以使用以下命令来生成一个名为
UserPolicy
的授权策略类文件,用于管理用户模型的授权。$ php artisan make:policy UserPolicy
所有生成的授权策略文件都会被放置在
app/Policies
文件夹下。为默认生成的用户授权策略添加
update
方法,用于用户更新时的权限验证。update
方法接收两个参数,第一个参数默认为当前登录用户实例,第二个参数则为要进行授权的用户实例。当两个 id 相同时,则代表两个用户是相同用户,用户通过授权,可以接着进行下一个操作。如果 id 不相同的话,将抛出 403 异常信息来拒绝访问。使用授权策略需要注意以下两点:
- 我们并不需要检查
$currentUser
是不是 NULL。未登录用户,框架会自动为其 所有权限 返回false
; - 调用时,默认情况下,我们 不需要 传递当前登录用户至该方法内,因为框架会自动加载当前登录用户(接着看下去,后面有例子);
- 我们并不需要检查
接下来我们还需要在
AuthServiceProvider
类中对授权策略进行设置。AuthServiceProvider
包含了一个policies
属性,该属性用于将各种模型对应到管理它们的授权策略上。我们需要为用户模型User
指定授权策略UserPolicy
。授权策略定义完成之后,我们便可以通过在用户控制器中使用
authorize
方法来验证用户授权策略。默认的App\Http\Controllers\Controller
类包含了 Laravel 的AuthorizesRequests
trait。此 trait 提供了authorize
方法,它可以被用于快速授权一个指定的行为,当无权限运行该行为时会抛出 HttpException。authorize
方法接收两个参数,第一个为授权策略的名称,第二个为进行授权验证的数据。需要为
edit
和update
方法加上这行:$this->authorize('update', $user);
这里
update
是指授权类里的update
授权方法,$user
对应传参update
授权方法的第二个参数。正如上面定义update
授权方法时候提起的,调用时,默认情况下,我们 不需要 传递第一个参数,也就是当前登录用户至该方法内,因为框架会自动加载当前登录用户。重定向到用户之前尝试访问的页面:
当一个未登录的用户尝试访问自己的资料编辑页面时,将会自动跳转到登录页面,这时候如果用户再进行登录,则会重定向到其个人中心页面上,这种方式的用户体验并不好。更好的做法是,将用户重定向到他之前尝试访问的页面,即自己的个人编辑页面。
redirect()
实例提供了一个intended
方法,该方法可将页面重定向到上一次请求尝试访问的页面上,并接收一个默认跳转地址参数,当上一次请求记录为空时,跳转到默认地址上。使用 Auth 中间件仅允许已登录的用户访问,使用 Guest 中间件仅允许未登录的用户访问。
列出所有用户信息
用户列表:
用户列表对应用户控制器的
index
动作,页面 URL 对应/users
。接下来我们将在用户控制器中加入index
动作。并且因为用户列表的访问权限是公开的,所以我们还需要在 Auth 中间件except
中新增index
动作来允许游客访问。批量生成假数据(示例):
假数据的生成分为两个阶段:
模型工厂:
模型工厂用于指定数据表中字段(假数据)的填充规则。Laravel 默认为我们集成了 Faker 扩展包,使用该扩展包可以让我们很方便的生成一些假数据。可以借助 Faker 和 Eloquent 模型工厂来为指定模型的每个字段设置随机值。
define
定义了一个指定数据模型(如此例子User
)的模型工厂。define
方法接收两个参数,第一个参数为指定的 Eloquent 模型类,第二个参数为一个闭包函数,该闭包函数接收一个Faker
PHP 函数库的实例,让我们可以在函数内部使用 Faker 方法来生成假数据并为模型的指定字段赋值。数据填充:
使用
Seeder
类来为数据库批量填充测试数据。所有的 Seeder 类文件都放在database/seeds
目录下,文件名需要按照『驼峰式』来命名,且严格遵守大小写规范。Laravel 默认为我们定义了一个DatabaseSeeder
类,我们可以在该类中使用call
方法来运行其它的Seeder
类,以此控制数据填充的顺序。我们可以使用下面命令来生成一个UsersTableSeeder
文件,用于填充用户相关的假数据。$ php artisan make:seeder UsersTableSeeder
在我们定义好了用户模型工厂之后,便可以在生成的用户数据填充文件中使用
factory
这个辅助函数来生成一个使用假数据的用户对象。times
和make
方法是由 FactoryBuilder 类 提供的 API。times
接受一个参数用于指定要创建的模型数量,make
方法调用后将为模型创建一个 集合。makeVisible
方法临时显示 User 模型里指定的隐藏属性$hidden
,接着我们使用了insert
方法来将生成假用户列表数据批量插入到数据库中。最后我们还对第一位用户的信息进行了更新,方便后面我们使用此账号登录。接着我们还需要在
DatabaseSeeder
中调用call
方法来指定我们要运行假数据填充的文件。完成上面操作之后,我们便可以开始为用户生成批量假数据了,在运行生成假数据的命令之前,我们需要使用
migrate:refresh
命令来重置数据库,之后再使用db:seed
执行数据填充。$ php artisan migrate:refresh
$ php artisan db:seed如果我们要单独指定执行
UserTableSeeder
数据库填充文件,则可以这么做:$ php artisan migrate:refresh
$ php artisan db:seed --class=UsersTableSeeder你也可以使用下面一条命令来同时完成数据库的重置和填充操作:
$ php artisan migrate:refresh --seed
分页:
默认状况下,页面的当前页数由 HTTP 请求所带的 page 参数决定,当你访问 http://sample.app/users?page=2 链接时,获取的是第二页的用户列表信息,Laravel 会自动检测到 page 的值并插入由分页器生成的链接中。
$users = User::paginate(10);
中使用 paginate 方法来指定每页生成的数据数量为 10 条,即当我们有 50 个用户时,用户列表将被分为五页进行展示。在调用
paginate
方法获取用户列表之后,便可以通过以下代码在用户列表页上渲染分页链接。{!! $users->render() !!}
由
render
方法生成的 HTML 代码默认会使用 Bootstrap 框架的样式,渲染出来的视图链接也都统一会带上?page
参数来设置指定页数的链接。另外还需要注意的一点是,渲染分页视图的代码必须使用{!! !!}
语法,而不是,这样生成 HTML 链接才不会被转义。
删除用户&配置管理员权限
管理员:
我们需要生成一个迁移文件来为用户表新增管理员字段。在生成迁移文件时,带上
--table
选项可以为指定数据表生成迁移文件。现在,让我们运行下面命令来为用户表新增管理员字段。$ php artisan make:migration add_is_admin_to_users_table --table=users
我们需要在新建的迁移文件中为用户添加一个
is_admin
的布尔值类型字段来判别用户是否拥有管理员身份,该字段默认为false
,在迁移文件执行时对该字段进行创建,回滚时则需要对该字段进行移除。使用
dropColumn
方法来对指定字段进行移除。destroy 动作:
删除用户的动作,有两个逻辑需要提前考虑:
- 只有当前登录用户为管理员才能执行删除操作;
- 删除的用户对象不是自己(即使是管理员也不能自己删自己)。
Laravel 授权策略提供了
@can
Blade 命令,允许我们在 Blade 模板中做授权判断。接下来让我们利用@can
指令,在用户列表页加上只有管理员才能看到的删除用户按钮。在 destroy 动作中,我们首先会根据路由发送过来的用户 id 进行数据查找,查找到指定用户之后再调用 Eloquent 模型提供的
delete
方法对用户资源进行删除,成功删除后在页面顶部进行消息提示。最后将用户重定向到上一次进行删除操作的页面,即用户列表页。删除授权策略
destroy
我们已经在上面创建了,这里我们在用户控制器中使用authorize
方法来对删除操作进行授权验证即可。在删除动作的授权中,我们规定只有当前用户为管理员,且被删除用户不是自己时,授权才能通过。
Voyager 后台管理框架的使用
参考 GitHub 项目主页。
安装
1. Require the Package
After creating your new Laravel application you can include the Voyager package with the following command:
composer require tcg/voyager |
2. Add the DB Credentials & APP_URL
Next make sure to create a new database and add your database credentials to your .env file:
DB_HOST=localhost |
You will also want to update your website URL inside of the APP_URL
variable inside the .env file:
APP_URL=http://localhost:8000 |
Only if you are on Laravel 5.4 will you need to Add the Service Provider.
3. Run The Installer
Lastly, we can install voyager. You can do this either with or without dummy data. The dummy data will include 1 admin account (if no users already exists), 1 demo page, 4 demo posts, 2 categories and 7 settings.
To install Voyager without dummy simply run
php artisan voyager:install |
If you prefer installing it with dummy run
php artisan voyager:install --with-dummy |
Troubleshooting: Specified key was too long error. If you see this error message you have an outdated version of MySQL, use the following solution: https://laravel-news.com/laravel-5-4-key-too-long-error
And we’re all good to go!
Start up a local development server with php artisan serve
And, visit http://localhost:8000/admin.
Creating an Admin User
If you did go ahead with the dummy data, a user should have been created for you with the following login credentials:
email:
admin@admin.com
password:password
NOTE: Please note that a dummy user is only created if there are no current users in your database.
If you did not go with the dummy user, you may wish to assign admin privileges to an existing user. This can easily be done by running this command:
php artisan voyager:admin your@email.com |
If you did not install the dummy data and you wish to create a new admin user you can pass the --create
flag, like so:
php artisan voyager:admin your@email.com --create |
And you will be prompted for the user’s name and password.
手动填充数据 seeder
安装完成后,需要手动将 VoyagerDatabaseSeeder 在 DatabaseSeeder 类中进行调用,这样在运行 db:seed 命令时可以填充 Voyager 的数据。
$this->call(VoyagerDatabaseSeeder::class); |
we don’t add the Voyager seeder to the default seeder, and adding the --seed
flag to migrate:refresh
doesn’t let you specify what seeder class should be run. The solution there is to either do as you’ve done, or add the single VoyagerDatabaseSeeder instead of the list like you’ve done, or just call it manually:
> php artisan migrate:refresh --seed |