/** * 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); } } }
/** * Loads a record from the database * * @throws fNotFoundException When the record could not be found in the database * * @return fActiveRecord The record object, to allow for method chaining */ public function load() { $class = get_class($this); if (fORM::getActiveRecordMethod($class, 'load')) { return $this->__call('load', array()); } try { $table = fORM::tablize($class); $sql = 'SELECT * FROM ' . $table . ' WHERE ' . fORMDatabase::createPrimaryKeyWhereClause($table, $table, $this->values, $this->old_values); $result = fORMDatabase::retrieve()->translatedQuery($sql); $result->tossIfNoRows(); } catch (fExpectedException $e) { throw new fNotFoundException('The %s requested could not be found', fORM::getRecordName($class)); } $this->loadFromResult($result, TRUE); return $this; }