| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- <?php
- /**
- * DB class.
- *
- * This handy class originated from Pippin's Easy Digital Downloads.
- * https://github.com/easydigitaldownloads/easy-digital-downloads/blob/master/includes/class-edd-db.php
- *
- * Sub-classes should define $table_name, $version, and $primary_key in __construct() method.
- *
- * @since 1.1.6
- */
- abstract class WPForms_DB {
- /**
- * Database table name.
- *
- * @since 1.1.6
- *
- * @var string
- */
- public $table_name;
- /**
- * Database version.
- *
- * @since 1.1.6
- *
- * @var string
- */
- public $version;
- /**
- * Primary key (unique field) for the database table.
- *
- * @since 1.1.6
- *
- * @var string
- */
- public $primary_key;
- /**
- * Database type identifier.
- *
- * @since 1.5.1
- *
- * @var string
- */
- public $type;
- /**
- * Retrieve the list of columns for the database table.
- * Sub-classes should define an array of columns here.
- *
- * @since 1.1.6
- *
- * @return array List of columns.
- */
- public function get_columns() {
- return [];
- }
- /**
- * Retrieve column defaults.
- * Sub-classes can define default for any/all of columns defined in the get_columns() method.
- *
- * @since 1.1.6
- *
- * @return array All defined column defaults.
- */
- public function get_column_defaults() {
- return [];
- }
- /**
- * Retrieve a row from the database based on a given row ID.
- *
- * @since 1.1.6
- *
- * @param int $row_id Row ID.
- *
- * @return null|object
- */
- public function get( $row_id ) {
- global $wpdb;
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
- return $wpdb->get_row(
- $wpdb->prepare(
- "SELECT * FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- (int) $row_id
- )
- );
- }
- /**
- * Retrieve a row based on column and row ID.
- *
- * @since 1.1.6
- *
- * @param string $column Column name.
- * @param int|string $value Column value.
- *
- * @return object|null Database query result, object or null on failure.
- */
- public function get_by( $column, $value ) {
- global $wpdb;
- if (
- empty( $value ) ||
- ! array_key_exists( $column, $this->get_columns() )
- ) {
- return null;
- }
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
- return $wpdb->get_row(
- $wpdb->prepare(
- "SELECT * FROM $this->table_name WHERE $column = %s LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $value
- )
- );
- }
- /**
- * Retrieve a value based on column name and row ID.
- *
- * @since 1.1.6
- *
- * @param string $column Column name.
- * @param int|string $row_id Row ID.
- *
- * @return string|null Database query result (as string), or null on failure.
- */
- public function get_column( $column, $row_id ) {
- global $wpdb;
- if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
- return null;
- }
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
- return $wpdb->get_var(
- $wpdb->prepare(
- "SELECT $column FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- (int) $row_id
- )
- );
- }
- /**
- * Retrieve one column value based on another given column and matching value.
- *
- * @since 1.1.6
- *
- * @param string $column Column name.
- * @param string $column_where Column to match against in the WHERE clause.
- * @param string $column_value Value to match to the column in the WHERE clause.
- *
- * @return string|null Database query result (as string), or null on failure.
- */
- public function get_column_by( $column, $column_where, $column_value ) {
- global $wpdb;
- if (
- empty( $column ) ||
- empty( $column_where ) ||
- empty( $column_value ) ||
- ! array_key_exists( $column_where, $this->get_columns() ) ||
- ! array_key_exists( $column, $this->get_columns() )
- ) {
- return null;
- }
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
- return $wpdb->get_var(
- $wpdb->prepare(
- "SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- $column_value
- )
- );
- }
- /**
- * Insert a new record into the database.
- *
- * @since 1.1.6
- *
- * @param array $data Column data.
- * @param string $type Optional. Data type context.
- *
- * @return int ID for the newly inserted record. 0 otherwise.
- */
- public function add( $data, $type = '' ) {
- global $wpdb;
- // Set default values.
- $data = (array) wp_parse_args( $data, $this->get_column_defaults() );
- do_action( 'wpforms_pre_insert_' . $type, $data );
- // Initialise column format array.
- $column_formats = $this->get_columns();
- // Force fields to lower case.
- $data = array_change_key_case( $data );
- // White list columns.
- $data = array_intersect_key( $data, $column_formats );
- // Reorder $column_formats to match the order of columns given in $data.
- $data_keys = array_keys( $data );
- $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
- $wpdb->insert( $this->table_name, $data, $column_formats );
- do_action( 'wpforms_post_insert_' . $type, $wpdb->insert_id, $data );
- return $wpdb->insert_id;
- }
- /**
- * Insert a new record into the database. This runs the add() method.
- *
- * @see add()
- *
- * @since 1.1.6
- *
- * @param array $data Column data.
- *
- * @return int ID for the newly inserted record.
- */
- public function insert( $data ) {
- return $this->add( $data );
- }
- /**
- * Update an existing record in the database.
- *
- * @since 1.1.6
- *
- * @param int|string $row_id Row ID for the record being updated.
- * @param array $data Optional. Array of columns and associated data to update. Default empty array.
- * @param string $where Optional. Column to match against in the WHERE clause. If empty, $primary_key
- * will be used. Default empty.
- * @param string $type Optional. Data type context, e.g. 'affiliate', 'creative', etc. Default empty.
- *
- * @return bool False if the record could not be updated, true otherwise.
- */
- public function update( $row_id, $data = [], $where = '', $type = '' ) {
- global $wpdb;
- // Row ID must be a positive integer.
- $row_id = absint( $row_id );
- if ( empty( $row_id ) ) {
- return false;
- }
- if ( empty( $where ) ) {
- $where = $this->primary_key;
- }
- do_action( 'wpforms_pre_update_' . $type, $data );
- // Initialise column format array.
- $column_formats = $this->get_columns();
- // Force fields to lower case.
- $data = array_change_key_case( $data );
- // White list columns.
- $data = array_intersect_key( $data, $column_formats );
- // Reorder $column_formats to match the order of columns given in $data.
- $data_keys = array_keys( $data );
- $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
- if ( $wpdb->update( $this->table_name, $data, [ $where => $row_id ], $column_formats ) === false ) {
- return false;
- }
- do_action( 'wpforms_post_update_' . $type, $data );
- return true;
- }
- /**
- * Delete a record from the database.
- *
- * @since 1.1.6
- *
- * @param int|string $row_id Row ID.
- *
- * @return bool False if the record could not be deleted, true otherwise.
- */
- public function delete( $row_id = 0 ) {
- global $wpdb;
- // Row ID must be positive integer.
- $row_id = absint( $row_id );
- if ( empty( $row_id ) ) {
- return false;
- }
- do_action( 'wpforms_pre_delete', $row_id );
- do_action( 'wpforms_pre_delete_' . $this->type, $row_id );
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- if ( $wpdb->query( $wpdb->prepare( "DELETE FROM $this->table_name WHERE $this->primary_key = %d", $row_id ) ) === false ) {
- return false;
- }
- do_action( 'wpforms_post_delete', $row_id );
- do_action( 'wpforms_post_delete_' . $this->type, $row_id );
- return true;
- }
- /**
- * Delete a record from the database by column.
- *
- * @since 1.1.6
- *
- * @param string $column Column name.
- * @param int|string $column_value Column value.
- *
- * @return bool False if the record could not be deleted, true otherwise.
- */
- public function delete_by( $column, $column_value ) {
- global $wpdb;
- if (
- empty( $column ) ||
- empty( $column_value ) ||
- ! array_key_exists( $column, $this->get_columns() )
- ) {
- return false;
- }
- do_action( 'wpforms_pre_delete', $column_value );
- do_action( 'wpforms_pre_delete_' . $this->type, $column_value );
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
- if ( $wpdb->query( $wpdb->prepare( "DELETE FROM $this->table_name WHERE $column = %s", $column_value ) ) === false ) {
- return false;
- }
- do_action( 'wpforms_post_delete', $column_value );
- do_action( 'wpforms_post_delete_' . $this->type, $column_value );
- return true;
- }
- /**
- * Delete record(s) from the database using WHERE IN syntax.
- *
- * @since 1.6.4
- *
- * @param string $column Column name.
- * @param mixed $column_values Column values.
- *
- * @return int|bool Number of deleted records, false otherwise.
- */
- public function delete_where_in( $column, $column_values ) {
- global $wpdb;
- if ( empty( $column ) || empty( $column_values ) ) {
- return false;
- }
- if ( ! array_key_exists( $column, $this->get_columns() ) ) {
- return false;
- }
- $values = is_array( $column_values ) ? $column_values : [ $column_values ];
- foreach ( $values as $key => $value ) {
- // Check if a string contains an integer and sanitize accordingly.
- if ( (string) (int) $value === $value ) {
- $values[ $key ] = (int) $value;
- $placeholders[ $key ] = '%d';
- } else {
- $values[ $key ] = sanitize_text_field( $value );
- $placeholders[ $key ] = '%s';
- }
- }
- $placeholders = isset( $placeholders ) ? implode( ',', $placeholders ) : '';
- $sql = "DELETE FROM $this->table_name WHERE $column IN ( $placeholders )";
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
- return $wpdb->query( $wpdb->prepare( $sql, $values ) );
- }
- /**
- * Check if the given table exists.
- *
- * @since 1.1.6
- * @since 1.5.9 Default value is now the current child class table name.
- *
- * @param string $table The table name. Defaults to the child class table name.
- *
- * @return bool If the table name exists.
- */
- public function table_exists( $table = '' ) {
- global $wpdb;
- if ( ! empty( $table ) ) {
- $table = sanitize_text_field( $table );
- } else {
- $table = $this->table_name;
- }
- // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
- return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
- }
- }
|