diff --git a/query.php b/query.php index 0bdeedd..839fbb4 100644 --- a/query.php +++ b/query.php @@ -391,7 +391,7 @@ private function set_prefix() { } /** - * Set columns objects + * Set columns objects. * * @since 1.0.0 */ @@ -412,7 +412,7 @@ private function set_columns() { } /** - * Set the default item shape if none exists + * Set the default item shape if none exists. * * @since 1.0.0 */ @@ -423,7 +423,7 @@ private function set_item_shape() { } /** - * Set default query vars based on columns + * Set default query vars based on columns. * * @since 1.0.0 */ @@ -489,7 +489,7 @@ private function set_query_var_defaults() { } /** - * Set the request clauses + * Set the request clauses. * * @since 1.0.0 * @@ -547,7 +547,7 @@ private function set_request_clauses( $clauses = array() ) { } /** - * Set the request + * Set the request. * * @since 1.0.0 */ @@ -699,7 +699,7 @@ private function get_date_query( $args = array() ) { } /** - * Return the current time as a UTC timestamp + * Return the current time as a UTC timestamp. * * This is used by add_item() and update_item() * @@ -723,7 +723,7 @@ private function get_table_name() { } /** - * Return array of column names + * Return array of column names. * * @since 1.0.0 * @@ -734,7 +734,7 @@ private function get_column_names() { } /** - * Return the primary database column name + * Return the primary database column name. * * @since 1.0.0 * @@ -745,7 +745,7 @@ private function get_primary_column_name() { } /** - * Get a column from an array of arguments + * Get a column from an array of arguments. * * @since 1.0.0 * @@ -753,7 +753,7 @@ private function get_primary_column_name() { */ private function get_column_field( $args = array(), $field = '', $default = false ) { - // Get column + // Get the column $column = $this->get_column_by( $args ); // Return field, or default @@ -763,7 +763,7 @@ private function get_column_field( $args = array(), $field = '', $default = fals } /** - * Get a column from an array of arguments + * Get a column from an array of arguments. * * @since 1.0.0 * @@ -781,7 +781,7 @@ private function get_column_by( $args = array() ) { } /** - * Get columns from an array of arguments + * Get columns from an array of arguments. * * @since 1.0.0 */ @@ -817,10 +817,13 @@ private function get_item_raw( $column_name = '', $column_value = '' ) { return false; } - // Query database for row - $pattern = $this->get_column_field( array( 'name' => $column_name ), 'pattern', '%s' ); + // Get query parts $table = $this->get_table_name(); - $select = $this->get_db()->prepare( "SELECT * FROM {$table} WHERE {$column_name} = {$pattern}", $column_value ); + $pattern = $this->get_column_field( array( 'name' => $column_name ), 'pattern', '%s' ); + + // Query database + $query = "SELECT * FROM {$table} WHERE {$column_name} = {$pattern} LIMIT 1"; + $select = $this->get_db()->prepare( $query, $column_value ); $result = $this->get_db()->get_row( $select ); // Bail on failure @@ -906,7 +909,8 @@ private function get_items() { * * @since 1.0.0 * - * @return int|array A single count of item IDs if a count query. An array of item IDs if a full query. + * @return int|array A single count of item IDs if a count query. An array + * of item IDs if a full query. */ private function get_item_ids() { @@ -994,7 +998,8 @@ private function get_item_ids() { private function get_order_by( $order = '' ) { // Default orderby primary column - $orderby = "{$this->parse_orderby()} {$order}"; + $parsed = $this->parse_orderby(); + $orderby = "{$parsed} {$order}"; // Disable ORDER BY if counting, or: 'none', an empty array, or false. if ( ! empty( $this->query_vars['count'] ) || in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) { @@ -1065,7 +1070,8 @@ private function get_order_by( $order = '' ) { } /** - * Used internally to generate an SQL string for searching across multiple columns. + * Used internally to generate an SQL string for searching across multiple + * columns. * * @since 1.0.0 * @@ -1125,7 +1131,7 @@ private function parse_query( $query = array() ) { } /** - * Parse the where clauses for all known columns + * Parse the where clauses for all known columns. * * @todo split this method into smaller parts * @@ -1276,7 +1282,7 @@ private function parse_where() { /** Query Classes *****************************************************/ - // Get the primary column & table + // Get the primary column name & meta table $primary = $this->get_primary_column_name(); $table = $this->get_meta_type(); $and = '/^\s*AND\s*/'; @@ -1348,7 +1354,7 @@ private function parse_where() { } /** - * Parse which fields to query for + * Parse which fields to query for. * * @since 1.0.0 * @@ -1384,7 +1390,7 @@ private function parse_fields( $fields = '', $alias = true ) { } /** - * Parses and sanitizes the 'groupby' keys passed into the item query + * Parses and sanitizes the 'groupby' keys passed into the item query. * * @since 1.0.0 * @@ -1438,7 +1444,8 @@ private function parse_groupby( $groupby = '', $alias = true ) { private function parse_orderby( $orderby = 'id' ) { // Default value - $parsed = "{$this->table_alias}.{$this->get_primary_column_name()}"; + $primary = $this->get_primary_column_name(); + $parsed = "{$this->table_alias}.{$primary}"; // __in if ( false !== strstr( $orderby, '__in' ) ) { @@ -1465,7 +1472,8 @@ private function parse_orderby( $orderby = 'id' ) { } /** - * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as necessary. + * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as + * necessary. * * @since 1.0.0 * @@ -1546,7 +1554,7 @@ private function shape_items( $items = array() ) { */ private function get_item_fields( $items = array() ) { - // Get the primary column + // Get the primary column name $primary = $this->get_primary_column_name(); $fields = $this->query_vars['fields']; @@ -1577,7 +1585,7 @@ private function get_item_fields( $items = array() ) { } /** - * Shape an item ID from an object, array, or numeric value + * Shape an item ID from an object, array, or numeric value. * * @since 1.0.0 * @@ -1633,10 +1641,10 @@ public function get_item( $item_id = 0 ) { } // Get the primary column name - $column_name = $this->get_primary_column_name(); + $primary = $this->get_primary_column_name(); // Get item by ID - return $this->get_item_by( $column_name, $item_id ); + return $this->get_item_by( $primary, $item_id ); } /** @@ -1671,7 +1679,7 @@ public function get_item_by( $column_name = '', $column_value = '' ) { return $retval; } - // Get column names + // Get the column names $columns = $this->get_column_names(); // Bail if column does not exist @@ -1710,7 +1718,7 @@ public function get_item_by( $column_name = '', $column_value = '' ) { } /** - * Add an item to the database + * Add an item to the database. * * @since 1.0.0 * @@ -1719,7 +1727,7 @@ public function get_item_by( $column_name = '', $column_value = '' ) { */ public function add_item( $data = array() ) { - // Get primary column + // Get the primary column name $primary = $this->get_primary_column_name(); // If data includes primary column, check if item already exists @@ -1801,7 +1809,39 @@ public function add_item( $data = array() ) { } /** - * Update an item in the database + * Copy an item in the database to a new item. + * + * @since 1.1.0 + * + * @param int $item_id + * @param array $data + * @return bool + */ + public function copy_item( $item_id = 0, $data = array() ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get item by ID (from database, not cache) + $item = $this->get_item_raw( $primary, $item_id ); + + // Bail if item does not exist + if ( empty( $item ) ) { + return false; + } + + // Merge data with original item + $save = array_merge( $item, $data ); + + // Unset the primary key + unset( $save[ $primary ] ); + + // Return result + return $this->add_item( $save ); + } + + /** + * Update an item in the database. * * @since 1.0.0 * @@ -1817,7 +1857,7 @@ public function update_item( $item_id = 0, $data = array() ) { return false; } - // Get primary column + // Get the primary column name $primary = $this->get_primary_column_name(); // Get item to update (from database, not cache) @@ -1860,10 +1900,10 @@ public function update_item( $item_id = 0, $data = array() ) { } // Try to update - $where = array( $primary => $item_id ); $table = $this->get_table_name(); $reduce = $this->reduce_item( 'update', $save ); $save = $this->validate_item( $reduce ); + $where = array( $primary => $item_id ); $result = ! empty( $save ) ? $this->get_db()->update( $table, $save, $where ) : false; @@ -1884,7 +1924,7 @@ public function update_item( $item_id = 0, $data = array() ) { } /** - * Delete an item from the database + * Delete an item from the database. * * @since 1.0.0 * @@ -1899,7 +1939,7 @@ public function delete_item( $item_id = 0 ) { return false; } - // Get vars + // Get the primary column name $primary = $this->get_primary_column_name(); // Get item (before it's deleted) @@ -1919,9 +1959,9 @@ public function delete_item( $item_id = 0 ) { } // Try to delete - $table = $this->get_table_name(); - $where = array( $primary => $item_id ); - $result = $this->get_db()->delete( $table, $where ); + $table = $this->get_table_name(); + $where = array( $primary => $item_id ); + $result = $this->get_db()->delete( $table, $where ); // Bail on failure if ( ! $this->is_success( $result ) ) { @@ -2004,7 +2044,7 @@ private function validate_item( $item = array() ) { $value = stripslashes( $value ); } - // Get column + // Get the column $column = $this->get_column_by( array( 'name' => $key ) ); // Null value is special for all item keys @@ -2067,7 +2107,7 @@ private function reduce_item( $method = 'update', $item = array() ) { // Loop through item attributes foreach ( $item as $key => $value ) { - // Get callback for column + // Get capabilities for this column $caps = $this->get_column_field( array( 'name' => $key ), 'caps' ); // Unset if not explicitly allowed @@ -2091,7 +2131,7 @@ private function reduce_item( $method = 'update', $item = array() ) { } /** - * Return an item comprised of all default values + * Return an item comprised of all default values. * * This is used by `add_item()` to populate known default values, to ensure * new item data is always what we expect it to be. @@ -2105,7 +2145,7 @@ private function default_item() { // Default return value $retval = array(); - // Get column names and defaults + // Get the column names and their defaults $names = $this->get_columns( array(), 'and', 'name' ); $defaults = $this->get_columns( array(), 'and', 'default' ); @@ -2193,7 +2233,7 @@ private function transition_item( $new_data = array(), $old_data = array() ) { /** Meta ******************************************************************/ /** - * Add meta data to an item + * Add meta data to an item. * * @since 1.0.0 * @@ -2216,7 +2256,7 @@ protected function add_item_meta( $item_id = 0, $meta_key = '', $meta_value = '' return false; } - // Get meta type + // Get the meta type $meta_type = $this->get_meta_type(); // Return results of adding meta data @@ -2224,7 +2264,7 @@ protected function add_item_meta( $item_id = 0, $meta_key = '', $meta_value = '' } /** - * Get meta data for an item + * Get meta data for an item. * * @since 1.0.0 * @@ -2246,7 +2286,7 @@ protected function get_item_meta( $item_id = 0, $meta_key = '', $single = false return false; } - // Get meta type + // Get the meta type $meta_type = $this->get_meta_type(); // Return results of getting meta data @@ -2254,7 +2294,7 @@ protected function get_item_meta( $item_id = 0, $meta_key = '', $single = false } /** - * Update meta data for an item + * Update meta data for an item. * * @since 1.0.0 * @@ -2277,7 +2317,7 @@ protected function update_item_meta( $item_id = 0, $meta_key = '', $meta_value = return false; } - // Get meta type + // Get the meta type $meta_type = $this->get_meta_type(); // Return results of updating meta data @@ -2285,7 +2325,7 @@ protected function update_item_meta( $item_id = 0, $meta_key = '', $meta_value = } /** - * Delete meta data for an item + * Delete meta data for an item. * * @since 1.0.0 * @@ -2308,7 +2348,7 @@ protected function delete_item_meta( $item_id = 0, $meta_key = '', $meta_value = return false; } - // Get meta type + // Get the meta type $meta_type = $this->get_meta_type(); // Return results of deleting meta data @@ -2316,7 +2356,7 @@ protected function delete_item_meta( $item_id = 0, $meta_key = '', $meta_value = } /** - * Get registered meta data keys + * Get registered meta data keys. * * @since 1.0.0 * @@ -2334,7 +2374,7 @@ private function get_registered_meta_keys( $object_subtype = '' ) { } /** - * Maybe update meta values on item update/save + * Maybe update meta values on item update/save. * * @since 1.0.0 * @@ -2371,7 +2411,7 @@ private function save_extra_item_meta( $item_id = 0, $meta = array() ) { } /** - * Delete all meta data for an item + * Delete all meta data for an item. * * @since 1.0.0 * @@ -2385,7 +2425,7 @@ private function delete_all_item_meta( $item_id = 0 ) { return; } - // Get meta table name + // Get the meta table name $table = $this->get_meta_table_name(); // Bail if no meta table exists @@ -2398,8 +2438,8 @@ private function delete_all_item_meta( $item_id = 0 ) { $item_id_column = $this->apply_prefix( "{$this->item_name}_{$primary_id}" ); // Get meta IDs - $sql = "SELECT meta_id FROM {$table} WHERE {$item_id_column} = %d"; - $prepared = $this->get_db()->prepare( $sql, $item_id ); + $query = "SELECT meta_id FROM {$table} WHERE {$item_id_column} = %d"; + $prepared = $this->get_db()->prepare( $query, $item_id ); $meta_ids = $this->get_db()->get_col( $prepared ); // Bail if no meta IDs to delete @@ -2417,7 +2457,7 @@ private function delete_all_item_meta( $item_id = 0 ) { } /** - * Get the meta table for this query + * Get the meta table for this query. * * Forked from WordPress\_get_meta_table() so it can be more accurately * predicted in a future iteration and default to returning false. @@ -2447,7 +2487,7 @@ private function get_meta_table_name() { } /** - * Get the meta type for this query + * Get the meta type for this query. * * This method exists to reduce some duplication for now. Future iterations * will likely use Column::relationships to @@ -2511,7 +2551,7 @@ private function get_cache_group( $group = '' ) { } /** - * Get array of which database columns have uniquely cached groups + * Get array of which database columns have uniquely cached groups. * * @since 1.0.0 * @@ -2522,12 +2562,12 @@ private function get_cache_groups() { // Return value $cache_groups = array(); - // Get cache groups + // Get the cache groups $groups = $this->get_columns( array( 'cache_key' => true ), 'and', 'name' ); if ( ! empty( $groups ) ) { - // Get the primary column + // Get the primary column name $primary = $this->get_primary_column_name(); // Setup return values @@ -2582,11 +2622,13 @@ private function prime_item_caches( $item_ids = array(), $force = false ) { return false; } - // Query + // Get query parts $table = $this->get_table_name(); $primary = $this->get_primary_column_name(); + + // Query database $query = "SELECT * FROM {$table} WHERE {$primary} IN (%s)"; - $ids = join( ',', array_map( 'absint', $ids ) ); + $ids = implode( ',', array_map( 'absint', $ids ) ); $prepare = sprintf( $query, $ids ); $results = $this->get_db()->get_results( $prepare ); @@ -2632,7 +2674,7 @@ private function update_item_cache( $items = array() ) { $items = array( $items ); } - // Get cache groups + // Get the cache groups $groups = $this->get_cache_groups(); // Loop through all items and cache them @@ -2682,7 +2724,7 @@ private function clean_item_cache( $items = array() ) { $items = array( $items ); } - // Get all cache groups + // Get the cache groups $groups = $this->get_cache_groups(); // Loop through all items and clean them @@ -2706,9 +2748,11 @@ private function clean_item_cache( $items = array() ) { } /** - * Update the last_changed key for the cache group + * Update the last_changed key for the cache group. * * @since 1.0.0 + * + * @return string The last time a cache group was changed. */ private function update_last_changed_cache( $group = '' ) { @@ -2725,13 +2769,13 @@ private function update_last_changed_cache( $group = '' ) { } /** - * Get the last_changed key for a cache group + * Get the last_changed key for a cache group. * * @since 1.0.0 * * @param string $group Cache group. Defaults to $this->cache_group * - * @return int The last time a cache group was changed + * @return string The last time a cache group was changed. */ private function get_last_changed_cache( $group = '' ) { @@ -2826,7 +2870,7 @@ private function cache_get( $key = '', $group = '', $force = false ) { // Get the cache group $group = $this->get_cache_group( $group ); - // Get from the cache + // Return from the cache return wp_cache_get( $key, $group, $force ); } @@ -2914,28 +2958,36 @@ private function cache_delete( $key = '', $group = '' ) { */ public function get_results( $cols = array(), $where_cols = array(), $limit = 25, $offset = null, $output = OBJECT ) { - // Bail if no columns have been passed. + // Bail if no columns have been passed if ( empty( $cols ) ) { return null; } - // Fetch all the columns for the table being queried. + // Fetch all the columns for the table being queried $column_names = $this->get_column_names(); - // Ensure valid column names have been passed for the `SELECT` clause. + // Ensure valid column names have been passed for the `SELECT` clause foreach ( $cols as $index => $column ) { if ( ! array_key_exists( $column, $column_names ) ) { unset( $cols[ $index ] ); } } - // Setup base SQL query. - $query = "SELECT "; - $query .= implode( ',', $cols ); - $query .= " FROM {$this->get_table_name()} {$this->table_alias} "; - $query .= " WHERE 1=1 "; + // Columns to retrieve + $columns = implode( ',', $cols ); + + // Get the table name + $table = $this->get_table_name(); + + // Setup base query + $query = implode( ' ', array( + "SELECT", + $columns, + "FROM {$table} {$this->table_alias}", + "WHERE 1=1" + ) ); - // Ensure valid columns have been passed for the `WHERE` clause. + // Ensure valid columns have been passed for the `WHERE` clause if ( ! empty( $where_cols ) ) { // Get keys from where columns @@ -2948,27 +3000,27 @@ public function get_results( $cols = array(), $where_cols = array(), $limit = 25 } } - // Parse WHERE clauses. + // Parse WHERE clauses foreach ( $where_cols as $column => $compare ) { - // Basic WHERE clause. + // Basic WHERE clause if ( ! is_array( $compare ) ) { $pattern = $this->get_column_field( array( 'name' => $column ), 'pattern', '%s' ); $statement = " AND {$this->table_alias}.{$column} = {$pattern} "; $query .= $this->get_db()->prepare( $statement, $compare ); - // More complex WHERE clause. + // More complex WHERE clause } else { $value = isset( $compare['value'] ) ? $compare['value'] : false; - // Skip if a value was not provided. + // Skip if a value was not provided if ( false === $value ) { continue; } - // Default compare clause to equals. + // Default compare clause to equals $compare_clause = isset( $compare['compare_query'] ) ? trim( strtoupper( $compare['compare_query'] ) ) : '='; @@ -2976,16 +3028,16 @@ public function get_results( $cols = array(), $where_cols = array(), $limit = 25 // Array (unprepared) if ( is_array( $compare['value'] ) ) { - // Default to IN if clause not specified. + // Default to IN if clause not specified if ( ! in_array( $compare_clause, array( 'IN', 'NOT IN', 'BETWEEN' ), true ) ) { $compare_clause = 'IN'; } - // Parse & escape for IN and NOT IN. + // Parse & escape for IN and NOT IN if ( 'IN' === $compare_clause || 'NOT IN' === $compare_clause ) { $value = "('" . implode( "','", $this->get_db()->_escape( $compare['value'] ) ) . "')"; - // Parse & escape for BETWEEN. + // Parse & escape for BETWEEN } elseif ( is_array( $value ) && 2 === count( $value ) && 'BETWEEN' === $compare_clause ) { $_this = $this->get_db()->_escape( $value[0] ); $_that = $this->get_db()->_escape( $value[1] ); @@ -2993,13 +3045,13 @@ public function get_results( $cols = array(), $where_cols = array(), $limit = 25 } } - // Add WHERE clause. + // Add WHERE clause $query .= " AND {$this->table_alias}.{$column} {$compare_clause} {$value} "; } } } - // Maybe set an offset. + // Maybe set an offset if ( ! empty( $offset ) ) { $values = explode( ',', $offset ); $values = array_filter( $values, 'intval' ); @@ -3007,16 +3059,16 @@ public function get_results( $cols = array(), $where_cols = array(), $limit = 25 $query .= " OFFSET {$offset} "; } - // Maybe set a limit. + // Maybe set a limit if ( ! empty( $limit ) && ( $limit > 0 ) ) { $limit = intval( $limit ); $query .= " LIMIT {$limit} "; } - // Execute query. + // Execute query $results = $this->get_db()->get_results( $query, $output ); - // Return results. + // Return results return $results; } } diff --git a/table.php b/table.php index fa5f705..66ee846 100644 --- a/table.php +++ b/table.php @@ -591,10 +591,15 @@ public function index_exists( $name = '', $column = 'Key_name' ) { return false; } + // Limit $column to Key or Column name, until we can do better + if ( ! in_array( $column, array( 'Key_name', 'Column_name' ), true ) ) { + $column = 'Key_name'; + } + // Query statement - $query = "SHOW INDEXES FROM {$this->table_name} WHERE %s LIKE %s"; + $query = "SHOW INDEXES FROM {$this->table_name} WHERE {$column} LIKE %s"; $like = $db->esc_like( $name ); - $prepared = $db->prepare( $query, $column, $like ); + $prepared = $db->prepare( $query, $like ); $result = $db->query( $prepared ); // Does the index exist?