1: <?php
2: /**
3: * This file contains the implementation of the interface ISettingsManager
4: * in the class UserSettingsManager for management of the user settings.
5: *
6: * @package System
7: *
8: * @author Oleg Schildt
9: */
10:
11: namespace SmartFactory;
12:
13: use \SmartFactory\Interfaces\ISettingsManager;
14: use \SmartFactory\Interfaces\IErrorHandler;
15: use \SmartFactory\DatabaseWorkers\DBWorker;
16: use SmartFactory\Interfaces\ISettingsValidator;
17:
18: /**
19: * Class for management of the user settings.
20: *
21: * When you introduce a new user setting. You have to create a column for it in the corresponding
22: * table add it to the initialization and specify the data type.
23: *
24: * The user settings are loaded only once by the start of the session and are kept until the session
25: * is valid. Saving of the user settings updates both the session and the database. When a settings are
26: * requested, it is taken from the session, not from the database.
27: *
28: * @see ConfigSettingsManager
29: * @see RuntimeSettingsManager
30: *
31: * @uses DatabaseWorkers\DBWorker
32: *
33: * @author Oleg Schildt
34: */
35: class UserSettingsManager implements ISettingsManager
36: {
37: /**
38: * Internal variable for storing the user id.
39: *
40: * @var string
41: *
42: * @see UserSettingsManager::setUserID()
43: *
44: * @author Oleg Schildt
45: */
46: protected string $user_id = "";
47:
48: /**
49: * Internal variable for storing the dbworker.
50: *
51: * @var ?DatabaseWorkers\DBWorker
52: *
53: * @author Oleg Schildt
54: */
55: protected ?DatabaseWorkers\DBWorker $dbworker;
56:
57: /**
58: * Internal variable for storing the state whether the translation should be started or commited or
59: * no transaction should be used because the saving process is a part of other saving process.
60: *
61: * @var bool
62: *
63: * @author Oleg Schildt
64: */
65: protected bool $no_own_transaction = true;
66:
67: /**
68: * Internal array for storing the settings tables.
69: *
70: * @var array
71: *
72: * @author Oleg Schildt
73: */
74: protected array $settings_tables = [];
75:
76: /**
77: * Internal array for storing the auxiliary tables for storing the multichoce values.
78: *
79: * @var array
80: *
81: * @author Oleg Schildt
82: */
83: protected array $multichoice_tables = [];
84:
85: /**
86: * Internal variable for storing the current context.
87: *
88: * @var string
89: *
90: * @see UserSettingsManager::getContext()
91: * @see UserSettingsManager::setContext()
92: *
93: * @author Oleg Schildt
94: */
95: protected string $context = "default";
96:
97: /**
98: * Internal variable for storing the validator.
99: *
100: * @var ?\SmartFactory\Interfaces\ISettingsValidator
101: *
102: * @see UserSettingsManager::getValidator()
103: * @see UserSettingsManager::setValidator()
104: *
105: * @author Oleg Schildt
106: */
107: protected ?\SmartFactory\Interfaces\ISettingsValidator $validator = null;
108:
109: /**
110: * Internal variable for storing the array of the settings values.
111: *
112: * @var array
113: *
114: * @author Oleg Schildt
115: */
116: protected array $settings = [];
117:
118: /**
119: * This is internal auxiliary function for checking that the settings
120: * manager is intialized correctly.
121: *
122: * @return void
123: *
124: * @throws \Exception
125: * It might throw an exception in the case of any errors:
126: *
127: * - if some parameters are missing.
128: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
129: * - if some parameters are not of the proper type.
130: *
131: * @author Oleg Schildt
132: */
133: protected function validateParameters(): void
134: {
135: if (empty($this->dbworker)) {
136: throw new \Exception("The 'dbworker' is not specified!");
137: }
138:
139: if (!$this->dbworker instanceof DBWorker) {
140: throw new \Exception(sprintf("The 'dbworker' does not extends the class '%s'!", DBWorker::class));
141: }
142:
143: if (empty($this->settings_tables)) {
144: throw new \Exception("The 'settings_tables' are not defined!");
145: }
146:
147: if (!is_array($this->settings_tables)) {
148: throw new \Exception("Settings tables 'settings_tables' must be an array!");
149: }
150:
151: if (!empty($this->multichoice_tables) && !is_array($this->multichoice_tables)) {
152: throw new \Exception("Multichoice tables 'multichoice_tables' must be an array!");
153: }
154: } // validateParameters
155:
156: /**
157: * This is internal auxiliary function for storing the settings
158: * to the target user table defined by the initialization.
159: *
160: * @param array $data
161: * The array with the settings values to be saved.
162: *
163: * @return void
164: *
165: * @throws \Throwable
166: * It might throw an exception in the case of any errors:
167: *
168: * - if the query fails or if some object names are invalid.
169: * - if some parameters are missing.
170: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
171: * - if some parameters are not of the proper type.
172: * - if the query fails or if some object names are invalid.
173: *
174: * @see UserSettingsManager::loadSettingsData()
175: *
176: * @author Oleg Schildt
177: */
178: protected function saveSettingsData(array $data): void
179: {
180: $this->validateParameters();
181:
182: $this->dbworker->connect();
183:
184: if (empty($this->no_own_transaction)) {
185: $this->dbworker->start_transaction();
186: }
187:
188: try {
189: foreach ($this->settings_tables as $table => $fields) {
190: // First field is the ID field
191: $uid_field = "";
192: $uid_field_type = "";
193:
194: $update_string = "";
195:
196: $insert_fields_string = "";
197: $insert_values_string = "";
198:
199: $c = 0;
200: foreach ($fields as $field => $field_type) {
201: $c++;
202:
203: if ($c == 1) {
204: $uid_field = $field;
205: $uid_field_type = $field_type;
206: continue;
207: }
208:
209: $value = "";
210:
211: if (!empty($data[$table . "." . $field])) {
212: $value = $data[$table . "." . $field];
213: }
214:
215: if (isset($data[$field])) {
216: $value = $data[$field];
217: }
218:
219: $value = $this->dbworker->prepare_for_query($value, $field_type);
220:
221: $update_string .= $field . " = " . $value . ",\n";
222:
223: $insert_fields_string .= $field . ", ";
224: $insert_values_string .= $value . ", ";
225: }
226:
227: $user_id = $this->dbworker->prepare_for_query($this->user_id, $uid_field_type);
228:
229: $insert_fields_string .= $uid_field . ", ";
230: $insert_values_string .= $user_id . ", ";
231:
232: $query = "select\n";
233: $query .= "1\n";
234: $query .= "from " . $table . "\n";
235: $query .= "where " . $uid_field . " = " . $user_id;
236:
237: $this->dbworker->execute_query($query);
238:
239: $must_insert = false;
240: if (!$this->dbworker->fetch_row()) {
241: $must_insert = true;
242: }
243:
244: $this->dbworker->free_result();
245:
246: if ($must_insert) {
247: $query = "insert into " . $table . "\n";
248: $query .= "(" . trim($insert_fields_string, ", ") . ")\n";
249: $query .= "values\n";
250: $query .= "(" . trim($insert_values_string, ", ") . ")\n";
251: } else {
252: $query = "update " . $table . " set\n";
253: $query .= trim($update_string, ",\n") . "\n";
254: $query .= "where " . $uid_field . " = " . $user_id;
255: }
256:
257: $this->dbworker->execute_query($query);
258: }
259:
260: // update the subtables
261:
262: foreach ($this->multichoice_tables as $table => $fields) {
263: // First field is the ID field
264: $uid_field = "";
265: $uid_field_type = "";
266:
267: // Second field is the value field
268: $value_field = "";
269: $value_field_type = "";
270:
271: $c = 1;
272: foreach ($fields as $field => $field_type) {
273: if ($c == 1) {
274: $uid_field = $field;
275: $uid_field_type = $field_type;
276: } elseif ($c == 2) {
277: $value_field = $field;
278: $value_field_type = $field_type;
279: } else {
280: break;
281: }
282:
283: $c++;
284: }
285:
286: if (!empty($data[$table])) {
287: $value = $data[$table];
288: } else {
289: $value = [];
290: }
291:
292: // insert the values that are in the list but not in the table
293:
294: $in_list = "";
295: $user_id = $this->dbworker->prepare_for_query($this->user_id, $uid_field_type);
296:
297: foreach ($value as $entry) {
298: if (empty($entry)) {
299: continue;
300: }
301:
302: $entry = $this->dbworker->prepare_for_query($entry, $value_field_type);
303:
304: $query = "select 1 from $table where $uid_field = $user_id";
305:
306: if ($value == "NULL") {
307: $query .= " and $value_field is NULL";
308: } else {
309: $query .= " and $value_field = $entry";
310: }
311:
312: $this->dbworker->execute_query($query);
313:
314: $must_insert = true;
315: if ($this->dbworker->fetch_row()) {
316: $must_insert = false;
317: }
318:
319: $this->dbworker->free_result();
320:
321: if ($must_insert) {
322: $query = "insert into $table ($uid_field, $value_field) values ($user_id, $entry)";
323:
324: $this->dbworker->execute_query($query);
325: }
326:
327: $in_list .= $entry . ",\n";
328: }
329:
330: $in_list = trim($in_list, " ,\n\r");
331:
332: $where = "where " . $uid_field . " = " . $user_id;
333:
334: // delete the values that are no more in the new list but still in the table.
335:
336: if (empty($in_list)) {
337: $query = "delete from $table\n" . $where;
338: } else {
339: $query = "delete from $table\n" . $where . " and " . $value_field . " not in ($in_list)";
340: }
341:
342: $this->dbworker->execute_query($query);
343: }
344: } catch (\Throwable $ex) {
345: if (empty($this->no_own_transaction)) {
346: $this->dbworker->rollback_transaction();
347: }
348:
349: singleton(IErrorHandler::class)->handleException($ex, E_USER_ERROR);
350:
351: throw $ex;
352: }
353:
354: if (empty($this->no_own_transaction)) {
355: $this->dbworker->commit_transaction();
356: }
357: } // saveSettingsData
358:
359: /**
360: * This is internal auxiliary function for loading the settings from the target user table
361: * defined by the initialization.
362: *
363: * @param array &$data
364: * The target array with the settings values to be loaded.
365: *
366: * @return void
367: *
368: * @throws \Exception
369: * It might throw an exception in the case of any errors:
370: *
371: * - if the query fails or if some object names are invalid.
372: * - if some parameters are missing.
373: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
374: * - if some parameters are not of the proper type.
375: * - if the query fails or if some object names are invalid.
376: *
377: * @see UserSettingsManager::saveSettingsData()
378: *
379: * @author Oleg Schildt
380: */
381: protected function loadSettingsData(array &$data): void
382: {
383: $this->validateParameters();
384:
385: $this->dbworker->connect();
386:
387: foreach ($this->settings_tables as $table => $fields) {
388: // First field is the ID field
389: $uid_field = "";
390: $uid_field_type = "";
391:
392: foreach ($fields as $field => $field_type) {
393: $uid_field = $field;
394: $uid_field_type = $field_type;
395: break;
396: }
397:
398: $query = "select\n";
399:
400: $query .= implode(", ", array_keys($fields)) . "\n";
401:
402: $query .= "from " . $table . "\n";
403:
404: $user_id = $this->dbworker->prepare_for_query($this->user_id, $uid_field_type);
405: $query .= "where " . $uid_field . " = " . $user_id;
406:
407: $this->dbworker->execute_query($query);
408:
409: if ($this->dbworker->fetch_row()) {
410: foreach ($fields as $field => $type) {
411: $data[$field] = $this->dbworker->field_by_name($field, $type); // short name (only field name)
412: $data[$table . "." . $field] = $data[$field]; // full name (table name and field name)
413:
414: }
415: }
416:
417: $this->dbworker->free_result();
418: }
419:
420: if (empty($this->multichoice_tables)) {
421: return;
422: }
423:
424: foreach ($this->multichoice_tables as $table => $fields) {
425: // First field is the ID field
426: $uid_field = "";
427: $uid_field_type = "";
428:
429: // Second field is the value field
430: $value_field = "";
431: $value_field_type = "";
432:
433: $c = 1;
434: foreach ($fields as $field => $field_type) {
435: if ($c == 1) {
436: $uid_field = $field;
437: $uid_field_type = $field_type;
438: } elseif ($c == 2) {
439: $value_field = $field;
440: $value_field_type = $field_type;
441: } else {
442: break;
443: }
444:
445: $c++;
446: }
447:
448: $query = "select " . $value_field . "\n";
449:
450: $query .= "from " . $table . "\n";
451:
452: $user_id = $this->dbworker->prepare_for_query($this->user_id, $uid_field_type);
453: $query .= "where " . $uid_field . " = " . $user_id;
454:
455: $this->dbworker->execute_query($query);
456:
457: $data[$table] = [];
458:
459: while ($this->dbworker->fetch_row()) {
460: $data[$table][] = $this->dbworker->field_by_name($value_field, $value_field_type);
461: }
462:
463: $this->dbworker->free_result();
464: }
465: } // loadSettingsData
466:
467: /**
468: * Initializes the settings manager parameters.
469: *
470: * @param array $parameters
471: * Settings for saving and loading as an associative array in the form key => value:
472: *
473: * - $parameters["dbworker"] - the dbworker to use for loading and storing settings.
474: * - $parameters["settings_tables"] - the definitions of the settings tables.
475: * - $parameters["multichoice_tables"] - the definitions of the auxiliary tables for the multichoice values.
476: *
477: * Example:
478: *
479: * ```php
480: * $instance->init([
481: * "dbworker" => app_dbworker(),
482: *
483: * "settings_tables" => [
484: * "users" => [
485: * "id" => DBWorker::DB_NUMBER,
486: * "language" => DBWorker::DB_STRING,
487: * "time_zone" => DBWorker::DB_STRING
488: * ],
489: * "user_forum_settings" => [
490: * "user_id" => DBWorker::DB_NUMBER,
491: * "signature" => DBWorker::DB_STRING,
492: * "status" => DBWorker::DB_STRING,
493: * "hide_pictures" => DBWorker::DB_NUMBER,
494: * "hide_signatures" => DBWorker::DB_NUMBER
495: * ]
496: * ],
497: *
498: * "multichoice_tables" => [
499: * "user_colors" => [
500: * "user_id" => DBWorker::DB_NUMBER,
501: * "color" => DBWorker::DB_STRING
502: * ]
503: * ]
504: * ]);
505: * ```
506: *
507: * @return void
508: *
509: * @throws \Exception
510: * It might throw an exception in the case of any errors:
511: *
512: * - if some parameters are missing.
513: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
514: * - if some parameters are not of the proper type.
515: *
516: * @throws \Exception
517: * It might throw an exception in the case of any errors.
518: *
519: * @author Oleg Schildt
520: */
521: public function init(array $parameters): void
522: {
523: if (!empty($parameters["dbworker"])) {
524: $this->dbworker = $parameters["dbworker"];
525: }
526:
527: if (!empty($parameters["settings_tables"])) {
528: $this->settings_tables = $parameters["settings_tables"];
529: }
530: if (!empty($parameters["multichoice_tables"])) {
531: $this->multichoice_tables = $parameters["multichoice_tables"];
532: }
533:
534: $this->validateParameters();
535: } // init
536:
537: /**
538: * Sets the dbworker to be used for working with the database.
539: *
540: * @param DatabaseWorkers\DBWorker $dbworker
541: * The dbworker to be used for working with the database.
542: *
543: * @return void
544: *
545: * @see RecordsetManager::getDBWorker()
546: *
547: * @author Oleg Schildt
548: */
549:
550: /**
551: * Sets the dbworker to use for loading and storing settings.
552: *
553: * @param DatabaseWorkers\DBWorker $dbworker
554: * The dbworker to be used for loading and storing settings.
555: *
556: * @param bool $no_own_transcation
557: * The state whether the translation should be started or commited or
558: * no transaction should be used because the saving process is a part of other saving process.
559: *
560: * @return void
561: *
562: * @throws \Exception
563: * It might throw an exception in the case of any errors.
564: *
565: * @author Oleg Schildt
566: * @see RecordsetManager::getDBWorker()
567: *
568: */
569: public function setDBWorker(DatabaseWorkers\DBWorker $dbworker, bool $no_own_transcation = false): void
570: {
571: $this->dbworker = $dbworker;
572: $this->no_own_transaction = $no_own_transcation;
573:
574: if (empty($this->dbworker)) {
575: throw new \Exception("The 'dbworker' is not specified!");
576: }
577:
578: if (!$this->dbworker instanceof DBWorker) {
579: throw new \Exception(sprintf("The 'dbworker' does not extends the class '%s'!", DBWorker::class));
580: }
581: } // setDBWorker
582:
583: /**
584: * Sets the validator for the settings.
585: *
586: * @param ISettingsValidator $validator
587: * The settings validator.
588: *
589: * @return void
590: *
591: * @see UserSettingsManager::getValidator()
592: * @see UserSettingsManager::validateSettings()
593: *
594: * @author Oleg Schildt
595: */
596: public function setValidator(ISettingsValidator $validator): void
597: {
598: $this->validator = $validator;
599: } // setValidator
600:
601: /**
602: * Returns the validator for the settings.
603: *
604: * @return ?\SmartFactory\Interfaces\ISettingsValidator
605: * Returns the validator for the settings or null if none is defined.
606: *
607: * @see UserSettingsManager::setValidator()
608: * @see UserSettingsManager::validateSettings()
609: *
610: * @author Oleg Schildt
611: */
612: public function getValidator(): ?\SmartFactory\Interfaces\ISettingsValidator
613: {
614: return $this->validator;
615: } // getValidator
616:
617: /**
618: * Sets the settings context.
619: *
620: * Settings might be edited not in one dialog,
621: * There can be several masks for different type of settings,
622: * or the settings can be configured in a wizard.
623: * In this case, only a subset of settings has to be
624: * saved and validated.
625: * To be able to write a flexible validator for the subsets,
626: * the $context is used. It can be - step1, step1, server_settings,
627: * db_connection_settings etc.
628: *
629: * @param string $context
630: * The settings context.
631: *
632: * @return void
633: *
634: * @see UserSettingsManager::getContext()
635: *
636: * @author Oleg Schildt
637: */
638: public function setContext(string $context = "default"): void
639: {
640: $this->context = $context;
641: } // setContext
642:
643: /**
644: * Returns the current settings context.
645: *
646: * Settings might be edited not in one dialog,
647: * There can be several masks for different type of settings,
648: * or the settings can be configured in a wizard.
649: * In this case, only a subset of settings has to be
650: * saved and validated.
651: * To be able to write a flexible validator for the subsets,
652: * the $context is used. It can be - step1, step1, server_settings,
653: * db_connection_settings etc.
654: *
655: * @return string
656: * Returns the current settings context.
657: *
658: * @see UserSettingsManager::setContext()
659: *
660: * @author Oleg Schildt
661: */
662: public function getContext(): string
663: {
664: return $this->context;
665: } // getContext
666:
667: /**
668: * Sets a settings parameter.
669: *
670: * @param string $name
671: * The name of the settings parameter.
672: *
673: * @param mixed $value
674: * The value of the settings parameter.
675: *
676: * @return void
677: *
678: * @throws \Exception
679: * It might throw an exception in the case of any errors:
680: *
681: * - if some parameters are missing.
682: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
683: * - if some parameters are not of the proper type.
684: * - if the query fails or if some object names are invalid.
685: *
686: * @see UserSettingsManager::getParameter()
687: * @see UserSettingsManager::setParameters()
688: *
689: * @author Oleg Schildt
690: */
691: public function setParameter(string $name, mixed $value): void
692: {
693: if (empty($this->settings)) {
694: $this->loadSettings();
695: }
696:
697: $this->settings[$name] = $value;
698: } // setParameter
699:
700: /**
701: * Sets settings parameters from an array.
702: *
703: * @param array $parameters
704: * Array of parameters in the form key => value.
705: *
706: * @param bool $force_creation
707: * Flag which defines whether the parameter should be created
708: * if not exists. If false, only existing parameters are updated.
709: * In the UserSettingsManager, this flag is ignored, because
710: * the parameters are mapped to the database fields and cannot be created
711: * on the fly.
712: *
713: * @return void
714: *
715: * @throws \Exception
716: * It might throw an exception in the case of any errors:
717: *
718: * - if some parameters are missing.
719: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
720: * - if the query fails or if some object names are invalid.
721: * - if the config file is not readable.
722: *
723: * @see UserSettingsManager::getParameter()
724: * @see UserSettingsManager::setParameter()
725: *
726: * @author Oleg Schildt
727: */
728: public function setParameters(array $parameters, bool $force_creation = false): void
729: {
730: if (empty($this->settings)) {
731: $this->loadSettings();
732: }
733:
734: foreach ($parameters as $key => $val) {
735: if (!array_key_exists($key, $this->settings)) {
736: continue;
737: }
738:
739: $this->settings[$key] = $val;
740: }
741: } // setParameters
742:
743: /**
744: * Returns the value of a settings parameter.
745: *
746: * @param string $name
747: * The name of the settings parameter.
748: *
749: * @param mixed|null $default
750: * The default value of the settings parameter if it is not set yet.
751: * The parameter is a conformable way to pre-set a parameter
752: * to a default value if its value is not set yet.
753: *
754: * @return mixed
755: * Returns the value of the settings parameter.
756: *
757: * @throws \Exception
758: * It might throw an exception in the case of any errors:
759: *
760: * - if some parameters are missing.
761: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
762: * - if some parameters are not of the proper type.
763: * - if the query fails or if some object names are invalid.
764: *
765: * @see UserSettingsManager::setParameter()
766: * @see UserSettingsManager::setParameters()
767: *
768: * @author Oleg Schildt
769: */
770: public function getParameter(string $name, mixed $default = null): mixed
771: {
772: if (empty($this->settings)) {
773: $this->loadSettings();
774: }
775:
776: if (!isset($this->settings[$name])) {
777: return $default;
778: }
779:
780: return $this->settings[$name];
781: } // getParameter
782:
783: /**
784: * Validates the current settings values.
785: *
786: * It should be called after settings the new values of the parameters
787: * and before their saving.
788: *
789: * @return void
790: *
791: * @throws \Exception
792: * It might throw exceptions in the case of any errors.
793: *
794: * @uses Interfaces\ISettingsValidator
795: *
796: * @see UserSettingsManager::getValidator()
797: * @see UserSettingsManager::setValidator()
798: *
799: * @author Oleg Schildt
800: */
801: public function validateSettings(): void
802: {
803: if (empty($this->validator)) {
804: return;
805: }
806:
807: $this->validator->validate($this, $this->context);
808: } // validateSettings
809:
810: /**
811: * Loads the settings from the target user table.
812: *
813: * The user ID must be set before loading settings, see {@see \SmartFactory\UserSettingsManager::setUserID()}.
814: *
815: * @return void
816: *
817: * @throws \Exception
818: * It might throw an exception in the case of any errors:
819: *
820: * - if some parameters are missing.
821: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
822: * - if some parameters are not of the proper type.
823: * - if the query fails or if some object names are invalid.
824: *
825: * @see UserSettingsManager::saveSettings()
826: *
827: * @author Oleg Schildt
828: */
829: public function loadSettings(): void
830: {
831: $this->loadSettingsData($this->settings);
832: } // loadSettings
833:
834: /**
835: * Saves the settings from to the target user table.
836: *
837: * @return void
838: *
839: * @throws \Exception|\Throwable
840: * It might throw an exception in the case of any errors:
841: *
842: * - if some parameters are missing.
843: * - if dbworker does not extend {@see \SmartFactory\DatabaseWorkers\DBWorker}.
844: * - if some parameters are not of the proper type.
845: * - if the query fails or if some object names are invalid.
846: *
847: * @see UserSettingsManager::loadSettings()
848: *
849: * @author Oleg Schildt
850: */
851: public function saveSettings(): void
852: {
853: if (empty($this->settings)) {
854: $this->loadSettings();
855: }
856:
857: $this->saveSettingsData($this->settings);
858: } // saveSettings
859:
860: /**
861: * Sets the user id to be used for loading settings.
862: *
863: * The user ID must be set before loading settings, see {@see \SmartFactory\UserSettingsManager::loadSettings()}.
864: *
865: * @param string $user_id
866: * The user ID.
867: *
868: * @return void
869: *
870: * @see UserSettingsManager::loadSettings()
871: *
872: * @see UserSettingsManager::getUserID()
873: * @author Oleg Schildt
874: */
875: public function setUserID(string $user_id): void
876: {
877: $this->user_id = $user_id;
878: } // setUserID
879:
880: /**
881: * Gets the user id to be used for loading settings.
882: *
883: * @return int|string|null
884: * Returns the user id or null if not set.
885: *
886: * @see UserSettingsManager::setUserID()
887: *
888: * @author Oleg Schildt
889: */
890: public function getUserID(): int|string|null
891: {
892: return $this->user_id;
893: } // getUserID
894: } // UserSettingsManager