Attached Files |
priority_eh.patch [^] (10,721 bytes) 2010-09-07 12:31
[Show Content]
Index: units/priorites/priorites_config.php
===================================================================
--- units/priorites/priorites_config.php (revision 0)
+++ units/priorites/priorites_config.php (revision 0)
@@ -0,0 +1,30 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => '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()
+ );
+?>
\ No newline at end of file
Index: units/priorites/priority_eh.php
===================================================================
--- units/priorites/priority_eh.php (revision 0)
+++ units/priorites/priority_eh.php (revision 0)
@@ -0,0 +1,316 @@
+<?php
+
+class PriorityEventHandler extends kDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+ $permissions = Array(
+ 'OnRecalculatePriorities' => 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');
+ 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,
+ $hook['Mode'],
+ $event->Prefix,
+ $hook['DoSpecial'],
+ $hook['DoEvent'],
+ $hook['Conditional']
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Should be hooked to OnAfterItemLoad, OnPreSaveCreated (why latter?)
+ *
+ * @param kEvent $event
+ */
+ function OnPreparePriorities(&$event)
+ {
+ if (!$this->Application->IsAdmin()) return;
+ $priority_helper =& $this->Application->recallObject('PriorityHelper');
+ /* @var $priority_helper kPriorityHelper */
+
+ $is_new = $event->MasterEvent->Name == 'OnPreCreate' || $event->MasterEvent->Name == 'OnPreSaveCreated';
+ $priority_helper->preparePriorities($event->MasterEvent, $is_new);
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ */
+ function OnSavePriorityChanges(&$event)
+ {
+ $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');
+
+ $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();
+ $del[] = $event->MasterEvent->Prefix;
+ $this->Application->StoreVar('priority_deleted'.$this->Application->GetVar('m_wid'), serialize(array_unique($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 $prefix) {
+ $dummy_event = new kEvent( array('prefix'=>$prefix, 'name'=>'Dummy' ) );
+
+ $ids = $priority_helper->recalculatePriorities($dummy_event);
+ if ($ids) {
+ $my_event = new kEvent('api:OnAddToQueue');
+ $my_event->setEventParam('prefix', $prefix);
+ $my_event->setEventParam('ids', array_unique($ids));
+ $this->Application->HandleEvent($my_event);
+ }
+ }
+ $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 */
+
+ $ids = $priority_helper->updatePriorities($event->MasterEvent, $changes, $event->MasterEvent->getEventParam('ids'));
+ if ($ids) {
+ $my_event = new kEvent('api:OnAddToQueue');
+ $my_event->setEventParam('prefix', $event->MasterEvent->Prefix);
+ $my_event->setEventParam('ids', array_unique($ids));
+ $this->Application->HandleEvent($my_event);
+ }
+ }
+
+ function OnItemCreate(&$event)
+ {
+ $obj =& $event->MasterEvent->getObject();
+ if ($obj->GetDBField('Priority') == 0) {
+ $priority_helper =& $this->Application->recallObject('PriorityHelper');
+ /* @var $priority_helper kPriorityHelper */
+
+ $priority_helper->preparePriorities($event->MasterEvent, true);
+ }
+ }
+
+ /**
+ * 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');
+// $parent_id = $this->Application->GetVar('m_cat_id');
+
+ $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);
+ $min_priorirty = $this->Conn->GetOne('SELECT IFNULL(MIN(Priority),-1) FROM '.$table_name);
+
+ $priority_helper =& $this->Application->recallObject('PriorityHelper');
+ /* @var $priority_helper kPriorityHelper */
+
+ foreach ($ids as $id) {
+ $new_priority = $priorities[$id] + ($event->Name == 'OnMassMoveUp' ? +1 : -1);
+ if ($new_priority > -1 || $new_priority < $min_priorirty) {
+ continue;
+ }
+
+ $changes = Array (
+ $id => Array ('old' => $priorities[$id], 'new' => $new_priority),
+ );
+
+ $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));
+ if ($ids) {
+ $my_event = new kEvent('api:OnAddToQueue');
+ $my_event->setEventParam('prefix', $prefix);
+ $my_event->setEventParam('ids', array_unique($ids));
+ $this->Application->HandleEvent($my_event);
+ }
+ }
+ }
+
+ $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' ) );
+
+ $ids = $priority_helper->recalculatePriorities($dummy_event);
+ if ($ids) {
+ $my_event = new kEvent('api:OnAddToQueue');
+ $my_event->setEventParam('prefix', $prefix);
+ $my_event->setEventParam('ids', array_unique($ids));
+ $this->Application->HandleEvent($my_event);
+ }
+ }
+
+}
\ No newline at end of file
priority_eh_v2.patch [^] (30,816 bytes) 2011-05-18 05:43
[Show Content]
Index: kernel/db/db_event_handler.php
===================================================================
--- kernel/db/db_event_handler.php (revision 14318)
+++ kernel/db/db_event_handler.php (working copy)
@@ -2931,4 +2931,15 @@
$clones[$subitem_prefix] = Array ('ParentPrefix' => $event->Prefix);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
}
+
+ /**
+ * Returns constrain for priority calculations
+ *
+ * @see PriorityEventHandler
+ * @param kEvent $event
+ */
+ 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 14318)
+++ units/categories/categories_event_handler.php (working copy)
@@ -763,12 +763,6 @@
$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
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
@@ -801,16 +795,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'));
}
@@ -819,7 +803,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);
@@ -867,12 +851,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);
}
@@ -895,7 +873,6 @@
$this->Conn->Query($sql);
}
-
/**
* Exclude root categories from deleting
*
@@ -920,25 +897,6 @@
$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();
-
- $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));
- }
}
/**
@@ -1026,14 +984,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();
}
@@ -1159,13 +1109,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')) {
@@ -1966,37 +1924,9 @@
unset($field_options['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 prioriry right after load for comparing when updating
- $object->SetDBField('OldPriority', $object->GetDBField('Priority'));
}
/**
- * 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
@@ -2059,39 +1989,9 @@
return;
}
- $object =& $event->getObject( Array('skip_autoload' => true) );
- $ids = $this->StoreSelectedIDs($event);
+ $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
+ $event->CallSubEvent('priority:' . $event->Name);
- 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();
}
@@ -2108,11 +2008,9 @@
return;
}
- $priority_helper =& $this->Application->recallObject('PriorityHelper');
- /* @var $priority_helper kPriorityHelper */
+ $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
+ $event->CallSubEvent('priority:OnRecalculatePriorities');
- $parent_id = $this->Application->GetVar('m_cat_id');
- $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id);
$this->_resetMenuCache();
}
@@ -2438,4 +2336,34 @@
$object->setID($id);
}
}
+
+ /**
+ * Returns constrain for priority calculations
+ *
+ * @see PriorityEventHandler
+ * @param kEvent $event
+ */
+ 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();
+ $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 14318)
+++ units/helpers/priority_helper.php (working copy)
@@ -16,16 +16,16 @@
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();
@@ -33,30 +33,33 @@
$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 (!isset($object->Fields['OldPriority'])) {
+ if ( !isset($object->Fields['OldPriority']) ) {
$object->VirtualFields['OldPriority'] = Array('type' => 'int', 'default' => 0);
}
$items_count = $this->Conn->GetOne($sql);
- // instanceof is not used, because PHP4 doesn't support it
+ // TODO: 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 prioriry right after load for comparing when updating
$object->SetDBField('OldPriority', $current_priority);
}
@@ -65,26 +68,29 @@
}
$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
*/
- 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);
}
@@ -92,57 +98,69 @@
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
- $ids = array();
+ $ids = Array ();
$not_processed = array_keys($changes);
foreach ($changes as $id => $pair) {
array_push($ids, $id);
- $constrain = isset($pair['parent']) ? 'ParentId = '.$pair['parent'].' AND ' : '';
- if ($pair['old'] == 'new') {
+ $constrain = isset($pair['constrain']) ? $this->normalizeConstrain($pair['constrain']) . ' AND ' : '';
+
+ 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];
$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 . ' ' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')';
$min_priority = (int)$this->Conn->GetOne($sql) - 1;
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)] );
}
+
return $ids;
}
@@ -151,25 +169,67 @@
*
* @param kEvent $event
* @param string $constrain
+ * @param string $joins
*/
- 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';
+ $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;
+ }
+
+ /**
+ * Peforms 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 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => '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'
+ ),
+ );
Index: units/priorites/priority_eh.php
===================================================================
--- units/priorites/priority_eh.php (revision 0)
+++ units/priorites/priority_eh.php (revision 0)
@@ -0,0 +1,369 @@
+<?php
+
+class PriorityEventHandler extends kDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+
+ $permissions = Array (
+ 'OnRecalculatePriorities' => 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');
+
+ 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,
+ $hook['Mode'],
+ $event->Prefix,
+ $hook['DoSpecial'],
+ $hook['DoEvent'],
+ $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, $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');
+
+ $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');
+ }
+}
priority_eh_v3.patch [^] (30,659 bytes) 2011-05-26 03:15
[Show Content]
Index: kernel/db/db_event_handler.php
===================================================================
--- kernel/db/db_event_handler.php (revision 14349)
+++ kernel/db/db_event_handler.php (working copy)
@@ -2964,4 +2964,15 @@
$clones[$subitem_prefix] = Array ('ParentPrefix' => $event->Prefix);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
}
+
+ /**
+ * Returns constrain for priority calculations
+ *
+ * @see PriorityEventHandler
+ * @param kEvent $event
+ */
+ 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 14320)
+++ units/categories/categories_event_handler.php (working copy)
@@ -763,12 +763,6 @@
$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
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
@@ -801,16 +795,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'));
}
@@ -819,7 +803,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);
@@ -867,12 +851,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);
}
@@ -895,7 +873,6 @@
$this->Conn->Query($sql);
}
-
/**
* Exclude root categories from deleting
*
@@ -920,25 +897,6 @@
$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();
-
- $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));
- }
}
/**
@@ -1026,14 +984,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();
}
@@ -1159,13 +1109,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')) {
@@ -1966,37 +1924,9 @@
unset($field_options['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 prioriry right after load for comparing when updating
- $object->SetDBField('OldPriority', $object->GetDBField('Priority'));
}
/**
- * 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
@@ -2059,39 +1989,9 @@
return;
}
- $object =& $event->getObject( Array('skip_autoload' => true) );
- $ids = $this->StoreSelectedIDs($event);
+ $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
+ $event->CallSubEvent('priority:' . $event->Name);
- 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();
}
@@ -2108,11 +2008,9 @@
return;
}
- $priority_helper =& $this->Application->recallObject('PriorityHelper');
- /* @var $priority_helper kPriorityHelper */
+ $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
+ $event->CallSubEvent('priority:OnRecalculatePriorities');
- $parent_id = $this->Application->GetVar('m_cat_id');
- $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id);
$this->_resetMenuCache();
}
@@ -2438,4 +2336,34 @@
$object->setID($id);
}
}
+
+ /**
+ * Returns constrain for priority calculations
+ *
+ * @see PriorityEventHandler
+ * @param kEvent $event
+ */
+ 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();
+ $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 14318)
+++ units/helpers/priority_helper.php (working copy)
@@ -16,16 +16,16 @@
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();
@@ -33,30 +33,33 @@
$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 (!isset($object->Fields['OldPriority'])) {
+ if ( !isset($object->Fields['OldPriority']) ) {
$object->VirtualFields['OldPriority'] = Array('type' => 'int', 'default' => 0);
}
$items_count = $this->Conn->GetOne($sql);
- // instanceof is not used, because PHP4 doesn't support it
+ // TODO: 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 prioriry right after load for comparing when updating
$object->SetDBField('OldPriority', $current_priority);
}
@@ -65,26 +68,29 @@
}
$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
*/
- 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);
}
@@ -92,57 +98,69 @@
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
- $ids = array();
+ $ids = Array ();
$not_processed = array_keys($changes);
foreach ($changes as $id => $pair) {
array_push($ids, $id);
- $constrain = isset($pair['parent']) ? 'ParentId = '.$pair['parent'].' AND ' : '';
- if ($pair['old'] == 'new') {
+ $constrain = isset($pair['constrain']) ? $this->normalizeConstrain($pair['constrain']) . ' AND ' : '';
+
+ 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];
$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) {
$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)] );
}
+
return $ids;
}
@@ -151,25 +169,67 @@
*
* @param kEvent $event
* @param string $constrain
+ * @param string $joins
*/
- 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';
+ $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;
+ }
+
+ /**
+ * Peforms 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 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => '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'
+ ),
+ );
Index: units/priorites/priority_eh.php
===================================================================
--- units/priorites/priority_eh.php (revision 0)
+++ units/priorites/priority_eh.php (revision 0)
@@ -0,0 +1,369 @@
+<?php
+
+class PriorityEventHandler extends kDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+
+ $permissions = Array (
+ 'OnRecalculatePriorities' => 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');
+
+ 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,
+ $hook['Mode'],
+ $event->Prefix,
+ $hook['DoSpecial'],
+ $hook['DoEvent'],
+ $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');
+
+ $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
priority_eh_v4.patch [^] (31,501 bytes) 2011-08-30 09:45
[Show Content]
Index: kernel/db/db_event_handler.php
===================================================================
--- kernel/db/db_event_handler.php (revision 14476)
+++ kernel/db/db_event_handler.php (working copy)
@@ -2964,4 +2964,15 @@
$clones[$subitem_prefix] = Array ('ParentPrefix' => $event->Prefix);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
}
+
+ /**
+ * Returns constrain for priority calculations
+ *
+ * @see PriorityEventHandler
+ * @param kEvent $event
+ */
+ 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 14511)
+++ units/categories/categories_event_handler.php (working copy)
@@ -775,12 +775,6 @@
$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
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
@@ -813,16 +807,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'));
}
@@ -831,7 +815,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);
@@ -879,12 +863,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);
}
@@ -907,7 +885,6 @@
$this->Conn->Query($sql);
}
-
/**
* Exclude root categories from deleting
*
@@ -932,25 +909,6 @@
$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();
-
- $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));
- }
}
/**
@@ -1038,14 +996,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();
}
@@ -1171,13 +1121,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')) {
@@ -1979,37 +1937,9 @@
unset($field_options['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 prioriry right after load for comparing when updating
- $object->SetDBField('OldPriority', $object->GetDBField('Priority'));
}
/**
- * 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
@@ -2072,39 +2002,9 @@
return;
}
- $object =& $event->getObject( Array('skip_autoload' => true) );
- $ids = $this->StoreSelectedIDs($event);
+ $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
+ $event->CallSubEvent('priority:' . $event->Name);
- 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();
}
@@ -2121,11 +2021,9 @@
return;
}
- $priority_helper =& $this->Application->recallObject('PriorityHelper');
- /* @var $priority_helper kPriorityHelper */
+ $this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
+ $event->CallSubEvent('priority:OnRecalculatePriorities');
- $parent_id = $this->Application->GetVar('m_cat_id');
- $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id);
$this->_resetMenuCache();
}
@@ -2466,4 +2364,34 @@
$object->setID($id);
}
}
+
+ /**
+ * Returns constrain for priority calculations
+ *
+ * @see PriorityEventHandler
+ * @param kEvent $event
+ */
+ 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();
+ $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 14476)
+++ units/helpers/priority_helper.php (working copy)
@@ -16,47 +16,54 @@
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();
$field_options = $object->GetFieldOptions('Priority');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
+ if ( $object->IsTempTable() ) {
+ $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $object->Prefix);
+ }
+
$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 (!isset($object->Fields['OldPriority'])) {
+ if ( !isset($object->Fields['OldPriority']) ) {
$object->VirtualFields['OldPriority'] = Array('type' => 'int', 'default' => 0);
}
$items_count = $this->Conn->GetOne($sql);
- // instanceof is not used, because PHP4 doesn't support it
+ // TODO: 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 prioriry right after load for comparing when updating
$object->SetDBField('OldPriority', $current_priority);
}
@@ -65,26 +72,29 @@
}
$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
*/
- 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);
}
@@ -92,57 +102,73 @@
$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 ' : '';
- if ($pair['old'] == 'new') {
+ $constrain = isset($pair['constrain']) ? $this->normalizeConstrain($pair['constrain']) . ' AND ' : '';
+
+ 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];
$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) {
$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)] );
}
+
return $ids;
}
@@ -151,25 +177,71 @@
*
* @param kEvent $event
* @param string $constrain
+ * @param string $joins
*/
- 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;
+ }
+
+ /**
+ * Peforms 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 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => '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,373 @@
+<?php
+
+class PriorityEventHandler extends kDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+
+ $permissions = Array (
+ 'OnRecalculatePriorities' => 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');
+
+ 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,
+ $hook['Mode'],
+ $event->Prefix,
+ $hook['DoSpecial'],
+ $hook['DoEvent'],
+ $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
priority_eh_v4_520.patch [^] (34,737 bytes) 2011-10-03 09:47
[Show Content]
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 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => '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 @@
+<?php
+
+class PriorityEventHandler extends kDBEventHandler {
+
+ /**
+ * Allows to override standart permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+
+ $permissions = Array (
+ 'OnRecalculatePriorities' => 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
|