LLMS_DB_Upgrader

Manage database updates and migrations


Source Source

File: includes/class-llms-db-ugrader.php

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
class LLMS_DB_Upgrader {
 
    /**
     * DB Version that's being upgraded from.
     *
     * @var string
     */
    protected $db_version = '';
 
    /**
     * Instance of the bg updater class
     *
     * @var LLMS_Background_Updater
     */
    protected $updater = null;
 
    /**
     * Update list
     *
     * @var array
     */
    protected $updates = array();
 
    /**
     * Constructor
     *
     * @since 5.2.0
     *
     * @see includes/schemas/llms-db-updates.php For an example updates schema.
     *
     * @param string       $db_version The DB version that is being upgraded from.
     * @param null|array[] $updates    A list of database updates conforming to the database updates schema
     *                                 or null to load the LifterLMS core schema.
     */
    public function __construct( $db_version, $updates = null ) {
 
        $this->updater = LLMS_Install::$background_updater;
 
        // Background updates may trigger a notice during a cron and notices might not be available.
        require_once LLMS_PLUGIN_DIR . 'includes/admin/class.llms.admin.notices.php';
 
        if ( is_null( $updates ) ) {
            $updates = require LLMS_PLUGIN_DIR . 'includes/schemas/llms-db-updates.php';
        }
 
        $this->db_version = $db_version;
        $this->updates    = $updates;
 
    }
 
    /**
     * Determine if an auto-update is possible from the specified DB version
     *
     * Auto updating is possible as long as none of the required updates are marked as "manual".
     *
     * @since 5.2.0
     *
     * @return boolean Returns `true` when an auto-update is possible and `false` if manual updating
     *                 is required.
     */
    public function can_auto_update() {
 
        $autoupdate = true;
 
        foreach ( $this->get_required_updates( $this->db_version ) as $update ) {
 
            // If we find a manual update we cannot auto-update.
            if ( 'manual' === $update['type'] ) {
                $autoupdate = false;
                break;
            }
        }
 
        /**
         * Filters the list of database updates.
         *
         * @since 5.2.0
         *
         * @param boolean          $autoupdate Whether or not an automatic update can be run.
         * @param string           $db_version The specified DB that's being upgraded from.
         * @param LLMS_DB_Upgrader $upgrader   Instance of the database upgrader.
         */
        return apply_filters( 'llms_can_auto_update_db', $autoupdate, $this->db_version, $this );
 
    }
 
    /**
     * Retrieve the callback's prefix string based on the schema's namespace declaration.
     *
     * If `$info['namespace']` is empty, no prefix will be added.
     * If `$info['namespace']` is `true`, the namespace is assumed to be `LLMS\Updates`.
     * If `$info['namespace']` is a string, that string will be used.
     *
     * If a namespace is found, `\Version_X_X_X` will automatically be appended to the namespace. The
     * string `X_X_X` is the database version for the upgrade substituting underscores for dots.
     *
     * @since 5.6.0
     *
     * @param array  $info    Upgrade schema array.
     * @param string $version Version string for the upgrade.
     * @return string
     */
    protected function get_callback_prefix( $info, $version ) {
 
        if ( ! empty( $info['namespace'] ) ) {
 
            $ver = explode( '-', $version ); // Drop prerelease data.
            $ver = str_replace( '.', '_', $ver[0] );
            $ns  = true === $info['namespace'] ? 'LLMS\Updates' : $info['namespace'];
            return sprintf( '%1$s\\Version_%2$s\\', $ns, $ver );
 
        }
 
        return '';
 
    }
 
    /**
     * Enqueue and dispatch required updates
     *
     * Adds callbacks for all required updates to the LLMS_Background_Updater and dispatches
     * the updater in the background.
     *
     * If the update group cannot be auto-updated the following admin notices will be included:
     * + The "update started" notice will be immediately displayed/added.
     * + The "update complete" notice will be added to the end of the queue (and then displayed when the update is complete).
     *
     * @since 5.2.0
     * @since 5.6.0 Add namespace prefix to qualifying callback functions.
     *
     * @return void
     */
    public function enqueue_updates() {
 
        $queued = false;
        foreach ( $this->get_required_updates() as $version => $info ) {
 
            $prefix = $this->get_callback_prefix( $info, $version );
            foreach ( $info['updates'] as $callback ) {
 
                $callback = $prefix . $callback;
 
                $this->updater->log( sprintf( 'Queuing %s - %s', $version, $callback ) );
                $this->updater->push_to_queue( $callback );
                $queued = true;
 
            }
        }
 
        // No updates to add, return early.
        if ( ! $queued ) {
            return;
        }
 
        // Show a start and complete notice for manual updates.
        if ( ! $this->can_auto_update() ) {
            $this->show_notice_started();
            $this->updater->push_to_queue( array( $this, 'show_notice_complete' ) );
        }
 
        $this->updater->save();
 
        add_action( 'shutdown', array( 'LLMS_Install', 'dispatch_db_updates' ) );
 
    }
 
