2023年3月14日 星期二

AdonisJs第九天Provider

前一篇有稍微提到Provider,這個功能,今天在稍微深入講一下。 

Provider可以為 AdonisJS 應用程式提供許多不同的功能。AdonisJS 也提供了許多內置的 Provider,同時也允許開發人員創建自己的 Provider。

Provider需要實現 register ready boot shutdown四個生命週期。register 方法用於註冊 container,而 boot 方法則用於container已準備好的情況,ready shutdown上面都有各自的註解,目前小編也沒有什麼使用範例及情境就先暫時忽略 。

以下是一個簡單的 Provider 範例,在預設情況下,在創立專案的同時會附有/provider/AppProvider.ts檔案在專案中以利擴充:

import { ApplicationContract } from "@ioc:Adonis/Core/Application"
export default class AppProvider {
constructor(protected app: ApplicationContract) {}

public register() {
// Register your own bindings
}

public async boot() {
// IoC container is ready
// await import("@ioc:Adonis/Lucid/Database")
global.DB = require("@ioc:Adonis/Lucid/Database")
DB.transactionFn = async <T>(fn): Promise<T> => {
const trx = await DB.transaction()
let res
try {
res = (await fn(trx)) as T
await trx.commit()
} catch (e) {
await trx.rollback()
switch (e.name) {
case "ApiException":
case "E_VALIDATION_FAILURE":
throw e
default:
throw new ApiException(CommonCodes.SQL_ERROR, e.message)
}
}
return res
}
App.use("Adonis/Core/Event").on("db:query", (query) => {
DB.prettyPrint(query)
})
}

public async ready() {
// App is ready
}

public async shutdown() {
// Cleanup, since app is going down
}

在上面這個範例中我註冊了一個全域的變數,並把這個變數擴充了一個新的方法(transaction),另外又偵聽一個事件,只要有db操作,就會把sql打印出來。

這邊有一個值得注意的點是,在AppProvider觸發的時候,有些套件世上未初始化的,所以無法透過import方式引入,變得需要在boot時,用await import或require去引入套件,這是一個小雷。

在設置全域變數,ts當然也要做出相對應的設定,才不會在使用時看到一堆紅線,找到/global.d.ts的檔案(沒有責自己創建),輸入以下

import { DatabaseContract } from "@ioc:Adonis/Lucid/Database"
declare global {
var DB: DatabaseContract
}

當然小編不建議隨便把東西設為全域變數,這只是紀錄一下之前年少做過不懂事,踩過的坑。

最後還需檢查/.adonisrc.json裏面providers是否已經註冊了剛剛所編寫的AppProvider

{
"typescript": true,
......
"providers": [
"./providers/AppProvider", // here
......
]
}

當這一切準備好就可以進到使用的環節了

import { HttpContextContract } from "@ioc:Adonis/Core/HttpContext"
import { inject } from "@adonisjs/fold"
import TestService from "../Service/TestService"
import DeleteValidator from "../Validators/DeleteValidator"

@inject()
export default class TestController {
constructor(private service: TestService) {}

async delete({ request }: HttpContextContract) {
const { id } = await request.classValidate(DeleteValidator)
return DB.transactionFn((trx) => this.service.delete({ id, trx }))
}
}

這樣就大功告成拉。

沒有留言:

張貼留言