豪翔天下

Change My World by Program

0%

Datatables 安装

简单的HTML方式使用

使用NPM的方式安装datatables

官网的示例大全,可以在里面搜索到很多种使用场景

Datatables 配置大全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
$('#exampleTable').dataTable({
ajax: {
url: '/getData',
type: 'get',
headers: {},
data: function (data) { // 修改或添加请求的参数,常用于自己写的搜索框
data.searchName = 'xxxx';
},
dataSrc: function (res) { // 修改接口返回的数据
res.data.map(item => {
item.name = '<button>abc</button>';
})
return res.data;
}
},
buttons: [{
text: "Bulk Make as Completed",
className: 'marked-as-complate-btn'
}],
columns: [ // 从数据源dataSrc中取哪些列进行展示
{ data: 'name' },
{ data: 'status' },
{
className: 'test', // 给某一列添加类
data: 'id', // 列的数据名
orderable: true, // 是否允许排序
render: function (data, type, row) { // 给某一列单独添加渲染方式,而不是直接展示值
return '<input type="checkbox" class="form-control" value=' + row.value +'>';
},
searchable: false, // 是否允许过滤
type: 'date', // 设置该列的类型,例如date、num、num-fmt(比如货币等$100,000)、html-num、html-num-fmt、html、string
visible: true, // 设置列是否可见
width: '20%', // 强行设置列的宽度,支持数字和CSS写法
},
],
columnDefs: [{ // 相当于批量设置columns
targets: [0, 1], // 多少列,这里表示第0列和第1列
orderable: false // 定义是否可以拖动排序
}],
createdRow: function (row, data, index) {
$(row).addClass('test');
},
data: {}, // 以数组的方式设置初始化数据,当然一般还是用的ajax
displayLength: 10, // 默认展示的每页的记录数
/* dom:定义表哥的控制元素以什么样式显示
l - length:长度改变输入控制
f - filtering:过滤输入框
t - table:表格本身
i - information:信息概览元素
p - pagination:翻页控制元素
r - processing:处理中显示元素
Bootstrap 3的样式默认值为
"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>"
Bootstrap 4的样式默认值为
"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>"
jQuery UI的样式默认值为
'<"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-tl ui-corner-tr"lfr>'+
't'+
'<"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-bl ui-corner-br"ip>',
*/
dom: "<'row'<'col-sm-12 col-md-6'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-12 col-md-2'l><'col-sm-12 col-md-2'i><'col-sm-12 col-md-8'p>>", // 这里分三个部分进行设置,第一个row表示标题头,第二个row表示table内容,第三个row表示底部信息栏
drawCallback: function (settings) { // 重新渲染完成后执行
var api = this.api();
console.log( api.rows( {page:'current'} ).data() ); // 获取当前页码
},
info: true, // 是否显示总数信息
language: { // 对表格进行国际化
emptyTable: '表中没有可用数据了',
info: "_START_ - _END_ of _TOTAL_", // 修改10 - 20 of 30文字
infoEmpty: "没有记录",
infoFiltered: "从 _MAX_ 条记录中过滤"
lengthMenu: '每页显示 _MENU_ 条', // show xx entries
loadingRecords: '加载中',
processing: '处理中',
search: '搜索',
zeroRecords: '没有找到符合提交的数据',
paginate: {
first: '首页',
last: '尾页',
next: '下一页',
previous: '上一页'
}
},
lengthMenu: [10, 20, 50, 100], // 允许用户选择每页的现实数量
ordering: false, // 全局控制整个列表所有列的排序功能
paging: false, // 是否开启分页
/*
分页按钮样式
numbers:仅显示数字
simple:只显示Previous和Next
simple_numbers: 显示Previous、Next、总页数
full:显示First、Previous、Next、Last
full_number:显示First、Previous、Next、Last、总页数
first_last_numbers:显示First、Last、总页数
*/
pagintType: 'simple_numbers', // 分页按钮的样式
processing: true, // 是否在数据加载时出现“Processing”的提示
responsive: true,
rowReorder: true, // 和下面这个不同的是这个只是简单的允许拖动排序,仅仅是第一列可以拖动
rowReorder: { // 根据指定字段自动进行排序
dataSrc: 'order', // 指定排序字段
selector: 'tr td:not(:last-child)' // 指定可拖动的行元素,如果仅仅是'tr',那么整行都是可以直接拖动的
}
scrollX: true,
searching: false, // 屏蔽搜索框
serverSide: true, // 是否服务器端分页
});
阅读全文 »

