PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.3.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.3.0
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
← All changes | inc/database/register.php +2 -248 trunk1.3.0 View file →
@@ -10,10 +10,8 @@
10 10
11 11 namespace SRFM\Inc\Database;
12 12
13 13 use SRFM\Inc\Database\Tables\Entries;
14 -use SRFM\Inc\Database\Tables\Payments;
15 -use SRFM\Inc\Helper;
16 14
17 15 // Exit if accessed directly.
18 16 defined( 'ABSPATH' ) || exit;
19 17
@@ -23,31 +21,8 @@
23 21 * @since 0.0.13
24 22 */
25 23 class Register {
26 24 /**
27 - * Transient caching a healthy entries-table check.
28 - *
29 - * Only the healthy answer is ever cached. A missing table is re-queried every
30 - * time, so the warning disappears the moment the table is back rather than
31 - * lingering for the rest of the TTL.
32 - *
33 - * @since 2.12.6
34 - */
35 - public const ENTRIES_TABLE_CHECK_TRANSIENT = 'srfm_entries_table_present';
36 -
37 - /**
38 - * Per-request memo for the entries-table check.
39 - *
40 - * The check is consulted from three places in one admin page load (notice
41 - * registration, notice rendering, analytics), and this keeps that to a single
42 - * transient read.
43 - *
44 - * @var bool|null
45 - * @since 2.12.6
46 - */
47 - private static $entries_table_present = null;
48 -
49 - /**
50 25 * Init database registration.
51 26 *
52 27 * @since 0.0.13
53 28 * @return void
@@ -59,13 +34,10 @@
59 34 * 2. Init create method, which create the table if the table does not exists.
60 35 * 3. Init maybe_add_new_columns, it only runs if we have new columns definition and DB is upgradable ( has new version ).
61 36 * 4. Init maybe_rename_columns, it only runs if got any columns to rename and DB is upgradable ( has new version ).
62 37 * 5. Finally, stop the DB upgrade and update the current version in option table.
63 - *
64 - * Replaced self::get_db_tables() to static::get_db_tables() for allowing overrides.
65 - * @since 1.13.0
66 38 */
67 - foreach ( static::get_db_tables() as $instance ) {
39 + foreach ( self::get_db_tables() as $instance ) {
68 40 $instance->start_db_upgrade();
69 41
70 42 if ( $instance->is_db_upgradable() ) {
71 43 // Only execute below methods if DB is upgradable.
@@ -86,226 +58,8 @@
86 58 * @return array<string,\SRFM\Inc\Database\Base>
87 59 */
88 60 public static function get_db_tables() {
89 61 return [
90 - 'entries' => Entries::get_instance(),
91 - 'payments' => Payments::get_instance(),
62 + 'entries' => Entries::get_instance(),
92 63 ];
93 - }
94 -
95 - /**
96 - * Whether the entries table is missing from the database.
97 - *
98 - * A dropped table is never recreated on its own: `srfm_database_table_versions`
99 - * still records the current version, so start_db_upgrade() marks the table
100 - * non-upgradable and create() early-returns. Nothing else in the plugin notices,
101 - * and every submission silently fails to save. This is what surfaces that.
102 - *
103 - * Returns false while the stored version is absent — Register::init() is going
104 - * to create the table on this very request, so reporting it missing would show
105 - * a "your database needs updating" notice during a perfectly normal install.
106 - *
107 - * @param bool $force Skip both caches and re-query.
108 - * @since 2.12.6
109 - * @return bool
110 - */
111 - public static function is_entries_table_missing( $force = false ) {
112 - if ( ! $force && null !== self::$entries_table_present ) {
113 - return ! self::$entries_table_present;
114 - }
115 -
116 - if ( ! $force && get_transient( self::ENTRIES_TABLE_CHECK_TRANSIENT ) ) {
117 - self::$entries_table_present = true;
118 - return false;
119 - }
120 -
121 - $versions = Helper::get_array_value( get_option( 'srfm_database_table_versions', [] ) );
122 -
123 - // No recorded version means this is a fresh install or an upgrade in
124 - // progress; init() creates the table this request. Nothing to warn about.
125 - if ( empty( $versions['entries'] ) ) {
126 - self::$entries_table_present = true;
127 - return false;
128 - }
129 -
130 - $present = Entries::get_instance()->table_exists();
131 -
132 - // Cache only the healthy answer. See the transient's docblock.
133 - if ( $present ) {
134 - set_transient( self::ENTRIES_TABLE_CHECK_TRANSIENT, 1, DAY_IN_SECONDS );
135 - // Backfill the owner signature once, so a table created before this plugin
136 - // wrote signatures can still be proven ours if the prefix later changes.
137 - if ( ! get_option( 'srfm_entries_owner_stamped' ) ) {
138 - Entries::get_instance()->stamp_owner_signature();
139 - update_option( 'srfm_entries_owner_stamped', 1, false );
140 - }
141 - } else {
142 - delete_transient( self::ENTRIES_TABLE_CHECK_TRANSIENT );
143 - }
144 -
145 - self::$entries_table_present = $present;
146 -
147 - return ! $present;
148 - }
149 -
150 - /**
151 - * Recreate the entries table when it is missing.
152 - *
153 - * Clearing the stored version is the whole repair: start_db_upgrade() then
154 - * treats the table as new, and init() runs the same ordered steps it runs on a
155 - * fresh install. Reusing init() rather than re-implementing those steps is
156 - * deliberate — the repair path cannot drift from the install path.
157 - *
158 - * Only the `entries` key is removed. The option is shared with the payments
159 - * table and, when Pro is active, three more; clearing the whole option would
160 - * force an unrelated re-upgrade pass across all of them from free-plugin code.
161 - *
162 - * The result is a fresh existence check, never create()'s return value. A
163 - * repair that reported success on the strength of create() alone could record
164 - * the version again while the table was still missing — which would hide the
165 - * problem permanently and be worse than doing nothing.
166 - *
167 - * @since 2.12.6
168 - * @return bool True when the table exists afterwards.
169 - */
170 - public static function repair_entries_table() {
171 - $entries = Entries::get_instance();
172 -
173 - // Prefer adopting the site's own data over manufacturing an empty table.
174 - // A changed table prefix leaves the rows behind under the old name, and
175 - // creating a fresh table would strand every stored entry while looking like
176 - // a successful repair.
177 - $adoptable = $entries->find_adoptable_table();
178 -
179 - if ( '' !== $adoptable ) {
180 - if ( $entries->table_belongs_to_site( $adoptable ) ) {
181 - // Provenance confirms this site owns the table: safe to rename it in.
182 - if ( $entries->adopt_table( $adoptable ) ) {
183 - self::run_entries_schema_catchup();
184 - delete_option( 'srfm_entries_unrecovered' );
185 - return ! self::is_entries_table_missing( true );
186 - }
187 -
188 - // The table is ours but the rename failed — e.g. the DB user lacks the
189 - // privilege RENAME needs, or a metadata-lock timeout. Manufacturing an
190 - // empty table over recoverable data and reporting success would be worse
191 - // than doing nothing, so refuse and leave a durable trail for support.
192 - self::record_unrecovered_entries_table( $adoptable, 'adopt_failed' );
193 - return false;
194 - }
195 -
196 - // A single same-schema candidate exists but its ownership cannot be
197 - // proven. On shared hosting it may belong to an unrelated install, and
198 - // renaming it in would destroy that site's data. Leave it untouched,
199 - // record it so it can be recovered by hand, then fall back to a fresh
200 - // table below.
201 - self::record_unrecovered_entries_table( $adoptable, 'unverified' );
202 - }
203 -
204 - $versions = Helper::get_array_value( get_option( 'srfm_database_table_versions', [] ) );
205 -
206 - unset( $versions['entries'] );
207 - update_option( 'srfm_database_table_versions', $versions );
208 -
209 - static::init();
210 -
211 - return ! self::is_entries_table_missing( true );
212 - }
213 -
214 - /**
215 - * Drop the cached entries-table detection so the next check re-queries.
216 - *
217 - * Called when a live entries write fails: a table cached as present earlier in
218 - * the day may have just been dropped, and trusting the stale healthy answer
219 - * would hide the notice for up to the transient's lifetime.
220 - *
221 - * @since 2.12.6
222 - * @return void
223 - */
224 - public static function flush_entries_table_cache() {
225 - self::$entries_table_present = null;
226 - delete_transient( self::ENTRIES_TABLE_CHECK_TRANSIENT );
227 - }
228 -
229 - /**
230 - * The entries table sitting under a different prefix, if there is one.
231 - *
232 - * Exposed so the notice can say whether the repair will bring existing entries
233 - * back with it or start from empty — the difference matters a great deal to
234 - * whoever is about to click the button.
235 - *
236 - * @since 2.12.6
237 - * @return string Full table name, or '' when there is nothing to adopt.
238 - */
239 - public static function get_adoptable_entries_table() {
240 - if ( ! self::is_entries_table_missing() ) {
241 - return '';
242 - }
243 -
244 - $entries = Entries::get_instance();
245 - $candidate = $entries->find_adoptable_table();
246 -
247 - // Only report a candidate the repair would actually adopt — one we can prove
248 - // belongs to this site. An unverifiable table is left untouched and a fresh
249 - // table created instead, so the notice must not promise to keep its entries.
250 - if ( '' === $candidate || ! $entries->table_belongs_to_site( $candidate ) ) {
251 - return '';
252 - }
253 -
254 - return $candidate;
255 - }
256 -
257 - /**
258 - * Re-run the install-time schema steps against a just-adopted table.
259 - *
260 - * An adopted table can carry an older revision of this plugin's schema (a
261 - * superset of column names still passes the adoption guard), so reuse the same
262 - * ordered create/add-column/rename pass the install path runs rather than
263 - * assuming the adopted schema is already current. create() is CREATE TABLE IF
264 - * NOT EXISTS, so it is a no-op on the table that is now in place.
265 - *
266 - * @since 2.12.6
267 - * @return void
268 - */
269 - private static function run_entries_schema_catchup() {
270 - $versions = Helper::get_array_value( get_option( 'srfm_database_table_versions', [] ) );
271 -
272 - unset( $versions['entries'] );
273 - update_option( 'srfm_database_table_versions', $versions );
274 -
275 - static::init();
276 - }
277 -
278 - /**
279 - * Record a table that holds recoverable entries but was not adopted.
280 - *
281 - * Fired when a candidate is found that either cannot be proven to belong to
282 - * this site or could not be renamed in. Persists the name and reason so a
283 - * support engineer can find and reconnect it by hand, rather than letting it
284 - * be discarded silently the moment a fresh empty table exists.
285 - *
286 - * @param string $table Full name of the table left in place.
287 - * @param string $reason 'unverified' or 'adopt_failed'.
288 - * @since 2.12.6
289 - * @return void
290 - */
291 - private static function record_unrecovered_entries_table( $table, $reason ) {
292 - update_option(
293 - 'srfm_entries_unrecovered',
294 - [
295 - 'table' => $table,
296 - 'reason' => $reason,
297 - 'time' => time(),
298 - ],
299 - false
300 - );
301 -
302 - /**
303 - * Fires when entries data was found but not automatically recovered.
304 - *
305 - * @param string $table Full name of the table left in place.
306 - * @param string $reason 'unverified' or 'adopt_failed'.
307 - * @since 2.12.6
308 - */
309 - do_action( 'srfm_entries_table_unrecovered', $table, $reason );
310 64 }
311 65 }