corefwnode 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/CfwObject.js CHANGED
@@ -1,1626 +1,1629 @@
1
- /* eslint-disable no-underscore-dangle */
2
- const ErrorCodes = require('./ErrorCodes.js');
3
- const Decorator = require('./Decorator.js');
4
- const Validator = require('./Validator.js');
5
- const ErrorControl = require('./ErrorControl.js');
6
-
7
- /**
8
- * Class providing main Object Model for database insertion, validation, update, delete etc...
9
- *
10
- * This is a starting point of every object that uses database
11
- * Every object should extend this object
12
- * <code>
13
- * module.exports = class User_Base extends Object
14
- * {
15
- *
16
- * tableConf()
17
- * {
18
- * return {
19
- * 'tableName': 'users',
20
- * 'id': {
21
- * 'userId': {
22
- * 'fieldType': 'int',
23
- * 'maxlength': 20,
24
- * 'req': 0
25
- * )
26
- * ),
27
- * 'ownerField': 'userId',
28
- * 'fields': {
29
- * 'username': {
30
- * 'fieldType': 'sc',
31
- * 'maxlength': 255,
32
- * 'minlength': 1,
33
- * 'req': 1
34
- * ),
35
- * 'updateDateTime': {
36
- * 'fieldType': 'dateTime',
37
- * 'req': 1
38
- * )
39
- * )
40
- * );
41
- * }
42
- *
43
- * insertRow(param)
44
- * {
45
- * me.username = param['username'];
46
- * me.updateDateTime = _cfw_lib_GeneralHandling::datetimeNow();
47
- * return me.insert();
48
- * }
49
- *
50
- * updateRow(param)
51
- * {
52
- * param['updateDateTime'] = _cfw_lib_GeneralHandling::datetimeNow();
53
- *
54
- * return parent::updateRow(param);
55
- * }
56
- * }
57
- * </code>
58
- * In the above example, we extended the object, called the new module.exports = class User cause it will
59
- * hold user database table mapping, we then override tableConf() method to define * table specification.
60
- * 'tableName' is the exact table name as it is written in database
61
- * 'id' array holds primary key values, if they are autoincrement then
62
- * 'req' should be '0' else they should be specified on insert
63
- * 'ownerField' is used to define which field holds value that will be checked
64
- * of 'owner action' is checked in ACL. If that is the case 'ownerField' will be checked against Session::userId value.
65
- * 'fields' holds columns except primary key values
66
- * we can define each column properties with following:
67
- * <ul>
68
- * <li>fieldType - (required) define as 'text', 'int', 'float', 'dateTime', 'date', 'sc (special case)'</li>
69
- * <li>maxlength - String max length</li>
70
- * <li>minlegth - String min length</li>
71
- * <li>maxvalue - Int or float max value</li>
72
- * <li>minvalue - Int or float min value</li>
73
- * <li>req - (required) define if this field is optional</li>
74
- * <li>decorators - {) of decorators that should be used before validating and inserting/updating</li>
75
- * </ul>
76
- * We then override insertRow if we want to do some preprocessing like in
77
- * this example in which updateDateTime was not given in parameters then we insert it ourselves.
78
- * We can also override functions like we did in updateRow only to add a single parameter
79
- *
80
- * @todo Make this an abstract class
81
- * @author Dario Filkovic <dfilkovi@gmail.com>
82
- *
83
- * @since 1.0
84
- *
85
- * @package CoreFw
86
- */
87
- module.exports = class CfwObject
88
- {
89
- /**
90
- * Get objects from Registry
91
- *
92
- * @author Dario Filkovic <dfilkovi@gmail.com>
93
- *
94
- * @since 1.0
95
- *
96
- * @package CoreFw
97
- *
98
- * @return void
99
- */
100
- constructor(session)
101
- {
102
- const me = this;
103
-
104
- me.events = {};
105
- me.ownerActionGlob = false;
106
- me.companyActionGlob = false;
107
- me.functionNameGlob = false;
108
- me.modelLoaded = false;
109
- me.assocData = {};
110
-
111
- me.objectNameGlob = this.constructor.name.toLowerCase();
112
-
113
- if (typeof session === 'undefined' && me.objectNameGlob !== 'session' && me.objectNameGlob !== 'translator')
114
- {
115
- return new Proxy(this,
116
- {
117
- get: function get(target)
118
- {
119
- return function wrapper()
120
- {
121
- throw (`Please provide session for object instantiation: ${me.objectNameGlob} ${target}`);
122
- };
123
- },
124
- });
125
- }
126
-
127
- me.lib = global.lib;
128
- me.session = session;
129
- if (typeof me.session === 'undefined')
130
- {
131
- me.session = me.lib.unregisteredSession;
132
- }
133
- me.errorControl = new ErrorControl(me.session);
134
- me.aclLangId = 1;
135
- me.aclGroupId = 2;
136
- if (typeof me.session !== 'undefined')
137
- {
138
- me.aclLangId = me.session.langId;
139
- me.aclGroupId = me.session.groupId;
140
- if (me.session.tranDb && me.session.tranDb.dbname === me.session.db.dbname)
141
- {
142
- me.db = me.session.tranDb;
143
- }
144
- else
145
- {
146
- me.db = me.session.db;
147
- }
148
- }
149
- else
150
- {
151
- me.db = me.lib.db;
152
- }
153
- me.props = me.lib.props;
154
- me.lang = me.lib.lang;
155
- if (typeof me.tableConf !== 'undefined')
156
- {
157
- me.tableConfig = me.tableConf();
158
- if (typeof me.tableConfig.tableName !== 'undefined')
159
- {
160
- me.tableName = me.tableConfig.tableName;
161
- }
162
- if (typeof me.tableConfig.id !== 'undefined')
163
- {
164
- me.idField = me.tableConfig.id;
165
- }
166
- }
167
-
168
- me.config = me.lib.config;
169
- me.dbName = 'db';
170
-
171
- return new Proxy(this,
172
- {
173
- get: function get(target, name)
174
- {
175
- if (typeof me[name] === 'function')
176
- {
177
- return function wrapper(...args)
178
- {
179
- return me.__call(name, args);
180
- };
181
- }
182
- return me[name];
183
- },
184
- });
185
- }
186
-
187
- /**
188
- * Magic method that gets called every time a (method) is triggered
189
- *
190
- * This is MOST important, if you want to use out-of-the box
191
- * ACL management for objects and methods, functions should be named protected
192
- * Every time a is triggered __call gets fired before which checks privilage on module.exports = class and method
193
- * NOTICE!!! Observer is also called here, every function that
194
- * you want to observe needs to be protected to get __call method to be fired
195
- *
196
- * @see Observer
197
- * @author Dario Filkovic <dfilkovi@gmail.com>
198
- *
199
- * @since 1.0
200
- *
201
- * @package CoreFw
202
- * @param String methodName
203
- * @param mixed[] argumentsin
204
- * @return void
205
- */
206
- async __call(methodName, argumentsin)
207
- {
208
- const me = this;
209
-
210
- if (methodName === 'translate' || methodName === 'on')
211
- {
212
- return me[methodName](...argumentsin);
213
- }
214
-
215
- let error = false;
216
-
217
- if (typeof me.lib.acl[me.aclGroupId][me.objectNameGlob] !== 'undefined'
218
- && typeof me.lib.acl[me.aclGroupId][me.objectNameGlob][methodName.toLowerCase()] !== 'undefined')
219
- {
220
- me.functionNameGlob = methodName.toLowerCase();
221
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].ownerAction === 1)
222
- {
223
- me.ownerActionGlob = true;
224
- }
225
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].companyAction === 1)
226
- {
227
- me.companyActionGlob = true;
228
- }
229
-
230
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].instantiate === 0)
231
- {
232
- error = true;
233
- }
234
- }
235
- else if (typeof me.lib.acl[me.aclGroupId][me.objectNameGlob] !== 'undefined'
236
- && typeof me.lib.acl[me.aclGroupId][me.objectNameGlob].instantiate !== 'undefined')
237
- {
238
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob].ownerAction === 1)
239
- {
240
- me.ownerActionGlob = true;
241
- }
242
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob].companyAction === 1)
243
- {
244
- me.companyActionGlob = true;
245
- }
246
-
247
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob].instantiate === 0)
248
- {
249
- error = true;
250
- }
251
- }
252
- else
253
- {
254
- error = true;
255
- }
256
-
257
- // check if method really exists
258
- if (typeof me[methodName] === 'undefined')
259
- {
260
- throw (ErrorCodes.error('method_not_found', {
261
- method: methodName,
262
- classname: me.objectNameGlob,
263
- }));
264
- }
265
-
266
- const observer = global.lib.observer;
267
-
268
- observer.beforeCall({
269
- method: methodName,
270
- classname: me.objectNameGlob,
271
- argumentsin: argumentsin,
272
- session: me.session,
273
- });
274
-
275
-
276
- if (error === true)
277
- {
278
- throw (ErrorCodes.error('no_privilage', {
279
- method: methodName,
280
- classname: me.objectNameGlob,
281
- }));
282
- }
283
-
284
- let retValue;
285
- try
286
- {
287
- const val = await me[methodName](...argumentsin);
288
- retValue = val;
289
- return val;
290
- }
291
- catch(error)
292
- {
293
- retValue = error;
294
- throw(error);
295
- }
296
- finally
297
- {
298
- observer.afterCall({
299
- method: methodName,
300
- classname: me.objectNameGlob,
301
- argumentsin: argumentsin,
302
- res: retValue,
303
- session: me.session,
304
- });
305
- }
306
- }
307
-
308
- /**
309
- * Translate key based on current langId
310
- *
311
- * @author Dario Filkovic <dfilkovi@gmail.com>
312
- *
313
- * @since 1.0
314
- *
315
- * @package CoreFw
316
- *
317
- * @return string Translated word
318
- */
319
- translate(key)
320
- {
321
- const me = this;
322
- const val = me.lang.translate(key, me.aclLangId);
323
- return val;
324
- }
325
-
326
- /**
327
- * Select a single row from this table based on id
328
- *
329
- * <code>
330
- * user = new User;
331
- * user.id = 5;
332
- * user.select();
333
- * </code>
334
- * In the above example if an user with id 5 is found in
335
- * database user object get's populated with data that can be fetched by:
336
- * <code>
337
- * user.username;
338
- * </code>
339
- * for example.
340
- * If table has more than one primary key you can select it like this:
341
- * <code>
342
- * user = new User;
343
- * user.id = {'id': 5, 'group': 4);
344
- * user.select();
345
- * </code>
346
- *
347
- * @author Dario Filkovic <dfilkovi@gmail.com>
348
- *
349
- * @since 1.0
350
- *
351
- * @package CoreFw
352
- *
353
- * @return booelan True if record found false instead
354
- */
355
- async select()
356
- {
357
- const me = this;
358
-
359
- const params = [];
360
- const strings = [];
361
- if (typeof me.id === 'object')
362
- {
363
- for (const key of Object.keys(me.idField))
364
- {
365
- strings.push(`\`${key}\`=?`);
366
- params.push(me.id[key]);
367
- }
368
- }
369
- else
370
- {
371
- strings.push(`\`${Object.keys(me.idField)[0]}\`=?`);
372
- params.push(me.id);
373
- }
374
-
375
- const string = ` WHERE ${strings.join(' AND ')}`;
376
- const results = await me[me.dbName].query(`SELECT * FROM \`${me.tableName}\` ${string}`, params);
377
-
378
- me.modelLoaded = true;
379
-
380
- if (typeof results[0] !== 'undefined')
381
- {
382
- [me.assocData] = results;
383
- for (const key in results[0])
384
- {
385
- if (typeof me[key] === 'undefined')
386
- {
387
- me[key] = results[0][key];
388
- }
389
- }
390
- return true;
391
- }
392
- throw (ErrorCodes.error('record_not_found', { object: me.objectNameGlob, method: me.functionNameGlob }));
393
- }
394
-
395
- /**
396
- * Used to cast value before update or insert to it's mathcing field type
397
- *
398
- * @author Dario Filkovic <dfilkovi@gmail.com>
399
- *
400
- * @since 1.0
401
- *
402
- * @package CoreFw
403
- * @param String value
404
- * @param String fieldType
405
- * @return String|int Casted value
406
- */
407
- static defineType(value, field)
408
- {
409
- if (typeof value === 'object')
410
- {
411
- return value;
412
- }
413
-
414
- let valSec = value;
415
-
416
- const { fieldType } = field;
417
-
418
- switch (fieldType)
419
- {
420
- case 'int':
421
- valSec = parseInt(value, 10) || 0;
422
- break;
423
- case 'float':
424
- valSec = parseFloat(value) || 0;
425
- break;
426
- case 'string':
427
- valSec = value.toString();
428
- break;
429
- case 'num':
430
- valSec = value.toString();
431
- break;
432
- default:
433
- valSec = value.toString();
434
- break;
435
- }
436
-
437
- if (valSec === '' && typeof field.null !== 'undefined' && field.null === true)
438
- {
439
- valSec = null;
440
- }
441
-
442
- return valSec;
443
- }
444
-
445
- /**
446
- * Used before insert or update to validate all fields
447
- *
448
- * @author Dario Filkovic <dfilkovi@gmail.com>
449
- *
450
- * @since 1.0
451
- *
452
- * @package CoreFw
453
- * @param Array param Array of values
454
- * @param Array update
455
- * @return boolean True if succes false otherwise
456
- */
457
- async checkInsert(paramIn, updateIn)
458
- {
459
- const me = this;
460
-
461
- let param = paramIn;
462
- let update = updateIn;
463
-
464
- if (typeof param === 'undefined')
465
- {
466
- param = false;
467
- }
468
- if (typeof update === 'undefined')
469
- {
470
- update = false;
471
- }
472
-
473
- if (update !== false && !me.modelLoaded)
474
- {
475
- me.select();
476
- }
477
-
478
- if (typeof me.id !== 'undefined' && typeof me.id === 'object')
479
- {
480
- for (const key in me.id)
481
- {
482
- if (me.id[key] !== undefined)
483
- {
484
- me[key] = me.id[key];
485
- }
486
- }
487
- }
488
- else if (typeof me.id !== 'undefined')
489
- {
490
- me[Object.keys(me.idField)[0]] = me.id;
491
- }
492
-
493
- if (param !== false)
494
- {
495
- for (const key in param)
496
- {
497
- if (param[key] !== undefined)
498
- {
499
- me[key] = param[key];
500
- }
501
- }
502
- }
503
-
504
- const valuesCheck = {};
505
- for (const key in me.tableConfig.fields)
506
- {
507
- if (typeof me[key] !== 'undefined')
508
- {
509
- valuesCheck[key] = me[key];
510
- }
511
- }
512
-
513
- for (const key in me.idField)
514
- {
515
- if (typeof me[key] !== 'undefined' && me[key] !== '')
516
- {
517
- valuesCheck[key] = me[key];
518
- }
519
- }
520
-
521
- await me.checkFields(valuesCheck);
522
- }
523
-
524
- /**
525
- * Used for inserting new row into table
526
- *
527
- * <code>
528
- * user = new User;
529
- * user.username = 'mirko';
530
- * user.dateEntered = date('Y-m-d H:i:s');
531
- * val = user.insert();
532
- * </code>
533
- * In this example val will hold an array with 'error'
534
- * boolean which if it is true, error happened and 'notice' string is also in array
535
- * which holds the error message or error array if more than one error is given
536
- * On succes var will hold error: false and 'lastId'
537
- * parameter which holds last autoincrement Id for further processing (chaining)
538
- *
539
- * @author Dario Filkovic <dfilkovi@gmail.com>
540
- *
541
- * @since 1.0
542
- *
543
- * @package CoreFw
544
- *
545
- * @return mixed[] Array with 'error' and 'notice' if error true, and 'lastId' if error false
546
- */
547
- async insert()
548
- {
549
- const me = this;
550
-
551
- if (typeof me.id !== 'undefined' && typeof me.id === 'object')
552
- {
553
- for (const key in me.id)
554
- {
555
- if (me.id[key] !== undefined)
556
- {
557
- me[key] = me.id[key];
558
- }
559
- }
560
- }
561
- else if (typeof me.id !== 'undefined')
562
- {
563
- me[Object.keys(me.idField)[0]] = me.id;
564
- }
565
-
566
- if (typeof me.userId === 'undefined')
567
- {
568
- me.userId = me.session.userId;
569
- }
570
- if (typeof me.companyId === 'undefined')
571
- {
572
- me.companyId = me.session.companyId;
573
- }
574
-
575
- if (me.userId === false)
576
- {
577
- delete (me.userId);
578
- }
579
- if (me.companyId === false)
580
- {
581
- delete (me.companyId);
582
- }
583
-
584
- if (me.functionNameGlob !== false)
585
- {
586
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].insertAction === 0)
587
- {
588
- throw (ErrorCodes.error('no_privilage'));
589
- }
590
- }
591
- else if (me.objectNameGlob !== false)
592
- {
593
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob].insertAction === 0)
594
- {
595
- throw (ErrorCodes.error('no_privilage'));
596
- }
597
- }
598
-
599
- const valuesCheck = {};
600
- for (const key in me.tableConfig.fields)
601
- {
602
- if (typeof me[key] !== 'undefined')
603
- {
604
- valuesCheck[key] = me[key];
605
- }
606
- else if (typeof me.tableConfig.fields[key].default !== 'undefined')
607
- {
608
- if (typeof me.tableConfig.fields[key].default === 'function')
609
- {
610
- // eslint-disable-next-line no-await-in-loop
611
- me[key] = await me.tableConfig.fields[key].default.call(me);
612
- }
613
- else
614
- {
615
- me[key] = me.tableConfig.fields[key].default;
616
- }
617
-
618
- valuesCheck[key] = me[key];
619
- }
620
- }
621
-
622
- for (const key in me.idField)
623
- {
624
- if (typeof me[key] !== 'undefined' && me[key] !== '')
625
- {
626
- valuesCheck[key] = me[key];
627
- }
628
- else if (typeof me.idField[key].default !== 'undefined')
629
- {
630
- if (typeof me.tableConfig.fields[key].default === 'function')
631
- {
632
- // eslint-disable-next-line no-await-in-loop
633
- me[key] = await me.idField[key].default.call(me);
634
- }
635
- else
636
- {
637
- me[key] = me.idField[key].default;
638
- }
639
- valuesCheck[key] = me[key];
640
- }
641
- }
642
-
643
- await me.checkFields(valuesCheck);
644
-
645
- // call before insert
646
- await me.beforeInsert();
647
-
648
- const fields = [];
649
- const values = [];
650
- for (const key in me.tableConfig.fields)
651
- {
652
- if (typeof me[key] !== 'undefined')
653
- {
654
- fields.push(`\`${key}\``);
655
- values.push(CfwObject.defineType(me[key], me.tableConfig.fields[key]));
656
- }
657
- }
658
-
659
- for (const key in me.idField)
660
- {
661
- if (typeof me[key] !== 'undefined' && me[key] !== '')
662
- {
663
- fields.push(`\`${key}\``);
664
- values.push(CfwObject.defineType(me[key], me.tableConfig.id[key]));
665
- }
666
- }
667
-
668
- let duplic = '';
669
- const fieldsDupl = [];
670
-
671
- if (typeof me.tableConfig.onduplicate !== 'undefined')
672
- {
673
- const key = Object.keys(me.idField)[0];
674
- // this will see if the field isn't autoincrement
675
- if (me.idField[key].req === 0)
676
- {
677
- duplic = ` ON DUPLICATE KEY UPDATE \`${key}\`=LAST_INSERT_ID(\`${key}\`), `;
678
- }
679
- else
680
- {
681
- duplic = ' ON DUPLICATE KEY UPDATE ';
682
- }
683
- for (let i = 0; i < me.tableConfig.onduplicate.length; i += 1)
684
- {
685
- const value = me.tableConfig.onduplicate[i];
686
- if (typeof me[value] !== 'undefined')
687
- {
688
- fieldsDupl.push(`\`${value}\`=?`);
689
- if (typeof me.tableConfig.fields[value] !== 'undefined')
690
- {
691
- values.push(CfwObject.defineType(me[value], me.tableConfig.fields[value]));
692
- }
693
- else
694
- {
695
- values.push(CfwObject.defineType(me[value], me.idField[value]));
696
- }
697
- }
698
- }
699
- if (fieldsDupl.length > 0)
700
- {
701
- duplic += fieldsDupl.join(', ');
702
- }
703
- else
704
- {
705
- duplic = '';
706
- }
707
- }
708
-
709
- let fieldsq = '';
710
- if (fields.length > 0)
711
- {
712
- fieldsq = fields.join(', ');
713
- }
714
-
715
- const pSafe = [];
716
- for (let i = 0; i < fields.length; i += 1)
717
- {
718
- pSafe.push('?');
719
- }
720
-
721
- let pSafeq = '';
722
- if (pSafe.length > 0)
723
- {
724
- pSafeq = pSafe.join(', ');
725
- }
726
-
727
- const results = await me[me.dbName].query(
728
- `INSERT INTO \`${me.tableName}\` (${fieldsq}) VALUES (${pSafeq}) ${duplic}`,
729
- values,
730
- );
731
-
732
- me.lastId = results.insertId;
733
- me.id = me.lastId;
734
-
735
- // call after insert
736
- await me.afterInsert();
737
-
738
- return (
739
- {
740
- error: false,
741
- lastId: me.lastId,
742
- notice: 'success',
743
- });
744
- }
745
-
746
- /**
747
- * Called before insert into db
748
- *
749
- * @author Dario Filkovic <dfilkovi@gmail.com>
750
- *
751
- * @since 1.0
752
- *
753
- * @package CoreFw
754
- *
755
- * @return void
756
- */
757
- // eslint-disable-next-line class-methods-use-this
758
- async beforeInsert()
759
- {
760
- return (
761
- {
762
- error: false,
763
- notice: 'success',
764
- });
765
- }
766
-
767
- /**
768
- * Called after succesfull insert into db
769
- *
770
- * @author Dario Filkovic <dfilkovi@gmail.com>
771
- *
772
- * @since 1.0
773
- *
774
- * @package CoreFw
775
- *
776
- * @return void
777
- */
778
- // eslint-disable-next-line class-methods-use-this
779
- async afterInsert()
780
- {
781
- return (
782
- {
783
- error: false,
784
- notice: 'success',
785
- });
786
- }
787
-
788
- /**
789
- * Used for selection mainly from ExtJS and ajax requests
790
- * It automaticaly selects rows based on passed parameters in this object
791
- * Parameters are:
792
- * <ul>
793
- * <li>sort - sort by</li>
794
- * <li>dir - sort direction (ASC or DESC)</li>
795
- * <li>start - starting row</li>
796
- * <li>limit - number of records to fetch</li>
797
- * <li>query - every field in table is searched by this value (LIKE %value%)</li>
798
- * <li>initialId - if you want to inlcude a single value in this
799
- * search that would not normaly come, pass it with this parameter</li>
800
- * </ul>
801
- * If 'sort' parameter is not passed sorting is by first idField and
802
- * direction is DESC, if no start or limit parameters are passed, no limit is used
803
- *
804
- * <code>
805
- * user = new User;
806
- * val = user.selectRow({'sort': 'id', 'dir': 'DESC', 'start': 20, 'limit': 10));
807
- * </code>
808
- * In this example val will hold an array with 'error' boolean
809
- * if error happened and 'notice' string which holds the error message
810
- * or error array if more than one error is given
811
- * On succes var will hold 'root' which holds all row results
812
- * (empty array if no results) and 'totalCount' int that has number of
813
- * records without limit (for use with pagination)
814
- *
815
- * @author Dario Filkovic <dfilkovi@gmail.com>
816
- *
817
- * @since 1.0
818
- *
819
- * @package CoreFw
820
- * @param Array param An array of key: value pairs for selecting rows
821
- * @return mixed[] Array with 'error' and 'notice' if error true and 'root' and 'totalCount' if error false
822
- */
823
- async selectRow(param)
824
- {
825
- const me = this;
826
-
827
- let data = [];
828
-
829
- let sort;
830
-
831
- if (typeof param.sort !== 'undefined')
832
- {
833
- sort = me.db.escapeId(`t.${param.sort}`);
834
- }
835
- else
836
- {
837
- sort = `t.${Object.keys(me.idField)[0]}`;
838
- }
839
-
840
- let dir = 'DESC';
841
- if (typeof param.dir !== 'undefined')
842
- {
843
- switch (param.dir)
844
- {
845
- case 'asc':
846
- dir = 'ASC';
847
- break;
848
- default:
849
- dir = 'DESC';
850
- break;
851
- }
852
- }
853
-
854
- let limit = '';
855
- if (typeof param.start !== 'undefined' && typeof param.limit !== 'undefined')
856
- {
857
- const start = me.db.escape(parseInt(param.start, 10));
858
- const end = me.db.escape(parseInt(param.limit, 10));
859
- limit = ` LIMIT ${end} OFFSET ${start} `;
860
- }
861
-
862
- let whereSearch = '';
863
- const params = {};
864
- if (typeof param.query !== 'undefined' && param.query !== '')
865
- {
866
- const searchString = [];
867
- for (const key in me.tableConfig.fields)
868
- {
869
- if (me.tableConfig.fields[key])
870
- {
871
- const value = me.tableConfig.fields[key];
872
- if (value.fieldType === 'date' || value.fieldType === 'dateTime')
873
- {
874
- continue;
875
- }
876
- searchString.push(` t.${key} LIKE :${key} `);
877
- params[key] = `%${param.query}%`;
878
- }
879
- }
880
- if (searchString.length > 0)
881
- {
882
- whereSearch = ` AND (${searchString.join(' OR ')}) `;
883
- }
884
- }
885
-
886
- if (typeof param.conditions !== 'undefined' && param.conditions !== '')
887
- {
888
- for (const key in param.conditions)
889
- {
890
- if (me.tableConfig.fields[key])
891
- {
892
- whereSearch += ` AND t.${key} = :${key} `;
893
- params[key] = param.conditions[key];
894
- }
895
- }
896
- }
897
-
898
- if (typeof param.filters !== 'undefined' && param.filters !== '')
899
- {
900
- for (const key in param.filters)
901
- {
902
- if (me.tableConfig.fields[key])
903
- {
904
- whereSearch += ` AND t.${key} LIKE :${key} `;
905
- params[key] = `%${param.filters[key]}%`;
906
- }
907
- }
908
- }
909
-
910
- let ownerWhere = '';
911
- if (me.ownerActionGlob === true)
912
- {
913
- ownerWhere = ` AND t.${me.tableConfig.ownerField}=:sessionUserId `;
914
- params.sessionUserId = me.session.userId;
915
- }
916
-
917
- if (me.companyActionGlob === true)
918
- {
919
- ownerWhere += ` AND t.${me.tableConfig.companyField}=:sessionCompanyId `;
920
- params.sessionCompanyId = me.session.companyId;
921
- }
922
-
923
- let results = await me[me.dbName].query(
924
- `SELECT t.* FROM \`${me.tableName}\` t WHERE 1=1`
925
- + `${ownerWhere} ${whereSearch} ORDER BY ${sort} ${dir} ${limit}`,
926
- params,
927
- );
928
-
929
- for (let i = 0; i < results.length; i += 1)
930
- {
931
- data.push(results[i]);
932
- }
933
-
934
- if (typeof param.initialId !== 'undefined')
935
- {
936
- data = await me.findInitialId(data, param.initialId);
937
- }
938
-
939
- results = await me[me.dbName].query(
940
- `SELECT COUNT(*) AS cnt FROM \`${me.tableName}\` t WHERE 1=1 ${ownerWhere} ${whereSearch}`,
941
- params,
942
- );
943
-
944
- let numRows = 0;
945
- if (results[0] !== undefined)
946
- {
947
- numRows = results[0].cnt;
948
- }
949
-
950
- return (
951
- {
952
- root: data,
953
- totalCount: numRows,
954
- });
955
- }
956
-
957
- /**
958
- * Used for selection mainly from ExtJS and ajax requests
959
- * It automaticaly selects one row based on id passed,
960
- * if there are more columns in primary key, then pass those parameters as get variables
961
- * Parameters are:
962
- * <ul>
963
- * <li>id - id of the record you are searching</li>
964
- * </ul>
965
- *
966
- * <code>
967
- * user = new User;
968
- * val = user.selectRowById({'id': 1));
969
- *
970
- * user = new User;
971
- * val = user.selectRowById({'idOne': '15', 'idTwo': 25));
972
- * </code>
973
- * In this example val will hold an array with 'error' boolean
974
- * if error happened and 'notice' string which holds the error
975
- * message or error array if more than one error is given, also if record is not found it will return error
976
- * On succes var will hold 'root' which holds row result
977
- *
978
- * @author Dario Filkovic <dfilkovi@gmail.com>
979
- *
980
- * @since 1.0
981
- *
982
- * @package CoreFw
983
- * @param Array param An array of key: value pairs for selecting rows
984
- * @return mixed[] Array with 'error' and 'notice' if error true and 'root' if error false
985
- */
986
- async selectRowById(param)
987
- {
988
- const me = this;
989
-
990
- if (typeof me.id === 'object')
991
- {
992
- for (const key in me.idField)
993
- {
994
- if (param[key] !== undefined)
995
- {
996
- me.id[key] = param[key];
997
- }
998
- }
999
- }
1000
- else
1001
- {
1002
- me.id = param.id;
1003
- }
1004
-
1005
- await me.select();
1006
-
1007
- const data = {};
1008
- for (const key in me.tableConfig.fields)
1009
- {
1010
- if (me[key] !== undefined)
1011
- {
1012
- data[key] = me[key];
1013
- }
1014
- }
1015
-
1016
- for (const key in me.idField)
1017
- {
1018
- if (me[key] !== undefined)
1019
- {
1020
- data[key] = me[key];
1021
- }
1022
- }
1023
-
1024
- return (
1025
- {
1026
- error: false,
1027
- root: data,
1028
- });
1029
- }
1030
-
1031
- /**
1032
- * Used for selecting a single value from a table
1033
- * It is optimized to check first if value exists in given data if not, then selects it and appends it to an array
1034
- *
1035
- * @author Dario Filkovic <dfilkovi@gmail.com>
1036
- *
1037
- * @since 1.0
1038
- *
1039
- * @package CoreFw
1040
- *
1041
- * @param Array data Array with starting data
1042
- * @param mixed[] initialValue Value of ID field
1043
- * @return Array Final array with all data
1044
- */
1045
- async findInitialId(data, initialValue)
1046
- {
1047
- const me = this;
1048
-
1049
- let initialValues = [];
1050
- if (typeof initialValue === 'number' || typeof initialValue === 'string')
1051
- {
1052
- initialValues = [initialValue];
1053
- }
1054
- else
1055
- {
1056
- initialValues = initialValue;
1057
- }
1058
-
1059
- const promises = [];
1060
-
1061
- for (const val of initialValues)
1062
- {
1063
- const defKey = Object.keys(me.idField)[0];
1064
-
1065
- for (let i = 0; i < data.length; i += 1)
1066
- {
1067
- const value = data[i];
1068
- if (value[defKey] === val)
1069
- {
1070
- return data;
1071
- }
1072
- }
1073
-
1074
- let ownerWhere = '';
1075
- const params = {
1076
- initialId: val,
1077
- };
1078
- if (me.ownerActionGlob === true)
1079
- {
1080
- ownerWhere = ` AND i.${me.tableConfig.ownerField}=:sessionUserId `;
1081
- params.sessionUserId = me.session.userId;
1082
- }
1083
-
1084
- if (me.companyActionGlob === true)
1085
- {
1086
- ownerWhere += ` AND i.${me.tableConfig.companyField}=:sessionCompanyId `;
1087
- params.sessionCompanyId = me.session.companyId;
1088
- }
1089
-
1090
- // eslint-disable-next-line no-await-in-loop
1091
- promises.push(me[me.dbName].query(
1092
- `SELECT i.* FROM \`${me.tableName}\` i WHERE i.\`${defKey}\`=:initialId ${ownerWhere}`,
1093
- params,
1094
- ));
1095
- }
1096
-
1097
- const results = await Promise.all(promises);
1098
-
1099
- results.forEach((result) =>
1100
- {
1101
- if (typeof result[0] !== 'undefined')
1102
- {
1103
- data.push(result[0]);
1104
- }
1105
- });
1106
-
1107
- return data;
1108
- }
1109
-
1110
- /**
1111
- * Helper method for array insertion
1112
- *
1113
- * It iterates through param and sets every item as a key.value and returns an insert result
1114
- * <code>
1115
- * user = new User;
1116
- * param = {'username': 'mirko', 'dateTime': date('Y-m-d H:i:s'));
1117
- * return user.insertRow(param);
1118
- * </code>
1119
- *
1120
- * @author Dario Filkovic <dfilkovi@gmail.com>
1121
- *
1122
- * @since 1.0
1123
- *
1124
- * @package CoreFw
1125
- *
1126
- * @param Array param Array of key: value pairs for insertion
1127
- * @return Array Error boolean and notice message
1128
- */
1129
- insertRow(param)
1130
- {
1131
- const me = this;
1132
- for (const key in param)
1133
- {
1134
- if (param[key] !== undefined)
1135
- {
1136
- me[key] = param[key];
1137
- }
1138
- }
1139
- return me.insert();
1140
- }
1141
-
1142
- /**
1143
- * Helper method for object update through array parameters
1144
- *
1145
- * It iterates through param and sets every item as a key.value and returns an insert result, it needs an 'id' field
1146
- * <code>
1147
- * user = new User;
1148
- * param = {'id': 5, 'username': 'mirko', 'dateTime': date('Y-m-d H:i:s'));
1149
- * return user.updateRow(param);
1150
- * </code>
1151
- *
1152
- * @author Dario Filkovic <dfilkovi@gmail.com>
1153
- *
1154
- * @since 1.0
1155
- *
1156
- * @package CoreFw
1157
- *
1158
- * @param Array param Array of key: value pairs for insertion
1159
- * @return Array Error boolean and notice message
1160
- */
1161
- updateRow(param)
1162
- {
1163
- const me = this;
1164
- for (const key in param)
1165
- {
1166
- if (param[key] !== undefined)
1167
- {
1168
- me[key] = param[key];
1169
- }
1170
- }
1171
- if (typeof me.id !== 'undefined')
1172
- {
1173
- for (const key in me.idField)
1174
- {
1175
- if (typeof me[key] !== 'undefined' && typeof me.id !== 'object')
1176
- {
1177
- me.id = me[key];
1178
- }
1179
- }
1180
- }
1181
- return me.update();
1182
- }
1183
-
1184
- /**
1185
- * Helper method for object delete through array parameters
1186
- *
1187
- * It iterates through param and sets 'id' fields, it needs an 'id' field/s
1188
- * <code>
1189
- * user = new User;
1190
- * param = {'id': 5);
1191
- * return user.deleteRow(param);
1192
- * </code>
1193
- *
1194
- * @author Dario Filkovic <dfilkovi@gmail.com>
1195
- *
1196
- * @since 1.0
1197
- *
1198
- * @package CoreFw
1199
- *
1200
- * @param Array param Array of key: value pairs for insertion
1201
- * @return Array Error boolean and notice message
1202
- */
1203
- deleteRow(param)
1204
- {
1205
- const me = this;
1206
- for (const key in param)
1207
- {
1208
- if (param[key] !== undefined)
1209
- {
1210
- me[key] = param[key];
1211
- }
1212
- }
1213
- if (typeof me.id !== 'undefined')
1214
- {
1215
- for (const key in me.idField)
1216
- {
1217
- if (typeof me[key] !== 'undefined' && typeof me.id !== 'object')
1218
- {
1219
- me.id = me[key];
1220
- }
1221
- }
1222
- }
1223
- return me.delete();
1224
- }
1225
-
1226
- /**
1227
- * Helper method for object delete
1228
- *
1229
- * <code>
1230
- * user = new User;
1231
- * user.id = 5;
1232
- * return user.delete();
1233
- * </code>
1234
- *
1235
- * <code>
1236
- * user = new User;
1237
- * user.id = {'userId: 5, 'username': 'mirko'); //in case of multiple primary keys
1238
- * return user.delete();
1239
- * </code>
1240
- *
1241
- * @author Dario Filkovic <dfilkovi@gmail.com>
1242
- *
1243
- * @since 1.0
1244
- *
1245
- * @package CoreFw
1246
- *
1247
- * @return Array Error boolean and notice message
1248
- */
1249
- async delete()
1250
- {
1251
- const me = this;
1252
-
1253
- let ownerWhere = '';
1254
- const params = {};
1255
-
1256
- if (me.ownerActionGlob === true)
1257
- {
1258
- if (!me.modelLoaded)
1259
- {
1260
- await me.select();
1261
- }
1262
-
1263
-
1264
- if (me[me.tableConfig.ownerField] !== me.session.userId)
1265
- {
1266
- throw (ErrorCodes.error('no_privilage'));
1267
- }
1268
-
1269
- ownerWhere = ` AND ${me.tableConfig.ownerField}=:sessionUserId `;
1270
- params.sessionUserId = me.session.userId;
1271
- }
1272
-
1273
- if (me.companyActionGlob === true)
1274
- {
1275
- if (!me.modelLoaded)
1276
- {
1277
- await me.select();
1278
- }
1279
-
1280
- if (me[me.tableConfig.companyField] !== me.session.companyId)
1281
- {
1282
- throw (ErrorCodes.error('no_privilage'));
1283
- }
1284
-
1285
- ownerWhere += ` AND ${me.tableConfig.companyField}=:sessionCompanyId`;
1286
- params.sessionCompanyId = me.session.companyId;
1287
- }
1288
-
1289
- if (me.functionNameGlob !== false)
1290
- {
1291
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].deleteAction === 0)
1292
- {
1293
- throw (ErrorCodes.error('no_privilage'));
1294
- }
1295
- }
1296
- else if (me.objectNameGlob !== false)
1297
- {
1298
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob].deleteAction === 0)
1299
- {
1300
- throw (ErrorCodes.error('no_privilage'));
1301
- }
1302
- }
1303
-
1304
- // call before delete
1305
- await me.beforeDelete();
1306
-
1307
- const whereArr = [];
1308
- let where = '';
1309
-
1310
- if (typeof me.id === 'object')
1311
- {
1312
- // eslint-disable-next-line guard-for-in
1313
- for (const key in me.id)
1314
- {
1315
- if (me.id[key] === null)
1316
- {
1317
- whereArr.push(`\`${key}\` IS NULL`);
1318
- }
1319
- else
1320
- {
1321
- whereArr.push(`\`${key}\`=:${key}`);
1322
- }
1323
- params[key] = me.id[key];
1324
- }
1325
- where = whereArr.join(' AND ');
1326
- }
1327
- else
1328
- {
1329
- const key = Object.keys(me.idField)[0];
1330
- where = `\`${key}\`=:${key}`;
1331
- params[key] = me.id;
1332
- }
1333
-
1334
- await me[me.dbName].query(`DELETE FROM \`${me.tableName}\` WHERE ${where} ${ownerWhere}`, params);
1335
-
1336
- await me.afterDelete();
1337
-
1338
- return (
1339
- {
1340
- error: false,
1341
- notice: 'success',
1342
- });
1343
- }
1344
-
1345
- /**
1346
- * Called before delete from db
1347
- *
1348
- * @author Dario Filkovic <dfilkovi@gmail.com>
1349
- *
1350
- * @since 1.0
1351
- *
1352
- * @package CoreFw
1353
- *
1354
- * @return void
1355
- */
1356
- // eslint-disable-next-line class-methods-use-this
1357
- async beforeDelete()
1358
- {
1359
- return (
1360
- {
1361
- error: false,
1362
- notice: 'success',
1363
- });
1364
- }
1365
-
1366
- /**
1367
- * Called after succesfull delete from db
1368
- *
1369
- * @author Dario Filkovic <dfilkovi@gmail.com>
1370
- *
1371
- * @since 1.0
1372
- *
1373
- * @package CoreFw
1374
- *
1375
- * @return void
1376
- */
1377
- // eslint-disable-next-line class-methods-use-this
1378
- async afterDelete()
1379
- {
1380
- return (
1381
- {
1382
- error: false,
1383
- notice: 'success',
1384
- });
1385
- }
1386
-
1387
- /**
1388
- * Helper method for object update
1389
- *
1390
- * It validates data and returns error messages if not valid data
1391
- * <code> {'error': true, 'notice': {'username': 'Not valid')); </code>
1392
- * ('notice' becomes array of error notices in case of multiple errors) or
1393
- * returns <code> {'error': false, 'notice': 'Success'); </code>
1394
- * For succesfull update an 'id' field must be present
1395
- * <code>
1396
- * user = new User;
1397
- * user.id = 5;
1398
- * user.username = 'mirko';
1399
- * return user.update();
1400
- * </code>
1401
- *
1402
- * <code>
1403
- * user = new User;
1404
- * user.id = {'userId: 5, 'username': 'mirko'); //in case of multiple primary keys
1405
- * user.username = 'slavko';
1406
- * return user.update();
1407
- * </code>
1408
- *
1409
- * @author Dario Filkovic <dfilkovi@gmail.com>
1410
- *
1411
- * @since 1.0
1412
- *
1413
- * @package CoreFw
1414
- *
1415
- * @return Array Error boolean and notice message/messages
1416
- */
1417
- async update()
1418
- {
1419
- const me = this;
1420
-
1421
- if (typeof me.id === 'undefined')
1422
- {
1423
- throw (ErrorCodes.error('no_id_field_set'));
1424
- }
1425
-
1426
- if (!me.modelLoaded)
1427
- {
1428
- await me.select();
1429
- }
1430
-
1431
- let ownerWhere = '';
1432
- const values = {};
1433
- if (me.ownerActionGlob === true)
1434
- {
1435
- if (me[me.tableConfig.ownerField] !== me.session.userId)
1436
- {
1437
- throw (ErrorCodes.error('no_privilage'));
1438
- }
1439
- ownerWhere = ` AND ${me.tableConfig.ownerField}=:sessionUserId `;
1440
- values.sessionUserId = me.session.userId;
1441
- }
1442
-
1443
- if (me.companyActionGlob === true)
1444
- {
1445
- if (me[me.tableConfig.companyField] !== me.session.companyId)
1446
- {
1447
- throw (ErrorCodes.error('no_privilage'));
1448
- }
1449
- ownerWhere += ` AND ${me.tableConfig.companyField}=:sessionCompanyId `;
1450
- values.sessionCompanyId = me.session.companyId;
1451
- }
1452
-
1453
- if (me.functionNameGlob !== false)
1454
- {
1455
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].updateAction === 0)
1456
- {
1457
- throw (ErrorCodes.error('no_privilage'));
1458
- }
1459
- }
1460
- else if (me.objectNameGlob !== false)
1461
- {
1462
- if (me.lib.acl[me.aclGroupId][me.objectNameGlob].updateAction === 0)
1463
- {
1464
- throw (ErrorCodes.error('no_privilage'));
1465
- }
1466
- }
1467
-
1468
- const check = {};
1469
- if (typeof me.id === 'object')
1470
- {
1471
- for (const key in me.idField)
1472
- {
1473
- if (me.id[key] !== undefined)
1474
- {
1475
- check[key] = me.id[key];
1476
- }
1477
- }
1478
- }
1479
- else
1480
- {
1481
- check[Object.keys(me.idField)[0]] = me.id;
1482
- }
1483
-
1484
- for (const key in me.tableConfig.fields)
1485
- {
1486
- if (me[key] !== undefined)
1487
- {
1488
- check[key] = me[key];
1489
- }
1490
- }
1491
-
1492
- for (const key in me.idField)
1493
- {
1494
- if (me.idField[key].req === 1)
1495
- {
1496
- check[key] = me[key];
1497
- }
1498
- }
1499
-
1500
- await me.checkFields(check);
1501
-
1502
- // call before update
1503
- await me.beforeUpdate();
1504
-
1505
- const strings = [];
1506
- if (typeof me.id === 'object')
1507
- {
1508
- for (const key in me.idField)
1509
- {
1510
- if (me.idField[key] !== undefined)
1511
- {
1512
- strings.push(`\`${key}\`=:${key}`);
1513
- values[key] = CfwObject.defineType(me.id[key], me.idField[key]);
1514
- }
1515
- }
1516
- }
1517
- else
1518
- {
1519
- const key = Object.keys(me.idField)[0];
1520
- strings.push(`\`${key}\`=:${key}`);
1521
- values[key] = CfwObject.defineType(me.id, me.idField[key]);
1522
- }
1523
-
1524
- const string = ` WHERE ${strings.join(' AND ')}`;
1525
-
1526
- const fieldsAr = [];
1527
- for (const key in me.tableConfig.fields)
1528
- {
1529
- if (me.tableConfig.fields[key])
1530
- {
1531
- fieldsAr.push(`\`${key}\`=:${key}`);
1532
- values[key] = CfwObject.defineType(me[key], me.tableConfig.fields[key]);
1533
- }
1534
- }
1535
-
1536
- for (const key in me.idField)
1537
- {
1538
- if (me.idField[key].req === 1)
1539
- {
1540
- fieldsAr.push(`\`${key}\`=:${key}`);
1541
- values[key] = CfwObject.defineType(me[key], me.tableConfig.id[key]);
1542
- }
1543
- }
1544
-
1545
- const fields = fieldsAr.join(', ');
1546
-
1547
- await me[me.dbName].query(`UPDATE \`${me.tableName}\` SET ${fields} ${string} ${ownerWhere}`, values);
1548
-
1549
- // call after update
1550
- await me.afterUpdate();
1551
- me.lastId = me.id;
1552
-
1553
- return (
1554
- {
1555
- error: false,
1556
- notice: 'success',
1557
- lastId: me.id,
1558
- });
1559
- }
1560
-
1561
- /**
1562
- * Called before update db
1563
- *
1564
- * @author Dario Filkovic <dfilkovi@gmail.com>
1565
- *
1566
- * @since 1.0
1567
- *
1568
- * @package CoreFw
1569
- *
1570
- * @return void
1571
- */
1572
- // eslint-disable-next-line class-methods-use-this
1573
- async beforeUpdate()
1574
- {
1575
- return (
1576
- {
1577
- error: false,
1578
- notice: 'success',
1579
- });
1580
- }
1581
-
1582
- /**
1583
- * Called after succesfull update db
1584
- *
1585
- * @author Dario Filkovic <dfilkovi@gmail.com>
1586
- *
1587
- * @since 1.0
1588
- *
1589
- * @package CoreFw
1590
- *
1591
- * @return void
1592
- */
1593
- // eslint-disable-next-line class-methods-use-this
1594
- async afterUpdate()
1595
- {
1596
- return (
1597
- {
1598
- error: false,
1599
- notice: 'success',
1600
- });
1601
- }
1602
-
1603
- /**
1604
- * Validate and decorate fields
1605
- *
1606
- * First it decorates data if decorators are passed in an object table definition,
1607
- * then validates fields for insertion/update
1608
- *
1609
- * @see Decorator
1610
- *
1611
- * @author Dario Filkovic <dfilkovi@gmail.com>
1612
- *
1613
- * @since 1.0
1614
- *
1615
- * @package CoreFw
1616
- * @param Array insert Values
1617
- * @param Array update Update
1618
- * @return Array Error boolean and notice message/messages
1619
- */
1620
- async checkFields(insert)
1621
- {
1622
- const decorator = new Decorator(this, insert);
1623
- const val = await Validator.validate(decorator.insert, this);
1624
- return val;
1625
- }
1626
- };
1
+ /* eslint-disable no-underscore-dangle */
2
+ const ErrorCodes = require('./ErrorCodes.js');
3
+ const Decorator = require('./Decorator.js');
4
+ const Validator = require('./Validator.js');
5
+ const ErrorControl = require('./ErrorControl.js');
6
+
7
+ /**
8
+ * Class providing main Object Model for database insertion, validation, update, delete etc...
9
+ *
10
+ * This is a starting point of every object that uses database
11
+ * Every object should extend this object
12
+ * <code>
13
+ * module.exports = class User_Base extends Object
14
+ * {
15
+ *
16
+ * tableConf()
17
+ * {
18
+ * return {
19
+ * 'tableName': 'users',
20
+ * 'id': {
21
+ * 'userId': {
22
+ * 'fieldType': 'int',
23
+ * 'maxlength': 20,
24
+ * 'req': 0
25
+ * )
26
+ * ),
27
+ * 'ownerField': 'userId',
28
+ * 'fields': {
29
+ * 'username': {
30
+ * 'fieldType': 'sc',
31
+ * 'maxlength': 255,
32
+ * 'minlength': 1,
33
+ * 'req': 1
34
+ * ),
35
+ * 'updateDateTime': {
36
+ * 'fieldType': 'dateTime',
37
+ * 'req': 1
38
+ * )
39
+ * )
40
+ * );
41
+ * }
42
+ *
43
+ * insertRow(param)
44
+ * {
45
+ * me.username = param['username'];
46
+ * me.updateDateTime = _cfw_lib_GeneralHandling::datetimeNow();
47
+ * return me.insert();
48
+ * }
49
+ *
50
+ * updateRow(param)
51
+ * {
52
+ * param['updateDateTime'] = _cfw_lib_GeneralHandling::datetimeNow();
53
+ *
54
+ * return parent::updateRow(param);
55
+ * }
56
+ * }
57
+ * </code>
58
+ * In the above example, we extended the object, called the new module.exports = class User cause it will
59
+ * hold user database table mapping, we then override tableConf() method to define * table specification.
60
+ * 'tableName' is the exact table name as it is written in database
61
+ * 'id' array holds primary key values, if they are autoincrement then
62
+ * 'req' should be '0' else they should be specified on insert
63
+ * 'ownerField' is used to define which field holds value that will be checked
64
+ * of 'owner action' is checked in ACL. If that is the case 'ownerField' will be checked against Session::userId value.
65
+ * 'fields' holds columns except primary key values
66
+ * we can define each column properties with following:
67
+ * <ul>
68
+ * <li>fieldType - (required) define as 'text', 'int', 'float', 'dateTime', 'date', 'sc (special case)'</li>
69
+ * <li>maxlength - String max length</li>
70
+ * <li>minlegth - String min length</li>
71
+ * <li>maxvalue - Int or float max value</li>
72
+ * <li>minvalue - Int or float min value</li>
73
+ * <li>req - (required) define if this field is optional</li>
74
+ * <li>decorators - {) of decorators that should be used before validating and inserting/updating</li>
75
+ * </ul>
76
+ * We then override insertRow if we want to do some preprocessing like in
77
+ * this example in which updateDateTime was not given in parameters then we insert it ourselves.
78
+ * We can also override functions like we did in updateRow only to add a single parameter
79
+ *
80
+ * @todo Make this an abstract class
81
+ * @author Dario Filkovic <dfilkovi@gmail.com>
82
+ *
83
+ * @since 1.0
84
+ *
85
+ * @package CoreFw
86
+ */
87
+ module.exports = class CfwObject
88
+ {
89
+ /**
90
+ * Get objects from Registry
91
+ *
92
+ * @author Dario Filkovic <dfilkovi@gmail.com>
93
+ *
94
+ * @since 1.0
95
+ *
96
+ * @package CoreFw
97
+ *
98
+ * @return void
99
+ */
100
+ constructor(session)
101
+ {
102
+ const me = this;
103
+
104
+ me.events = {};
105
+ me.ownerActionGlob = false;
106
+ me.companyActionGlob = false;
107
+ me.functionNameGlob = false;
108
+ me.modelLoaded = false;
109
+ me.assocData = {};
110
+
111
+ me.objectNameGlob = this.constructor.name;
112
+
113
+ if (typeof session === 'undefined' && me.objectNameGlob !== 'Session' && me.objectNameGlob !== 'Translator')
114
+ {
115
+ return new Proxy(this,
116
+ {
117
+ get: function get(target)
118
+ {
119
+ return function wrapper()
120
+ {
121
+ throw (`Please provide session for object instantiation: ${me.objectNameGlob} ${target}`);
122
+ };
123
+ },
124
+ });
125
+ }
126
+
127
+ me.lib = global.lib;
128
+ me.session = session;
129
+ if (typeof me.session === 'undefined')
130
+ {
131
+ me.session = me.lib.unregisteredSession;
132
+ }
133
+ me.errorControl = new ErrorControl(me.session);
134
+ me.aclLangId = 1;
135
+ me.aclGroupId = 2;
136
+ if (typeof me.session !== 'undefined')
137
+ {
138
+ me.aclLangId = me.session.langId;
139
+ me.aclGroupId = me.session.groupId;
140
+ if (me.session.tranDb && me.session.tranDb.dbname === me.session.db.dbname)
141
+ {
142
+ me.db = me.session.tranDb;
143
+ }
144
+ else
145
+ {
146
+ me.db = me.session.db;
147
+ }
148
+ }
149
+ else
150
+ {
151
+ me.db = me.lib.db;
152
+ }
153
+ me.props = me.lib.props;
154
+ me.lang = me.lib.lang;
155
+ if (typeof me.tableConf !== 'undefined')
156
+ {
157
+ me.tableConfig = me.tableConf();
158
+ if (typeof me.tableConfig.tableName !== 'undefined')
159
+ {
160
+ me.tableName = me.tableConfig.tableName;
161
+ }
162
+ if (typeof me.tableConfig.id !== 'undefined')
163
+ {
164
+ me.idField = me.tableConfig.id;
165
+ }
166
+ }
167
+
168
+ me.config = me.lib.config;
169
+ me.dbName = 'db';
170
+
171
+ return new Proxy(this,
172
+ {
173
+ get: function get(target, name)
174
+ {
175
+ if (typeof me[name] === 'function')
176
+ {
177
+ return function wrapper(...args)
178
+ {
179
+ return me.__call(name, args);
180
+ };
181
+ }
182
+ return me[name];
183
+ },
184
+ });
185
+ }
186
+
187
+ /**
188
+ * Magic method that gets called every time a (method) is triggered
189
+ *
190
+ * This is MOST important, if you want to use out-of-the box
191
+ * ACL management for objects and methods, functions should be named protected
192
+ * Every time a is triggered __call gets fired before which checks privilage on module.exports = class and method
193
+ * NOTICE!!! Observer is also called here, every function that
194
+ * you want to observe needs to be protected to get __call method to be fired
195
+ *
196
+ * @see Observer
197
+ * @author Dario Filkovic <dfilkovi@gmail.com>
198
+ *
199
+ * @since 1.0
200
+ *
201
+ * @package CoreFw
202
+ * @param String methodName
203
+ * @param mixed[] argumentsin
204
+ * @return void
205
+ */
206
+ async __call(methodName, argumentsin)
207
+ {
208
+ const me = this;
209
+
210
+ if (methodName === 'translate' || methodName === 'on')
211
+ {
212
+ return me[methodName](...argumentsin);
213
+ }
214
+
215
+ me.methodName = (me.functionNameGlob !== false) ? me.functionNameGlob : methodName;
216
+ let error = false;
217
+
218
+ const objectNameGlob = me.objectNameGlob.toLowerCase();
219
+
220
+ if (typeof me.lib.acl[me.aclGroupId][objectNameGlob] !== 'undefined'
221
+ && typeof me.lib.acl[me.aclGroupId][objectNameGlob][methodName.toLowerCase()] !== 'undefined')
222
+ {
223
+ me.functionNameGlob = methodName;
224
+ if (me.lib.acl[me.aclGroupId][objectNameGlob][me.functionNameGlob.toLowerCase()].ownerAction === 1)
225
+ {
226
+ me.ownerActionGlob = true;
227
+ }
228
+ if (me.lib.acl[me.aclGroupId][objectNameGlob][me.functionNameGlob.toLowerCase()].companyAction === 1)
229
+ {
230
+ me.companyActionGlob = true;
231
+ }
232
+
233
+ if (me.lib.acl[me.aclGroupId][objectNameGlob][me.functionNameGlob.toLowerCase()].instantiate === 0)
234
+ {
235
+ error = true;
236
+ }
237
+ }
238
+ else if (typeof me.lib.acl[me.aclGroupId][objectNameGlob] !== 'undefined'
239
+ && typeof me.lib.acl[me.aclGroupId][objectNameGlob].instantiate !== 'undefined')
240
+ {
241
+ if (me.lib.acl[me.aclGroupId][objectNameGlob].ownerAction === 1)
242
+ {
243
+ me.ownerActionGlob = true;
244
+ }
245
+ if (me.lib.acl[me.aclGroupId][objectNameGlob].companyAction === 1)
246
+ {
247
+ me.companyActionGlob = true;
248
+ }
249
+
250
+ if (me.lib.acl[me.aclGroupId][objectNameGlob].instantiate === 0)
251
+ {
252
+ error = true;
253
+ }
254
+ }
255
+ else
256
+ {
257
+ error = true;
258
+ }
259
+
260
+ // check if method really exists
261
+ if (typeof me[methodName] === 'undefined')
262
+ {
263
+ throw (ErrorCodes.error('method_not_found', {
264
+ method: methodName,
265
+ classname: me.objectNameGlob,
266
+ }));
267
+ }
268
+
269
+ const observer = global.lib.observer;
270
+
271
+ observer.beforeCall({
272
+ method: methodName,
273
+ classname: me.objectNameGlob,
274
+ argumentsin: argumentsin,
275
+ session: me.session,
276
+ });
277
+
278
+
279
+ if (error === true)
280
+ {
281
+ throw (ErrorCodes.error('no_privilage', {
282
+ method: methodName,
283
+ classname: me.objectNameGlob,
284
+ }));
285
+ }
286
+
287
+ let retValue;
288
+ try
289
+ {
290
+ const val = await me[methodName](...argumentsin);
291
+ retValue = val;
292
+ return val;
293
+ }
294
+ catch(error)
295
+ {
296
+ retValue = error;
297
+ throw(error);
298
+ }
299
+ finally
300
+ {
301
+ observer.afterCall({
302
+ method: methodName,
303
+ classname: me.objectNameGlob,
304
+ argumentsin: argumentsin,
305
+ res: retValue,
306
+ session: me.session,
307
+ });
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Translate key based on current langId
313
+ *
314
+ * @author Dario Filkovic <dfilkovi@gmail.com>
315
+ *
316
+ * @since 1.0
317
+ *
318
+ * @package CoreFw
319
+ *
320
+ * @return string Translated word
321
+ */
322
+ translate(key)
323
+ {
324
+ const me = this;
325
+ const val = me.lang.translate(key, me.aclLangId);
326
+ return val;
327
+ }
328
+
329
+ /**
330
+ * Select a single row from this table based on id
331
+ *
332
+ * <code>
333
+ * user = new User;
334
+ * user.id = 5;
335
+ * user.select();
336
+ * </code>
337
+ * In the above example if an user with id 5 is found in
338
+ * database user object get's populated with data that can be fetched by:
339
+ * <code>
340
+ * user.username;
341
+ * </code>
342
+ * for example.
343
+ * If table has more than one primary key you can select it like this:
344
+ * <code>
345
+ * user = new User;
346
+ * user.id = {'id': 5, 'group': 4);
347
+ * user.select();
348
+ * </code>
349
+ *
350
+ * @author Dario Filkovic <dfilkovi@gmail.com>
351
+ *
352
+ * @since 1.0
353
+ *
354
+ * @package CoreFw
355
+ *
356
+ * @return booelan True if record found false instead
357
+ */
358
+ async select()
359
+ {
360
+ const me = this;
361
+
362
+ const params = [];
363
+ const strings = [];
364
+ if (typeof me.id === 'object')
365
+ {
366
+ for (const key of Object.keys(me.idField))
367
+ {
368
+ strings.push(`\`${key}\`=?`);
369
+ params.push(me.id[key]);
370
+ }
371
+ }
372
+ else
373
+ {
374
+ strings.push(`\`${Object.keys(me.idField)[0]}\`=?`);
375
+ params.push(me.id);
376
+ }
377
+
378
+ const string = ` WHERE ${strings.join(' AND ')}`;
379
+ const results = await me[me.dbName].query(`SELECT * FROM \`${me.tableName}\` ${string}`, params);
380
+
381
+ me.modelLoaded = true;
382
+
383
+ if (typeof results[0] !== 'undefined')
384
+ {
385
+ [me.assocData] = results;
386
+ for (const key in results[0])
387
+ {
388
+ if (typeof me[key] === 'undefined')
389
+ {
390
+ me[key] = results[0][key];
391
+ }
392
+ }
393
+ return true;
394
+ }
395
+ throw (ErrorCodes.error('record_not_found', { object: me.objectNameGlob, method: me.functionNameGlob }));
396
+ }
397
+
398
+ /**
399
+ * Used to cast value before update or insert to it's mathcing field type
400
+ *
401
+ * @author Dario Filkovic <dfilkovi@gmail.com>
402
+ *
403
+ * @since 1.0
404
+ *
405
+ * @package CoreFw
406
+ * @param String value
407
+ * @param String fieldType
408
+ * @return String|int Casted value
409
+ */
410
+ static defineType(value, field)
411
+ {
412
+ if (typeof value === 'object')
413
+ {
414
+ return value;
415
+ }
416
+
417
+ let valSec = value;
418
+
419
+ const { fieldType } = field;
420
+
421
+ switch (fieldType)
422
+ {
423
+ case 'int':
424
+ valSec = parseInt(value, 10) || 0;
425
+ break;
426
+ case 'float':
427
+ valSec = parseFloat(value) || 0;
428
+ break;
429
+ case 'string':
430
+ valSec = value.toString();
431
+ break;
432
+ case 'num':
433
+ valSec = value.toString();
434
+ break;
435
+ default:
436
+ valSec = value.toString();
437
+ break;
438
+ }
439
+
440
+ if (valSec === '' && typeof field.null !== 'undefined' && field.null === true)
441
+ {
442
+ valSec = null;
443
+ }
444
+
445
+ return valSec;
446
+ }
447
+
448
+ /**
449
+ * Used before insert or update to validate all fields
450
+ *
451
+ * @author Dario Filkovic <dfilkovi@gmail.com>
452
+ *
453
+ * @since 1.0
454
+ *
455
+ * @package CoreFw
456
+ * @param Array param Array of values
457
+ * @param Array update
458
+ * @return boolean True if succes false otherwise
459
+ */
460
+ async checkInsert(paramIn, updateIn)
461
+ {
462
+ const me = this;
463
+
464
+ let param = paramIn;
465
+ let update = updateIn;
466
+
467
+ if (typeof param === 'undefined')
468
+ {
469
+ param = false;
470
+ }
471
+ if (typeof update === 'undefined')
472
+ {
473
+ update = false;
474
+ }
475
+
476
+ if (update !== false && !me.modelLoaded)
477
+ {
478
+ me.select();
479
+ }
480
+
481
+ if (typeof me.id !== 'undefined' && typeof me.id === 'object')
482
+ {
483
+ for (const key in me.id)
484
+ {
485
+ if (me.id[key] !== undefined)
486
+ {
487
+ me[key] = me.id[key];
488
+ }
489
+ }
490
+ }
491
+ else if (typeof me.id !== 'undefined')
492
+ {
493
+ me[Object.keys(me.idField)[0]] = me.id;
494
+ }
495
+
496
+ if (param !== false)
497
+ {
498
+ for (const key in param)
499
+ {
500
+ if (param[key] !== undefined)
501
+ {
502
+ me[key] = param[key];
503
+ }
504
+ }
505
+ }
506
+
507
+ const valuesCheck = {};
508
+ for (const key in me.tableConfig.fields)
509
+ {
510
+ if (typeof me[key] !== 'undefined')
511
+ {
512
+ valuesCheck[key] = me[key];
513
+ }
514
+ }
515
+
516
+ for (const key in me.idField)
517
+ {
518
+ if (typeof me[key] !== 'undefined' && me[key] !== '')
519
+ {
520
+ valuesCheck[key] = me[key];
521
+ }
522
+ }
523
+
524
+ await me.checkFields(valuesCheck);
525
+ }
526
+
527
+ /**
528
+ * Used for inserting new row into table
529
+ *
530
+ * <code>
531
+ * user = new User;
532
+ * user.username = 'mirko';
533
+ * user.dateEntered = date('Y-m-d H:i:s');
534
+ * val = user.insert();
535
+ * </code>
536
+ * In this example val will hold an array with 'error'
537
+ * boolean which if it is true, error happened and 'notice' string is also in array
538
+ * which holds the error message or error array if more than one error is given
539
+ * On succes var will hold error: false and 'lastId'
540
+ * parameter which holds last autoincrement Id for further processing (chaining)
541
+ *
542
+ * @author Dario Filkovic <dfilkovi@gmail.com>
543
+ *
544
+ * @since 1.0
545
+ *
546
+ * @package CoreFw
547
+ *
548
+ * @return mixed[] Array with 'error' and 'notice' if error true, and 'lastId' if error false
549
+ */
550
+ async insert()
551
+ {
552
+ const me = this;
553
+
554
+ if (typeof me.id !== 'undefined' && typeof me.id === 'object')
555
+ {
556
+ for (const key in me.id)
557
+ {
558
+ if (me.id[key] !== undefined)
559
+ {
560
+ me[key] = me.id[key];
561
+ }
562
+ }
563
+ }
564
+ else if (typeof me.id !== 'undefined')
565
+ {
566
+ me[Object.keys(me.idField)[0]] = me.id;
567
+ }
568
+
569
+ if (typeof me.userId === 'undefined')
570
+ {
571
+ me.userId = me.session.userId;
572
+ }
573
+ if (typeof me.companyId === 'undefined')
574
+ {
575
+ me.companyId = me.session.companyId;
576
+ }
577
+
578
+ if (me.userId === false)
579
+ {
580
+ delete (me.userId);
581
+ }
582
+ if (me.companyId === false)
583
+ {
584
+ delete (me.companyId);
585
+ }
586
+
587
+ if (me.functionNameGlob !== false)
588
+ {
589
+ if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].insertAction === 0)
590
+ {
591
+ throw (ErrorCodes.error('no_privilage'));
592
+ }
593
+ }
594
+ else if (me.objectNameGlob !== false)
595
+ {
596
+ if (me.lib.acl[me.aclGroupId][me.objectNameGlob].insertAction === 0)
597
+ {
598
+ throw (ErrorCodes.error('no_privilage'));
599
+ }
600
+ }
601
+
602
+ const valuesCheck = {};
603
+ for (const key in me.tableConfig.fields)
604
+ {
605
+ if (typeof me[key] !== 'undefined')
606
+ {
607
+ valuesCheck[key] = me[key];
608
+ }
609
+ else if (typeof me.tableConfig.fields[key].default !== 'undefined')
610
+ {
611
+ if (typeof me.tableConfig.fields[key].default === 'function')
612
+ {
613
+ // eslint-disable-next-line no-await-in-loop
614
+ me[key] = await me.tableConfig.fields[key].default.call(me);
615
+ }
616
+ else
617
+ {
618
+ me[key] = me.tableConfig.fields[key].default;
619
+ }
620
+
621
+ valuesCheck[key] = me[key];
622
+ }
623
+ }
624
+
625
+ for (const key in me.idField)
626
+ {
627
+ if (typeof me[key] !== 'undefined' && me[key] !== '')
628
+ {
629
+ valuesCheck[key] = me[key];
630
+ }
631
+ else if (typeof me.idField[key].default !== 'undefined')
632
+ {
633
+ if (typeof me.tableConfig.fields[key].default === 'function')
634
+ {
635
+ // eslint-disable-next-line no-await-in-loop
636
+ me[key] = await me.idField[key].default.call(me);
637
+ }
638
+ else
639
+ {
640
+ me[key] = me.idField[key].default;
641
+ }
642
+ valuesCheck[key] = me[key];
643
+ }
644
+ }
645
+
646
+ await me.checkFields(valuesCheck);
647
+
648
+ // call before insert
649
+ await me.beforeInsert();
650
+
651
+ const fields = [];
652
+ const values = [];
653
+ for (const key in me.tableConfig.fields)
654
+ {
655
+ if (typeof me[key] !== 'undefined')
656
+ {
657
+ fields.push(`\`${key}\``);
658
+ values.push(CfwObject.defineType(me[key], me.tableConfig.fields[key]));
659
+ }
660
+ }
661
+
662
+ for (const key in me.idField)
663
+ {
664
+ if (typeof me[key] !== 'undefined' && me[key] !== '')
665
+ {
666
+ fields.push(`\`${key}\``);
667
+ values.push(CfwObject.defineType(me[key], me.tableConfig.id[key]));
668
+ }
669
+ }
670
+
671
+ let duplic = '';
672
+ const fieldsDupl = [];
673
+
674
+ if (typeof me.tableConfig.onduplicate !== 'undefined')
675
+ {
676
+ const key = Object.keys(me.idField)[0];
677
+ // this will see if the field isn't autoincrement
678
+ if (me.idField[key].req === 0)
679
+ {
680
+ duplic = ` ON DUPLICATE KEY UPDATE \`${key}\`=LAST_INSERT_ID(\`${key}\`), `;
681
+ }
682
+ else
683
+ {
684
+ duplic = ' ON DUPLICATE KEY UPDATE ';
685
+ }
686
+ for (let i = 0; i < me.tableConfig.onduplicate.length; i += 1)
687
+ {
688
+ const value = me.tableConfig.onduplicate[i];
689
+ if (typeof me[value] !== 'undefined')
690
+ {
691
+ fieldsDupl.push(`\`${value}\`=?`);
692
+ if (typeof me.tableConfig.fields[value] !== 'undefined')
693
+ {
694
+ values.push(CfwObject.defineType(me[value], me.tableConfig.fields[value]));
695
+ }
696
+ else
697
+ {
698
+ values.push(CfwObject.defineType(me[value], me.idField[value]));
699
+ }
700
+ }
701
+ }
702
+ if (fieldsDupl.length > 0)
703
+ {
704
+ duplic += fieldsDupl.join(', ');
705
+ }
706
+ else
707
+ {
708
+ duplic = '';
709
+ }
710
+ }
711
+
712
+ let fieldsq = '';
713
+ if (fields.length > 0)
714
+ {
715
+ fieldsq = fields.join(', ');
716
+ }
717
+
718
+ const pSafe = [];
719
+ for (let i = 0; i < fields.length; i += 1)
720
+ {
721
+ pSafe.push('?');
722
+ }
723
+
724
+ let pSafeq = '';
725
+ if (pSafe.length > 0)
726
+ {
727
+ pSafeq = pSafe.join(', ');
728
+ }
729
+
730
+ const results = await me[me.dbName].query(
731
+ `INSERT INTO \`${me.tableName}\` (${fieldsq}) VALUES (${pSafeq}) ${duplic}`,
732
+ values,
733
+ );
734
+
735
+ me.lastId = results.insertId;
736
+ me.id = me.lastId;
737
+
738
+ // call after insert
739
+ await me.afterInsert();
740
+
741
+ return (
742
+ {
743
+ error: false,
744
+ lastId: me.lastId,
745
+ notice: 'success',
746
+ });
747
+ }
748
+
749
+ /**
750
+ * Called before insert into db
751
+ *
752
+ * @author Dario Filkovic <dfilkovi@gmail.com>
753
+ *
754
+ * @since 1.0
755
+ *
756
+ * @package CoreFw
757
+ *
758
+ * @return void
759
+ */
760
+ // eslint-disable-next-line class-methods-use-this
761
+ async beforeInsert()
762
+ {
763
+ return (
764
+ {
765
+ error: false,
766
+ notice: 'success',
767
+ });
768
+ }
769
+
770
+ /**
771
+ * Called after succesfull insert into db
772
+ *
773
+ * @author Dario Filkovic <dfilkovi@gmail.com>
774
+ *
775
+ * @since 1.0
776
+ *
777
+ * @package CoreFw
778
+ *
779
+ * @return void
780
+ */
781
+ // eslint-disable-next-line class-methods-use-this
782
+ async afterInsert()
783
+ {
784
+ return (
785
+ {
786
+ error: false,
787
+ notice: 'success',
788
+ });
789
+ }
790
+
791
+ /**
792
+ * Used for selection mainly from ExtJS and ajax requests
793
+ * It automaticaly selects rows based on passed parameters in this object
794
+ * Parameters are:
795
+ * <ul>
796
+ * <li>sort - sort by</li>
797
+ * <li>dir - sort direction (ASC or DESC)</li>
798
+ * <li>start - starting row</li>
799
+ * <li>limit - number of records to fetch</li>
800
+ * <li>query - every field in table is searched by this value (LIKE %value%)</li>
801
+ * <li>initialId - if you want to inlcude a single value in this
802
+ * search that would not normaly come, pass it with this parameter</li>
803
+ * </ul>
804
+ * If 'sort' parameter is not passed sorting is by first idField and
805
+ * direction is DESC, if no start or limit parameters are passed, no limit is used
806
+ *
807
+ * <code>
808
+ * user = new User;
809
+ * val = user.selectRow({'sort': 'id', 'dir': 'DESC', 'start': 20, 'limit': 10));
810
+ * </code>
811
+ * In this example val will hold an array with 'error' boolean
812
+ * if error happened and 'notice' string which holds the error message
813
+ * or error array if more than one error is given
814
+ * On succes var will hold 'root' which holds all row results
815
+ * (empty array if no results) and 'totalCount' int that has number of
816
+ * records without limit (for use with pagination)
817
+ *
818
+ * @author Dario Filkovic <dfilkovi@gmail.com>
819
+ *
820
+ * @since 1.0
821
+ *
822
+ * @package CoreFw
823
+ * @param Array param An array of key: value pairs for selecting rows
824
+ * @return mixed[] Array with 'error' and 'notice' if error true and 'root' and 'totalCount' if error false
825
+ */
826
+ async selectRow(param)
827
+ {
828
+ const me = this;
829
+
830
+ let data = [];
831
+
832
+ let sort;
833
+
834
+ if (typeof param.sort !== 'undefined')
835
+ {
836
+ sort = me.db.escapeId(`t.${param.sort}`);
837
+ }
838
+ else
839
+ {
840
+ sort = `t.${Object.keys(me.idField)[0]}`;
841
+ }
842
+
843
+ let dir = 'DESC';
844
+ if (typeof param.dir !== 'undefined')
845
+ {
846
+ switch (param.dir)
847
+ {
848
+ case 'asc':
849
+ dir = 'ASC';
850
+ break;
851
+ default:
852
+ dir = 'DESC';
853
+ break;
854
+ }
855
+ }
856
+
857
+ let limit = '';
858
+ if (typeof param.start !== 'undefined' && typeof param.limit !== 'undefined')
859
+ {
860
+ const start = me.db.escape(parseInt(param.start, 10));
861
+ const end = me.db.escape(parseInt(param.limit, 10));
862
+ limit = ` LIMIT ${end} OFFSET ${start} `;
863
+ }
864
+
865
+ let whereSearch = '';
866
+ const params = {};
867
+ if (typeof param.query !== 'undefined' && param.query !== '')
868
+ {
869
+ const searchString = [];
870
+ for (const key in me.tableConfig.fields)
871
+ {
872
+ if (me.tableConfig.fields[key])
873
+ {
874
+ const value = me.tableConfig.fields[key];
875
+ if (value.fieldType === 'date' || value.fieldType === 'dateTime')
876
+ {
877
+ continue;
878
+ }
879
+ searchString.push(` t.${key} LIKE :${key} `);
880
+ params[key] = `%${param.query}%`;
881
+ }
882
+ }
883
+ if (searchString.length > 0)
884
+ {
885
+ whereSearch = ` AND (${searchString.join(' OR ')}) `;
886
+ }
887
+ }
888
+
889
+ if (typeof param.conditions !== 'undefined' && param.conditions !== '')
890
+ {
891
+ for (const key in param.conditions)
892
+ {
893
+ if (me.tableConfig.fields[key])
894
+ {
895
+ whereSearch += ` AND t.${key} = :${key} `;
896
+ params[key] = param.conditions[key];
897
+ }
898
+ }
899
+ }
900
+
901
+ if (typeof param.filters !== 'undefined' && param.filters !== '')
902
+ {
903
+ for (const key in param.filters)
904
+ {
905
+ if (me.tableConfig.fields[key])
906
+ {
907
+ whereSearch += ` AND t.${key} LIKE :${key} `;
908
+ params[key] = `%${param.filters[key]}%`;
909
+ }
910
+ }
911
+ }
912
+
913
+ let ownerWhere = '';
914
+ if (me.ownerActionGlob === true)
915
+ {
916
+ ownerWhere = ` AND t.${me.tableConfig.ownerField}=:sessionUserId `;
917
+ params.sessionUserId = me.session.userId;
918
+ }
919
+
920
+ if (me.companyActionGlob === true)
921
+ {
922
+ ownerWhere += ` AND t.${me.tableConfig.companyField}=:sessionCompanyId `;
923
+ params.sessionCompanyId = me.session.companyId;
924
+ }
925
+
926
+ let results = await me[me.dbName].query(
927
+ `SELECT t.* FROM \`${me.tableName}\` t WHERE 1=1`
928
+ + `${ownerWhere} ${whereSearch} ORDER BY ${sort} ${dir} ${limit}`,
929
+ params,
930
+ );
931
+
932
+ for (let i = 0; i < results.length; i += 1)
933
+ {
934
+ data.push(results[i]);
935
+ }
936
+
937
+ if (typeof param.initialId !== 'undefined')
938
+ {
939
+ data = await me.findInitialId(data, param.initialId);
940
+ }
941
+
942
+ results = await me[me.dbName].query(
943
+ `SELECT COUNT(*) AS cnt FROM \`${me.tableName}\` t WHERE 1=1 ${ownerWhere} ${whereSearch}`,
944
+ params,
945
+ );
946
+
947
+ let numRows = 0;
948
+ if (results[0] !== undefined)
949
+ {
950
+ numRows = results[0].cnt;
951
+ }
952
+
953
+ return (
954
+ {
955
+ root: data,
956
+ totalCount: numRows,
957
+ });
958
+ }
959
+
960
+ /**
961
+ * Used for selection mainly from ExtJS and ajax requests
962
+ * It automaticaly selects one row based on id passed,
963
+ * if there are more columns in primary key, then pass those parameters as get variables
964
+ * Parameters are:
965
+ * <ul>
966
+ * <li>id - id of the record you are searching</li>
967
+ * </ul>
968
+ *
969
+ * <code>
970
+ * user = new User;
971
+ * val = user.selectRowById({'id': 1));
972
+ *
973
+ * user = new User;
974
+ * val = user.selectRowById({'idOne': '15', 'idTwo': 25));
975
+ * </code>
976
+ * In this example val will hold an array with 'error' boolean
977
+ * if error happened and 'notice' string which holds the error
978
+ * message or error array if more than one error is given, also if record is not found it will return error
979
+ * On succes var will hold 'root' which holds row result
980
+ *
981
+ * @author Dario Filkovic <dfilkovi@gmail.com>
982
+ *
983
+ * @since 1.0
984
+ *
985
+ * @package CoreFw
986
+ * @param Array param An array of key: value pairs for selecting rows
987
+ * @return mixed[] Array with 'error' and 'notice' if error true and 'root' if error false
988
+ */
989
+ async selectRowById(param)
990
+ {
991
+ const me = this;
992
+
993
+ if (typeof me.id === 'object')
994
+ {
995
+ for (const key in me.idField)
996
+ {
997
+ if (param[key] !== undefined)
998
+ {
999
+ me.id[key] = param[key];
1000
+ }
1001
+ }
1002
+ }
1003
+ else
1004
+ {
1005
+ me.id = param.id;
1006
+ }
1007
+
1008
+ await me.select();
1009
+
1010
+ const data = {};
1011
+ for (const key in me.tableConfig.fields)
1012
+ {
1013
+ if (me[key] !== undefined)
1014
+ {
1015
+ data[key] = me[key];
1016
+ }
1017
+ }
1018
+
1019
+ for (const key in me.idField)
1020
+ {
1021
+ if (me[key] !== undefined)
1022
+ {
1023
+ data[key] = me[key];
1024
+ }
1025
+ }
1026
+
1027
+ return (
1028
+ {
1029
+ error: false,
1030
+ root: data,
1031
+ });
1032
+ }
1033
+
1034
+ /**
1035
+ * Used for selecting a single value from a table
1036
+ * It is optimized to check first if value exists in given data if not, then selects it and appends it to an array
1037
+ *
1038
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1039
+ *
1040
+ * @since 1.0
1041
+ *
1042
+ * @package CoreFw
1043
+ *
1044
+ * @param Array data Array with starting data
1045
+ * @param mixed[] initialValue Value of ID field
1046
+ * @return Array Final array with all data
1047
+ */
1048
+ async findInitialId(data, initialValue)
1049
+ {
1050
+ const me = this;
1051
+
1052
+ let initialValues = [];
1053
+ if (typeof initialValue === 'number' || typeof initialValue === 'string')
1054
+ {
1055
+ initialValues = [initialValue];
1056
+ }
1057
+ else
1058
+ {
1059
+ initialValues = initialValue;
1060
+ }
1061
+
1062
+ const promises = [];
1063
+
1064
+ for (const val of initialValues)
1065
+ {
1066
+ const defKey = Object.keys(me.idField)[0];
1067
+
1068
+ for (let i = 0; i < data.length; i += 1)
1069
+ {
1070
+ const value = data[i];
1071
+ if (value[defKey] === val)
1072
+ {
1073
+ return data;
1074
+ }
1075
+ }
1076
+
1077
+ let ownerWhere = '';
1078
+ const params = {
1079
+ initialId: val,
1080
+ };
1081
+ if (me.ownerActionGlob === true)
1082
+ {
1083
+ ownerWhere = ` AND i.${me.tableConfig.ownerField}=:sessionUserId `;
1084
+ params.sessionUserId = me.session.userId;
1085
+ }
1086
+
1087
+ if (me.companyActionGlob === true)
1088
+ {
1089
+ ownerWhere += ` AND i.${me.tableConfig.companyField}=:sessionCompanyId `;
1090
+ params.sessionCompanyId = me.session.companyId;
1091
+ }
1092
+
1093
+ // eslint-disable-next-line no-await-in-loop
1094
+ promises.push(me[me.dbName].query(
1095
+ `SELECT i.* FROM \`${me.tableName}\` i WHERE i.\`${defKey}\`=:initialId ${ownerWhere}`,
1096
+ params,
1097
+ ));
1098
+ }
1099
+
1100
+ const results = await Promise.all(promises);
1101
+
1102
+ results.forEach((result) =>
1103
+ {
1104
+ if (typeof result[0] !== 'undefined')
1105
+ {
1106
+ data.push(result[0]);
1107
+ }
1108
+ });
1109
+
1110
+ return data;
1111
+ }
1112
+
1113
+ /**
1114
+ * Helper method for array insertion
1115
+ *
1116
+ * It iterates through param and sets every item as a key.value and returns an insert result
1117
+ * <code>
1118
+ * user = new User;
1119
+ * param = {'username': 'mirko', 'dateTime': date('Y-m-d H:i:s'));
1120
+ * return user.insertRow(param);
1121
+ * </code>
1122
+ *
1123
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1124
+ *
1125
+ * @since 1.0
1126
+ *
1127
+ * @package CoreFw
1128
+ *
1129
+ * @param Array param Array of key: value pairs for insertion
1130
+ * @return Array Error boolean and notice message
1131
+ */
1132
+ insertRow(param)
1133
+ {
1134
+ const me = this;
1135
+ for (const key in param)
1136
+ {
1137
+ if (param[key] !== undefined)
1138
+ {
1139
+ me[key] = param[key];
1140
+ }
1141
+ }
1142
+ return me.insert();
1143
+ }
1144
+
1145
+ /**
1146
+ * Helper method for object update through array parameters
1147
+ *
1148
+ * It iterates through param and sets every item as a key.value and returns an insert result, it needs an 'id' field
1149
+ * <code>
1150
+ * user = new User;
1151
+ * param = {'id': 5, 'username': 'mirko', 'dateTime': date('Y-m-d H:i:s'));
1152
+ * return user.updateRow(param);
1153
+ * </code>
1154
+ *
1155
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1156
+ *
1157
+ * @since 1.0
1158
+ *
1159
+ * @package CoreFw
1160
+ *
1161
+ * @param Array param Array of key: value pairs for insertion
1162
+ * @return Array Error boolean and notice message
1163
+ */
1164
+ updateRow(param)
1165
+ {
1166
+ const me = this;
1167
+ for (const key in param)
1168
+ {
1169
+ if (param[key] !== undefined)
1170
+ {
1171
+ me[key] = param[key];
1172
+ }
1173
+ }
1174
+ if (typeof me.id !== 'undefined')
1175
+ {
1176
+ for (const key in me.idField)
1177
+ {
1178
+ if (typeof me[key] !== 'undefined' && typeof me.id !== 'object')
1179
+ {
1180
+ me.id = me[key];
1181
+ }
1182
+ }
1183
+ }
1184
+ return me.update();
1185
+ }
1186
+
1187
+ /**
1188
+ * Helper method for object delete through array parameters
1189
+ *
1190
+ * It iterates through param and sets 'id' fields, it needs an 'id' field/s
1191
+ * <code>
1192
+ * user = new User;
1193
+ * param = {'id': 5);
1194
+ * return user.deleteRow(param);
1195
+ * </code>
1196
+ *
1197
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1198
+ *
1199
+ * @since 1.0
1200
+ *
1201
+ * @package CoreFw
1202
+ *
1203
+ * @param Array param Array of key: value pairs for insertion
1204
+ * @return Array Error boolean and notice message
1205
+ */
1206
+ deleteRow(param)
1207
+ {
1208
+ const me = this;
1209
+ for (const key in param)
1210
+ {
1211
+ if (param[key] !== undefined)
1212
+ {
1213
+ me[key] = param[key];
1214
+ }
1215
+ }
1216
+ if (typeof me.id !== 'undefined')
1217
+ {
1218
+ for (const key in me.idField)
1219
+ {
1220
+ if (typeof me[key] !== 'undefined' && typeof me.id !== 'object')
1221
+ {
1222
+ me.id = me[key];
1223
+ }
1224
+ }
1225
+ }
1226
+ return me.delete();
1227
+ }
1228
+
1229
+ /**
1230
+ * Helper method for object delete
1231
+ *
1232
+ * <code>
1233
+ * user = new User;
1234
+ * user.id = 5;
1235
+ * return user.delete();
1236
+ * </code>
1237
+ *
1238
+ * <code>
1239
+ * user = new User;
1240
+ * user.id = {'userId: 5, 'username': 'mirko'); //in case of multiple primary keys
1241
+ * return user.delete();
1242
+ * </code>
1243
+ *
1244
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1245
+ *
1246
+ * @since 1.0
1247
+ *
1248
+ * @package CoreFw
1249
+ *
1250
+ * @return Array Error boolean and notice message
1251
+ */
1252
+ async delete()
1253
+ {
1254
+ const me = this;
1255
+
1256
+ let ownerWhere = '';
1257
+ const params = {};
1258
+
1259
+ if (me.ownerActionGlob === true)
1260
+ {
1261
+ if (!me.modelLoaded)
1262
+ {
1263
+ await me.select();
1264
+ }
1265
+
1266
+
1267
+ if (me[me.tableConfig.ownerField] !== me.session.userId)
1268
+ {
1269
+ throw (ErrorCodes.error('no_privilage'));
1270
+ }
1271
+
1272
+ ownerWhere = ` AND ${me.tableConfig.ownerField}=:sessionUserId `;
1273
+ params.sessionUserId = me.session.userId;
1274
+ }
1275
+
1276
+ if (me.companyActionGlob === true)
1277
+ {
1278
+ if (!me.modelLoaded)
1279
+ {
1280
+ await me.select();
1281
+ }
1282
+
1283
+ if (me[me.tableConfig.companyField] !== me.session.companyId)
1284
+ {
1285
+ throw (ErrorCodes.error('no_privilage'));
1286
+ }
1287
+
1288
+ ownerWhere += ` AND ${me.tableConfig.companyField}=:sessionCompanyId`;
1289
+ params.sessionCompanyId = me.session.companyId;
1290
+ }
1291
+
1292
+ if (me.functionNameGlob !== false)
1293
+ {
1294
+ if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].deleteAction === 0)
1295
+ {
1296
+ throw (ErrorCodes.error('no_privilage'));
1297
+ }
1298
+ }
1299
+ else if (me.objectNameGlob !== false)
1300
+ {
1301
+ if (me.lib.acl[me.aclGroupId][me.objectNameGlob].deleteAction === 0)
1302
+ {
1303
+ throw (ErrorCodes.error('no_privilage'));
1304
+ }
1305
+ }
1306
+
1307
+ // call before delete
1308
+ await me.beforeDelete();
1309
+
1310
+ const whereArr = [];
1311
+ let where = '';
1312
+
1313
+ if (typeof me.id === 'object')
1314
+ {
1315
+ // eslint-disable-next-line guard-for-in
1316
+ for (const key in me.id)
1317
+ {
1318
+ if (me.id[key] === null)
1319
+ {
1320
+ whereArr.push(`\`${key}\` IS NULL`);
1321
+ }
1322
+ else
1323
+ {
1324
+ whereArr.push(`\`${key}\`=:${key}`);
1325
+ }
1326
+ params[key] = me.id[key];
1327
+ }
1328
+ where = whereArr.join(' AND ');
1329
+ }
1330
+ else
1331
+ {
1332
+ const key = Object.keys(me.idField)[0];
1333
+ where = `\`${key}\`=:${key}`;
1334
+ params[key] = me.id;
1335
+ }
1336
+
1337
+ await me[me.dbName].query(`DELETE FROM \`${me.tableName}\` WHERE ${where} ${ownerWhere}`, params);
1338
+
1339
+ await me.afterDelete();
1340
+
1341
+ return (
1342
+ {
1343
+ error: false,
1344
+ notice: 'success',
1345
+ });
1346
+ }
1347
+
1348
+ /**
1349
+ * Called before delete from db
1350
+ *
1351
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1352
+ *
1353
+ * @since 1.0
1354
+ *
1355
+ * @package CoreFw
1356
+ *
1357
+ * @return void
1358
+ */
1359
+ // eslint-disable-next-line class-methods-use-this
1360
+ async beforeDelete()
1361
+ {
1362
+ return (
1363
+ {
1364
+ error: false,
1365
+ notice: 'success',
1366
+ });
1367
+ }
1368
+
1369
+ /**
1370
+ * Called after succesfull delete from db
1371
+ *
1372
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1373
+ *
1374
+ * @since 1.0
1375
+ *
1376
+ * @package CoreFw
1377
+ *
1378
+ * @return void
1379
+ */
1380
+ // eslint-disable-next-line class-methods-use-this
1381
+ async afterDelete()
1382
+ {
1383
+ return (
1384
+ {
1385
+ error: false,
1386
+ notice: 'success',
1387
+ });
1388
+ }
1389
+
1390
+ /**
1391
+ * Helper method for object update
1392
+ *
1393
+ * It validates data and returns error messages if not valid data
1394
+ * <code> {'error': true, 'notice': {'username': 'Not valid')); </code>
1395
+ * ('notice' becomes array of error notices in case of multiple errors) or
1396
+ * returns <code> {'error': false, 'notice': 'Success'); </code>
1397
+ * For succesfull update an 'id' field must be present
1398
+ * <code>
1399
+ * user = new User;
1400
+ * user.id = 5;
1401
+ * user.username = 'mirko';
1402
+ * return user.update();
1403
+ * </code>
1404
+ *
1405
+ * <code>
1406
+ * user = new User;
1407
+ * user.id = {'userId: 5, 'username': 'mirko'); //in case of multiple primary keys
1408
+ * user.username = 'slavko';
1409
+ * return user.update();
1410
+ * </code>
1411
+ *
1412
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1413
+ *
1414
+ * @since 1.0
1415
+ *
1416
+ * @package CoreFw
1417
+ *
1418
+ * @return Array Error boolean and notice message/messages
1419
+ */
1420
+ async update()
1421
+ {
1422
+ const me = this;
1423
+
1424
+ if (typeof me.id === 'undefined')
1425
+ {
1426
+ throw (ErrorCodes.error('no_id_field_set'));
1427
+ }
1428
+
1429
+ if (!me.modelLoaded)
1430
+ {
1431
+ await me.select();
1432
+ }
1433
+
1434
+ let ownerWhere = '';
1435
+ const values = {};
1436
+ if (me.ownerActionGlob === true)
1437
+ {
1438
+ if (me[me.tableConfig.ownerField] !== me.session.userId)
1439
+ {
1440
+ throw (ErrorCodes.error('no_privilage'));
1441
+ }
1442
+ ownerWhere = ` AND ${me.tableConfig.ownerField}=:sessionUserId `;
1443
+ values.sessionUserId = me.session.userId;
1444
+ }
1445
+
1446
+ if (me.companyActionGlob === true)
1447
+ {
1448
+ if (me[me.tableConfig.companyField] !== me.session.companyId)
1449
+ {
1450
+ throw (ErrorCodes.error('no_privilage'));
1451
+ }
1452
+ ownerWhere += ` AND ${me.tableConfig.companyField}=:sessionCompanyId `;
1453
+ values.sessionCompanyId = me.session.companyId;
1454
+ }
1455
+
1456
+ if (me.functionNameGlob !== false)
1457
+ {
1458
+ if (me.lib.acl[me.aclGroupId][me.objectNameGlob][me.functionNameGlob].updateAction === 0)
1459
+ {
1460
+ throw (ErrorCodes.error('no_privilage'));
1461
+ }
1462
+ }
1463
+ else if (me.objectNameGlob !== false)
1464
+ {
1465
+ if (me.lib.acl[me.aclGroupId][me.objectNameGlob].updateAction === 0)
1466
+ {
1467
+ throw (ErrorCodes.error('no_privilage'));
1468
+ }
1469
+ }
1470
+
1471
+ const check = {};
1472
+ if (typeof me.id === 'object')
1473
+ {
1474
+ for (const key in me.idField)
1475
+ {
1476
+ if (me.id[key] !== undefined)
1477
+ {
1478
+ check[key] = me.id[key];
1479
+ }
1480
+ }
1481
+ }
1482
+ else
1483
+ {
1484
+ check[Object.keys(me.idField)[0]] = me.id;
1485
+ }
1486
+
1487
+ for (const key in me.tableConfig.fields)
1488
+ {
1489
+ if (me[key] !== undefined)
1490
+ {
1491
+ check[key] = me[key];
1492
+ }
1493
+ }
1494
+
1495
+ for (const key in me.idField)
1496
+ {
1497
+ if (me.idField[key].req === 1)
1498
+ {
1499
+ check[key] = me[key];
1500
+ }
1501
+ }
1502
+
1503
+ await me.checkFields(check);
1504
+
1505
+ // call before update
1506
+ await me.beforeUpdate();
1507
+
1508
+ const strings = [];
1509
+ if (typeof me.id === 'object')
1510
+ {
1511
+ for (const key in me.idField)
1512
+ {
1513
+ if (me.idField[key] !== undefined)
1514
+ {
1515
+ strings.push(`\`${key}\`=:${key}`);
1516
+ values[key] = CfwObject.defineType(me.id[key], me.idField[key]);
1517
+ }
1518
+ }
1519
+ }
1520
+ else
1521
+ {
1522
+ const key = Object.keys(me.idField)[0];
1523
+ strings.push(`\`${key}\`=:${key}`);
1524
+ values[key] = CfwObject.defineType(me.id, me.idField[key]);
1525
+ }
1526
+
1527
+ const string = ` WHERE ${strings.join(' AND ')}`;
1528
+
1529
+ const fieldsAr = [];
1530
+ for (const key in me.tableConfig.fields)
1531
+ {
1532
+ if (me.tableConfig.fields[key])
1533
+ {
1534
+ fieldsAr.push(`\`${key}\`=:${key}`);
1535
+ values[key] = CfwObject.defineType(me[key], me.tableConfig.fields[key]);
1536
+ }
1537
+ }
1538
+
1539
+ for (const key in me.idField)
1540
+ {
1541
+ if (me.idField[key].req === 1)
1542
+ {
1543
+ fieldsAr.push(`\`${key}\`=:${key}`);
1544
+ values[key] = CfwObject.defineType(me[key], me.tableConfig.id[key]);
1545
+ }
1546
+ }
1547
+
1548
+ const fields = fieldsAr.join(', ');
1549
+
1550
+ await me[me.dbName].query(`UPDATE \`${me.tableName}\` SET ${fields} ${string} ${ownerWhere}`, values);
1551
+
1552
+ // call after update
1553
+ await me.afterUpdate();
1554
+ me.lastId = me.id;
1555
+
1556
+ return (
1557
+ {
1558
+ error: false,
1559
+ notice: 'success',
1560
+ lastId: me.id,
1561
+ });
1562
+ }
1563
+
1564
+ /**
1565
+ * Called before update db
1566
+ *
1567
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1568
+ *
1569
+ * @since 1.0
1570
+ *
1571
+ * @package CoreFw
1572
+ *
1573
+ * @return void
1574
+ */
1575
+ // eslint-disable-next-line class-methods-use-this
1576
+ async beforeUpdate()
1577
+ {
1578
+ return (
1579
+ {
1580
+ error: false,
1581
+ notice: 'success',
1582
+ });
1583
+ }
1584
+
1585
+ /**
1586
+ * Called after succesfull update db
1587
+ *
1588
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1589
+ *
1590
+ * @since 1.0
1591
+ *
1592
+ * @package CoreFw
1593
+ *
1594
+ * @return void
1595
+ */
1596
+ // eslint-disable-next-line class-methods-use-this
1597
+ async afterUpdate()
1598
+ {
1599
+ return (
1600
+ {
1601
+ error: false,
1602
+ notice: 'success',
1603
+ });
1604
+ }
1605
+
1606
+ /**
1607
+ * Validate and decorate fields
1608
+ *
1609
+ * First it decorates data if decorators are passed in an object table definition,
1610
+ * then validates fields for insertion/update
1611
+ *
1612
+ * @see Decorator
1613
+ *
1614
+ * @author Dario Filkovic <dfilkovi@gmail.com>
1615
+ *
1616
+ * @since 1.0
1617
+ *
1618
+ * @package CoreFw
1619
+ * @param Array insert Values
1620
+ * @param Array update Update
1621
+ * @return Array Error boolean and notice message/messages
1622
+ */
1623
+ async checkFields(insert)
1624
+ {
1625
+ const decorator = new Decorator(this, insert);
1626
+ const val = await Validator.validate(decorator.insert, this);
1627
+ return val;
1628
+ }
1629
+ };