0, 'variation_id' => 0, 'order_id' => 0, 'order_item_id' => 0, 'customer_id' => 0, 'start_date' => '', 'end_date' => '', 'units' => 1, 'quantity' => 1, 'status' => 'pending', ) ); $wpdb->insert( self::table(), $row ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery return (int) $wpdb->insert_id; } /** * Move every booking of an order to a status. * * @since 1.0.0 * @param int $order_id Order holding the bookings. * @param string $status New status. */ public static function set_order_status( $order_id, $status ) { global $wpdb; if ( ! in_array( $status, self::STATUSES, true ) ) { return; } $wpdb->update( self::table(), array( 'status' => $status ), array( 'order_id' => (int) $order_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery } /** * Move one booking to a status. * * @since 1.0.0 * @param int $booking_id Booking to move. * @param string $status New status. * @return bool Whether the row changed. */ public static function update_status( $booking_id, $status ) { global $wpdb; if ( ! in_array( $status, self::STATUSES, true ) ) { return false; } // phpcs:ignore WordPress.DB.DirectDatabaseQuery return (bool) $wpdb->update( self::table(), array( 'status' => $status ), array( 'id' => (int) $booking_id ) ); } /** * Move the booking of an order line to new dates, back at the first step. * * @since 1.0.1 * @param int $order_item_id Order line holding the booking. * @param array $dates Start, end and units, as Dates returns them. */ public static function move_item( $order_item_id, array $dates ) { global $wpdb; $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery self::table(), array( 'start_date' => $dates['start'], 'end_date' => $dates['end'], 'units' => (int) $dates['units'], 'status' => 'pending', ), array( 'order_item_id' => (int) $order_item_id ) ); } /** * Change the fields of one booking. * * @since 1.1.0 * @param int $booking_id Booking to change. * @param array $fields Columns to write, as create() takes them. * @return bool Whether the write went through. */ public static function update( $booking_id, array $fields ) { global $wpdb; if ( isset( $fields['status'] ) && ! in_array( $fields['status'], self::STATUSES, true ) ) { return false; } // phpcs:ignore WordPress.DB.DirectDatabaseQuery return false !== $wpdb->update( self::table(), $fields, array( 'id' => (int) $booking_id ) ); } /** * Remove one booking. * * @since 1.1.0 * @param int $booking_id Booking to remove. * @return bool Whether a row went. */ public static function delete( $booking_id ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery return (bool) $wpdb->delete( self::table(), array( 'id' => (int) $booking_id ) ); } /** * Every booking still in play, cancelled and finished ones left aside. * * @since 1.0.0 * @return array */ public static function open() { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (array) $wpdb->get_results( "SELECT * FROM {$table} WHERE status NOT IN ( 'cancelled', 'completed' )" ); } /** * Every booking of an order. * * @since 1.0.0 * @param int $order_id Order to read. * @return array */ public static function for_order( $order_id ) { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (array) $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE order_id = %d", (int) $order_id ) ); } /** * One booking. * * @since 1.0.0 * @param int $booking_id Booking to read. * @return object|null */ public static function find( $booking_id ) { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d", (int) $booking_id ) ); } /** * Whether an order already has its bookings, so a second save adds nothing. * * @since 1.0.0 * @param int $order_id Order to look up. * @return bool */ public static function order_has_bookings( $order_id ) { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (bool) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$table} WHERE order_id = %d", (int) $order_id ) ); } /** * A page of bookings, newest arrival first. * * @since 1.0.0 * @param array $args Filters: status, product_id, start, end, per_page, page. * @return array */ public static function query( array $args = array() ) { global $wpdb; $args = wp_parse_args( $args, array( 'per_page' => 20, 'page' => 1 ) ); list( $where, $vals ) = self::conditions( $args ); $vals[] = max( 1, (int) $args['per_page'] ); $vals[] = ( max( 1, (int) $args['page'] ) - 1 ) * max( 1, (int) $args['per_page'] ); $sql = 'SELECT * FROM ' . self::table() . ' WHERE ' . $where . ' ORDER BY start_date DESC, id DESC LIMIT %d OFFSET %d'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (array) $wpdb->get_results( $wpdb->prepare( $sql, $vals ) ); } /** * Every booking touching a period, arrival first. * * @since 1.0.0 * @param string $from First day of the period. * @param string $to Last day of the period. * @return array */ public static function between( $from, $to ) { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (array) $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared "SELECT * FROM {$table} WHERE status <> 'cancelled' AND start_date <= %s AND end_date >= %s ORDER BY start_date ASC", $to, $from ) ); } /** * Every booking of a product ending on a day or later, cancelled ones left aside. * * @since 1.1.0 * @param int $product_id Product booked. * @param string $from First day that matters. * @return array */ public static function for_product( $product_id, $from ) { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (array) $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE product_id = %d AND status <> 'cancelled' AND end_date >= %s", (int) $product_id, $from ) ); } /** * How many bookings match the filters. * * @since 1.0.0 * @param array $args Same filters as query(). * @return int */ public static function count( array $args = array() ) { global $wpdb; list( $where, $vals ) = self::conditions( $args ); $sql = 'SELECT COUNT(id) FROM ' . self::table() . ' WHERE ' . $where; if ( ! $vals ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (int) $wpdb->get_var( $sql ); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter return (int) $wpdb->get_var( $wpdb->prepare( $sql, $vals ) ); } /** * What a set of filters asks of the bookings, and the values it needs. * * @since 1.0.1 * @param array $args Filters: status, product_id, start, end. * @return array The conditions joined together, then their values. */ private static function conditions( array $args ) { $args = wp_parse_args( $args, array( 'status' => '', 'product_id' => 0, 'start' => '', 'end' => '' ) ); $where = array( '1=1' ); $vals = array(); if ( $args['status'] && in_array( $args['status'], self::STATUSES, true ) ) { $where[] = 'status = %s'; $vals[] = $args['status']; } if ( $args['product_id'] ) { $where[] = 'product_id = %d'; $vals[] = (int) $args['product_id']; } foreach ( array( 'start' => 'start_date', 'end' => 'end_date' ) as $key => $column ) { if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', (string) $args[ $key ] ) ) { $where[] = $column . ' = %s'; $vals[] = $args[ $key ]; } } return array( implode( ' AND ', $where ), $vals ); } /** * Name of the bookings table. * * @since 1.0.0 * @return string */ private static function table() { global $wpdb; return $wpdb->prefix . 'abfw_bookings'; } }