    /**
     * Retrieves the updates list
     *
     * @since 5.2.0
     *
     * @return array
     */
    public function get_updates() {
 
        /**
         * Filters the list of database updates.
         *
         * @since 5.2.0
         *
         * @param array            $updates  List of updates to be run.
         * @param LLMS_DB_Upgrader $upgrader Instance of the database upgrader.
         */
        return apply_filters( 'llms_db_updates_list', $this->updates, $this );
 
    }
 
    /**
     * Retrieve a filtered list of updates as required by the specified DB version
     *
     * All updates greater than the specified version will be returned.
     *
     * @since 5.2.0
     *
     * @return array[]
     */
    public function get_required_updates() {
 
        $db_version = $this->db_version;
 
        return array_filter(
            $this->get_updates(),
            function( $update_version ) use ( $db_version ) {
                return version_compare( $db_version, $update_version, '<' );
            },
            ARRAY_FILTER_USE_KEY
        );
 
    }
 
    /**
     * Determine whether or not there are required updates for a specified DB version.
     *
     * @since 5.2.0
     *
     * @return boolean Returns `true` if there are updates to run, otherwise returns `false`.
     */
    public function has_required_updates() {
 
        $required = $this->get_required_updates( $this->db_version );
        return ! empty( $required );
 
    }
 
    /**
     * Show the db upgrade admin notice.
     *
     * Users can click this notice to start the database upgrade(s).
     *
     * @since 5.2.0
     *
     * @return void
     */
    protected function show_notice_pending() {
 
        $notice_id = 'bg-db-update';
 
        if ( LLMS_Admin_Notices::has_notice( $notice_id ) ) {
            LLMS_Admin_Notices::delete_notice( $notice_id );
        }
 
        LLMS_Admin_Notices::add_notice(
            $notice_id,
            array(
                'dismissible'  => false,
                'template'     => 'db-update.php',
                'default_path' => LLMS_PLUGIN_DIR . 'includes/admin/views/notices/',
            )
        );
 
    }
 
    /**
     * Show a notice when a manual update is started.
     *
     * @since 5.2.0
     *
     * @return void
     */
    protected function show_notice_started() {
 
        LLMS_Admin_Notices::add_notice(
            'bg-db-update-started',
            __( 'Your database is being upgraded in the background. Feel free to leave this page. A notice like this will appear when the update is complete.', 'lifterlms' ),
            array(
                'dismissible'      => true,
                'dismiss_for_days' => 0,
            )
        );
 
    }
 
    /**
     * Show a notice when the update is complete
     *
     * This will also delete the started notice. When short updates run quickly the started and completed notice
     * may show up on the same page load which is confusing to look at it. If we just started and it's already done
     * when the next page loads we only need to see that update is complete.
     *
     * @since 5.2.0
     *
     * @return void
     */
    public function show_notice_complete() {
 
        // If the update started notice exists, delete it to avoid confusing UX when the update finishes before the page loads.
        if ( LLMS_Admin_Notices::has_notice( 'bg-db-update-started' ) ) {
            LLMS_Admin_Notices::delete_notice( 'bg-db-update-started' );
        }
 
        LLMS_Admin_Notices::add_notice(
            'bg-db-update-complete',
            __( 'The LifterLMS database update is complete.', 'lifterlms' ),
            array(
                'dismissible'      => true,
                'dismiss_for_days' => 0,
            )
        );
 
    }
 
    /**
     * Start the update
     *
     * If autoupdating is possible, will enqueue and dispatch the bg updater. Otherwise
     * it will show the update pending notice which will prompt an admin to manually
     * start the update.
     *
     * @since 5.2.0
     *
     * @return boolean Returns `false` if there are no updates to run and `true` otherwise.
     */
    public function update() {
 
        if ( ! $this->has_required_updates() ) {
            return false;
        }
 
        // Auto update if it can.
        if ( $this->can_auto_update() ) {
            $this->enqueue_updates();
        } else {
            $this->show_notice_pending();
        }
 
        return true;
 
    }
 
}

Top ↑

Methods Methods


Top ↑

Changelog Changelog

Changelog
Version Description
5.2.0 Introduced.

Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.