$old_id, 'n' => 0, 'p' => '', 'e' => '', ); ++$entry['n']; if ( $old_id !== $new_id ) { unset( $all[ $old_id ] ); } $all[ $new_id ] = $entry; self::$counted[ $new_id ] = true; self::save( $all, $new_id ); } public static function on_rescheduled( $session_id = 0, $old_start = '', $old_end = '', $new_start = '', $new_end = '', $occurrence_id = 0 ): void { unset( $session_id, $old_end ); $id = (int) $occurrence_id; if ( $id <= 0 || '' === (string) $new_start || (string) $old_start === (string) $new_start ) { return; } $all = self::all(); $entry = $all[ $id ] ?? array( 'o' => $id, 'n' => 0, 'p' => '', 'e' => '', ); if ( ! isset( self::$counted[ $id ] ) ) { ++$entry['n']; self::$counted[ $id ] = true; } $entry['p'] = self::utc( (string) $old_start ); $entry['e'] = self::utc( (string) $new_end ); $all[ $id ] = $entry; self::save( $all, 0 ); } public static function on_state( $session_id = 0, $change = '' ): void { if ( 'created' === $change ) { return; } $session = \RoosterLMS\Domain\Services::live_session_repo()->get( (int) $session_id ); if ( null === $session ) { return; } $now = new \DateTimeImmutable( '@' . Clock::timestamp() ); $all = self::all(); $dirty = false; foreach ( \RoosterLMS\Domain\Services::live_session_repo()->occurrences( $session->id, $now, $now->modify( '+' . Feed::WINDOW_MONTHS . ' months' ) ) as $o ) { $cancelled = $o->is_cancelled() || ! $session->is_active(); $entry = $all[ $o->id ] ?? array( 'o' => $o->id, 'n' => 0, 'p' => '', 'e' => $o->ends_at, ); if ( (bool) ( $entry['k'] ?? false ) === $cancelled ) { continue; } $entry['k'] = $cancelled; $entry['c'] = (int) ( $entry['c'] ?? 0 ) + 1; $entry['e'] = $o->ends_at; $all[ $o->id ] = $entry; $dirty = true; } if ( $dirty ) { self::save( $all, 0 ); } } public static function on_occurrence_cancelled( $occurrence_id = 0, $session_id = 0 ): void { unset( $occurrence_id ); self::on_state( $session_id, 'occurrence' ); } public static function of( int $occurrence_id ): array { $entry = self::all()[ $occurrence_id ] ?? null; return array( 'o' => is_array( $entry ) ? max( 1, (int) ( $entry['o'] ?? $occurrence_id ) ) : $occurrence_id, 'n' => is_array( $entry ) ? max( 0, (int) ( $entry['n'] ?? 0 ) ) : 0, 'p' => is_array( $entry ) ? (string) ( $entry['p'] ?? '' ) : '', ); } public static function uid( int $occurrence_id ): string { $host = (string) wp_parse_url( home_url( '/' ), PHP_URL_HOST ); return 'rooster-lms-event-' . self::of( $occurrence_id )['o'] . '@' . ( '' !== $host ? $host : 'localhost' ); } public static function sequence( int $occurrence_id, bool $cancelled ): int { $entry = self::all()[ $occurrence_id ] ?? array(); $steps = is_array( $entry ) ? max( 0, (int) ( $entry['c'] ?? 0 ) ) : 0; return self::of( $occurrence_id )['n'] + $steps + ( $cancelled && 0 === $steps ? 1 : 0 ); } public static function reset(): void { self::$counted = array(); } private static function all(): array { $all = wp_load_alloptions(); $value = isset( $all[ self::OPTION ] ) ? maybe_unserialize( $all[ self::OPTION ] ) : array(); return is_array( $value ) ? $value : array(); } private static function save( array $all, int $fresh ): void { if ( $fresh > 0 && '' === (string) ( $all[ $fresh ]['e'] ?? '' ) ) { $o = \RoosterLMS\Domain\Services::live_session_repo()->occurrence( $fresh ); $all[ $fresh ]['e'] = null === $o ? '' : $o->ends_at; } $now = gmdate( 'Y-m-d H:i:s', Clock::timestamp() - DAY_IN_SECONDS ); foreach ( $all as $id => $entry ) { $end = is_array( $entry ) ? (string) ( $entry['e'] ?? '' ) : ''; if ( ! is_array( $entry ) || ( '' !== $end && $end < $now ) ) { unset( $all[ $id ] ); } } if ( count( $all ) > self::MAX ) { $all = array_slice( $all, -self::MAX, null, true ); } update_option( self::OPTION, $all, true ); } private static function utc( string $value ): string { return 1 === preg_match( '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $value ) ? $value : ''; } }