前言
上之介紹過adonisjs/fold的inject,讀過inject的源碼可以知道inject會把宣告的class直接注入進目前class的inject內的instance,而且是static,然後底層透過Route呼叫controller在把instance一一實現出來。那這樣問題來了,如果不是透過Route想要實現自動注入該如何處理。
例如Seeder中偶爾會寫一些腳本,但最好的方法是呼叫service執行相對應的function讓程式走已經經過測試的流程,才不會出現漏改或資料不完整等資料問題。那seeder並非透過route來呼叫,所以無法使用inject,在此我開發了一個套件供大家簡單使用
// install commands
yarn add @lu7766lu7766/adonis-utils
node ace invoke @lu7766lu7766/adonis-utils
// seeders
import BaseSeeder from '@ioc:Adonis/Lucid/Seeder'
import { InjectService } from '@ioc:Adonis/Utils'
export default class ProdDataChange0428 extends BaseSeeder {
@InjectService() // @InjectService(SurveyService)
service: SurveyService
public async run() {
console.log(this.service)
}
}
套件是開源的,源碼也很簡單,下面給大家展示一下。這也不限於只能使用在adonisjs上,甚至在其他專案也可以使用
export function InjectService(injectClass?: any) {
return function (target: Object, propKey?: string) {
if (propKey) {
const targetClass = injectClass ?? (Reflect.getMetadata("design:type", target, propKey) || [])
const params = Reflect.getMetadata("design:paramtypes", targetClass) || []
const service = new targetClass(...params)
Object.defineProperty(target, propKey, {
value: service,
writable: false,
})
}
}
}
後記
有些人喜歡用抽象或介面去管理程式碼,所以設計成參數可以設定要注入什麼,不輸入則自動注入類別,增加一點彈性。
5/23更新
我發現上面的源碼無法把注入的service,建構子裡的物件一並注入,簡單說他就是只有一層,如果要用到第二層的東西就掛了,所以我改用遞回方式去注入物件,下載到舊版的小夥伴記得去更版
沒有留言:
張貼留言