Add DBA::collapseCondition method
- Update Database->update for use with DBA::collapseCondition
This commit is contained in:
		
					parent
					
						
							
								5cc2dc7ca3
							
						
					
				
			
			
				commit
				
					
						ef6e9ef26b
					
				
			
		
					 2 changed files with 89 additions and 61 deletions
				
			
		|  | @ -529,67 +529,96 @@ class DBA | |||
| 	 */ | ||||
| 	public static function buildCondition(array &$condition = []) | ||||
| 	{ | ||||
| 		$condition = self::collapseCondition($condition); | ||||
| 		 | ||||
| 		$condition_string = ''; | ||||
| 		if (count($condition) > 0) { | ||||
| 			reset($condition); | ||||
| 			$first_key = key($condition); | ||||
| 			if (is_int($first_key)) { | ||||
| 				$condition_string = " WHERE (" . array_shift($condition) . ")"; | ||||
| 			} else { | ||||
| 				$new_values = []; | ||||
| 				$condition_string = ""; | ||||
| 				foreach ($condition as $field => $value) { | ||||
| 					if ($condition_string != "") { | ||||
| 						$condition_string .= " AND "; | ||||
| 					} | ||||
| 					if (is_array($value)) { | ||||
| 						if (count($value)) { | ||||
| 							/* Workaround for MySQL Bug #64791.
 | ||||
| 							 * Never mix data types inside any IN() condition. | ||||
| 							 * In case of mixed types, cast all as string. | ||||
| 							 * Logic needs to be consistent with DBA::p() data types. | ||||
| 							 */ | ||||
| 							$is_int = false; | ||||
| 							$is_alpha = false; | ||||
| 							foreach ($value as $single_value) { | ||||
| 								if (is_int($single_value)) { | ||||
| 									$is_int = true; | ||||
| 								} else { | ||||
| 									$is_alpha = true; | ||||
| 								} | ||||
| 							} | ||||
| 
 | ||||
| 							if ($is_int && $is_alpha) { | ||||
| 								foreach ($value as &$ref) { | ||||
| 									if (is_int($ref)) { | ||||
| 										$ref = (string)$ref; | ||||
| 									} | ||||
| 								} | ||||
| 								unset($ref); //Prevent accidental re-use.
 | ||||
| 							} | ||||
| 
 | ||||
| 							$new_values = array_merge($new_values, array_values($value)); | ||||
| 							$placeholders = substr(str_repeat("?, ", count($value)), 0, -2); | ||||
| 							$condition_string .= self::quoteIdentifier($field) . " IN (" . $placeholders . ")"; | ||||
| 						} else { | ||||
| 							// Empty value array isn't supported by IN and is logically equivalent to no match
 | ||||
| 							$condition_string .= "FALSE"; | ||||
| 						} | ||||
| 					} elseif (is_null($value)) { | ||||
| 						$condition_string .= self::quoteIdentifier($field) . " IS NULL"; | ||||
| 					} else { | ||||
| 						$new_values[$field] = $value; | ||||
| 						$condition_string .= self::quoteIdentifier($field) . " = ?"; | ||||
| 					} | ||||
| 				} | ||||
| 				$condition_string = " WHERE (" . $condition_string . ")"; | ||||
| 				$condition = $new_values; | ||||
| 			} | ||||
| 			$condition_string = " WHERE (" . array_shift($condition) . ")"; | ||||
| 		} | ||||
| 
 | ||||
| 		return $condition_string; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Collapse an associative array condition into a SQL string + parameters condition array. | ||||
| 	 * | ||||
| 	 * ['uid' => 1, 'network' => ['dspr', 'apub']] | ||||
| 	 * | ||||
| 	 * gets transformed into | ||||
| 	 * | ||||
| 	 * ["`uid` = ? AND `network` IN (?, ?)", 1, 'dspr', 'apub'] | ||||
| 	 * | ||||
| 	 * @param array $condition | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public static function collapseCondition(array $condition) | ||||
| 	{ | ||||
| 		// Ensures an always true condition is returned
 | ||||
| 		if (count($condition) < 1) { | ||||
| 			return ['1']; | ||||
| 		} | ||||
| 
 | ||||
| 		reset($condition); | ||||
| 		$first_key = key($condition); | ||||
| 
 | ||||
| 		if (is_int($first_key)) { | ||||
| 			// Already collapsed
 | ||||
| 			return $condition; | ||||
| 		} | ||||
| 
 | ||||
| 		$values = []; | ||||
| 		$condition_string = ""; | ||||
| 		foreach ($condition as $field => $value) { | ||||
| 			if ($condition_string != "") { | ||||
| 				$condition_string .= " AND "; | ||||
| 			} | ||||
| 
 | ||||
| 			if (is_array($value)) { | ||||
| 				if (count($value)) { | ||||
| 					/* Workaround for MySQL Bug #64791.
 | ||||
| 					 * Never mix data types inside any IN() condition. | ||||
| 					 * In case of mixed types, cast all as string. | ||||
| 					 * Logic needs to be consistent with DBA::p() data types. | ||||
| 					 */ | ||||
| 					$is_int = false; | ||||
| 					$is_alpha = false; | ||||
| 					foreach ($value as $single_value) { | ||||
| 						if (is_int($single_value)) { | ||||
| 							$is_int = true; | ||||
| 						} else { | ||||
| 							$is_alpha = true; | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 					if ($is_int && $is_alpha) { | ||||
| 						foreach ($value as &$ref) { | ||||
| 							if (is_int($ref)) { | ||||
| 								$ref = (string)$ref; | ||||
| 							} | ||||
| 						} | ||||
| 						unset($ref); //Prevent accidental re-use.
 | ||||
| 					} | ||||
| 
 | ||||
| 					$values = array_merge($values, array_values($value)); | ||||
| 					$placeholders = substr(str_repeat("?, ", count($value)), 0, -2); | ||||
| 					$condition_string .= self::quoteIdentifier($field) . " IN (" . $placeholders . ")"; | ||||
| 				} else { | ||||
| 					// Empty value array isn't supported by IN and is logically equivalent to no match
 | ||||
| 					$condition_string .= "FALSE"; | ||||
| 				} | ||||
| 			} elseif (is_null($value)) { | ||||
| 				$condition_string .= self::quoteIdentifier($field) . " IS NULL"; | ||||
| 			} else { | ||||
| 				$values[$field] = $value; | ||||
| 				$condition_string .= self::quoteIdentifier($field) . " = ?"; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$condition = array_merge([$condition_string], array_values($values)); | ||||
| 
 | ||||
| 		return $condition; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @brief Returns the SQL parameter string built from the provided parameter array | ||||
| 	 * | ||||
|  |  | |||
|  | @ -1327,10 +1327,6 @@ class Database | |||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		$table_string = DBA::buildTableString($table); | ||||
| 
 | ||||
| 		$condition_string = DBA::buildCondition($condition); | ||||
| 
 | ||||
| 		if (is_bool($old_fields)) { | ||||
| 			$do_insert = $old_fields; | ||||
| 
 | ||||
|  | @ -1361,13 +1357,16 @@ class Database | |||
| 			return true; | ||||
| 		} | ||||
| 
 | ||||
| 		$table_string = DBA::buildTableString($table); | ||||
| 
 | ||||
| 		$condition_string = DBA::buildCondition($condition); | ||||
| 
 | ||||
| 		$sql = "UPDATE " . $table_string . " SET " | ||||
| 			. implode(" = ?, ", array_map([DBA::class, 'quoteIdentifier'], array_keys($fields))) . " = ?" | ||||
| 			. $condition_string; | ||||
| 
 | ||||
| 		$params1 = array_values($fields); | ||||
| 		$params2 = array_values($condition); | ||||
| 		$params  = array_merge_recursive($params1, $params2); | ||||
| 		// Combines the updated fields parameter values with the condition parameter values
 | ||||
| 		$params  = array_merge(array_values($fields), $condition); | ||||
| 
 | ||||
| 		return $this->e($sql, $params); | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue