/** * Prepares a ShoppDatabaseObject for entry into the database * * Iterates the properties of a ShoppDatabaseObject and formats the data * according to the datatype meta available for the property to create * an array of key/value pairs that are easy concatenate into a valid * SQL query * * @author Jonathan Davis * @since 1.0 * * @param ShoppDatabaseObject $Object The object to be prepared * @return array Data structure ready for query building **/ public static function prepare($Object, array $mapping = array()) { $data = array(); // Go through each data property of the object $properties = get_object_vars($Object); foreach ($properties as $var => $value) { $property = isset($mapping[$var]) ? $mapping[$var] : $var; if (!isset($Object->_datatypes[$property])) { continue; } // If the property is has a _datatype // it belongs in the database and needs // to be prepared // Process the data switch ($Object->_datatypes[$property]) { case 'string': // Escape characters in strings as needed if (is_array($value) || is_object($value)) { $data[$property] = "'" . addslashes(serialize($value)) . "'"; } else { $data[$property] = "'" . sDB::escape($value) . "'"; } break; case 'list': // If value is empty, skip setting the field // so it inherits the default value in the db if (!empty($value)) { $data[$property] = "'{$value}'"; } break; case 'date': // If it's an empty date, set it to the current time if (is_null($value)) { $value = current_time('mysql'); // If the date is an integer, convert it to an // sql YYYY-MM-DD HH:MM:SS format } elseif (!empty($value) && (is_int($value) || intval($value) > 86400)) { $value = sDB::mkdatetime(intval($value)); } $data[$property] = "'{$value}'"; break; case 'float': // Sanitize without rounding to protect precision if (is_string($value) && method_exists('ShoppCore', 'floatval')) { $value = ShoppCore::floatval($value, false); } else { $value = floatval($value); } case 'int': // Normalize for MySQL float representations (@see bug #853) // Force formating with full stop (.) decimals // Trim excess 0's followed by trimming (.) when there is no fractional value $value = rtrim(rtrim(number_format((double) $value, 6, '.', ''), '0'), '.'); $data[$property] = "'{$value}'"; if (empty($value)) { $data[$property] = "'0'"; } // Special exception for id fields if ('id' == $property && empty($value)) { $data[$property] = "NULL"; } break; default: // Anything not needing processing // passes through into the structure $data[$property] = "'{$value}'"; } } return $data; }
/** * Converts a numeric string to a floating point number * * @author Jonathan Davis * @since 1.0 * * @param string $value Numeric string to be converted * @param boolean $round (optional) Whether to round the value (default true for to round) * @param array $format (optional) The currency format to use for precision (defaults to the current base of operations) * @return float **/ public static function floatval($value, $round = true, array $format = array()) { $format = ShoppCore::currency_format($format); // Use ShoppCore here instead of Shopp here extract($format, EXTR_SKIP); $float = false; if (is_float($value)) { $float = $value; } $value = str_replace($currency, '', $value); // Strip the currency symbol if (!empty($thousands)) { $value = str_replace($thousands, '', $value); } // Remove thousands $value = preg_replace('/[^\\d\\,\\.\\·\'\\-]/', '', $value); // Remove any non-numeric string data // If we have full-stop decimals, try casting it to skip the funky stuff if ('.' == $decimals && (double) $value > 0) { $float = (double) $value; } if (false === $float) { // Nothing else worked, time to get down and dirty $value = preg_replace('/^\\./', '', $value); // Remove any decimals at the beginning of the string if ($precision > 0) { // Don't convert decimals if not required $value = preg_replace('/\\' . $decimals . '/', '.', $value); } // Convert decimal delimter $float = (double) $value; } return $round ? round($float, $precision) : $float; }