LLMS_Sessions

LLMS_Sessions class.


Source Source

File: includes/class-llms-sessions.php

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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
class LLMS_Sessions {
 
    use LLMS_Trait_Singleton;
 
    /**
     * Current user id.
     *
     * @var null
     */
    protected $user_id = null;
 
    /**
     * Private Constructor.
     *
     * @since 3.36.0
     * @since 3.37.2 Add filter to the cleanup cronjob interval.
     *
     * @return void
     */
    private function __construct() {
 
        add_filter( 'cron_schedules', array( $this, 'add_cron_schedule' ) );
 
        if ( ! wp_next_scheduled( 'llms_end_idle_sessions' ) ) {
            /**
             * Filter the recurrence interval at which LifterLMS closes idle sessions.
             *
             *
             * @since 3.37.2
             *
             * @param string $recurrence Cron job recurrence interval. Must be valid interval as retrieved from `wp_get_schedules()`. Default is "every_five_mins".
             */
            $recurrence = apply_filters( 'llms_sessions_end_idle_cron_recurrence', 'every_five_mins' );
            wp_schedule_event( time(), $recurrence, 'llms_end_idle_sessions' );
        }
        add_action( 'llms_end_idle_sessions', array( $this, 'end_idle_sessions' ) );
 
    }
 
    /**
     * Add cron schedule for session end interval checks.
     *
     * @since 3.36.0
     *
     * @param array $schedules Array of cron schedules.
     * @return array
     */
    public function add_cron_schedule( $schedules ) {
 
        // Adds every 5 minutes to the existing schedules.
        $schedules['every_five_mins'] = array(
            'interval' => MINUTE_IN_SECONDS * 5,
            'display'  => sprintf( __( 'Every %d Minutes', 'lifterlms' ), 5 ),
        );
        return $schedules;
 
    }
 
    /**
     * End the 50 oldest idle sessions.
     *
     * @since 3.36.0
     *
     * @return void
     */
    public function end_idle_sessions() {
 
        foreach ( $this->get_open_sessions() as $i => $event ) {
            if ( $this->is_session_idle( $event ) ) {
                $this->end( $event );
            }
        }
 
    }
 
    /**
     * End a session.
     *
     * @since 3.36.0
     * @since 4.5.0 Delete open session entry from the `wp_lifterlms_events_open_sessions` table.
     *
     * @param LLMS_Event $start Event object for a session start.
     * @return LLMS_Event|WP_Error
     */
    protected function end( $start ) {
 
        $end = llms()->events()->record(
            array(
                'actor_id'     => $start->get( 'actor_id' ),
                'object_type'  => 'session',
                'object_id'    => $start->get( 'object_id' ),
                'event_type'   => 'session',
                'event_action' => 'end',
            )
        );
 
        if ( ! is_wp_error( $end ) ) {
            global $wpdb;
            $wpdb->query(
                $wpdb->prepare(
                    "
                    DELETE FROM {$wpdb->prefix}lifterlms_events_open_sessions
                    WHERE `event_id` = %d
                    ",
                    $start->get( 'id' )
                )
            ); // db call ok; no-cache ok.
        }
 
        return $end;
    }
 
    /**
     * Ends the currently active session for the logged in user.
     *
     * @since 3.36.0
     *
     * @return LLMS_Event|WP_Error|false
     */
    public function end_current() {
 
        $current = $this->get_current();
        if ( ! $current ) {
            return false;
        }
 
        return $this->end( $current );
 
    }
 
    /**
     * Retrieve the current session start event record for a given user.
     *
     * @since 3.36.0
     * @since 4.5.0 Added optional `$user_id` parameter.
     *
     * @param int $user_id Optional. WP_User ID of a student. Default `null`
     *                     If not provided, or a falsy is provided, will fall back on the current user id.
     * @return LLMS_Event|false
     */
    public function get_current( $user_id = null ) {
 
        $user_id = $user_id ? $user_id : get_current_user_id();
        if ( ! $user_id ) {
            return false;
        }
 
        $session = $this->get_last_session( $user_id );
        if ( ! $session ) {
            return false;
        }
 
        $session = new LLMS_Event( $session->id );
 
        if ( ! $this->is_session_open( $session ) ) {
            return false;
        }
 
        return $session;
 
    }
 