Django自带了表单功能,可以与前端及后端完美集成,能非常方便地提供创建、更新或删除模型。

表单定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Post(models.Model):
name = models.CharField()
subtitle = models.CharField(blank=True)
content = models.TextField()
created_at = models.DatetimeField()
user = models.ForeignField(User)

class PostForm(forms.ModelForm):
error_css_class = 'error' # 统一定义错误行的类
required_css_class = 'required' # 统一定义必填项的样式

another_field = forms.DateField(
required=True, # 是否必填,如果是模型本身字段在Model定义时用blank=True
label="Custom Field Name", # 在表单中该字段展示的的label
label_suffix=":", # 默认情况label后面是冒号,这个参数可以指定后缀
initial="abc", # 字段显示的初始值
help_text="除Model本身字段以外的额外的字段",
error_messages=[] # 字段的错误消息列表
validators=[] # 验证函数列表,也可以在下面定义clean_字段名进行验证
disabled=False # 是否设置为disabled
widget={ # 扩展小部件,Meta里面也能批量进行控制
}
)
choice_field = forms.ModelChoiceField(queryset=MyChoices.objects.all())

class Meta:
model = Post # 对应的Model
fields = ("name", "subtitle", "content", "another_field") # 定义前端能够编辑的字段
labels = {"name": "Input the Name"} # 批量定义label
help_texts = {"name": "Enter a correct name"} # 批量定义提示信息
error_messages = {"name": {
"max_length": "字段太长了" # 定义指定错误的错误提示信息
}}
field_classes = { # 批量定义字段的css类
"name": "my_text"
}
widgets = {
"created_at": forms.TextInput(attrs={ # 设置html的一些属性
"type": "date",
"class": "my-class custom-class"
"placeholder": "设置placeholder"
}),
"description": forms.Textarea(attrs={"rows": 1, "cols": 20}) # 设置textarea的默认行数和列数
}

