Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F803511
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Feb 25, 1:20 PM
Size
20 KB
Mime Type
text/x-diff
Expires
Thu, Feb 27, 1:20 PM (19 h, 57 m)
Engine
blob
Format
Raw Data
Handle
576321
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/core/units/priorites/priority_eh.php
===================================================================
--- branches/5.2.x/core/units/priorites/priority_eh.php (revision 15261)
+++ branches/5.2.x/core/units/priorites/priority_eh.php (revision 15262)
@@ -1,398 +1,399 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PriorityEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnRecalculatePriorities' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
parent::mapEvents();
$events_map = Array (
'OnMassMoveUp' => 'OnChangePriority',
'OnMassMoveDown' => 'OnChangePriority',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Occurs, when config was parsed, allows to change config data dynamically
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterConfigRead(kEvent $event)
{
parent::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 != kEvent::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($prefix . ':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_special', $event->MasterEvent->Special);
$constrain_event->setEventParam('original_event', $event->MasterEvent->Name);
$this->Application->HandleEvent($constrain_event);
return $constrain_event->getEventParam('constrain_info');
}
}
Index: branches/5.2.x/core/units/helpers/priority_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/priority_helper.php (revision 15261)
+++ branches/5.2.x/core/units/helpers/priority_helper.php (revision 15262)
@@ -1,245 +1,248 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
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 = '', $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 . ' 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);
$object->setVirtualFields($virtual_fields);
}
$items_count = $this->Conn->GetOne($sql);
$current_priority = $object instanceof kDBList ? 0 : $object->GetDBField('Priority');
if ( $is_new || $current_priority == -($items_count + 1) ) {
$items_count++;
}
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);
}
for ($i = 1; $i <= $items_count; $i++) {
$field_options['options'][-$i] = $i;
}
$object->SetFieldOptions('Priority', $field_options);
}
/**
* Updates priorities for changed items
*
* @param kEvent $event
* @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 = '', $joins = '')
{
// 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 && !isset($pair['constrain']) ) {
// adding new item without constrain -> priority stays the same
return Array ($id);
}
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
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['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(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 item_table.Priority = item_table.Priority + 1';
$where = ' WHERE ' . $constrain . '
item_table.Priority >= ' . $pair['new'] . '
AND
item_table.Priority < ' . $pair['old'] . '
AND
' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')';
}
elseif ( $pair['new'] > $pair['old'] ) {
$set = ' SET item_table.Priority = item_table.Priority - 1';
$where = ' WHERE ' . $constrain . '
item_table.Priority > ' . $pair['old'] . '
AND
item_table.Priority <= ' . $pair['new'] . '
AND
' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')';
}
else {
$set = ' SET item_table.Priority = ' . $pair['new'];
$where = ' WHERE ' . $id_field . ' = ' . $id;
}
$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;
}
/**
* Recalculates priorities
*
* @param kEvent $event
* @param string $constrain
* @param string $joins
* @return Array
*/
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);
+
+ if ( $constrain ) {
+ $constrain = $this->normalizeConstrain($constrain);
+ }
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;
$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
Event Timeline
Log In to Comment