    /**
     * Determine if a session is idle.
     *
     * A session is considered idle if it's open and no new events have been recorded
     * in the last 30 minutes.
     *
     * @since 3.36.0
     * @since 4.7.0 When retrieving the last event, instantiate the events query passing `no_found_rows` arg as `true`,
     *              to improve performance.
     *
     * @param LLMS_Event $start Event record for the start of the session.
     * @return bool
     */
    public function is_session_idle( $start ) {
 
        // Session is closed so it can't be idle.
        if ( ! $this->is_session_open( $start ) ) {
            return false;
        }
 
        $now = llms_current_time( 'timestamp' );
 
        /**
         * Filter the time (in minutes) to allow a session to remain open before it's considered an "idle" session.
         *
         * @param int $minutes Number of minutes.
         */
        $timeout = absint( apply_filters( 'llms_idle_session_timeout', 30 ) ) * MINUTE_IN_SECONDS;
 
        // Session has started within the idle window, so it can't have expired yet.
        if ( ( $now - strtotime( $start->get( 'date' ) ) ) < $timeout ) {
            return false;
        }
 
        $events = $this->get_session_events(
            $start,
            array(
                'per_page'      => 1,
                'sort'          => array(
                    'date' => 'DESC',
                ),
                'no_found_rows' => true,
            )
        );
 
        // No events, the session is idle.
        if ( ! $events ) {
            return true;
        }
 
        $last_event = array_shift( $events );
        return ( ( $now - strtotime( $last_event->get( 'date' ) ) ) > $timeout );
 
    }
 
    /**
     * Determines if the given session is open (has not ended)
     *
     * @since 3.36.0
     *
     * @param LLMS_Event Event record for the start of the session.
     * @return bool
     */
    public function is_session_open( $start ) {
 
        return is_null( $this->get_session_end( $start ) );
 
    }
 