def __init__(self, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.fields["name"].label = "Post Name" # 可以在这里修改model或者form class的字段的label或者其他值
self.fields['user'].queryset = User.objects.filter(id__in[1,2,3]) # 自定义外键的queryset,这个queryset结果不仅用于显示,还用于验证,表单提交的时候该字段也必须在这些值里面
self.fields['my_choice_field'] = forms.ChoiceField(choices=[1,2,3]) # 定义choice字段的可选值

def clean_name(self): # 自定义指定字段的验证,这里验证的是name字段
data = self.cleaned_data['name']
if 'test' in data:
raise ValidationError(_('Invalid name'))
return data
阅读全文 »

python自带库ftplib对ftp的连接提供了支持。下面是其基本的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ftp = ftplib.FTP(timeout=300)	# 连接基本的FTP
ftp = ftplib.FTP_TLS(timeout=300) # 连接FTPS

ftp.connect(host, port) # 连接目标服务器
ftp.login(username, password) # 登陆目标服务器
ftp.mkd('/abc') # 创建远程目录
ftp.dir() # 显示当前目录下的文件及目录,会直接打印到标准输出
ftp.nlst() # 返回当前目录下的文件及目录
ftp.cwd('') # 切换目录
ftp.pwd() # 返回当前所在目录
ftp.rmd(dirname) # 删除远程目录
ftp.delete(filename) # 删除远程文件
ftp.rename(fromname, toname) # 给远程文件重命名
ftp.close() # 关闭连接
ftp.voidcmd('NOOP') # 判断连接是否存活

## 上传文件
local_file_handler = open('test.txt', 'rb')
ftp.storbinary("STOR " + os.path.join(remote_path, filename), local_file_handler)

## 下载文件
local_file_handler = open('test.txt', 'rb')
ftp.retrbinary("RETR " + os.path.join(remote_path, filename), file_handler.write)
local_file_handler.seek(0)
阅读全文 »

  • 在本地开发的时候,由于有很多东西依赖于cookie,有些插件在写入cookie的时候可能没有判断服务端口导致无法写入cookie,功能无法正常使用,所以在开发和使用过程中最好用正常的http端口,即80443

  • 开发时最好打开调试模式:

    1
    2
    3
    4
    # vim wp-config.php
    define('WP_DEBUG', true);
    define('WP_DEBUG_LOG', true);
    define('SCRIPT_DEBUG', true);

插件开发基本概念

插件目录结构

  • wordpress源码的/wp-content/plugins下,一个目录就是一个插件

  • 插件内部的目录结构一般是这样的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    test-plugin
    ├── assets
    │   ├── css
    │ │ └── test-plugin.css
    │ └── js
    │ └── test-plugin.js
    ├── include
    │ └── test-plugin.php
    └── readme.txt

帮助函数

用户相关函数

wp_signon

  • 通过用户名密码获取用户信息
1
2
$user = wp_signon(['user_login' => 'xxx', 'user_password' => 'xxx'], false);
echo $user->id

wp_update_user

  • 更新用户指定字段,但不知道为什么,就是不能更新用户的user_status字段,最后我只能$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_status = 1 WHERE ID = %d", $user->ID ))来吧用户spam了
1
2
3
4
wp_update_user([
'ID' => $userId,
'user_url => 'xxx',
])

get_user_by

  • 通过制定字段获取用户
1
get_user_by( 'id', $userId );

get_user_meta

阅读全文 »

目前项目要为所有的请求添加调用频率限制,使用的是node-rate-limiter-flexible插件,后端api项目可以直接在将其作为一个Koa Middleware,但是前端却不能直接这样引用,因为我们前端使用了nuxtjs,如果直接将该插件作为koa middleware插入app中,那么每一个请求都会经过该插件的统计,包括页面中所有的静态文件请求等,但这其实并不是我们想要的,我们其实只想针对路由route进行统计和过滤。这时候可以将该插件插入nuxtjsserverMiddleware中去,作为nuxtjs的服务端中间件使用。

  • serverMiddleware的执行时机是服务端开始渲染页面之前,所以是服务端渲染的中间件

  • serverMiddleware可以针对指定的路由,如果不指定,则表示针对所有的路由

其配置是在nuxt.config.js中的,例如:

1
2
3
4
5
6
7
8
9
serverMiddleware: [
'~/serverMiddleware/rate-limiter.js', // 这里定义我们编写的rate-limiter插件,针对的是所有路由,注意是路由,不是每个页面请求

// Will register file from project api directory to handle /api/* requires
{ path: '/api', handler: '~/api/index.js' },

// We can create custom instances too
{ path: '/static2', handler: serveStatic(__dirname + '/static2') }
]
阅读全文 »

官方中文文档

常用命令CLI

1
2
3
4
5
6
7
npm install --save-dev @types/node @types/validator
npm install sequelize reflect-metadata sequelize-typescript

npm install mysql2 --save

npm install --save-dev sequelize-cli # 安装命令行工具npx
npx sequelize-cli init # 初始化,会创建config/migrations/seeders/models目录

注意上一步创建的config目录默认是json格式的,我们一般会想从.env文件中读取配置,通常要将它改成config.js文件,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require('dotenv').config()

module.exports = {
development: {
username: process.env.DB_USERNAME,
password: null,
database: 'database_development',
host: '127.0.0.1',
dialect: 'mysql',
},
test: {
username: 'root',
password: null,
database: 'database_test',
host: '127.0.0.1',
dialect: 'mysql',
},
production: {
username: 'root',
password: null,
database: 'database_production',
host: '127.0.0.1',
dialect: 'mysql',
},
};

数据库连接

1
2
3
4
5
6
7
var sequelize = new Sequelize('mysql://用户名:密码@HOST:3306/数据库', {
dialect: 'mysql', // 如果不指定这个参数,可能会报错Dialect needs to be explicitly supplied as of v4.0.0
logging: false // 默认会将sql查询都输出到console.log中,设置为false可以不用输出,不输出sql语句
})

// 直接执行SQL raw queries
const records = await sequelize.query("SELECT * FROM `users`", { type: QueryTypes.SELECT });

模型定义

  • 数据类型包括:
    • 字符串:STRING、STRING(1024)、STRING.BINARY、TEXT、TEXT(‘tiny’)、CITEXT(仅PostgreSQL和SQLite)、TSVECTOR(仅PostgreSQL)
    • 布尔:BOOLEAN
    • 数字:INTEGER、INTEGER.UNSIGNED、INTEGER.ZEROFILL、INTEGER.UNSIGNED.ZEROFILL、BIGING、BIGING(11)、FLOAT、FLOAT(11)、FLOAT(11, 10)、REAL(仅PostgreSQL)、REAL(11)(PostgreSQL)、REAL(11, 10)(仅PostgreSQL)、DOUBLE、DOUBLE(11)、DOUBLE(11, 10)、DECIMAL、DECIMAL(10, 2)
    • 日期:DATE、DATE(6)(仅MySQL)、DATEONLY
    • UUID:可以自动为字段生成UUID,type为UUID,defaultValue为UUIDV1或者UUIDV4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// 定义方式零,纯typescript的方式可以使用https://github.com/RobinBuschmann/sequelize-typescript
@Column(DataType.VIRTUAL)
accessToken: string; // 添加virtual额外的字段

@Column(DataType.JSON) data: any // JSON字段

@Column({field: 'user_id'})
userID: number; // 自定义字段名称

// 定义方式一,typescript方式
class PostModel extends Model {
// 定义一些值可以让其增加typescript声明
public id: number
public name: string

// 为typescript增加获取关联对象的方法声明
public getUser! BelongsToGetAssociationMixin<BandModel>

static initModel (sequelize: Sequelize): void {
id: {
autoIncrement: true,
primaryKey: true,
type: INTEGER
},
name: {
type: STRING,
allowNull: false,
defaultValue: 'test',
validate: { // 数据校验
is: /^[a-z]+$/i, // 满足某个正则
is: ["^[a-z]+$",'i'], // 同上,只是正则用数组来写
not: /^[a-z]+$/i,
not: ["^[a-z]+$",'i'],
isEmail: true,
isUrl: true,
isIP: true,
isIPv4: true,
isIPv6: true,
isAlpha: true,
isAlphanumeric: true,
isNumeric: true,
isInt: true,
isFloat: true,
isDecimal: true,
isLowercase: true,
isUppercase: true,
notNull: true,
isNull: true, // 只允许null
notEmpty: true, // 不能是空字符串
equals: 'specific value',
contains: 'foo',
notIn: [['foo', 'bar']],
isIn: [['foo', 'bar']],
notContains: 'bar',
len: [2,10],
isUUID: 4,
isDate: true,
isAfter: "2011-11-05",
isBefore: "2011-11-05",
max: 23,
min: 23,
isCreditCard: true, // 是否是信用卡数字
isEven(value) { // 自定义校验
if (parseInt(value) % 2 !== 0) {
throw new Error('Only even values are allowed!');
}
}
},
isIn: {
args: [['en', 'zh']],
msg: "Must be English or Chinese" // 上面的校验方式都能够自定义,但是min和max不知道为啥不行,如果是min或者max就改成用len吧
}
}
}

static relate (): void {
PostModel.belongsTo(UserModel, {
as: 'user',
foreignKey: 'user_id'
})
}

@AfterUpdate
static createUser(user: UserModel) {
console.log(user.id);
}

@AfterDestroy // 软删除也是这里
static async afterDestroy(use: UserModel) {}
}

// 定义方式二
const Post = sequelize.define('post', {
id: {
autoIncrement: true,
primaryKey: true,
type: INTEGER
},
name: {
type: STRING,
allowNull: false,
defaultValue: 'test'
},
firstName: {
type: STRING,
field: 'first_name' // 自定义列名称,
comment: '列注释' // 注释仅针对MySQL、MariaDB、PostgreSQL、MSSQL
},
fullName: {
type: VIRTUAL, // 定义virtual字段,即实际不存在数据库中的字段
get: function (this: UserModel) {
return this.firstName + this.name
},
set: function (val) {
this.setDataValue('name', val)
}
},
date: {
type: DATE,
defaultValue: NOW
},
// unique参数的值可以是不二值或者字符串,如果多格列具有相同的字符串unique,他们会组成一个复合唯一键
uniqueOne: { type: DataTypes.STRING, unique: 'compositeIndex' },
uniqueTwo: { type: DataTypes.INTEGER, unique: 'compositeIndex' },

data: {
type: JSON
},
created_at: {
type: DATE
}
}, {
indexes: [{ unique: true, fields: ['field1']}], // 也可以在最后创建索引
timestamps: true, // 是否自动添加createdAt和updatedAt
tableName: 'MyPosts' // 自定义table name,如果不提供,sequelize会根据模型名称自动以复数形式设置表名
paranoid: true, // 定义该表为偏执表,即自带软删除,使用destroy能自动软删除
deletedAt: 'mydelete', // 偏执表软删除字段默认为deletedAt,这里可以指定自定义的字段名
validate: { // 基于model的校验,可以同时校验多个字段
bothCoordsOrNone() {
if ((this.latitude === null) !== (this.longitude === null)) {
throw new Error('Either both latitude and longitude, or neither!');
}
}
}
}
);

// 定义模型关系
Post.associate = () => {
Post.User = Post.belongsTo(app.model.Post)
}

User.associate = () => {
User.hasMany(Post)
}

// 定义模型类方法
Post.customQuery = () => {}

// 定义模型实例方法
Post.prototype.customQuery = () => {}

关联关系定义

  • sequelize默认会给关联关系添加对应的读取方法,例如如果和user关联,那么会有getUser方法,而如果是一对多,或者多对多,那么会有getUsers方法,但是如果是typescript,就需要我们先将该方法声明一下

    1
    2
    3
    public getUsers: BelongsToManyGetAssociationsMixin<UserModel>	// 懒加载

    await fooInstance.$get('bar'); // sequelize-typescript不使用include手动获取关联对象

One to One一对一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 装饰器定义
@ForeignKey(() => Person)
@Column
authorId: number;
@BelongsTo(() => Person)
author: Person;

@BelongsTo(() => Person, 'person_id') // 指定外键
author: Person;

Post.User = Post.belongsTo(app.model.Post, { foreignKey: 'post_id', as: 'Post' }),
Post.PostOwn = User.belongsTo(app.model.Post, {'foreignKey': 'id', as: 'PostOwn'}) // 如果要与当前表自身做join等操作,那么也需要定义一个与自身的关联
PostModel.belongsTo(UserModel)

// hasOne自动添加的方法
fooInstance.getBar()
fooInstance.setBar()
fooInstance.createBar()

One to Many 一对多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const Foo = sequelize.define('foo', { name: DataTypes.STRING });
const Bar = sequelize.define('bar', { status: DataTypes.STRING });
Foo.hasMany(Bar, {
scope: { // 可以通过scope限制某个关联表的字段
status: 'open'
},
as: 'openBars'
});

// hasMany自动添加的方法
fooInstance.getBars()
fooInstance.countBars()
fooInstance.hasBar()
fooInstance.hasBars()
fooInstance.setBars()
fooInstance.addBar()
fooInstance.addBars()
fooInstance.removeBar()
fooInstance.removeBars()
fooInstance.createBar()

// belongsToMany自动添加的方法
fooInstance.getBars()
fooInstance.countBars()
fooInstance.hasBar()
fooInstance.hasBars()
fooInstance.setBars()
fooInstance.addBar()
fooInstance.addBars()
fooInstance.removeBar()
fooInstance.removeBars()
fooInstance.createBar()

Many to Many 多对多

多态多对多
  • 有中间表,且使用target_idtarget_type来表示关联的表的类型
  • 除了我下面这个例子,还可以参考Sequelize中文文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 例如一个用户有多篇文章,多辆车,一篇文章或者一辆车也能同时属于多个用户,那么就有这么几张表: Car, Post, User, UserThings关联表
CarModel.belongsToMany(UserModel, {
through: {
model: UserThingModel, // 中间表
unique: false, // 如果unique为true,那么表示只有一个
scope: {
targetType: 'car', // 当关联的是car时,其`target_type`字段为car
},
foreighKey: 'target_id',
constraints: false
}
})

PostModel.belongsToMany(UserModel, {
through: {
model: UserThingModel, // 中间表
unique: false, // 如果unique为true,那么表示只有一个
scope: {
targetType: 'post', // 当关联的是post时,其`target_type`字段为post
},
foreighKey: 'target_id',
constraints: false
}
})

增删改查

创建操作

1
2
3
4
5
6
7
8
9
10
11
12
const user = await User.create({ firstName: "Jane", lastName: "Doe" });

// 批量创建
const captains = await Captain.bulkCreate([
{ name: 'Jack Sparrow' },
{ name: 'Davy Jones' }
]);

await User.findOrCreate({
where:{}, // 比较的字段
defaults: {} // 填入的字段
})
阅读全文 »

常用语法

基本标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 转义,显示原始html内容
{!! $name !!}

# 转义花括号,因为花括号是特殊字符,如果要直接显示{{}}等内容需要在前面加入@符号
@{{ $name }} // 会直接显示{{ $name }}

# 使用or简化三目运算符
{{ $name or 'Default'}} // {{ isset($name) ? $name : 'Default' }}

# 时间格式转换
{{ $user->created_at->format('d/m/Y') }}

# 获取当前路由
{{ url()->current() == route('/user') }}

# 获取路由参数
{{ request()->get('abc') }}

# 带路由参数的路由生成
{{ route('/users', $id)}}
{{ route('/users', [$id])}}
{{ route('/users', ['id' => $id])}}

{{-- 模板的注释语法 --}}
阅读全文 »

Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 获取请求指定字段
$request->name; // 直接获取
$request->input('name');
$request->input('name', 'Sally'); // 指定默认值
$request->input('user.name'); // 可以直接用点号获取JSON格式的请求体
$request->input('products.0.name'); // 如果请求数据是数组可以用这个方法获取数组内部元素
$request->input('products.*.name'); // 同上
$request->query('name'); // 获取查询参数
$request->query('name', 'Helen'); // 带默认值
$request->all(); // 获取所有请求参数为一个数组
$request->input(); // 同上
$request->query(); // 所有查询参数转换为数组
$request->boolean('archived'); // 获取布尔值,能够自动判断1/"1"/true/"true"/"on"/"yes",6.x开始
$request->only(['username', 'password']); // 仅获取指定字段的请求
$request->except(['credit_card']); // 仅排除指定字段的请求

// 判断请求是否包含某个key
$request->has('name');
$request->has(['name', 'email']);
$request->hasAny(['name', 'email']);
$request->filled('name'); // 是否包含并且不为空
$request->missing('name'); // 不包含

// 获取请求地址
$request->path(); // 获取请求路径,例如https://domain.com/foo/bar就会返回foo/bar
$request->is('admin/*'); // 正则匹配请求路径
$request->fullUrl(); // 包含请求参数的完整url,例如https://dmoain.com/foo/bar?abc=def
$request->url(); // 不包含请求参数的完整url,例如https://dmoain.com/foo/bar
$request->root(); // 获取域名部分,包括http,例如https://domain.com
$request()->getHost(); // 获取纯域名部分,例如domain.com

// 获取请求方法
$request->method();
$request->isMethod('post');// 判断请求方法

$request->route(); # 通过request获取Route对象

$request->cookie('name'); // 获取cookie,同Cookie::get('name');

// 动态改变或新增request的值
$request->merge([
'keyword' => $request->search,
'page' => 2
]);

// 判断请求类型
request()->ajax(); // 判断请求是否是ajax请求
request()->expectsJson(); // 判断客户端是否希望得到JSON响应

// 去掉路由参数
$request->route()->forgetParameter('param');
阅读全文 »

  • 默认启用了TrimStringsConvertEmptyStringsToNull两个中间件的,一个自动去除前后空白,一个将空字符串转换为null

直接验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'title' => ['required', 'unique:posts', 'max:255'], // 也可以写成数组的形式
'person.*.email' => 'email|unique:users', // 校验数组
'person.*.first_name' => 'required_with:person.*.last_name'
'title' => ['required', function ($attribute, $value, $fail) { // 简单的自定义验证规则可以不用建验证类,直接用匿名函数
if ($value === 'foo') {
$fail($attribute.' is invalid.');
}
},],
]);

// 或者这样创建
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);

// 判断请求类型,如果是ajax请求,那么返回json数据和422,如果非ajax那么重定向刷新页面
if ($validator->fails()) {
if ($request->ajax()) {
return response()->json($validator->messages(), Response::HTTP_BAD_REQUEST);
} else {
return redirect('post/create')
->withErrors($validator) // 刷新session中存储的错误信息,可用在view中
->withInput();
}
}

// 同样可以自定义错误信息
$messages = [
'required' => 'The :attribute field is required.',
];
$validator = Validator::make($input, $rules, $messages);

// 满足某个条件时才验证,例如下面当游戏>=100的时候才验证指定字段
$v->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
$v->sometimes(['reason', 'cost'], 'required', function ($input) {
return $input->games >= 100;
});
阅读全文 »