## HTTP Context
Route.get('/', ({ request, response, view }) => {
// request
// response
// view
})
OR
Route.get('/', (ctx) => {
// ctx.request
// ctx.response
// ctx.view
// etc
})
## Quản lý các thư viện phụ thuộc bằng IoC Container
IoC (Inversion of Control)
1. Binding dependencies
Dưới đây là ví dụ về ý tưởng xủ lý,
chúng ta sẽ biết cách đưa chúng vào ứng dụng khi dọc đến phần `Service Providers`.
Ví dụ:
<!-->
File Redis.js.
class Redis {
constructor (Config) {
const redisConfig = Config.get('redis')
// connect to redis server
}
}
module.exports = Redis
-->
const { ioc } = require('@adonisjs/fold')
const Redis = require('./Redis')
ioc.bind('My/Redis', function (app) {
const Config = app.use('Adonis/Src/Config')
return new Redis(Config)
})
==>
Sau đó có thể sử dụng như sau: `const redis = ioc.use('My/Redis')`
2. Singletons
Để tránh trường hợp đối tượng Redis bị khởi tạo quá nhiều lần, thì nên sử dụng Singleton.
<!-->
ioc.singleton('My/Redis', function (app) {
const Config = app.use('Adonis/Src/Config')
return new Redis(Config)
})
-->
-----------
3. Resolving dependencies
const redis = ioc.use('My/Redis')
Cũng có thể sử dụng global use: `const redis = use('My/Redis')`
4. ALIAS
Đăng kí ở start/app.js
aliases: {
MyRoute: 'Adonis/Src/Route'
}
==>
Sử dụng: `const Route = use('MyRoute')`
Adonis là APP_NAME
Src là phạm vi, ở đây là binding đến một thành phần của Core
(Nếu binding đến một packages bên ngoài core thì thay bằng `Addon`)
Route là Module name
5. Autoloading
Tất cả các file nằm trong thư mục app đều đang được load tự động với namespace là App.
Ví dụ:
1. File app/Services/Foo.js
class FooService {
}
module.exports = FooService
2. File app/Controllers/Http/UserController.js
const Foo = use('App/Services/Foo')
Nếu không có Autoloading thì lúc nào sử dụng file nào, đều phải dùng require.
require('../../Services/Foo').
## Service Providers
├── app
└── providers
└── MyProvider.js
└── start
└── app.js: Đăng kí providers khi apps được kích hoạt
Chúng ta đã biết về ioc.bind để đăng kí bindings. Tuy nhiên chưa biết đặt chúng vào đâu.
Lúc này đây, chúng ta tạo ra Service Providers để chứa các đăng kí này.
<!-->
const { ServiceProvider } = require('@adonisjs/fold')
class MyProvider extends ServiceProvider {
register () {
// register bindings
}
boot () {
// optionally do some initial setup
const View = this.app.use('Adonis/Src/View')
View.global('time', () => new Date().getTime())
}
}
module.exports = MyProvider
-->
1. npm package as a service provider.
(Đăng kí các npm package trở thành 1 service provider)
Installl npm package:
`npm install bee-queue`
`npm install redis`
├── app
└── providers
└── Queue
└── index.js: Khởi tạo và trả về đối tượng BeeQueue
└── Provider.js: Đăng kí đối tượng BeeQueue để sử dụng
└── start
└── app.js: Đăng kí providers khi apps được kích hoạt
Ví dụ cấu hình sử dụng Queue với bee-queue: https://github.com/bee-queue/bee-queue
- Cấu hình config ở config/queue.js
- Đăng kí sử dụng ở Providers
File providers/Queue/index.js
<!-->
'use strict'
const BeeQueue = require('bee-queue')
class Queue {
constructor (Config) {
this.Config = Config
this._queuesPool = {}
}
get (name) {
// If there is an instance of queue already, then return it
if (this._queuesPool[name]) {
return this._queuesPool[name]
}
// Read configuration using Config | provider
const config = this.Config.get(`queue.${name}`)
// Create a new queue instance and save it's | reference
this._queuesPool[name] = new BeeQueue(name, config)
// Return the instance back
return this._queuesPool[name]
}
}
module.exports = Queue
-->
File providers/Queue/Provider.js
<!-->
const { ServiceProvider } = require('@adonisjs/fold')
class QueueProvider extends ServiceProvider {
register () {
this.app.singleton('Bee/Queue', () => {
const Config = this.app.use('Adonis/Src/Config')
return new (require('.'))(Config)
})
}
}
module.exports = QueueProvider
-->
File start/app.js
<!-->
const providers = [
path.join(__dirname, '..', 'providers', 'Queue/Provider')
]
-->
==>
Sử dụng:
const Queue = use('Bee/Queue')
Queue.get('addition').createJob({ x: 2, y: 3 }).save()
2. Xây dựng như một package mới
└── providers
└── QueueProvider.js
├── src
└── Queue
└── index.js
└── package.json
Bởi vì Queue/index.js là đang nằm khác thư mục,
nên cần đổi `Bee/Queue` thành `Adonis/Addons/Queue`.
File providers/QueueProvider.js:
<!-->
const { ServiceProvider } = require('@adonisjs/fold')
class QueueProvider extends ServiceProvider {
register () {
this.app.singleton('Adonis/Addons/Queue', () => {
const Config = this.app.use('Adonis/Src/Config')
return new (require('../src/Queue'))(Config)
})
}
}
module.exports = QueueProvider
-->
3. Test provider
npm i --save-dev japa
mkdir test
node test/example.spec.js
Run all your tests together:
`npm i --save-dev japa-cli`
`./node_modules/.bin/japa`
## Hooks
Đăng kí hooks ở File start/hooks.js
<!-->
const { hooks } = require('@adonisjs/ignitor')
hooks.after.providersBooted(() => {
const View = use('View')
View.global('time', () => new Date().getTime())
})
-->
hooks.after to register a view global after all providers have booted.
hooks.after | hooks.before
Hook Event Description
providersRegistered Before/after all providers have registered
providersBooted Before/after all providers have booted
preloading Before/after preloading registered files
httpServer Before/after HTTP server has started
aceCommand Before/after ace command is executed
## Preloading files
Load trước một số file trước khi HTTP Server chạy. Chấp nhận bất kì file Javascript nào.
<!-->
File server.js.
new Ignitor(require('@adonisjs/fold'))
.appRoot(__dirname)
.preLoad('start/fire-zombies1')
.preLoad('start/fire-zombies2')
.preLoad('start/fire-zombies3')
.fireHttpServer()
.catch(console.error)
-->
## Ignitor methods
Một số methods của Ignitor mà có thể config ở file `server.js`.
1. .appRoot(__dirname)
Xác định đường dẫn đến thư mục app.
2. .modulesRoot(path.join(__dirname, '..'))
Xác định thư mục cha của node_modules
3. .appFile('start/app.js')
Xác định đường dẫn đến file app.js
4. .loadCommands()
Chỉ định cho Ignitor load ace providers và commands.
## Configuration
Lấy dữ liệu từ file config
<!-->
// File start/routes.js
Route.get('/test', (ctx) => {
// get config | fileName.key
const Config = use('Config')
const appSecret = Config.get('app.appKey')
console.log(appSecret)
console.log(Config.get('database.mysql.connection.host'))
console.log(Config.get('app.appSecret',"default secret")) // set default value
})
-->
## Env Provider
1. Lấy thông tin đã thiết lập trong file .env
const Env = use('Env')
const appSecret = Env.get('DB_HOST')
const dbUser = Env.get('DB_USER', 'root') // set default value
Chú ý là `Env.get` luôn luôn trả về một String.
Nếu muốn sử dụng như một Boolean thì có thể sử dụng như bên dưới:
`const myBoolean = Env.get('MY_BOOLEAN') === 'true'`
Ném một lỗi với các ENV bắt buộc phải có thì sử dụng `Env.getOrFail`.
const Env = use('Env')
// Throw "Make sure to define APP_SECRET inside .env file."
Env.getOrFail('APP_SECRET')
2. Load một file env đặc biệt
Khi khởi chạy dự án thì chạy command `ENV_PATH=/user/.env adonis serve`
3. Không sử dụng file env nữa thì chạy command `ENV_SILENT=true adonis serve`
4. Sử dụng file env để cấu hình cho nhiều môi trường khác nhau
Ví dụ khi bạn chạy ứng dụng với command `NODE_ENV=develop adonis serve`
thì AdonisJs sẽ load file `.env.develop` và merge những giá trị của nó vào file .env
Không có nhận xét nào:
Đăng nhận xét