    /**
     * Retrieve the last session object for the current user.
     *
     * @since 3.36.0
     * @since 4.5.0 Added optional `$user_id` parameter.
     *
     * @param int $user_id Optional. WP_User ID of a student. Default `null`
     *                     If not provided, or a falsy is provided, will fall back on the current user id.
     * @return obj|null
     */
    protected function get_last_session( $user_id = null ) {
        $user_id = $user_id ? $user_id : get_current_user_id();
 
        global $wpdb;
        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT *
               FROM {$wpdb->prefix}lifterlms_events
              WHERE actor_id = %d
                AND object_type = 'session'
                AND event_type = 'session'
                AND event_action = 'start'
           ORDER BY date DESC
              LIMIT 1;",
                $user_id
            )
        ); // db call ok; no-cache ok.
 
    }
 
    /**
     * Retrieve open sessions.
     *
     * @since 3.36.0
     * @since 4.5.0 Retrieve open sessions from the `wp_lifterlms_events_open_sessions` table.
     *
     * @param int $limit Number of sessions to return.
     * @param int $skip  Number of sessions to skip.
     * @return LLMS_Event[]
     */
    protected function get_open_sessions( $limit = 50, $skip = 0 ) {
 
        global $wpdb;
        $sessions = $wpdb->get_col(
            $wpdb->prepare(
                "
               SELECT event_id
               FROM {$wpdb->prefix}lifterlms_events_open_sessions
               ORDER BY event_id ASC
               LIMIT %d, %d
        ",
                $skip,
                $limit
            )
        ); // db call ok; no-cache ok.
 
        $ret = array();
        if ( count( $sessions ) ) {
            foreach ( $sessions as $id ) {
                $ret[] = new LLMS_Event( $id );
            }
        }
 
        return $ret;
 
    }
 
    /**
     * Retrieve an array of events which occurred during a session.
     *
     * @since 3.36.0
     *
     * @param LLMS_Event $start Event record for the session.start event.
     * @param array      $args  Array of additional arguments to pass to the LLMS_Events_Query.
     * @return LLMS_Event[]
     */
    public function get_session_events( $start, $args = array() ) {
 
        $end = $this->get_session_end( $start );
 
        $args = wp_parse_args(
            $args,
            array(
                'date_after' => $start->get( 'date' ),
                'exclude'    => array( $start->get( 'id' ) ),
                'actor'      => $start->get( 'actor_id' ),
                'sort'       => array(
                    'date' => 'ASC',
                ),
                'per_page'   => 10,
            )
        );
 
        if ( $end ) {
            $args['date_before'] = $end->get( 'date' );
            $args['exclude'][]   = $end->get( 'id' );
        }
 
        $query = new LLMS_Events_Query( $args );
        return $query->get_events();
 
    }
 
    /**
     * Retrieve session end record for by session id.
     *
     * @since 3.36.0
     *
     * @param LLMS_Event $start Event record for the session.start event.
     * @return LLMS_Event|end
     */
    public function get_session_end( $start ) {
 
        global $wpdb;
        $end = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT id
               FROM {$wpdb->prefix}lifterlms_events
              WHERE actor_id = %d
                AND object_id = %d
                AND object_type = 'session'
                AND event_type = 'session'
                AND event_action = 'end'
           ORDER BY date DESC
              LIMIT 1;",
                $start->get( 'actor_id' ),
                $start->get( 'object_id' )
            )
        ); // db call ok; no-cache ok.
 
        if ( ! $end ) {
            return null;
        }
 
        return new LLMS_Event( $end );
 
    }
 
    /**
     * Retrieve a new session ID.
     *
     * @since 3.36.0
     * @since 4.5.0 Added optional `$user_id` parameter.
     *
     * @param int $user_id Optional. WP_User ID of a student. Default `null`
     *                     If not provided, or a falsy is provided, will fall back on the current user id.
     * @return int
     */
    protected function get_new_id( $user_id = null ) {
 
        $user_id = $user_id ? $user_id : get_current_user_id();
 
        $last = $this->get_last_session( $user_id );
        if ( ! $last ) {
            return 1;
        }
 
        return ++$last->object_id;
 
    }
 
    /**
     * Start a new session for the current user.
     *
     * @since 3.36.0
     * @since 4.5.0 Create open session entry in the `wp_lifterlms_events_open_sessions` table.
     *                  Added optional `$user_id` parameter.
     *
     * @param int $user_id Optional. WP_User ID of a student. Default `null`
     *                     If not provided, or a falsy is provided, will fall back on the current user id.
     * @return false|LLMS_Event|WP_Error
     */
    public function start( $user_id = null ) {
 
        $user_id = $user_id ? $user_id : get_current_user_id();
        if ( ! $user_id ) {
            return false;
        }
 
        $start = llms()->events()->record(
            array(
                'actor_id'     => $user_id,
                'object_type'  => 'session',
                'object_id'    => $this->get_new_id( $user_id ),
                'event_type'   => 'session',
                'event_action' => 'start',
            )
        );
 
        if ( ! is_wp_error( $start ) ) {
            global $wpdb;
            $wpdb->query( // db call ok; no-cache ok.
                $wpdb->prepare(
                    "
                    INSERT INTO {$wpdb->prefix}lifterlms_events_open_sessions ( `event_id` ) VALUES ( %d )
                    ",
                    $start->get( 'id' )
                )
            );
        }
 
        return $start;
 
    }
 
}

Top ↑

Methods Methods


Top ↑

Changelog Changelog

Changelog
Version Description
6.0.0 Removed the deprecated LLMS_Sessions::$_instance property.
5.3.0 Replace singleton code with LLMS_Trait_Singleton.
3.37.2 Add filter llms_sessions_end_idle_cron_recurrence to allow customization of the recurrence of the idle session cleanup cronjob.
3.36.0 Introduced.

Top ↑

User Contributed Notes User Contributed Notes

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