PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / services / SettingsModePreference.php

SettingsModePreference.php in 404 Solution trunk, at includes/services/SettingsModePreference.php

141 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Per-user UI preference: tracks whether the current WP user wants
9 * the plugin's settings/admin surface rendered in "simple" or
10 * "advanced" mode. Backed by `user_meta` (key `abj404_settings_mode`).
11 *
12 * Owns getSettingsMode / setSettingsMode previously hosted on
13 * PluginLogic. Composed through abj_service('settings_mode_preference').
14 *
15 * Unknown / missing / unauthenticated callers fall back to 'simple'
16 * (the safer default for a brand-new install).
17 */
18 class ABJ_404_Solution_SettingsModePreference {
19
20 const META_KEY = 'abj404_settings_mode';
21 const MODE_SIMPLE = 'simple';
22 const MODE_ADVANCED = 'advanced';
23
24 /** @var self|null */
25 private static $instance = null;
26
27 /** @var bool */
28 private static $loggedUserLookupFailure = false;
29
30 /** @return self */
31 public static function getInstance(): self {
32 if (self::$instance !== null) {
33 return self::$instance;
34 }
35 self::$instance = new self();
36 return self::$instance;
37 }
38
39 /** Test-seam reset. @return void */
40 public static function reset(): void {
41 self::$instance = null;
42 self::$loggedUserLookupFailure = false;
43 }
44
45 /**
46 * Get the current user's settings mode preference.
47 *
48 * @return string 'simple' or 'advanced'
49 */
50 public function getMode(): string {
51 if (!function_exists('get_current_user_id')) {
52 return self::MODE_SIMPLE;
53 }
54 try {
55 $userId = get_current_user_id();
56 } catch (\Throwable $e) {
57 // Delegated to logUserLookupFailure(), which preserves the error
58 // once per process to avoid parallel-test stderr floods. No
59 // allow-silent-catch marker: the delegate call is what makes this
60 // catch non-silent, and a marker here would keep the audit green
61 // if that call were ever removed.
62 $this->logUserLookupFailure($e);
63 return self::MODE_SIMPLE;
64 }
65 if (!$userId) {
66 return self::MODE_SIMPLE;
67 }
68 if (!function_exists('get_user_meta')) {
69 return self::MODE_SIMPLE;
70 }
71 try {
72 $mode = get_user_meta($userId, self::META_KEY, true);
73 } catch (\Throwable $e) {
74 $this->logWarning('settings mode read failed (code ' .
75 $e->getCode() . '): ' . $e->getMessage());
76 return self::MODE_SIMPLE;
77 }
78 return ($mode === self::MODE_ADVANCED) ? self::MODE_ADVANCED : self::MODE_SIMPLE;
79 }
80
81 /**
82 * Set the current user's settings mode preference. Unknown values
83 * are clamped to 'simple'.
84 *
85 * @param string $mode 'simple' or 'advanced'
86 * @return bool|int Meta ID on insert, true on update, false on failure / no user
87 */
88 public function setMode($mode) {
89 if (!function_exists('get_current_user_id')) {
90 return false;
91 }
92 try {
93 $userId = get_current_user_id();
94 } catch (\Throwable $e) {
95 // Delegated to logUserLookupFailure(), which preserves the error
96 // once per process to avoid parallel-test stderr floods. No
97 // allow-silent-catch marker: the delegate call is what makes this
98 // catch non-silent, and a marker here would keep the audit green
99 // if that call were ever removed.
100 $this->logUserLookupFailure($e);
101 return false;
102 }
103 if (!$userId) {
104 return false;
105 }
106 if (!function_exists('update_user_meta')) {
107 return false;
108 }
109 $validMode = ($mode === self::MODE_ADVANCED) ? self::MODE_ADVANCED : self::MODE_SIMPLE;
110 try {
111 return update_user_meta($userId, self::META_KEY, $validMode);
112 } catch (\Throwable $e) {
113 $this->logWarning('settings mode write failed (code ' .
114 $e->getCode() . '): ' . $e->getMessage());
115 return false;
116 }
117 }
118
119 private function logUserLookupFailure(\Throwable $e): void {
120 if (strpos($e->getMessage(), 'not defined nor mocked') !== false) {
121 return;
122 }
123 if (self::$loggedUserLookupFailure) {
124 return;
125 }
126 self::$loggedUserLookupFailure = true;
127 $this->logWarning('settings mode user lookup failed (code ' .
128 $e->getCode() . '): ' . $e->getMessage());
129 }
130
131 private function logWarning(string $message): void {
132 $logger = function_exists('abj_service_optional') ? abj_service_optional('logging') : null;
133 if (is_object($logger) && method_exists($logger, 'warn')) {
134 $logger->warn($message);
135 return;
136 }
137
138 abj404_logPhpFallback('service-resolution-fallback', $message);
139 }
140 }
141