UNPKG

5.1 kBJavaScriptView Raw
1/**
2 * @copyright Copyright (c) 2019 Maxim Khorin <maksimovichu@gmail.com>
3 */
4'use strict';
5
6const Base = require('../base/Component');
7
8module.exports = class Router extends Base {
9
10 constructor (config) {
11 super({
12 depends: '#end',
13 defaultController: 'default',
14 // defaultModule: 'moduleName'
15 ...config
16 });
17 }
18
19 init () {
20 this.createControllerMap();
21 this.addActions();
22 this.module.on(this.module.EVENT_AFTER_MODULE_INIT, this.afterModuleInit.bind(this));
23 }
24
25 afterModuleInit () {
26 this.defaultModule
27 ? this.addDefaultModule(this.defaultModule)
28 : this.addDefaultAction(this.getDefaultController());
29 if (this.errors) {
30 this.addErrorHandlers(this.errors);
31 }
32 }
33
34 addDefaultModule (name) {
35 const module = this.module.getModule(name);
36 if (!module) {
37 return this.log('error', `Module not found: ${name}`);
38 }
39 const url = module.get('urlManager').resolve('');
40 this.module.addHandler(['all'], '', (req, res) => res.redirect(url));
41 }
42
43 // CONTROLLER
44
45 createControllerMap () {
46 this._controllerMap = this.getControllerMap(this.module.getControllerDirectory());
47 if (this.module.original) {
48 this._controllerMap = {
49 ...this.getControllerMap(this.module.original.getControllerDirectory()),
50 ...this._controllerMap
51 };
52 }
53 }
54
55 getDefaultController () {
56 return this.getController(this.defaultController);
57 }
58
59 getController (id) {
60 return this._controllerMap.hasOwnProperty(id) ? this._controllerMap[id] : null;
61 }
62
63 getControllerMap (dir, relative = '') {
64 let files = [];
65 try {
66 files = fs.readdirSync(dir);
67 } catch {
68 }
69 const result = {};
70 for (const file of files) {
71 this.setControllerMapFile(path.join(dir, file), relative, result);
72 }
73 return result;
74 }
75
76 setControllerMapFile (file, relative, map) {
77 const stat = fs.lstatSync(file);
78 if (stat.isDirectory()) {
79 Object.assign(map, this.getControllerMap(file, `${relative}${path.basename(file)}/`));
80 } else {
81 file = require(file);
82 map[relative + file.getBaseName()] = file;
83 }
84 }
85
86 resolveControllerId (id) {
87 return id.replace(/\//g, '-');
88 }
89
90 createController (Controller, config) {
91 config.user = config.res.locals.user;
92 config.language = config.res.locals.language;
93 return new Controller(config);
94 }
95
96 // ACTION
97
98 addDefaultAction (Controller) {
99 if (Controller && Controller.DEFAULT_ACTION) {
100 if (Controller.getActionKeys().includes(Controller.DEFAULT_ACTION)) {
101 this.addAction(Controller.DEFAULT_ACTION, Controller, '');
102 }
103 }
104 }
105
106 addActions () {
107 for (const id of Object.keys(this._controllerMap)) {
108 const route = `/${this.resolveControllerId(id)}`;
109 const Controller = this._controllerMap[id];
110 for (const actionId of Controller.getActionKeys()) {
111 this.addAction(actionId, Controller, `${route}/${actionId}`);
112 if (Controller.DEFAULT_ACTION === actionId) {
113 this.addAction(actionId, Controller, route);
114 }
115 }
116 }
117 }
118
119 addAction (id, Controller, route) {
120 const action = (req, res, next) => {
121 this.createController(Controller, {req, res, module: res.locals.module})
122 .execute(id)
123 .catch(next);
124 };
125 let methods = Controller.METHODS[id] || Controller.METHODS['*'] || ['all'];
126 if (!Array.isArray(methods)) {
127 methods = [methods];
128 }
129 for (const method of methods) {
130 this.module.addHandler(method.toLowerCase(), route, action);
131 }
132 }
133
134 addErrorHandlers (config) {
135 const Controller = this.getController(config.controller) || this.getDefaultController();
136 this.module.addHandler('all', '*', (req, res, next) => next(new NotFound));
137 this.module.addHandler('use', (err, req, res, next) => {
138 if (!(err instanceof HttpException)) {
139 err = new ServerError(err);
140 }
141 err.setParams(req, res);
142 if (!Controller) {
143 return next(err);
144 }
145 this.createController(Controller, {err, req, res, module: this.module})
146 .execute(config.action || 'error')
147 .catch(next);
148 });
149 }
150};
151
152const fs = require('fs');
153const path = require('path');
154const HttpException = require('../error/HttpException');
155const NotFound = require('../error/http/NotFound');
156const ServerError = require('../error/http/ServerError');
\No newline at end of file