/** * Sets the money column and then tries to objectify it with an related currency column * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @param string $method_name The method that was called * @param array $parameters The parameters passed to the method * @return fActiveRecord The record object, to allow for method chaining */ public static function setMoneyColumn($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters) { list($action, $column) = fORM::parseMethod($method_name); $class = get_class($object); if (count($parameters) < 1) { throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name); } $value = $parameters[0]; fActiveRecord::assign($values, $old_values, $column, $value); $currency_column = self::$money_columns[$class][$column]; // See if we can make an fMoney object out of the values self::objectifyMoneyWithCurrency($values, $old_values, $column, $currency_column); if ($currency_column) { if ($value instanceof fMoney) { fActiveRecord::assign($values, $old_values, $currency_column, $value->getCurrency()); } } return $object; }
/** * Uploads a file * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @param string $method_name The method that was called * @param array $parameters The parameters passed to the method * @return fFile The uploaded file */ public static function upload($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters) { $class = get_class($object); list($action, $column) = fORM::parseMethod($method_name); $existing_temp_file = FALSE; // Try to upload the file putting it in the temp dir incase there is a validation problem with the record try { $upload_dir = self::$file_upload_columns[$class][$column]; $temp_dir = self::prepareTempDir($upload_dir); if (!fUpload::check($column)) { throw new fExpectedException('Please upload a file'); } $uploader = self::setUpFUpload($class, $column); $file = $uploader->move($temp_dir, $column); // If there was an eror, check to see if we have an existing file } catch (fExpectedException $e) { // If there is an existing file and none was uploaded, substitute the existing file $existing_file = fRequest::get('existing-' . $column); $delete_file = fRequest::get('delete-' . $column, 'boolean'); $no_upload = $e->getMessage() == self::compose('Please upload a file'); if ($existing_file && $delete_file && $no_upload) { $file = NULL; } elseif ($existing_file) { $file_path = $upload_dir->getPath() . $existing_file; $file = fFilesystem::createObject($file_path); $current_file = $values[$column]; // If the existing file is the same as the current file, we can just exit now if ($current_file && $file->getPath() == $current_file->getPath()) { return; } $existing_temp_file = TRUE; } else { $file = NULL; } } // Assign the file fActiveRecord::assign($values, $old_values, $column, $file); // Perform the file upload inheritance if (!empty(self::$column_inheritence[$class][$column])) { foreach (self::$column_inheritence[$class][$column] as $other_column) { if ($file) { // Image columns will only inherit if it is an fImage object if (!$file instanceof fImage && isset(self::$image_upload_columns[$class][$other_column])) { continue; } $other_upload_dir = self::$file_upload_columns[$class][$other_column]; $other_temp_dir = self::prepareTempDir($other_upload_dir); if ($existing_temp_file) { $other_file = fFilesystem::createObject($other_temp_dir->getPath() . $file->getName()); } else { $other_file = $file->duplicate($other_temp_dir, FALSE); } } else { $other_file = $file; } fActiveRecord::assign($values, $old_values, $other_column, $other_file); if (!$existing_temp_file && $other_file) { self::processImage($class, $other_column, $other_file); } } } // Process the file if (!$existing_temp_file && $file) { self::processImage($class, $column, $file); } return $file; }
/** * Sets the timezone column and then tries to objectify the related timestamp column * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @param string $method_name The method that was called * @param array $parameters The parameters passed to the method * @return fActiveRecord The record object, to allow for method chaining */ public static function setTimezoneColumn($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters) { list($action, $subject) = fORM::parseMethod($method_name); $column = fGrammar::underscorize($subject); $class = get_class($object); if (!isset($parameters[0])) { throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name); } fActiveRecord::assign($values, $old_values, $column, $parameters[0]); // See if we can make an fTimestamp object out of the values self::objectifyTimestampWithTimezone($values, $old_values, self::$timezone_columns[$class][$column], $column); return $object; }
/** * Re-orders the object based on it's current state and new position * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @return void */ public static function reorder($object, &$values, &$old_values, &$related_records, &$cache) { $class = get_class($object); $table = fORM::tablize($class); $db = fORMDatabase::retrieve($class, 'write'); $schema = fORMSchema::retrieve($class); foreach (self::$ordering_columns[$class] as $column => $other_columns) { $current_value = $values[$column]; if (!$object->exists()) { $old_value = fActiveRecord::retrieveOld($old_values, $column); } else { $params = array("SELECT %r FROM %r WHERE ", $column, $table); $params = fORMDatabase::addPrimaryKeyWhereParams($schema, $params, $table, $table, $values, $old_values); $old_value = call_user_func_array($db->translatedQuery, $params)->fetchScalar(); } // Figure out the range we are dealing with $params = array("SELECT MAX(%r) FROM %r", $column, $table); if ($other_columns) { $params[0] .= ' WHERE '; $params = self::addOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values); } $current_max_value = (int) call_user_func_array($db->translatedQuery, $params)->fetchScalar(); $new_max_value = $current_max_value; if ($new_set = self::isInNewSet($column, $other_columns, $values, $old_values)) { $new_max_value = $current_max_value + 1; } $changed = FALSE; // If a blank value was set, correct it to the old value (if there // was one), or a new value at the end of the set if ($current_value === '' || $current_value === NULL) { if ($old_value) { $current_value = $old_value; } else { $current_value = $new_max_value; } $changed = TRUE; } // When we move an object into a new set and the value didn't change then move it to the end of the new set if ($new_set && $object->exists() && ($old_value === NULL || $old_value == $current_value)) { $current_value = $new_max_value; $changed = TRUE; } // If the value is too high, then set it to the last value if ($current_value > $new_max_value) { $current_value = $new_max_value; $changed = TRUE; } if ($changed) { fActiveRecord::assign($values, $old_values, $column, $current_value); } // If the value didn't change, we can exit $value_didnt_change = $old_value && $current_value == $old_value || !$old_value; if (!$new_set && $value_didnt_change) { continue; } // If we are entering a new record at the end of the set we don't need to shuffle anything either if (!$object->exists() && $new_set && $current_value == $new_max_value) { continue; } // If the object already exists in the database, grab the ordering value // right now in case some other object reordered it since it was loaded if ($object->exists()) { $params = array("SELECT %r FROM %r WHERE ", $column, $table); $params = fORMDatabase::addPrimaryKeyWhereParams($schema, $params, $table, $table, $values, $old_values); $db_value = (int) call_user_func_array($db->translatedQuery, $params)->fetchScalar(); } // We only need to move things in the new set around if we are inserting into the middle // of a new set, or if we are moving around in the current set if (!$new_set || $new_set && $current_value != $new_max_value) { $shift_down = $new_max_value + 10; // To prevent issues with the unique constraint, we move everything below 0 $params = array("UPDATE %r SET %r = %r - %i WHERE ", $table, $column, $column, $shift_down); $conditions = array(); // If we are moving into the middle of a new set we just push everything up one value if ($new_set) { $shift_up = $new_max_value + 11; $conditions[] = fORMDatabase::makeCondition($schema, $table, $column, '>=', $current_value); $params[] = $table . '.' . $column; $params[] = $current_value; // If we are moving a value down in a set, we push values in the difference zone up one } elseif ($current_value < $db_value) { $shift_up = $new_max_value + 11; $conditions[] = fORMDatabase::makeCondition($schema, $table, $column, '<', $db_value); $params[] = $table . '.' . $column; $params[] = $db_value; $conditions[] = fORMDatabase::makeCondition($schema, $table, $column, '>=', $current_value); $params[] = $table . '.' . $column; $params[] = $current_value; // If we are moving a value up in a set, we push values in the difference zone down one } else { $shift_up = $new_max_value + 9; $conditions[] = fORMDatabase::makeCondition($schema, $table, $column, '>', $db_value); $params[] = $table . '.' . $column; $params[] = $db_value; $conditions[] = fORMDatabase::makeCondition($schema, $table, $column, '<=', $current_value); $params[] = $table . '.' . $column; $params[] = $current_value; } $params[0] .= join(' AND ', $conditions); if ($other_columns) { $params[0] .= " AND "; $params = self::addOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values); } call_user_func_array($db->translatedQuery, $params); if ($object->exists()) { // Put the actual record we are changing in limbo to be updated when the actual update happens $params = array("UPDATE %r SET %r = 0 WHERE %r = %i", $table, $column, $column, $db_value); if ($other_columns) { $params[0] .= " AND "; $params = self::addOldOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values, $old_values); } call_user_func_array($db->translatedQuery, $params); } // Anything below zero needs to be moved back up into its new position $params = array("UPDATE %r SET %r = %r + %i WHERE %r < 0", $table, $column, $column, $shift_up, $column); if ($other_columns) { $params[0] .= " AND "; $params = self::addOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values); } call_user_func_array($db->translatedQuery, $params); } // If there was an old set, we need to close the gap if ($object->exists() && $new_set) { $params = array("SELECT MAX(%r) FROM %r WHERE ", $column, $table); $params = self::addOldOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values, $old_values); $old_set_max = (int) call_user_func_array($db->translatedQuery, $params)->fetchScalar(); // We only need to close the gap if the record was not at the end if ($db_value < $old_set_max) { $shift_down = $old_set_max + 10; $shift_up = $old_set_max + 9; // To prevent issues with the unique constraint, we move everything below 0 and then back up above $params = array("UPDATE %r SET %r = %r - %i WHERE %r > %i AND ", $table, $column, $column, $shift_down, $column, $db_value); $params = self::addOldOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values, $old_values); call_user_func_array($db->translatedQuery, $params); if ($current_value == $new_max_value) { // Put the actual record we are changing in limbo to be updated when the actual update happens $params = array("UPDATE %r SET %r = 0 WHERE %r = %i", $table, $column, $column, $db_value); if ($other_columns) { $params[0] .= " AND "; $params = self::addOldOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values, $old_values); } call_user_func_array($db->translatedQuery, $params); } $params = array("UPDATE %r SET %r = %r + %i WHERE %r < 0 AND ", $table, $column, $column, $shift_up, $column); $params = self::addOldOtherFieldsWhereParams($schema, $params, $table, $other_columns, $values, $old_values); call_user_func_array($db->translatedQuery, $params); } } } }
/** * Re-orders the object based on it's current state and new position * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @return void */ public static function reorder($object, &$values, &$old_values, &$related_records, &$cache) { $class = get_class($object); $table = fORM::tablize($class); $column = self::$ordering_columns[$class]['column']; $other_columns = self::$ordering_columns[$class]['other_columns']; $current_value = $values[$column]; if (!$object->exists()) { $old_value = fActiveRecord::retrieveOld($old_values, $column); } else { $old_value = fORMDatabase::retrieve()->translatedQuery("SELECT " . $column . " FROM " . $table . " WHERE " . fORMDatabase::createPrimaryKeyWhereClause($table, $table, $values, $old_values))->fetchScalar(); } // Figure out the range we are dealing with $sql = "SELECT max(" . $column . ") FROM " . $table; if ($other_columns) { $sql .= " WHERE " . self::createOtherFieldsWhereClause($table, $other_columns, $values); } $current_max_value = (int) fORMDatabase::retrieve()->translatedQuery($sql)->fetchScalar(); $new_max_value = $current_max_value; if ($new_set = self::isInNewSet($column, $other_columns, $values, $old_values)) { $new_max_value = $current_max_value + 1; } $changed = FALSE; // If a blank value was set, correct it to the old value (if there // was one), or a new value at the end of the set if ($current_value === '' || $current_value === NULL) { if ($old_value) { $current_value = $old_value; } else { $current_value = $new_max_value; } $changed = TRUE; } // When we move an object into a new set and the value didn't change then move it to the end of the new set if ($new_set && $object->exists() && ($old_value === NULL || $old_value == $current_value)) { $current_value = $new_max_value; $changed = TRUE; } // If the value is too high, then set it to the last value if ($current_value > $new_max_value) { $current_value = $new_max_value; $changed = TRUE; } if ($changed) { fActiveRecord::assign($values, $old_values, $column, $current_value); } // If the value didn't change, we can exit $value_didnt_change = $old_value && $current_value == $old_value || !$old_value; if (!$new_set && $value_didnt_change) { return; } // If we are entering a new record at the end of the set we don't need to shuffle anything either if (!$object->exists() && $new_set && $current_value == $new_max_value) { return; } // If the object already exists in the database, grab the ordering value // right now in case some other object reordered it since it was loaded if ($object->exists()) { $sql = "SELECT " . $column . " FROM " . $table . " WHERE "; $sql .= fORMDatabase::createPrimaryKeyWhereClause($table, $table, $values, $old_values); $db_value = (int) fORMDatabase::retrieve()->translatedQuery($sql)->fetchScalar(); } // We only need to move things in the new set around if we are inserting into the middle // of a new set, or if we are moving around in the current set if (!$new_set || $new_set && $current_value != $new_max_value) { $shift_down = $new_max_value + 10; // If we are moving into the middle of a new set we just push everything up one value if ($new_set) { $shift_up = $new_max_value + 11; $down_condition = $column . " >= " . $current_value; // If we are moving a value down in a set, we push values in the difference zone up one } elseif ($current_value < $db_value) { $shift_up = $new_max_value + 11; $down_condition = $column . " < " . $db_value . " AND " . $column . " >= " . $current_value; // If we are moving a value up in a set, we push values in the difference zone down one } else { $shift_up = $new_max_value + 9; $down_condition = $column . " > " . $db_value . " AND " . $column . " <= " . $current_value; } // To prevent issues with the unique constraint, we move everything below 0 $sql = "UPDATE " . $table . " SET " . $column . " = " . $column . " - " . $shift_down; $sql .= " WHERE " . $down_condition; if ($other_columns) { $sql .= " AND " . self::createOtherFieldsWhereClause($table, $other_columns, $values); } fORMDatabase::retrieve()->translatedQuery($sql); if ($object->exists()) { // Put the actual record we are changing in limbo to be updated when the actual update happens $sql = "UPDATE " . $table . " SET " . $column . " = 0"; $sql .= " WHERE " . $column . " = " . $db_value; if ($other_columns) { $sql .= " AND " . self::createOldOtherFieldsWhereClause($table, $other_columns, $values, $old_values); } fORMDatabase::retrieve()->translatedQuery($sql); } // Anything below zero needs to be moved back up into its new position $sql = "UPDATE " . $table . " SET " . $column . " = " . $column . " + " . $shift_up; $sql .= " WHERE " . $column . " < 0"; if ($other_columns) { $sql .= " AND " . self::createOtherFieldsWhereClause($table, $other_columns, $values); } fORMDatabase::retrieve()->translatedQuery($sql); } // If there was an old set, we need to close the gap if ($object->exists() && $new_set) { $sql = "SELECT max(" . $column . ") FROM " . $table . " WHERE "; $sql .= self::createOldOtherFieldsWhereClause($table, $other_columns, $values, $old_values); $old_set_max = (int) fORMDatabase::retrieve()->translatedQuery($sql)->fetchScalar(); // We only need to close the gap if the record was not at the end if ($db_value < $old_set_max) { $shift_down = $old_set_max + 10; $shift_up = $old_set_max + 9; // To prevent issues with the unique constraint, we move everything below 0 and then back up above $sql = "UPDATE " . $table . " SET " . $column . ' = ' . $column . ' - ' . $shift_down . " WHERE "; $sql .= self::createOldOtherFieldsWhereClause($table, $other_columns, $values, $old_values); $sql .= " AND " . $column . " > " . $db_value; fORMDatabase::retrieve()->translatedQuery($sql); if ($current_value == $new_max_value) { // Put the actual record we are changing in limbo to be updated when the actual update happens $sql = "UPDATE " . $table . " SET " . $column . " = 0"; $sql .= " WHERE " . $column . " = " . $db_value; if ($other_columns) { $sql .= " AND " . self::createOldOtherFieldsWhereClause($table, $other_columns, $values, $old_values); } fORMDatabase::retrieve()->translatedQuery($sql); } $sql = "UPDATE " . $table . " SET " . $column . ' = ' . $column . ' + ' . $shift_up . " WHERE "; $sql .= self::createOldOtherFieldsWhereClause($table, $other_columns, $values, $old_values); $sql .= " AND " . $column . " < 0"; fORMDatabase::retrieve()->translatedQuery($sql); } } }
/** * Sets the value for an email column, trimming the value if it is a valid email * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @param string $method_name The method that was called * @param array $parameters The parameters passed to the method * @return fActiveRecord The record object, to allow for method chaining */ public static function setEmailColumn($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters) { list($action, $subject) = fORM::parseMethod($method_name); $column = fGrammar::underscorize($subject); $class = get_class($object); if (count($parameters) < 1) { throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name); } $email = $parameters[0]; if (preg_match('#^\\s*[a-z0-9\\.\'_\\-\\+]+@(?:[a-z0-9\\-]+\\.)+[a-z]{2,}\\s*$#iD', $email)) { $email = trim($email); } if ($email === '') { $email = NULL; } fActiveRecord::assign($values, $old_values, $column, $email); return $object; }
/** * Generates a new random value for the * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @param string $method_name The method that was called * @param array $parameters The parameters passed to the method * @return string The encoded number */ public static function generate($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters) { list($action, $column) = fORM::parseMethod($method_name); $class = get_class($object); $table = fORM::tablize($class); $settings = self::$random_columns[$class][$column]; // Check to see if this is a unique column $unique_keys = fORMSchema::retrieve()->getKeys($table, 'unique'); $is_unique_column = FALSE; foreach ($unique_keys as $unique_key) { if ($unique_key == array($column)) { $is_unique_column = TRUE; do { $value = fCryptography::randomString($settings['length'], $settings['type']); // See if this is unique $sql = "SELECT " . $column . " FROM " . $table . " WHERE " . $column . " = " . fORMDatabase::retrieve()->escape('string', $value); } while (fORMDatabase::retrieve()->query($sql)->countReturnedRows()); } } // If is is not a unique column, just generate a value if (!$is_unique_column) { $value = fCryptography::randomString($settings['length'], $settings['type']); } fActiveRecord::assign($values, $old_values, $column, $value); }