66use RuntimeException ;
77
88/**
9- * Provides database storage for Settings.
10- * Uses local storage to minimize database calls.
9+ * Provides database persistence for Settings.
10+ * Uses ArrayHandler for storage to minimize database calls.
1111 */
12- class DatabaseHandler extends BaseHandler
12+ class DatabaseHandler extends ArrayHandler
1313{
1414 /**
1515 * The database table to use.
@@ -19,20 +19,11 @@ class DatabaseHandler extends BaseHandler
1919 private $ table ;
2020
2121 /**
22- * Storage for cached general settings.
23- * Format: ['class' => ['property' => ['value', 'type']]]
22+ * Array of contexts that have been stored.
2423 *
25- * @var array< string,array<string,array>>|null Will be null until hydrated
24+ * @var ? string[]
2625 */
27- private $ general ;
28-
29- /**
30- * Storage for cached context settings.
31- * Format: ['context' => ['class' => ['property' => ['value', 'type']]]]
32- *
33- * @var array<string,array|null>
34- */
35- private $ contexts = [];
26+ private $ hydrated = [];
3627
3728 /**
3829 * Stores the configured database table.
@@ -49,15 +40,7 @@ public function has(string $class, string $property, ?string $context = null): b
4940 {
5041 $ this ->hydrate ($ context );
5142
52- if ($ context === null ) {
53- return isset ($ this ->general [$ class ])
54- ? array_key_exists ($ property , $ this ->general [$ class ])
55- : false ;
56- }
57-
58- return isset ($ this ->contexts [$ context ][$ class ])
59- ? array_key_exists ($ property , $ this ->contexts [$ context ][$ class ])
60- : false ;
43+ return $ this ->hasStored ($ class , $ property , $ context );
6144 }
6245
6346 /**
@@ -70,13 +53,7 @@ public function has(string $class, string $property, ?string $context = null): b
7053 */
7154 public function get (string $ class , string $ property , ?string $ context = null )
7255 {
73- if (! $ this ->has ($ class , $ property , $ context )) {
74- return null ;
75- }
76-
77- return $ context === null
78- ? $ this ->parseValue (...$ this ->general [$ class ][$ property ])
79- : $ this ->parseValue (...$ this ->contexts [$ context ][$ class ][$ property ]);
56+ return $ this ->getStored ($ class , $ property , $ context );
8057 }
8158
8259 /**
@@ -90,9 +67,9 @@ public function get(string $class, string $property, ?string $context = null)
9067 */
9168 public function set (string $ class , string $ property , $ value = null , ?string $ context = null )
9269 {
93- $ time = Time::now ()->format ('Y-m-d H:i:s ' );
94- $ type = gettype ($ value );
95- $ value = $ this ->prepareValue ($ value );
70+ $ time = Time::now ()->format ('Y-m-d H:i:s ' );
71+ $ type = gettype ($ value );
72+ $ prepared = $ this ->prepareValue ($ value );
9673
9774 // If it was stored then we need to update
9875 if ($ this ->has ($ class , $ property , $ context )) {
@@ -101,7 +78,7 @@ public function set(string $class, string $property, $value = null, ?string $con
10178 ->where ('key ' , $ property )
10279 ->where ('context ' , $ context )
10380 ->update ([
104- 'value ' => $ value ,
81+ 'value ' => $ prepared ,
10582 'type ' => $ type ,
10683 'context ' => $ context ,
10784 'updated_at ' => $ time ,
@@ -112,31 +89,21 @@ public function set(string $class, string $property, $value = null, ?string $con
11289 ->insert ([
11390 'class ' => $ class ,
11491 'key ' => $ property ,
115- 'value ' => $ value ,
92+ 'value ' => $ prepared ,
11693 'type ' => $ type ,
11794 'context ' => $ context ,
11895 'created_at ' => $ time ,
11996 'updated_at ' => $ time ,
12097 ]);
12198 }
12299
123- // Update storage
124- if ($ result === true ) {
125- if ($ context === null ) {
126- $ this ->general [$ class ][$ property ] = [
127- $ value ,
128- $ type ,
129- ];
130- } else {
131- $ this ->contexts [$ context ][$ class ][$ property ] = [
132- $ value ,
133- $ type ,
134- ];
135- }
136- } else {
100+ if ($ result !== true ) {
137101 throw new RuntimeException (db_connect ()->error ()['message ' ] ?? 'Error writing to the database. ' );
138102 }
139103
104+ // Update storage
105+ $ this ->setStored ($ class , $ property , $ value , $ context );
106+
140107 return $ result ;
141108 }
142109
@@ -160,64 +127,47 @@ public function forget(string $class, string $property, ?string $context = null)
160127 }
161128
162129 // Delete from local storage
163- if ($ context === null ) {
164- unset($ this ->general [$ class ][$ property ]);
165- } else {
166- unset($ this ->contexts [$ context ][$ class ][$ property ]);
167- }
130+ $ this ->forgetStored ($ class , $ property , $ context );
168131
169132 return $ result ;
170133 }
171134
172135 /**
173136 * Fetches values from the database in bulk to minimize calls.
174- * General is always fetched once, contexts are fetched in their
175- * entirety for each new request.
137+ * General (null) is always fetched once, contexts are fetched
138+ * in their entirety for each new request.
176139 *
177140 * @throws RuntimeException For database failures
178141 */
179142 private function hydrate (?string $ context )
180143 {
144+ // Check for completion
145+ if (in_array ($ context , $ this ->hydrated , true )) {
146+ return ;
147+ }
148+
181149 if ($ context === null ) {
182- // Check for completion
183- if ($ this ->general !== null ) {
184- return ;
185- }
150+ $ this ->hydrated [] = null ;
186151
187- $ this ->general = [];
188- $ query = db_connect ()->table ($ this ->table )->where ('context ' , null );
152+ $ query = db_connect ()->table ($ this ->table )->where ('context ' , null );
189153 } else {
190- // Check for completion
191- if (isset ($ this ->contexts [$ context ])) {
192- return ;
193- }
194-
195154 $ query = db_connect ()->table ($ this ->table )->where ('context ' , $ context );
196155
197156 // If general has not been hydrated we will do that at the same time
198- if ($ this ->general === null ) {
199- $ this ->general = [] ;
157+ if (! in_array ( null , $ this ->hydrated , true ) ) {
158+ $ this ->hydrated [] = null ;
200159 $ query ->orWhere ('context ' , null );
201160 }
202161
203- $ this ->contexts [ $ context ] = [] ;
162+ $ this ->hydrated [ ] = $ context ;
204163 }
205164
206165 if (is_bool ($ result = $ query ->get ())) {
207166 throw new RuntimeException (db_connect ()->error ()['message ' ] ?? 'Error reading from database. ' );
208167 }
209168
210169 foreach ($ result ->getResultObject () as $ row ) {
211- $ tuple = [
212- $ row ->value ,
213- $ row ->type ,
214- ];
215-
216- if ($ row ->context === null ) {
217- $ this ->general [$ row ->class ][$ row ->key ] = $ tuple ;
218- } else {
219- $ this ->contexts [$ row ->context ][$ row ->class ][$ row ->key ] = $ tuple ;
220- }
170+ $ this ->setStored ($ row ->class , $ row ->key , $ this ->parseValue ($ row ->value , $ row ->type ), $ row ->context );
221171 }
222172 }
223173}
0 commit comments