Page MenuHomeIn-Portal Phabricator

priority_helper.php
No OneTemporary

File Metadata

Created
Fri, Feb 7, 5:39 PM

priority_helper.php

<?php
/**
* @version $Id: priority_helper.php 16513 2017-01-20 14:10:53Z alex $
* @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 = '')
{
/** @var kDBItem $object */
$object = $event->getObject();
$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) || $this->isTempTableOnly($object) ) {
$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);
}
/**
* Determines if an item only exists in temp table.
*
* @param kDBBase $object Object.
*
* @return boolean
*/
protected function isTempTableOnly(kDBBase $object)
{
if ( !$object->IsTempTable() || ($object instanceof kDBList) ) {
return false;
}
return $object->GetID() <= 0;
}
/**
* 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 ();
}
$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');
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);
/** @var kDBItem $dummy */
$dummy = $this->Application->recallObject($prefix . '.-dummy', null, Array ('skip_autoload' => true));
$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();
}
}
}

Event Timeline