prefix . 'vizyt_schedule_breaks'; } private static function isValidTime( string $time ): bool { return (bool) preg_match( '/^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/', $time ); } /** * Get all breaks for a schedule, ordered by start_time ASC. */ public static function getBySchedule( int $schedule_id ): array { global $wpdb; return $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE schedule_id = %d ORDER BY start_time ASC', self::table(), $schedule_id ) ) ?: []; } /** * Batch-load breaks for multiple schedule IDs. * Returns an array keyed by schedule_id: [ schedule_id => [break, ...], ... ] */ public static function getByScheduleIds( array $ids ): array { if ( empty( $ids ) ) { return []; } global $wpdb; $ids = array_map( 'intval', $ids ); $rows = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE schedule_id IN (' . implode( ', ', array_fill( 0, count( $ids ), '%d' ) ) . ') ORDER BY start_time ASC', array_merge( [ self::table() ], $ids ) ) ) ?: []; $indexed = []; foreach ( $rows as $row ) { $indexed[ (int) $row->schedule_id ][] = $row; } return $indexed; } public static function getById( int $id ): ?object { global $wpdb; return $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', self::table(), $id ) ) ?: null; } /** * Create a new break. Returns new ID on success, false on validation failure. */ public static function create( int $schedule_id, string $start_time, string $end_time ): int|false { global $wpdb; if ( ! self::isValidTime( $start_time ) || ! self::isValidTime( $end_time ) ) { return false; } $start_time = substr( $start_time, 0, 5 ); $end_time = substr( $end_time, 0, 5 ); if ( $start_time >= $end_time ) { return false; } $result = $wpdb->insert( self::table(), [ 'schedule_id' => $schedule_id, 'start_time' => $start_time, 'end_time' => $end_time, ] ); return $result ? (int) $wpdb->insert_id : false; } /** * Update start_time and/or end_time of an existing break. */ public static function update( int $id, array $data ): bool { global $wpdb; $fields = []; if ( isset( $data['start_time'] ) ) { if ( ! self::isValidTime( $data['start_time'] ) ) { return false; } $fields['start_time'] = substr( $data['start_time'], 0, 5 ); } if ( isset( $data['end_time'] ) ) { if ( ! self::isValidTime( $data['end_time'] ) ) { return false; } $fields['end_time'] = substr( $data['end_time'], 0, 5 ); } if ( empty( $fields ) ) { return false; } // If both times provided, validate order. // If only one provided, load the other from DB. if ( isset( $fields['start_time'] ) && isset( $fields['end_time'] ) ) { if ( $fields['start_time'] >= $fields['end_time'] ) { return false; } } elseif ( isset( $fields['start_time'] ) || isset( $fields['end_time'] ) ) { $existing = self::getById( $id ); if ( ! $existing ) { return false; } $start = $fields['start_time'] ?? $existing->start_time; $end = $fields['end_time'] ?? $existing->end_time; if ( $start >= $end ) { return false; } } return $wpdb->update( self::table(), $fields, [ 'id' => $id ] ) !== false; } /** * Delete a single break by ID. */ public static function delete( int $id ): bool { global $wpdb; return $wpdb->delete( self::table(), [ 'id' => $id ] ) !== false; } /** * Delete all breaks for a given schedule. */ public static function deleteBySchedule( int $schedule_id ): void { global $wpdb; $wpdb->delete( self::table(), [ 'schedule_id' => $schedule_id ] ); } /** * Replace all breaks for a schedule atomically. * Validates all entries before writing — returns false without touching DB if any entry is invalid. * * @param array $breaks [ ['start_time' => 'HH:MM', 'end_time' => 'HH:MM'], ... ] */ public static function replaceAll( int $schedule_id, array $breaks ): bool { $rows = []; foreach ( $breaks as $break ) { $start = isset( $break['start_time'] ) ? substr( $break['start_time'], 0, 5 ) : ''; $end = isset( $break['end_time'] ) ? substr( $break['end_time'], 0, 5 ) : ''; if ( ! self::isValidTime( $start ) || ! self::isValidTime( $end ) || $start >= $end ) { return false; } $rows[] = [ 'schedule_id' => $schedule_id, 'start_time' => $start, 'end_time' => $end ]; } global $wpdb; $wpdb->delete( self::table(), [ 'schedule_id' => $schedule_id ] ); foreach ( $rows as $row ) { $wpdb->insert( self::table(), $row ); } return true; } }