Index: branches/5.2.x/core/units/helpers/priority_helper.php =================================================================== diff -u -N -r14244 -r14610 --- branches/5.2.x/core/units/helpers/priority_helper.php (.../priority_helper.php) (revision 14244) +++ branches/5.2.x/core/units/helpers/priority_helper.php (.../priority_helper.php) (revision 14610) @@ -1,6 +1,6 @@ getObject(); + /* @var $object kDBItem */ $field_options = $object->GetFieldOptions('Priority'); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); $sql = 'SELECT COUNT(*) - FROM '.$table_name; - if ($constrain) { - $sql .= ' WHERE '.$constrain; + FROM ' . $table_name . ' item_table + ' . $joins; + + if ( $constrain ) { + $sql .= ' WHERE ' . $this->normalizeConstrain($constrain); } if ( !$object->isField('OldPriority') ) { // make sure, then OldPriority field is defined $virtual_fields = $object->getVirtualFields(); - $virtual_fields['OldPriority'] = Array('type' => 'int', 'default' => 0); + $virtual_fields['OldPriority'] = Array ('type' => 'int', 'default' => 0); $object->setVirtualFields($virtual_fields); } $items_count = $this->Conn->GetOne($sql); + $current_priority = $object instanceof kDBList ? 0 : $object->GetDBField('Priority'); - // instanceof is not used, because PHP4 doesn't support it - $current_priority = is_a($object, 'kDBList') ? 0 : $object->GetDBField('Priority'); - - if ($is_new || $current_priority == -($items_count+1)) { + if ( $is_new || $current_priority == -($items_count + 1) ) { $items_count++; } - if ($is_new) { + if ( $is_new ) { // add new item to the end of list $object->SetDBField('Priority', -$items_count); $object->SetDBField('OldPriority', -$items_count); } else { + // storing priority right after load for comparing when updating $object->SetDBField('OldPriority', $current_priority); } @@ -68,84 +70,103 @@ } $object->SetFieldOptions('Priority', $field_options); - // storing prioriry right after load for comparing when updating } /** * Updates priorities for changed items * * @param kEvent $event - * @param Array $changes = Array (ID => Array ('parent' => ..., 'new' => ..., 'old' => ...), ...) + * @param Array $changes = Array (ID => Array ('constrain' => ..., 'new' => ..., 'old' => ...), ...) * @param Array $new_ids = Array (temp_id => live_id) * @param string $constrain + * @param string $joins + * @return Array */ - function updatePriorities(&$event, $changes, $new_ids, $constrain = '') + function updatePriorities(&$event, $changes, $new_ids, $constrain = '', $joins = '') { - if (!$changes) { + // TODO: no need pass external $constrain, since the one from $pair is used + + if ( !$changes ) { // no changes to process return Array (); } + list ($id, $pair) = each($changes); - if (!$id && !array_key_exists('parent', $pair)) { + if ( !$id && !isset($pair['constrain']) ) { // adding new item without constrain -> priority stays the same return Array ($id); } $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField'); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); - $ids = array(); + if ( $this->Application->IsTempMode($event->Prefix, $event->Special) ) { + $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $event->Prefix); + } + + $ids = Array (); $not_processed = array_keys($changes); foreach ($changes as $id => $pair) { array_push($ids, $id); - $constrain = isset($pair['parent']) ? 'ParentId = '.$pair['parent'].' AND ' : ''; + $constrain = isset($pair['constrain']) ? $this->normalizeConstrain($pair['constrain']) . ' AND ' : ''; - if ($pair['old'] == 'new') { + if ( $pair['old'] == 'new' ) { // replace 0 with newly created item id (from $new_ids mapping) - $not_processed[ array_search($id, $not_processed) ] = $new_ids[$id]; + $not_processed[array_search($id, $not_processed)] = $new_ids[$id]; $id = $new_ids[$id]; - $sql = 'SELECT MIN(Priority) - FROM '.$table_name.' - WHERE '.$constrain.' '.$id_field.' NOT IN ('.implode(',', $not_processed).')'; + $sql = 'SELECT MIN(item_table.Priority) + FROM ' . $table_name . ' item_table + ' . $joins . ' + WHERE ' . $constrain . ' item_table.' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')'; $min_priority = (int)$this->Conn->GetOne($sql) - 1; - if ($pair['new'] < $min_priority) { + if ( $pair['new'] < $min_priority ) { $pair['new'] = $min_priority; } + $pair['old'] = $min_priority; } - if ($pair['new'] < $pair['old']) { - $set = ' SET Priority = Priority + 1'; - $where =' WHERE '.$constrain.' - Priority >= '.$pair['new'].' + if ( $pair['new'] < $pair['old'] ) { + $set = ' SET item_table.Priority = item_table.Priority + 1'; + $where = ' WHERE ' . $constrain . ' + item_table.Priority >= ' . $pair['new'] . ' AND - Priority < '.$pair['old'].' + item_table.Priority < ' . $pair['old'] . ' AND - '.$id_field.' NOT IN ('.implode(',', $not_processed).')'; + ' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')'; } - elseif ($pair['new'] > $pair['old']) { - $set = ' SET Priority = Priority - 1'; - $where =' WHERE '.$constrain.' - Priority > '.$pair['old'].' + elseif ( $pair['new'] > $pair['old'] ) { + $set = ' SET item_table.Priority = item_table.Priority - 1'; + $where = ' WHERE ' . $constrain . ' + item_table.Priority > ' . $pair['old'] . ' AND - Priority <= '.$pair['new'].' + item_table.Priority <= ' . $pair['new'] . ' AND - '.$id_field.' NOT IN ('.implode(',', $not_processed).')'; + ' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')'; } else { - $set = 'SET Priority = '.$pair['new']; - $where = ' WHERE '.$id_field.' = '.$id; + $set = ' SET item_table.Priority = ' . $pair['new']; + $where = ' WHERE ' . $id_field . ' = ' . $id; } - $ids = array_merge($ids, $this->Conn->GetCol('SELECT '.$id_field.' FROM '.$table_name.$where)); - $q = 'UPDATE '.$table_name.' '.$set.$where; + + $sql = 'SELECT item_table.' . $id_field . ' + FROM ' . $table_name . ' item_table + ' . $joins . ' + ' . $where; + $ids = array_merge($ids, $this->Conn->GetCol($sql)); + + $q = 'UPDATE ' . $table_name . ' item_table + ' . $joins . ' + ' . $set . $where; $this->Conn->Query($q); - unset( $not_processed[array_search($id, $not_processed)] ); + unset($not_processed[array_search($id, $not_processed)]); } + return $ids; } @@ -154,25 +175,71 @@ * * @param kEvent $event * @param string $constrain + * @param string $joins + * @return Array */ - function recalculatePriorities(&$event, $constrain = '') + function recalculatePriorities(&$event, $constrain = '', $joins = '') { $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField'); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); + $constrain = $this->normalizeConstrain($constrain); - $sql = 'SELECT '.$id_field.' - FROM '.$table_name. - ($constrain ? ' WHERE '.$constrain : '').' - ORDER BY Priority DESC'; + if ( $this->Application->IsTempMode($event->Prefix, $event->Special) ) { + $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $event->Prefix); + } + $sql = 'SELECT ' . $id_field . ' + FROM ' . $table_name . ' item_table ' . + $joins . ' ' . + ($constrain ? ' WHERE ' . $constrain : '') . ' + ORDER BY item_table.Priority DESC'; $items = $this->Conn->GetCol($sql); foreach ($items as $item_number => $item_id) { - $sql = 'UPDATE '.$table_name.' - SET Priority = '.-($item_number + 1).' - WHERE '.$id_field.' = '.$item_id; + $sql = 'UPDATE ' . $table_name . ' + SET Priority = ' . -($item_number + 1) . ' + WHERE ' . $id_field . ' = ' . $item_id; $this->Conn->Query($sql); } + return $items; } + + /** + * Adds current table name into constrain if doesn't have it already (to prevent ambiguous columns during joins) + * + * @param string $constrain + * @return string + */ + function normalizeConstrain($constrain) + { + if ( strpos($constrain, '.') === false ) { + return 'item_table.' . $constrain; + } + + return $constrain; + } + + /** + * Performs fake kDBItem::Update call, so any OnBefore/OnAfter events would be notified of priority change + * + * @param string $prefix + * @param Array $ids + */ + function massUpdateChanged($prefix, $ids) + { + $ids = array_unique($ids); + + $dummy =& $this->Application->recallObject($prefix . '.-dummy', null, Array ('skip_autoload' => true)); + /* @var $dummy kDBItem */ + + $sql = $dummy->GetSelectSQL() . ' + WHERE ' . $dummy->TableName . '.' . $dummy->IDField . ' IN (' . implode(',', $ids) . ')'; + $records = $this->Conn->Query($sql); + + foreach ($records as $record) { + $dummy->LoadFromHash($record); + $dummy->Update(); + } + } } \ No newline at end of file