Thứ Ba, 13 tháng 4, 2021

Validator trong AdonisJS




## Set up
> adonis install @adonisjs/validator

- Đăng kí Validator Provider
File start/app.js
<!-->
const providers = [
'@adonisjs/validator/providers/ValidatorProvider'
]
-->

## Ví dụ cơ bản
File start/routes.js
> Route.resource('users', 'UserController')

Tạo file resources/views/user/create.edge
<!-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello Adonis</title>
{{ style('style') }}
{{ cspMeta() }}
</head>
<body>
<div class="subtitle">

<form method="POST" action="{{ route('UserController.store') }}">
<div>
<input type="text" name="email" value="{{ old('email', '') }}" />
<br/>
{{ elIf('<span>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
</div>

<div>
<input type="text" name="password" />
<br/>
{{ elIf('<span>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
</div>

{{ csrfField() }}
<br/>
<button type="submit"> Submit </button>
</form>

</div>
</body>
</html>
-->

File app/Controllers/Http/UserController.js
<!-->
'use strict'

const { validate } = use('Validator')
...
class UserController {
...
async create ({ request, response, view }) {
return view.render('user.create')
}

async store ({ request, response }) {
const rules = {
email: 'required|email|unique:users,email',
password: 'required'
}

const validation = await validate(request.all(), rules)

if (validation.fails()) {
session
.withErrors(validation.messages())
.flashExcept(['password'])

return response.redirect('back')
}

return response.route('UserController.index')
}
...
}
-->

Cơ bản xử lý:
1. Định nghĩa quy tắc mà post data phải đúng chuẩn mới được xử lý
2. Sử dụng method validate với tham số đầu vào là post data, tham số thứ 2 là quy tắc cần được áp dụng
3. kiểm tra với `validation.fails()`, nếu bằng true(tức là post data không đúng quy tắc)
thì ghi lỗi vào session flash và trở về trang trước đó

## Validator methods
1. validate(data, rules, [messages], [formatter])
Ví dụ: const validation = await validate(data, rules)
`validate` dừng xủ lý ngay khi phát hiện 1 rule bất kì không thỏa điều kiện.

2. validateAll(data, rules, [messages], [formatter])
Ví dụ: const validation = await validateAll(data, rules)
Khác với `validate``validateAll` sẽ quét qua tất cả các rules rồi mới dừng lại.

3. sanitize(data, rules)
Phương thức này trả về một đối tượng mới với dữ liệu được làm sạch
<!-->
const { sanitize } = use('Validator')
const data = sanitize(request.all(), rules)
-->

4. sanitizor
Trả về một tham chiếu sanitizor từ lớp Validator
<!-->
const { sanitizor } = use('Validator')
const slug = sanitizor.slug('My first blog post')
-->

5. formatters
Trả về một tham chiếu formatters từ lớp Validator
<!-->
const { formatters } = use('Validator')
validate(data, rules, messages, formatters.JsonApi)
-->

## Route validator
Để code gọn gàn hơn, sạch đẹp hơn.
Chúng ta sẽ đăng kí validator ngay ở phần khai báo route.

1. Cập nhật file start/routes.js
<!-->
// For a single route
Route
.post('users', 'UserController.store')
.validator('StoreUser')

// For a resourceful route
Route
.resource('users', 'UserController')
.validator(new Map([
[['users.store'], ['StoreUser']],
[['users.update'], ['UpdateUser']]
]))
-->

2. Tạo file Validator
> adonis make:validator StoreUser
==> File mới được tạo ra ở `app/Validators/StoreUser.js`
Cập nhật lại nội dung file như bên dưới:
<!-->
'use strict'

class StoreUser {
get validateAll () {
return true
}

get sanitizationRules () {
return {
email: 'normalize_email',
// age: 'to_int',
password: 'to_string'
}
}

get rules () {
return {
email: 'required|email|unique:users',
password: 'required'
}
}

get messages () {
return {
'email.required': 'You must provide a email address.',
'email.email': 'You must provide a valid email address.',
'email.unique': 'This email is already registered.',
'password.required': 'You must provide a password'
}
}
}

module.exports = StoreUser
-->

3. Chỉnh sửa lại file app/Controllers/Http/UserController.js
<!-->
async store ({ request, response }) {
// TODO: save data to database...
return response.route('UserController.index')
}
-->

4. Tùy chỉnh validation failure
Nếu bạn không thích cách hệ thống làm tự động, ban có thể xử lý lại như bên dưới:
<!-->
class StoreUser {
async fails (errorMessages) {
return this.ctx.response.send(errorMessages)
}
}

module.exports = StoreUser
-->

5. Validate các giá trị nằm ở header
Đôi khi ngoài việc validate post data, ta cần phải validate cả các giá trị nằm trên header gửi đến
<!-->
class StoreUser {
get rules () {
return {
sessionId: 'required'
}
}

get data () {
const requestBody = this.ctx.request.all()

// lấy session id từ header
const sessionId = this.ctx.request.header('X-Session-Id')
return Object.assign({}, requestBody, { sessionId })
}
}

module.exports = StoreUser
-->

6. Format kết quả trả về
<!-->
const { formatters } = use('Validator')

class StoreUser {
get formatter () {
return formatters.JsonApi // trả về json cho API
}
}
-->

7. Authorization
Trong trường hợp bạn muốn kiểm tra lại permission của user trước khi cho phép thực hiện.
<!-->
class StoreUser {
async authorize () {
if (!isAdmin) {
this.ctx.response.unauthorized('Not authorized')
return false
}

return true
}
}
module.exports = StoreUser
-->

8. Request context
Tất cả các route validators đều có thể truy cập vào đối tượng request(request object) thông qua this.ctx

## Custom Rules
Các rule mở rộng
1. unique(tableName, [fieldName], [ignoreField], [ignoreValue])
Kiểm tra giá trị nhập vào của field đó đã tồn tại trong DB chưa.

<!-->
'use strict'

class StoreUser {
get rules () {
return {
email: 'unique:users,email' // kiểm tra email đã tồn tại hay chưa
}
}
}
-->

Trong trường hợp update mà email không thay đổi thì cần igonre cái field này
<!-->
class StoreUser {
get rules () {
const userId = this.ctx.params.id

return {
email: `unique:users,email,id,${userId}`
}
}
}
-->

## Extending Validator
1. Thêm định nghĩa rule mới
<!-->
const Validator = use('Validator')
const Database = use('Database')

const existsFn = async (data, field, message, args, get) => {
const value = get(data, field)
if (!value) {
/**
* skip validation if value is not defined. `required` rule
* should take care of it.
*/
return
}

const [table, column] = args
const row = await Database.table(table).where(column, value).first()

if (!row) {
throw message
}
}

Validator.extend('exists', existsFn)
-->

2. Đăng ký ở Providers hoặc ở Ignitor Hooks

3. Sử dụng
get rules () {
return {
post_id: 'exists:posts,id'
}
}




Không có nhận xét nào:

Đăng nhận xét

Học lập trình web căn bản với PHP

Bài 1: Các kiến thức căn bản Part 1:  https://jimmyvan88.blogspot.com/2012/05/can-ban-lap-trinh-web-voi-php-bai-1-cac.html Part 2:  https://...