Index: kernel/db/db_event_handler.php =================================================================== --- kernel/db/db_event_handler.php (revision 14608) +++ kernel/db/db_event_handler.php (working copy) @@ -3088,4 +3088,17 @@ $clones[$subitem_prefix] = Array ('ParentPrefix' => $event->Prefix); $this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones); } + + /** + * Returns constrain for priority calculations + * + * @param kEvent $event + * @return void + * @see PriorityEventHandler + * @access protected + */ + protected function OnGetConstrainInfo(&$event) + { + $event->setEventParam('constrain_info', Array ('', '')); + } } \ No newline at end of file Index: units/categories/categories_event_handler.php =================================================================== --- units/categories/categories_event_handler.php (revision 14602) +++ units/categories/categories_event_handler.php (working copy) @@ -401,7 +401,7 @@ $p_item =& $this->Application->recallObject($related_prefix . '.current', null, Array('skip_autoload' => true)); /* @var $p_item kCatDBItem */ - + $p_item->Load( (int)$id ); $p_resource_id = $p_item->GetDBField('ResourceId'); @@ -792,18 +792,12 @@ // 2. preset template $category_id = $this->Application->GetVar('m_cat_id'); $root_category = $this->Application->getBaseCategory(); - + if ( $category_id == $root_category ) { $object->SetDBField('Template', $this->_getDefaultDesign()); } - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - // 3. prepare priorities dropdown - $priority_helper->preparePriorities($event, true, 'ParentId = ' . $category_id); - - // 4. set default owner + // 3. set default owner $object->SetDBField('CreatedById', $this->Application->RecallVar('user_id')); } @@ -830,16 +824,6 @@ return; } - // 1. update priorities - $tmp = $this->Application->RecallVar('priority_changes' . $this->Application->GetVar('m_wid')); - $changes = $tmp ? unserialize($tmp) : Array (); - $changed_ids = array_keys($changes); - - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - $priority_helper->updatePriorities($event, $changes, Array (0 => $event->getEventParam('ids'))); - if ( $this->Application->RecallVar('PermCache_UpdateRequired') ) { $this->Application->RemoveVar('IsRootCategory_' . $this->Application->GetVar('m_wid')); } @@ -848,7 +832,7 @@ $this->_resetMenuCache(); if ( $is_editing ) { - // 2. send email event to category owner, when it's status is changed (from admin) + // send email event to category owner, when it's status is changed (from admin) $object->SwitchToLive(); $new_statuses = $this->_getCategoryStatus($ids); $process_statuses = Array (STATUS_ACTIVE, STATUS_DISABLED); @@ -898,12 +882,6 @@ return; } - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - $category_id = $this->Application->GetVar('m_cat_id'); - $priority_helper->preparePriorities($event, true, 'ParentId = ' . $category_id); - parent::OnPreSaveCreated($event); } @@ -936,43 +914,26 @@ */ protected function customProcessing(&$event, $type) { - if ($event->Name == 'OnMassDelete' && $type == 'before') { + if ( $event->Name == 'OnMassDelete' && $type == 'before' ) { $ids = $event->getEventParam('ids'); - if (!$ids || $this->Application->ConfigValue('AllowDeleteRootCats')) { - return ; + if ( !$ids || $this->Application->ConfigValue('AllowDeleteRootCats') ) { + return; } + $root_categories = Array (); + // get module root categories and exclude them foreach ($this->Application->ModuleInfo as $module_info) { $root_categories[] = $module_info['RootCat']; } + $root_categories = array_unique($root_categories); - if ($root_categories && array_intersect($ids, $root_categories)) { + if ( $root_categories && array_intersect($ids, $root_categories) ) { $event->setEventParam('ids', array_diff($ids, $root_categories)); $this->Application->StoreVar('root_delete_error', 1); } } - - $change_events = Array ('OnPreSave', 'OnPreSaveCreated', 'OnUpdate', 'OnSave'); - if ($type == 'after' && in_array($event->Name, $change_events)) { - $object =& $event->getObject(); - /* @var $object kDBItem */ - - $tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid')); - $changes = $tmp ? unserialize($tmp) : array(); - - if (!isset($changes[$object->GetID()])) { - $changes[$object->GetId()]['old'] = $object->GetID() == 0 ? 'new' : $object->GetDBField('OldPriority'); - } - - if ($changes[$object->GetId()]['old'] == $object->GetDBField('Priority')) return ; - - $changes[$object->GetId()]['new'] = $object->GetDBField('Priority'); - $changes[$object->GetId()]['parent'] = $object->GetDBField('ParentId'); - - $this->Application->StoreVar('priority_changes'.$this->Application->GetVar('m_wid'), serialize($changes)); - } } /** @@ -1068,14 +1029,6 @@ } $this->clearSelectedIDs($event); - // update priorities - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - // after deleting categories, all priorities should be recalculated - $parent_id = $this->Application->GetVar('m_cat_id'); - $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); - $this->Application->StoreVar('RefreshStructureTree', 1); $this->_resetMenuCache(); } @@ -1208,13 +1161,21 @@ /* @var $priority_helper kPriorityHelper */ if ( $clipboard_data['cut'] ) { - $priority_helper->recalculatePriorities($event, 'ParentId = ' . $source_category_id); + $ids = $priority_helper->recalculatePriorities($event, 'ParentId = ' . $source_category_id); + + if ( $ids ) { + $priority_helper->massUpdateChanged($event->Prefix, $ids); + } } // recalculate priorities of newly pasted categories in destination category $parent_id = $this->Application->GetVar('m_cat_id'); - $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); + $ids = $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); + if ( $ids ) { + $priority_helper->massUpdateChanged($event->Prefix, $ids); + } + if ( $clipboard_data['cut'] || $clipboard_data['copy'] ) { // rebuild with progress bar if ( $this->Application->ConfigValue('QuickCategoryPermissionRebuild') ) { @@ -1570,7 +1531,7 @@ if ( $page->isLoaded() ) { $real_t = $page->GetDBField('CachedTemplate'); $this->Application->SetVar('m_cat_id', $page->GetDBField('CategoryId')); - + if ( $page->GetDBField('FormId') ) { $this->Application->SetVar('form_id', $page->GetDBField('FormId')); } @@ -2038,7 +1999,7 @@ if ( !$this->Application->isAdmin ) { // calculate priorities dropdown only for admin - return ; + return; } $object =& $event->getObject(); @@ -2050,42 +2011,14 @@ WHERE ParentPath LIKE "' . $object->GetDBField('ParentPath') . '%"'; $remove_categories = $this->Conn->GetCol($sql); - $field_options = $object->GetFieldOptions('ParentId'); + $options = $object->GetFieldOption('ParentId', 'options'); foreach ($remove_categories as $remove_category) { - unset($field_options['options'][$remove_category]); + unset($options[$remove_category]); } - $object->SetFieldOptions('ParentId', $field_options); - - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - $priority_helper->preparePriorities($event, false, 'ParentId = ' . $object->GetDBField('ParentId')); - - // storing priority right after load for comparing when updating - $object->SetDBField('OldPriority', $object->GetDBField('Priority')); + $object->SetFieldOption('ParentId', 'options', $options); } /** - * Builds list - * - * @param kEvent $event - * @access protected - */ - function OnListBuild(&$event) - { - parent::OnListBuild($event); - - if (!$this->Application->isAdminUser) { - return ; - } - - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - $priority_helper->preparePriorities($event, false, 'ParentId = '.$this->Application->GetVar('m_cat_id')); - } - - /** * Enter description here... * * @param kEvent $event @@ -2143,44 +2076,9 @@ */ function OnChangePriority(&$event) { - if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { - $event->status = kEvent::erFAIL; - return; - } + $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial()); + $event->CallSubEvent('priority:' . $event->Name); - $object =& $event->getObject( Array('skip_autoload' => true) ); - $ids = $this->StoreSelectedIDs($event); - - if ($ids) { - $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField'); - $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); - $parent_id = $this->Application->GetVar('m_cat_id'); - - $sql = 'SELECT Priority, '.$id_field.' - FROM '.$table_name.' - WHERE '.$id_field.' IN ('.implode(',', $ids).')'; - $priorities = $this->Conn->GetCol($sql, $id_field); - - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ - - foreach ($ids as $id) { - $new_priority = $priorities[$id] + ($event->Name == 'OnMassMoveUp' ? +1 : -1); - - $changes = Array ( - $id => Array ('old' => $priorities[$id], 'new' => $new_priority, 'parent' => $parent_id), - ); - - $sql = 'UPDATE '.$table_name.' - SET Priority = '.$new_priority.' - WHERE '.$id_field.' = '.$id; - $this->Conn->Query($sql); - - $priority_helper->updatePriorities($event, $changes, Array ($id => $id)); - } - } - - $this->clearSelectedIDs($event); $this->Application->StoreVar('RefreshStructureTree', 1); $this->_resetMenuCache(); } @@ -2197,11 +2095,9 @@ return; } - $priority_helper =& $this->Application->recallObject('PriorityHelper'); - /* @var $priority_helper kPriorityHelper */ + $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial()); + $event->CallSubEvent('priority:' . $event->Name); - $parent_id = $this->Application->GetVar('m_cat_id'); - $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id); $this->_resetMenuCache(); } @@ -2238,7 +2134,7 @@ $query_object =& $this->Application->recallObject('HTTPQuery'); /* @var $query_object kHTTPQuery */ - + $sql = 'SHOW TABLES LIKE "'.$search_table.'"'; if ( !isset($query_object->Get['keywords']) && !isset($query_object->Post['keywords']) && $this->Conn->Query($sql) ) { @@ -2551,4 +2447,38 @@ $object->setID($id); } } + + /** + * Returns constrain for priority calculations + * + * @param kEvent $event + * @return void + * @see PriorityEventHandler + * @access protected + */ + protected function OnGetConstrainInfo(&$event) + { + $contarain = ''; // for OnSave + + $event_name = $event->getEventParam('original_event'); + $actual_event_name = $event->getEventParam('actual_event'); + + if ( $actual_event_name == 'OnSavePriorityChanges' || $event_name == 'OnAfterItemLoad' || $event_name == 'OnAfterItemDelete' ) { + $object =& $event->getObject(); + /* @var $object kDBItem */ + + $contarain = 'ParentId = ' . $object->GetDBField('ParentId'); + } + elseif ( $actual_event_name == 'OnPreparePriorities' ) { + $contarain = 'ParentId = ' . $this->Application->GetVar('m_cat_id'); + } + elseif ( $event_name == 'OnSave' ) { + $contarain = ''; + } + else { + $contarain = 'ParentId = ' . $this->Application->GetVar('m_cat_id'); + } + + $event->setEventParam('constrain_info', Array ($contarain, '')); + } } \ No newline at end of file Index: units/helpers/priority_helper.php =================================================================== --- units/helpers/priority_helper.php (revision 14590) +++ units/helpers/priority_helper.php (working copy) @@ -16,50 +16,52 @@ class kPriorityHelper extends kHelper { - /** * Prepares options for priority dropdown * * @param kEvent $event * @param bool $is_new for newly created items add new priority to the end * @param string $constrain constrain for priority selection (if any) + * @param string $joins left joins, used by constrain (if any) * */ - function preparePriorities(&$event, $is_new = false, $constrain = '') + function preparePriorities(&$event, $is_new = false, $constrain = '', $joins = '') { $object =& $event->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,26 +70,30 @@ } $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); } @@ -95,57 +101,72 @@ $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 Index: units/priorites/priorites_config.php =================================================================== --- units/priorites/priorites_config.php (revision 0) +++ units/priorites/priorites_config.php (revision 0) @@ -0,0 +1,31 @@ + 'priority', + 'EventHandlerClass' => Array ('class' => 'PriorityEventHandler', 'file' => 'priority_eh.php', 'build_event' => 'OnBuild'), + + 'QueryString' => Array ( + 1 => 'prefix', + 2 => 'event', + ), + + 'Hooks' => Array ( + Array ( + 'Mode' => hAFTER, + 'Conditional' => false, + 'HookToPrefix' => 'adm', + 'HookToSpecial' => '*', + 'HookToEvent' => Array ('OnBeforeShutdown'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnBeforeShutdown', + 'Conditional' => false, + ), + ), + + 'PermSection' => Array ('main' => 'custom'), + + 'ProcessPrefixes' => Array( + 'c', 'st' + ), + ); Property changes on: units\priorites\priorites_config.php ___________________________________________________________________ Added: svn:keywords + Id Added: svn:eol-style + LF Index: units/priorites/priority_eh.php =================================================================== --- units/priorites/priority_eh.php (revision 0) +++ units/priorites/priority_eh.php (revision 0) @@ -0,0 +1,370 @@ + Array ('self' => true), + ); + + $this->permMapping = array_merge($this->permMapping, $permissions); + } + + function mapEvents() + { + parent::mapEvents(); + + $events_map = Array ( + 'OnMassMoveUp' => 'OnChangePriority', + 'OnMassMoveDown' => 'OnChangePriority', + ); + + $this->eventMethods = array_merge($this->eventMethods, $events_map); + } + + /** + * Enter description here... + * + * @param kEvent $event + */ + function OnAfterConfigRead(&$event) + { + $hooks = Array( + Array( + 'Mode' => hAFTER, + 'Conditional' => false, + 'HookToPrefix' => '', + 'HookToSpecial' => '*', + 'HookToEvent' => Array('OnAfterItemLoad', 'OnPreCreate', 'OnListBuild'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnPreparePriorities', + 'Conditional' => false, + ), + Array( + 'Mode' => hBEFORE, + 'Conditional' => false, + 'HookToPrefix' => '', + 'HookToSpecial' => '*', + 'HookToEvent' => Array('OnPreSaveCreated'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnPreparePriorities', + 'Conditional' => false, + ), + Array( + 'Mode' => hAFTER, + 'Conditional' => false, + 'HookToPrefix' => '', + 'HookToSpecial' => '*', + 'HookToEvent' => Array('OnPreSave', 'OnPreSaveCreated', 'OnSave', 'OnUpdate'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnSavePriorityChanges', + 'Conditional' => false, + ), + Array( + 'Mode' => hAFTER, + 'Conditional' => false, + 'HookToPrefix' => '', + 'HookToSpecial' => '*', + 'HookToEvent' => Array('OnSave'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnSaveItems', + 'Conditional' => false, + ), + Array( + 'Mode' => hBEFORE, + 'Conditional' => false, + 'HookToPrefix' => '', + 'HookToSpecial' => '*', + 'HookToEvent' => Array('OnBeforeItemCreate'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnItemCreate', + 'Conditional' => false, + ), + Array( + 'Mode' => hBEFORE, + 'Conditional' => false, + 'HookToPrefix' => '', + 'HookToSpecial' => '*', + 'HookToEvent' => Array('OnAfterItemDelete'), + 'DoPrefix' => 'priority', + 'DoSpecial' => '*', + 'DoEvent' => 'OnItemDelete', + 'Conditional' => false, + ) + ); + + $prefixes = $this->Application->getUnitOption($event->Prefix, 'ProcessPrefixes', Array ()); + /* @var $prefixes Array */ + + foreach ($prefixes as $prefix) { + foreach ($hooks as $hook) { + if ( !is_array($hook['HookToEvent']) ) { + $hook['HookToEvent'] = Array($hook['HookToEvent']); + } + + foreach ($hook['HookToEvent'] as $hook_event) { + $this->Application->registerHook( + $prefix . '.' . $hook['HookToSpecial'] . ':' . $hook_event, + $event->Prefix . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent'], + $hook['Mode'], + $hook['Conditional'] + ); + } + } + } + } + + /** + * Should be hooked to OnAfterItemLoad, OnPreSaveCreated (why latter?) + * + * @param kEvent $event + */ + function OnPreparePriorities(&$event) + { + if ( !$this->Application->isAdminUser ) { + return ; + } + + $priority_helper =& $this->Application->recallObject('PriorityHelper'); + /* @var $priority_helper kPriorityHelper */ + + list ($constrain, $joins) = $this->getConstrainInfo($event); + $is_new = $event->MasterEvent->Name == 'OnPreCreate' || $event->MasterEvent->Name == 'OnPreSaveCreated'; + $priority_helper->preparePriorities($event->MasterEvent, $is_new, $constrain, $joins); + } + + /** + * Enter description here... + * + * @param kEvent $event + */ + function OnSavePriorityChanges(&$event) + { + if ($event->MasterEvent->status != erSUCCESS) { + // don't update priorities, when OnSave validation failed + return ; + } + + $object =& $event->MasterEvent->getObject(); + + $tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid')); + $changes = $tmp ? unserialize($tmp) : array(); + + if (!isset($changes[$object->GetID()])) { + $changes[$object->GetId()]['old'] = $object->GetID() == 0 ? 'new' : $object->GetDBField('OldPriority'); + } + + if ($changes[$object->GetId()]['old'] == $object->GetDBField('Priority')) return ; + $changes[$object->GetId()]['new'] = $object->GetDBField('Priority'); + + list ($constrain, $joins) = $this->getConstrainInfo($event); + + if ($constrain) { + $changes[$object->GetId()]['constrain'] = $constrain; + } + + $this->Application->StoreVar('priority_changes'.$this->Application->GetVar('m_wid'), serialize($changes)); + } + + /** + * Enter description here... + * + * @param kEvent $event + */ + function OnItemDelete(&$event) + { + // just store the prefix in which the items were deleted + $del = $this->Application->RecallVar('priority_deleted' . $this->Application->GetVar('m_wid')); + $del = $del ? unserialize($del) : array(); + + list ($constrain, $joins) = $this->getConstrainInfo($event); + $cache_key = crc32($event->MasterEvent->Prefix . ':' . $constrain . ':' . $joins); + + if ( !isset($del[$cache_key]) ) { + $del[$cache_key] = Array ( + 'prefix' => $event->MasterEvent->Prefix, + 'constrain' => $constrain, + 'joins' => $joins, + ); + + $this->Application->StoreVar('priority_deleted' . $this->Application->GetVar('m_wid'), serialize($del)); + } + } + + /** + * Called before script shut-down and recalculate all deleted prefixes, to avoid recalculation on each deleted item + * + * @param kEvent $event + */ + function OnBeforeShutDown(&$event) + { + $del = $this->Application->RecallVar('priority_deleted'.$this->Application->GetVar('m_wid')); + $del = $del ? unserialize($del) : array(); + + $priority_helper =& $this->Application->recallObject('PriorityHelper'); + /* @var $priority_helper kPriorityHelper */ + + foreach ($del as $del_info) { + $dummy_event = new kEvent( array('prefix'=>$del_info['prefix'], 'name'=>'Dummy' ) ); + $ids = $priority_helper->recalculatePriorities($dummy_event, $del_info['constrain'], $del_info['joins']); + + if ($ids) { + $priority_helper->massUpdateChanged($del_info['prefix'], $ids); + } + } + + $this->Application->RemoveVar('priority_deleted'.$this->Application->GetVar('m_wid')); + } + + /** + * Enter description here... + * + * @param kEvent $event + */ + function OnSaveItems(&$event) + { + $tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid')); + $changes = $tmp ? unserialize($tmp) : array(); + + $priority_helper =& $this->Application->recallObject('PriorityHelper'); + /* @var $priority_helper kPriorityHelper */ + + list ($constrain, $joins) = $this->getConstrainInfo($event); + $ids = $priority_helper->updatePriorities($event->MasterEvent, $changes, Array (0 => $event->MasterEvent->getEventParam('ids')), $constrain, $joins); + + if ($ids) { + $priority_helper->massUpdateChanged($event->MasterEvent->Prefix, $ids); + } + } + + function OnItemCreate(&$event) + { + $obj =& $event->MasterEvent->getObject(); + if ($obj->GetDBField('Priority') == 0) { + $priority_helper =& $this->Application->recallObject('PriorityHelper'); + /* @var $priority_helper kPriorityHelper */ + + list ($constrain, $joins) = $this->getConstrainInfo($event); + $priority_helper->preparePriorities($event->MasterEvent, true, $constrain, $joins); + } + } + + /** + * Processes OnMassMoveUp, OnMassMoveDown events + * + * @param kEvent $event + */ + function OnChangePriority(&$event) + { + $prefix = $this->Application->GetVar('priority_prefix'); + $dummy_event = new kEvent( array('prefix'=>$prefix, 'name'=>'Dummy' ) ); + + $ids = $this->StoreSelectedIDs($dummy_event); + + if ($ids) { + $id_field = $this->Application->getUnitOption($prefix, 'IDField'); + $table_name = $this->Application->getUnitOption($prefix, 'TableName'); + + if ( $this->Application->IsTempMode($prefix) ) { + $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix); + } + + $sql = 'SELECT Priority, '.$id_field.' + FROM '.$table_name.' + WHERE '.$id_field.' IN ('.implode(',', $ids).') ORDER BY Priority DESC'; + $priorities = $this->Conn->GetCol($sql, $id_field); + + $priority_helper =& $this->Application->recallObject('PriorityHelper'); + /* @var $priority_helper kPriorityHelper */ + + list ($constrain, $joins) = $this->getConstrainInfo($event); + + $sql = 'SELECT IFNULL(MIN(item_table.Priority), -1) + FROM '.$table_name . ' item_table + ' . $joins; + + if ( $constrain ) { + $sql .= ' WHERE ' . $priority_helper->normalizeConstrain($constrain); + } + + $min_priority = $this->Conn->GetOne($sql); + + foreach ($ids as $id) { + $new_priority = $priorities[$id] + ($event->Name == 'OnMassMoveUp' ? +1 : -1); + if ($new_priority > -1 || $new_priority < $min_priority) { + continue; + } + + $changes = Array ( + $id => Array ('old' => $priorities[$id], 'new' => $new_priority), + ); + + if ($constrain) { + $changes[$id]['constrain'] = $constrain; + } + + $sql = 'UPDATE '.$table_name.' + SET Priority = '.$new_priority.' + WHERE '.$id_field.' = '.$id; + $this->Conn->Query($sql); + + $ids = $priority_helper->updatePriorities($dummy_event, $changes, Array ($id => $id), $constrain, $joins); + + if ($ids) { + $priority_helper->massUpdateChanged($prefix, $ids); + } + } + } + + $this->clearSelectedIDs($dummy_event); + } + + /** + * Completely recalculates priorities in current category + * + * @param kEvent $event + */ + function OnRecalculatePriorities(&$event) + { + $priority_helper =& $this->Application->recallObject('PriorityHelper'); + /* @var $priority_helper kPriorityHelper */ + + $prefix = $this->Application->GetVar('priority_prefix'); + $dummy_event = new kEvent( array('prefix'=>$prefix, 'name'=>'Dummy' ) ); + + list ($constrain, $joins) = $this->getConstrainInfo($event); + $ids = $priority_helper->recalculatePriorities($dummy_event, $constrain, $joins); + + if ($ids) { + $priority_helper->massUpdateChanged($prefix, $ids); + } + } + + /** + * Returns constrain for current priority calculations + * + * @param kEvent $event + * @return Array + */ + function getConstrainInfo(&$event) + { + $constrain_event = new kEvent($event->MasterEvent->getPrefixSpecial() . ':OnGetConstrainInfo'); + $constrain_event->setEventParam('actual_event', $event->Name); + $constrain_event->setEventParam('original_event', $event->MasterEvent->Name); + $this->Application->HandleEvent($constrain_event); + + return $constrain_event->getEventParam('constrain_info'); + } +} Property changes on: units\priorites\priority_eh.php ___________________________________________________________________ Added: svn:keywords + Id Added: svn:eol-style + LF