Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Tue, Sep 23, 1:14 PM

in-portal

Index: trunk/kernel/units/categories/categories_event_handler.php
===================================================================
--- trunk/kernel/units/categories/categories_event_handler.php (revision 5175)
+++ trunk/kernel/units/categories/categories_event_handler.php (revision 5176)
@@ -1,271 +1,287 @@
<?php
class CategoriesEventHandler extends InpDBEventHandler {
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnRebuildCache' => Array('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Apply system filter to categories list
*
* @param kEvent $event
*/
function SetCustomQuery(&$event)
{
parent::SetCustomQuery($event);
$types=$event->getEventParam('types');
$except_types=$event->getEventParam('except');
$object =& $event->getObject();
$type_clauses = Array();
$object =& $event->getObject();
if ( $event->getEventParam('parent_cat_id') ) {
$parent_cat_id = $event->getEventParam('parent_cat_id');
if ($parent_cat_id == 'Root') {
$module_name = $event->getEventParam('module') ? $event->getEventParam('module') : 'In-Commerce';
$module =& $this->Application->recallObject('mod.'.$module_name);
$parent_cat_id = $module->GetDBField('RootCat');
}
}
else {
$parent_cat_id = $this->Application->GetVar('c_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
if ($parent_cat_id != 'any') {
if ($event->getEventParam('recursive')) {
$current_path = $this->Conn->GetOne('SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId='.$parent_cat_id);
$subcats = $this->Conn->GetCol('SELECT CategoryId FROM '.TABLE_PREFIX.'Category WHERE ParentPath LIKE "'.$current_path.'%" ');
$object->addFilter('parent_filter', 'ParentId IN ('.implode(', ', $subcats).')');
}
else {
$object->addFilter('parent_filter', 'ParentId = '.$parent_cat_id);
}
}
$object->addFilter('parent_filter', 'ParentId = '.$parent_cat_id);
$object->addFilter('perm_filter', 'PermId = 1'); // check for CATEGORY.VIEW permission
if ($this->Application->GetVar('u_id') > 0) { // !$this->Application->IsAdmin() ||
// apply permission filters to all users except "root"
$groups = explode(',',$this->Application->RecallVar('UserGroups'));
foreach ($groups as $group) {
$view_filters[] = 'FIND_IN_SET('.$group.', acl) || ((NOT FIND_IN_SET('.$group.',dacl)) AND acl=\'\')';
}
$view_filter = implode(' OR ', $view_filters);
$object->addFilter('perm_filter2', $view_filter);
$object->addFilter('status_filter', $object->TableName.'.Status = 1');
}
if(strpos($types, 'category_related') !== false)
{
$object->removeFilter('parent_filter');
$resource_id = $this->Conn->GetOne('
SELECT ResourceId FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
WHERE CategoryId = '.$parent_cat_id
);
$sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'Relationship
WHERE SourceId = '.$resource_id.' AND SourceType = 1';
$related_cats = $this->Conn->GetCol($sql);
$related_cats = is_array($related_cats) ? $related_cats : Array();
$sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'Relationship
WHERE TargetId = '.$resource_id.' AND TargetType = 1 AND Type = 1';
$related_cats2 = $this->Conn->GetCol($sql);
$related_cats2 = is_array($related_cats2) ? $related_cats2 : Array();
$related_cats = array_unique( array_merge( $related_cats2, $related_cats ) );
if($related_cats)
{
$type_clauses['category_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')';
$type_clauses['category_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')';
}
else
{
$type_clauses['category_related']['include'] = '0';
$type_clauses['category_related']['except'] = '1';
}
$type_clauses['category_related']['having_filter'] = false;
}
if(strpos($types, 'product_related') !== false)
{
$object->removeFilter('parent_filter');
$product_id = $event->getEventParam('product_id') ? $event->getEventParam('product_id') : $this->Application->GetVar('p_id');
$resource_id = $this->Conn->GetOne('
SELECT ResourceId FROM '.$this->Application->getUnitOption('p', 'TableName').'
WHERE ProductId = '.$product_id
);
$sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'Relationship
WHERE SourceId = '.$resource_id.' AND TargetType = 1';
$related_cats = $this->Conn->GetCol($sql);
$related_cats = is_array($related_cats) ? $related_cats : Array();
$sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'Relationship
WHERE TargetId = '.$resource_id.' AND SourceType = 1 AND Type = 1';
$related_cats2 = $this->Conn->GetCol($sql);
$related_cats2 = is_array($related_cats2) ? $related_cats2 : Array();
$related_cats = array_unique( array_merge( $related_cats2, $related_cats ) );
if($related_cats)
{
$type_clauses['product_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')';
$type_clauses['product_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')';
}
else
{
$type_clauses['product_related']['include'] = '0';
$type_clauses['product_related']['except'] = '1';
}
$type_clauses['product_related']['having_filter'] = false;
}
/********************************************/
$includes_or_filter =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter->setType(FLT_TYPE_OR);
$excepts_and_filter =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter->setType(FLT_TYPE_AND);
$includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter_h->setType(FLT_TYPE_OR);
$excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter_h->setType(FLT_TYPE_AND);
$except_types_array=explode(',', $types);
if ($types){
$types_array=explode(',', $types);
for ($i=0; $i<sizeof($types_array); $i++){
$type=trim($types_array[$i]);
if (isset($type_clauses[$type])){
if ($type_clauses[$type]['having_filter']){
$includes_or_filter_h->removeFilter('filter_'.$type);
$includes_or_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}else{
$includes_or_filter->removeFilter('filter_'.$type);
$includes_or_filter->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}
}
}
}
if ($except_types){
$except_types_array=explode(',', $except_types);
for ($i=0; $i<sizeof($except_types_array); $i++){
$type=trim($except_types_array[$i]);
if (isset($type_clauses[$type])){
if ($type_clauses[$type]['having_filter']){
$excepts_and_filter_h->removeFilter('filter_'.$type);
$excepts_and_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}else{
$excepts_and_filter->removeFilter('filter_'.$type);
$excepts_and_filter->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}
}
}
}
$object->addFilter('includes_filter', $includes_or_filter);
$object->addFilter('excepts_filter', $excepts_and_filter);
$object->addFilter('includes_filter_h', $includes_or_filter_h, HAVING_FILTER);
$object->addFilter('excepts_filter_h', $excepts_and_filter_h, HAVING_FILTER);
}
function GetPassedId(&$event)
{
if ( $this->Application->IsAdmin() ) return parent::getPassedID($event);
$ret = $this->Application->GetVar('m_cat_id');
if($ret) return $ret;
return parent::getPassedID($event);
}
/**
* Rebuilds category cache
*
* @param kEvent $event
*/
function OnRebuildCache(&$event)
{
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
$event->SetRedirectParam('index_file', 'category/category_maint.php');
}
/**
* Adds calculates fields for item statuses
*
* @param kCatDBItem $object
* @param kEvent $event
*/
function prepareObject(&$object, &$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2,
IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue('Category_DaysNew').
'*3600*24), 1, 0),
%1$s.NewItem
)');
}
/**
* Set cache modification mark if needed
*
* @param kEvent $event
*/
function OnBeforeDeleteFromLive(&$event)
{
$id = $event->getEventParam('id');
if ($id == 0) {
// new category -> update chache
$this->Application->SetVar('require_cache_update', 1);
return ;
}
// existing category was edited, check if in-cache fields are modified
$temp_object =& $event->getObject( Array('skip_autoload' => true) );
$temp_object->Load($id);
$live_object =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('live_table' => true));
$live_object->Load($id);
$cached_fields = Array('Name', 'Filename', 'CategoryTemplate', 'ItemTemplate');
foreach ($cached_fields as $cached_field) {
if ($live_object->GetDBField($cached_field) != $temp_object->GetDBField($cached_field)) {
$this->Application->SetVar('require_cache_update', 1);
break;
}
}
}
+
+ /**
+ * Checks cache update mark and redirect to cache if needed
+ *
+ * @param kEvent $event
+ */
+ function OnSave(&$event)
+ {
+ parent::OnSave($event);
+ if ($event->status == erSUCCESS && $this->Application->GetVar('require_cache_update')) {
+ // "catalog" should be in opener stack by now
+ $opener_stack = unserialize($this->Application->RecallVar('opener_stack'));
+ $opener_stack[0] = str_replace('catalog', 'categories/cache_updater', $opener_stack[0]);
+ $this->Application->StoreVar('opener_stack', serialize($opener_stack));
+ }
+ }
}
?>
\ No newline at end of file
Property changes on: trunk/kernel/units/categories/categories_event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.15
\ No newline at end of property
+1.16
\ No newline at end of property
Index: trunk/kernel/units/categories/cache_updater.php
===================================================================
--- trunk/kernel/units/categories/cache_updater.php (revision 5175)
+++ trunk/kernel/units/categories/cache_updater.php (revision 5176)
@@ -1,355 +1,355 @@
<?php
class clsRecursionStack
{
var $Stack;
function clsRecursionStack()
{
$this->Stack = Array();
}
function Push($values)
{
array_push($this->Stack, $values);
}
function Pop()
{
if ($this->Count() > 0) {
return array_pop($this->Stack);
}
else {
return false;
}
}
function Get()
{
if ($this->Count() > 0) {
// return end($this->Stack);
return $this->Stack[count($this->Stack)-1];
}
else {
return false;
}
}
function Update($values)
{
$this->Stack[count($this->Stack)-1] = $values;
}
function Count()
{
return count($this->Stack);
}
}
class clsCachedPermissions
{
- var $Allow;
- var $Deny;
+ var $Allow = Array();
+ var $Deny = Array();
var $CatId;
function clsCachedPermissions($CatId)
{
$this->CatId = $CatId;
}
function SetCatId($CatId)
{
$this->CatId = $CatId;
}
function CheckPermArray($Perm)
{
if (!isset($this->Allow[$Perm])) {
$this->Allow[$Perm] = array();
$this->Deny[$Perm] = array();
}
}
function AddAllow($Perm, $GroupId)
{
$this->CheckPermArray($Perm);
if (!in_array($GroupId, $this->Allow[$Perm])) {
array_push($this->Allow[$Perm], $GroupId);
$this->RemoveDeny($Perm, $GroupId);
}
}
function AddDeny($Perm, $GroupId)
{
$this->CheckPermArray($Perm);
if (!in_array($GroupId, $this->Deny[$Perm])) {
array_push($this->Deny[$Perm], $GroupId);
$this->RemoveAllow($Perm, $GroupId);
}
}
function RemoveDeny($Perm, $GroupId)
{
if (in_array($GroupId, $this->Deny[$Perm])) {
array_splice($this->Deny[$Perm], array_search($GroupId, $this->Deny[$Perm]), 1);
}
}
function RemoveAllow($Perm, $GroupId)
{
if (in_array($GroupId, $this->Allow[$Perm])) {
array_splice($this->Allow[$Perm], array_search($GroupId, $this->Allow[$Perm]), 1);
}
}
function GetInsertSQL()
{
$values = array();
$has_deny = array();
foreach ($this->Deny as $perm => $groups) {
if (count($groups) > 0) {
$values[] = '('.$this->CatId.', '.$perm.', "", "'.join(',', $groups).'")';
$has_deny[] = $perm;
}
}
foreach ($this->Allow as $perm => $groups) {
if (in_array($perm, $has_deny)) continue;
if (count($groups) > 0) {
$values[] = '(' .$this->CatId. ', ' .$perm. ', "' .join(',', $groups). '", "")';
}
}
if (!$values) return '';
$sql = 'INSERT INTO '.TABLE_PREFIX.'PermCache (CategoryId, PermId, ACL, DACL) VALUES '.join(',', $values);
return $sql;
}
}
class kPermCacheUpdater extends kHelper
{
var $Stack;
var $iteration;
var $totalCats;
var $doneCats;
var $table;
var $root_prefixes = Array();
function Init($prefix, $special, $event_params = null)
{
parent::Init($prefix, $special, $event_params);
$continuing = $event_params['continue'];
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$this->root_prefixes[ $module_info['RootCat'] ] = $module_info['Var'];
}
$this->iteration = 0;
$this->table = $this->Application->GetTempName('permCacheUpdate');
if ($continuing == 1) {
$this->InitUpdater();
}
elseif ($continuing == 2) {
$this->getData();
}
}
function InitUpdater($continue)
{
$this->Stack =& new clsRecursionStack();
$sql = 'DELETE FROM '.TABLE_PREFIX.'PermCache';
$this->Conn->Query($sql);
$this->initData();
}
function getDonePercent()
{
if(!$this->totalCats)return 0;
return intval( round( $this->doneCats / $this->totalCats * 100 ) );
}
function getData()
{
$tmp = $this->Conn->GetOne('SELECT data FROM '.$this->table);
if ($tmp) $tmp = unserialize($tmp);
$this->totalCats = isset($tmp['totalCats']) ? $tmp['totalCats'] : 0;
$this->doneCats = isset($tmp['doneCats']) ? $tmp['doneCats'] : 0;
if (isset($tmp['stack'])) {
$this->Stack = $tmp['stack'];
}
else {
$this->Stack = & new clsRecursionStack();
}
}
function setData()
{
$tmp = Array (
'totalCats' => $this->totalCats,
'doneCats' => $this->doneCats,
'stack' => $this->Stack,
);
$this->Conn->Query('DELETE FROM '.$this->table);
$fields_hash = Array('data' => serialize($tmp));
$this->Conn->doInsert($fields_hash, $this->table);
}
function initData()
{
$this->clearData(); // drop table before starting anyway
$this->Conn->Query('CREATE TABLE '.$this->table.'(data LONGTEXT)');
$this->totalCats = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Category');
$this->doneCats = 0;
}
function clearData()
{
$this->Conn->Query('DROP TABLE IF EXISTS '.$this->table);
}
function DoTheJob()
{
$data = $this->Stack->Get();
if ($data === false) { //If Stack is empty
$data['current_id'] = 0;
$data['title'] = Array();
$data['named_path'] = Array();
$data['category_template'] = '';
$data['item_template'] = '';
$this->Stack->Push($data);
}
if (!isset($data['queried'])) {
$this->QueryTitle($data);
$this->QueryChildren($data);
$this->QueryPermissions($data);
$data['queried'] = 1;
if ($sql = $data['perms']->GetInsertSQL()) {
$this->Conn->Query($sql);
$this->doneCats++;
}
$this->iteration++;
}
// start with first child if we haven't started yet
if (!isset($data['current_child'])) $data['current_child'] = 0;
// if we have more children
if (isset($data['children'][$data['current_child']])) {
$next_data = Array();
$next_data['title'] = $data['title'];
$next_data['named_path'] = $data['named_path'];
$next_data['category_template'] = $data['category_template'];
$next_data['item_template'] = $data['item_template'];
$next_data['current_id'] = $data['children'][ $data['current_child'] ]; //next iteration should process child
$next_data['perms'] = $data['perms']; //we should copy our permissions to child - inheritance
$next_data['perms']->SetCatId($next_data['current_id']);
$data['current_child']++;
$this->Stack->Update($data); //we need to update ourself for the iteration after the next (or further) return to next child
$this->Stack->Push($next_data); //next iteration should process this child
return true;
}
else {
$this->UpdateCachedPath($data);
$this->Stack->Pop(); //remove ourself from stack if we have finished all the childs (or there are none)
// we are getting here if we finished with current level, so check if it's first level - then bail out.
return $this->Stack->Count() > 0;
}
}
function UpdateCachedPath(&$data)
{
$fields_hash = Array( 'CachedNavbar' => implode('>', $data['title']),
'NamedParentPath' => implode('/', $data['named_path'] ),
'CachedCategoryTemplate'=> $data['category_template'],
'CachedItemTemplate' => $data['item_template'],
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$data['current_id']);
}
function QueryTitle(&$data)
{
$category_id = $data['current_id'];
$sql = 'SELECT Name, Filename, CategoryTemplate, ItemTemplate
FROM '.TABLE_PREFIX.'Category
WHERE CategoryId = '.$category_id;
$record = $this->Conn->GetRow($sql);
if ($record) {
$data['title'][] = $record['Name'];
$data['named_path'][] = $record['Filename'];
// it is one of the modules root category
$root_prefix = isset($this->root_prefixes[$category_id]) ? $this->root_prefixes[$category_id] : false;
if ($root_prefix) {
$fields_hash = Array();
if (!$record['CategoryTemplate']) {
$record['CategoryTemplate'] = $this->Application->ConfigValue($root_prefix.'_CategoryTemplate');
$fields_hash['CategoryTemplate'] = $record['CategoryTemplate'];
}
if (!$record['ItemTemplate']) {
$record['ItemTemplate'] = $this->Application->ConfigValue($root_prefix.'_ItemTemplate');
$fields_hash['ItemTemplate'] = $record['ItemTemplate'];
}
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$category_id);
}
// if explicitly set, then use it; use parent template otherwise
if ($record['CategoryTemplate']) {
$data['category_template'] = $record['CategoryTemplate'];
}
if ($record['ItemTemplate']) {
$data['item_template'] = $record['ItemTemplate'];
}
}
}
function QueryChildren(&$data)
{
$sql = 'SELECT CategoryId
FROM '.TABLE_PREFIX.'Category
WHERE ParentId = '.$data['current_id'];
$data['children'] = $this->Conn->GetCol($sql);
}
function QueryPermissions(&$data)
{
// don't search for section "view" permissions here :)
$sql = 'SELECT ipc.PermissionConfigId, ip.GroupId, ip.PermissionValue
FROM '.TABLE_PREFIX.'Permissions AS ip
LEFT JOIN '.TABLE_PREFIX.'PermissionConfig AS ipc ON ipc.PermissionName = ip.Permission
WHERE (CatId = '.$data['current_id'].') AND (Permission LIKE "%.VIEW") AND (ip.Type = 0)';
$records = $this->Conn->Query($sql);
//create permissions array only if we don't have it yet (set by parent)
if (!isset($data['perms'])) {
$data['perms'] = new clsCachedPermissions($data['current_id']);
}
foreach ($records as $record) {
if ($record['PermissionValue'] == 1) {
$data['perms']->AddAllow($record['PermissionConfigId'], $record['GroupId']);
}
else {
$data['perms']->AddDeny($record['PermissionConfigId'], $record['GroupId']);
}
}
}
}
?>
\ No newline at end of file
Property changes on: trunk/kernel/units/categories/cache_updater.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
\ No newline at end of property
+1.4
\ No newline at end of property
Index: trunk/kernel/admin_templates/categories/cache_updater.tpl
===================================================================
--- trunk/kernel/admin_templates/categories/cache_updater.tpl (revision 5175)
+++ trunk/kernel/admin_templates/categories/cache_updater.tpl (revision 5176)
@@ -1,97 +1,87 @@
<inp2:m_RequireLogin permissions="CATEGORY.VIEW"/>
-
-
-<!-- do this from OnSave php event when substitung opener
-<inp2:m_if check="m_RecallEquals" name="PermCache_UpdateRequired" value="1" inverse="inverse">
- <script type="text/javascript">
- window.location.href = '<inp2:m_t t="catalog" pass="all" escape="1"/>';
- </script>
-</inp2:m_if>
--->
-
<inp2:m_include t="incs/header" nobody="yes"/>
<body topmargin="0" leftmargin="8" marginheight="0" marginwidth="8" bgcolor="#FFFFFF">
<inp2:m_ParseBlock name="section_header" prefix="c" icon="icon46_catalog" module="in-portal" title="!la_title_Categories!"/>
<inp2:m_ParseBlock name="blue_bar" prefix="c" title_preset="categories_update" module="in-portal" icon="icon46_catalog"/>
<inp2:m_if check="c_InitCacheUpdater" destination_template="catalog">
<table width="100%" border="0" cellspacing="0" cellpadding="2" class="tableborder">
<tr>
<td align="center" colspan="3" bgcolor="#FFFFFF">
<inp2:m_phrase name="la_confirm_maintenance"/>
</td>
</tr>
<tr>
<td align="center" colspan="3" bgcolor="#FFFFFF">
<inp2:m_phrase name="la_prompt_perform_now"/>
</td>
</tr>
<tr>
<td align="right" width="50%">
<input type="button" name="yes_btn" value="<inp2:m_phrase name="lu_yes"/>" onclick="goto_url('<inp2:m_t continue="1"/>');" class="button" />
</td>
<td>
<img src="img/spacer.gif" width="10" />
</td>
<td align="left" width="50%">
<input type="button" name="yes_btn" value="<inp2:m_phrase name="lu_no"/>" onclick="javascript:goto_url('<inp2:m_t continue="0"/>');" class="button" />
</td>
</tr>
</table>
<inp2:m_else/>
<script type="text/javascript" src="incs/ajax.js"></script>
<table cellspacing="0" cellpadding="2" width="100%" border="0" class="tableborder">
<tr>
<td id="current_percent" bgcolor="#4682B2" style="width: 0%;"></td>
<td id="percents_left" bgcolor="#FFFFFF" style="width: 100%;"><img src="img/spacer.gif" height="15" width="1" alt="" /></td>
</tr>
</table>
<script type="text/javascript">
function CacheUpdater($url) {
this.URL = $url;
this.BusyRequest = false;
this.Query();
}
CacheUpdater.prototype.Query = function() {
Request.makeRequest(this.URL, this.BusyRequest, '', this.successCallback, this.errorCallback, '', this);
}
CacheUpdater.prototype.successCallback = function($request, $params, $object) {
var $responce = $request.responseText;
if ($responce.match(/^#redirect#(.*)/)) {
$object.showProgress(100);
// redirect to external template requested
window.location.href = RegExp.$1;
return false;
}
$object.showProgress($responce);
$object.Query();
}
CacheUpdater.prototype.errorCallback = function($request, $params, $object) {
alert('AJAX ERROR: ' + Request.getErrorHtml($request));
}
CacheUpdater.prototype.showProgress = function ($percent) {
$percent = parseInt($percent);
document.getElementById('percents_done').innerHTML = '(' + $percent + '%)';
document.getElementById('current_percent').style.width = $percent + '%';
document.getElementById('percents_left').style.width = (100 - $percent) + '%';
}
$CacheUpdater = new CacheUpdater('<inp2:m_t t="xml/cache_updater" continue="2" no_amp="1"/>');
</script>
</inp2:m_if>
<script type="text/javascript">
function goto_url($url) {
window.location.href = $url;
}
</script>
<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Property changes on: trunk/kernel/admin_templates/categories/cache_updater.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/kernel/admin_templates/xml/categories_list.tpl
===================================================================
--- trunk/kernel/admin_templates/xml/categories_list.tpl (revision 5175)
+++ trunk/kernel/admin_templates/xml/categories_list.tpl (revision 5176)
@@ -1,72 +1,72 @@
<inp2:m_include t="incs/blocks"/>
<inp2:m_include t="incs/grid_blocks"/>
<inp2:c_InitList no_special="1" per_page="-1"/>
Grids['c'] = new Grid('c', 'table_white_selected', ':original', edit, a_toolbar);
Grids['c'].AddItemsByIdMask('td', /^c_([0-9-]+)/, 'c[$$ID$$][CategoryId]');
Grids['c'].InitItems();
Grids['c'].SetDependantToolbarButtons( new Array('edit','delete','approve','decline','sep3','cut','copy','move_up','move_down','sep6'));
<inp2:c_ViewMenu block="viewmenu_declaration" grid="Default" no_special="1" menu_perpage="no" menu_filters="yes" ajax="1"/>
<!-- substiture form action, like from was created from here -->
document.getElementById('categories_form').action = '<inp2:m_t pass="all" js_escape="1"/>';
$Catalog.setItemCount('c', '<inp2:c_TotalRecords no_special="1"/>');
$Catalog.ParentCategoryID = <inp2:c_GetParentCategory/>;
document.getElementById('c_search_warning').style.display = '<inp2:m_if check="m_RecallEquals" var="c_search_keyword" value="" inverse="inverse">block<inp2:m_else/>none</inp2:m_if>';
document.getElementById('c_search_keyword').value = '<inp2:c_SearchKeyword no_special="1" js_escape="1"/>';
<inp2:m_DefineElement name="root_cat_caption">
<span class="NAV_CURRENT_ITEM">
<inp2:m_if check="m_ParamEquals" name="current" value="1">
<inp2:c_RootCategoryName />
<inp2:m_else/>
<a class="control_link" href="javascript:$Catalog.go_to_cat(0);"><inp2:c_RootCategoryName /></a>
</inp2:m_if>
</span>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="category_caption">
<span class="NAV_CURRENT_ITEM">
<inp2:m_param name="separator"/>
<inp2:m_if check="m_ParamEquals" name="current" value="1" inverse="1">
<a class="control_link" href="javascript:$Catalog.go_to_cat(<inp2:m_param name="cat_id"/>);"><inp2:m_param name="cat_name"/></a>
<inp2:m_else/>
<inp2:m_param name="cat_name"/>
</inp2:m_if>
</span>
</inp2:m_DefineElement>
setInnerHTML('category_path', '<inp2:c_CategoryPath separator="&gt;" rootcatblock="root_cat_caption" rootmoduleblock="category_caption" currentblock="category_caption" block="category_caption" js_escape="1"/>');
<inp2:m_if check="m_GetEquals" name="m_cat_id" value="0">
a_toolbar.DisableButton('upcat');
a_toolbar.DisableButton('homecat');
<inp2:m_else/>
a_toolbar.EnableButton('upcat');
a_toolbar.EnableButton('homecat');
</inp2:m_if>
#separator#
<inp2:c_UpdateLastTemplate template="catalog"/>
<inp2:m_include t="categories/ci_blocks"/>
<br />
<table border="0" width="100%">
<inp2:m_DefineElement name="category_td">
<td valign="top" class="table_white text" id="<inp2:m_param name="PrefixSpecial"/>_<inp2:Field field="CategoryId"/>">
<input type="checkbox" name="<inp2:InputName field="$IdField"/>" id="<inp2:InputName field="$IdField"/>">
<img src="<inp2:ModulePath />img/itemicons/<inp2:ItemIcon grid="Default"/>">&nbsp;<span class="priority"><inp2:m_if check="FieldEquals" field="Priority" value="0" inverse="inverse"><sup><inp2:Field field="Priority"/></sup></inp2:m_if></span>
<a class="link" href="javascript:$Catalog.go_to_cat(<inp2:m_get name="c_id"/>);"><b><inp2:Field name="Name"/></b></a><span class="cat_desc">:</span>
- <span class="cat_pick"><inp2:m_if check="IsPick">Pick</inp2:m_if></span>
- <span class="cat_new"><inp2:m_if check="IsNew">New</inp2:m_if></span>
+ <inp2:m_RenderElement name="status_mark" field="EditorsPick" type="pick" PrefixSpecial="$PrefixSpecial"/>
+ <inp2:m_RenderElement name="status_mark" field="IsNew" type="new" PrefixSpecial="$PrefixSpecial"/>
<span class="cats_stats">(<inp2:SubCatCount/> / <inp2:ItemCount/>)</span><br>
<div style="padding-left: 3px;">
<span class="cat_desc"><inp2:Field field="Description"/></span><br>
<span class="cats_stats">(<inp2:Field field="CreatedOn" format="_regional_DateFormat"/>)</span>
</div>
</td>
</inp2:m_DefineElement>
<inp2:m_if check="c_TotalRecords" no_special="1">
<inp2:c_CategoryList no_special="1" block_main="category_td" per_page="-1" columns="2" direction="V" IdField="CategoryId" />
<inp2:m_else/>
<tr>
<td class="text">
<inp2:m_phrase name="la_text_NoCategories"/>
</td>
</tr>
</inp2:m_if>
</table></br>
Property changes on: trunk/kernel/admin_templates/xml/categories_list.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14
\ No newline at end of property
+1.15
\ No newline at end of property
Index: trunk/admin/category/permcacheupdate.php
===================================================================
--- trunk/admin/category/permcacheupdate.php (revision 5175)
+++ trunk/admin/category/permcacheupdate.php (revision 5176)
@@ -1,383 +1,383 @@
<?php
class clsRecursionStack
{
var $Stack;
function clsRecursionStack()
{
$this->Stack = Array();
}
function Push($values)
{
array_push($this->Stack, $values);
}
function Pop()
{
if ($this->Count() > 0) {
return array_pop($this->Stack);
}
else {
return false;
}
}
function Get()
{
if ($this->Count() > 0) {
// return end($this->Stack);
return $this->Stack[count($this->Stack)-1];
}
else {
return false;
}
}
function Update($values)
{
$this->Stack[count($this->Stack)-1] = $values;
}
function Count()
{
return count($this->Stack);
}
}
class clsCachedPermissions
{
- var $Allow;
- var $Deny;
+ var $Allow = Array();
+ var $Deny = Array();
var $CatId;
function clsCachedPermissions($CatId)
{
$this->CatId = $CatId;
}
function SetCatId($CatId)
{
$this->CatId = $CatId;
}
function CheckPermArray($Perm)
{
if (!isset($this->Allow[$Perm])) {
$this->Allow[$Perm] = array();
$this->Deny[$Perm] = array();
}
}
function AddAllow($Perm, $GroupId)
{
$this->CheckPermArray($Perm);
if (!in_array($GroupId, $this->Allow[$Perm])) {
array_push($this->Allow[$Perm], $GroupId);
$this->RemoveDeny($Perm, $GroupId);
}
}
function AddDeny($Perm, $GroupId)
{
$this->CheckPermArray($Perm);
if (!in_array($GroupId, $this->Deny[$Perm])) {
array_push($this->Deny[$Perm], $GroupId);
$this->RemoveAllow($Perm, $GroupId);
}
}
function RemoveDeny($Perm, $GroupId)
{
if (in_array($GroupId, $this->Deny[$Perm])) {
array_splice($this->Deny[$Perm], array_search($GroupId, $this->Deny[$Perm]), 1);
}
}
function RemoveAllow($Perm, $GroupId)
{
if (in_array($GroupId, $this->Allow[$Perm])) {
array_splice($this->Allow[$Perm], array_search($GroupId, $this->Allow[$Perm]), 1);
}
}
function GetInsertSQL()
{
$values = array();
$has_deny = array();
foreach ($this->Deny as $perm => $groups) {
if (count($groups) > 0) {
$values[] = '('.$this->CatId.', '.$perm.', "", "'.join(',', $groups).'")';
$has_deny[] = $perm;
}
}
foreach ($this->Allow as $perm => $groups) {
if (in_array($perm, $has_deny)) continue;
if (count($groups) > 0) {
$values[] = '(' .$this->CatId. ', ' .$perm. ', "' .join(',', $groups). '", "")';
}
}
if (!$values) return '';
$sql = 'INSERT INTO '.GetTablePrefix().'PermCache (CategoryId, PermId, ACL, DACL) VALUES '.join(',', $values);
return $sql;
}
}
class clsCacheUpdater
{
var $Stack;
var $iteration;
var $totalCats;
var $doneCats;
var $table;
var $root_prefixes = Array();
/**
* Kernel Application
*
* @var kApplication
*/
var $Application = null;
/**
* Enter description here...
*
* @var kDBConnection
*/
var $Conn = null;
function clsCacheUpdater($continuing=false)
{
$this->Application =& kApplication::Instance();
$this->Conn =& $this->Application->GetADODBConnection();
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$this->root_prefixes[ $module_info['RootCat'] ] = $module_info['Var'];
}
$this->conn =& GetADODBConnection();
$this->iteration = 0;
$this->table=$GLOBALS['objSession']->GetEditTable('permCacheUpdate');
if (!$continuing) {
$this->Stack =& new clsRecursionStack();
$sql = 'DELETE FROM '.GetTablePrefix().'PermCache';
$this->conn->Execute($sql);
$this->initData();
}
else {
$this->getData();
// $this->SetStack($data);
}
}
function getDonePercent()
{
if(!$this->totalCats)return 0;
return intval( round( $this->doneCats / $this->totalCats * 100 ) );
}
function getData()
{
$sql='SELECT data FROM '.$this->table;
if( $rs = $this->conn->Execute($sql) )
$tmp = unserialize($rs->fields['data']);
$this->totalCats = isset($tmp['totalCats']) ? $tmp['totalCats'] : 0;
$this->doneCats = isset($tmp['doneCats']) ? $tmp['doneCats'] : 0;
if(isset($tmp['stack']))
$this->Stack = $tmp['stack'];
else
$this->Stack = & new clsRecursionStack();
}
function setData()
{
$tmp=Array
(
'totalCats' =>$this->totalCats,
'doneCats' =>$this->doneCats,
'stack' =>$this->Stack,
);
$sql='DELETE FROM '.$this->table;
$this->conn->Execute($sql);
$sql='INSERT '.$this->table.' SET data="'.addslashes(serialize($tmp)).'"';
$this->conn->Execute($sql);
}
function initData()
{
$this->clearData(); // drop table before starting anyway
$sql = 'CREATE TABLE '.$this->table.'(data LONGTEXT)';
$this->conn->Execute($sql);
$sql='SELECT COUNT(*) as count FROM '.GetTablePrefix().'Category';
if( $rs = $this->conn->Execute($sql) )
$this->totalCats=$rs->fields['count'];
$this->doneCats=0;
}
function clearData()
{
$sql='DROP TABLE IF EXISTS '.$this->table;
$this->conn->Execute($sql);
}
function DoTheJob()
{
$data = $this->Stack->Get();
if ($data === false) { //If Stack is empty
$data['current_id'] = 0;
$data['title'] = Array();
$data['named_path'] = Array();
$data['category_template'] = '';
$data['item_template'] = '';
$this->Stack->Push($data);
}
if (!isset($data['queried'])) {
$this->QueryTitle($data);
$this->QueryChildren($data);
$this->QueryPermissions($data);
$data['queried'] = 1;
if($sql = $data['perms']->GetInsertSQL())
{
$this->conn->Execute($sql);
$this->doneCats++;
}
$this->iteration++;
}
// start with first child if we haven't started yet
if (!isset($data['current_child'])) $data['current_child'] = 0;
// if we have more children
if (isset($data['children'][$data['current_child']]))
{
$next_data = Array();
$next_data['title'] = $data['title'];
$next_data['named_path'] = $data['named_path'];
$next_data['category_template'] = $data['category_template'];
$next_data['item_template'] = $data['item_template'];
$next_data['current_id'] = $data['children'][$data['current_child']]; //next iteration should process child
$next_data['perms'] = $data['perms']; //we should copy our permissions to child - inheritance
$next_data['perms']->SetCatId($next_data['current_id']);
$data['current_child']++;
$this->Stack->Update($data); //we need to update ourself for the iteration after the next (or further) return to next child
$this->Stack->Push($next_data); //next iteration should process this child
return true;
}
else {
$this->UpdateCachedPath($data);
$this->Stack->Pop(); //remove ourself from stack if we have finished all the childs (or there are none)
// we are getting here if we finished with current level, so check if it's first level - then bail out.
return $this->Stack->Count() > 0;
}
}
function UpdateCachedPath(&$data)
{
$fields_hash = Array( 'CachedNavbar' => implode('>', $data['title']),
'NamedParentPath' => implode('/', $data['named_path'] ),
'CachedCategoryTemplate'=> $data['category_template'],
'CachedItemTemplate' => $data['item_template'],
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$data['current_id']);
}
function QueryTitle(&$data)
{
$category_id = $data['current_id'];
$sql = 'SELECT Name, Filename, CategoryTemplate, ItemTemplate
FROM '.GetTablePrefix().'Category
WHERE CategoryId = '.$category_id;
$rs = $this->conn->Execute($sql);
if ($rs && !$rs->EOF)
{
$data['title'][] = $rs->fields['Name'];
$data['named_path'][] = $rs->fields['Filename'];
// it is one of the modules root category
$root_prefix = isset($this->root_prefixes[$category_id]) ? $this->root_prefixes[$category_id] : false;
if ($root_prefix) {
$fields_hash = Array();
if (!$rs->fields['CategoryTemplate']) {
$rs->fields['CategoryTemplate'] = $this->Application->ConfigValue($root_prefix.'_CategoryTemplate');
$fields_hash['CategoryTemplate'] = $rs->fields['CategoryTemplate'];
}
if (!$rs->fields['ItemTemplate']) {
$rs->fields['ItemTemplate'] = $this->Application->ConfigValue($root_prefix.'_ItemTemplate');
$fields_hash['ItemTemplate'] = $rs->fields['ItemTemplate'];
}
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$category_id);
}
// if explicitly set, then use it; use parent template otherwise
if ($rs->fields['CategoryTemplate']) {
$data['category_template'] = $rs->fields['CategoryTemplate'];
}
if ($rs->fields['ItemTemplate']) {
$data['item_template'] = $rs->fields['ItemTemplate'];
}
}
}
function QueryChildren(&$data)
{
$sql = sprintf('SELECT CategoryId FROM '.GetTablePrefix().'Category WHERE ParentId = %s',
$data['current_id']);
$rs = $this->conn->Execute($sql);
$data['children'] = Array();
while ($rs && !$rs->EOF)
{
$data['children'][] = $rs->fields['CategoryId'];
$rs->MoveNext();
}
}
function QueryPermissions(&$data)
{
// don't search for section "view" permissions here :)
$sql = sprintf('SELECT ipc.PermissionConfigId, ip.GroupId, ip.PermissionValue FROM '.GetTablePrefix().'Permissions AS ip
LEFT JOIN '.GetTablePrefix().'PermissionConfig AS ipc
ON ipc.PermissionName = ip.Permission
WHERE (CatId = %s) AND (Permission LIKE "%%.VIEW") AND (ipc.PermissionConfigId IS NOT NULL)',
$data['current_id']);
$rs = $this->conn->Execute($sql);
//create permissions array only if we don't have it yet (set by parent)
if (!isset($data['perms'])) {
$data['perms'] = new clsCachedPermissions($data['current_id']);
}
while ($rs && !$rs->EOF)
{
if ($rs->fields['PermissionValue'] == 1) {
$data['perms']->AddAllow($rs->fields['PermissionConfigId'], $rs->fields['GroupId']);
}
else {
$data['perms']->AddDeny($rs->fields['PermissionConfigId'], $rs->fields['GroupId']);
}
$rs->MoveNext();
}
}
}
?>
\ No newline at end of file
Property changes on: trunk/admin/category/permcacheupdate.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.8
\ No newline at end of property
+1.9
\ No newline at end of property
Index: trunk/core/kernel/utility/temp_handler.php
===================================================================
--- trunk/core/kernel/utility/temp_handler.php (revision 5175)
+++ trunk/core/kernel/utility/temp_handler.php (revision 5176)
@@ -1,658 +1,658 @@
<?php
class kTempTablesHandler extends kBase {
var $Tables = Array();
/**
* Master table name for temp handler
*
* @var string
* @access private
*/
var $MasterTable = '';
/**
* IDs from master table
*
* @var Array
* @access private
*/
var $MasterIDs = Array();
var $AlreadyProcessed = Array();
var $DroppedTables = Array();
var $FinalRefs = Array();
var $CopiedTables = Array();
/**
* IDs of newly cloned items (key - prefix.special, value - array of ids)
*
* @var Array
*/
var $savedIDs = Array();
/**
* Description
*
* @var kDBConnection
* @access public
*/
var $Conn;
function kTempTablesHandler()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
function SetTables($tables)
{
// set tablename as key for tables array
$ret = Array();
$this->Tables = $tables;
$this->MasterTable = $tables['TableName'];
}
function saveID($prefix, $special = '', $id = null)
{
$this->savedIDs[$prefix.($special ? '.' : '').$special][] = $id;
}
/**
* Get temp table name
*
* @param string $table
* @return string
*/
function GetTempName($table)
{
return $this->Application->GetTempName($table);
}
function GetTempTablePrefix()
{
return $this->Application->GetTempTablePrefix();
}
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
function GetLiveName($temp_table)
{
return $this->Application->GetLiveName($temp_table);
}
function IsTempTable($table)
{
return $this->Application->IsTempTable($table);
}
/**
* Return temporary table name for master table
*
* @return string
* @access public
*/
function GetMasterTempName()
{
return $this->GetTempName($this->MasterTable);
}
function CreateTempTable($table)
{
$query = sprintf("CREATE TABLE %s SELECT * FROM %s WHERE 0",
$this->GetTempName($table),
$table);
$this->Conn->Query($query);
}
function BuildTables($prefix, $ids)
{
$this->TableIdCounter = 0;
$tables = Array(
'TableName' => $this->Application->getUnitOption($prefix, 'TableName'),
'IdField' => $this->Application->getUnitOption($prefix, 'IDField'),
'IDs' => $ids,
'Prefix' => $prefix,
'TableId' => $this->TableIdCounter++,
);
$parent_prefix = $this->Application->getUnitOption($prefix, 'ParentPrefix');
if ($parent_prefix) {
$tables['ForeignKey'] = $this->Application->getUnitOption($prefix, 'ForeignKey');
$tables['ParentPrefix'] = $parent_prefix;
$tables['ParentTableKey'] = $this->Application->getUnitOption($prefix, 'ParentTableKey');
}
$this->FinalRefs[ $tables['TableName'] ] = $tables['TableId']; // don't forget to add main table to FinalRefs too
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
if (is_array($SubItems)) {
foreach ($SubItems as $prefix) {
$this->AddTables($prefix, $tables);
}
}
$this->SetTables($tables);
}
function AddTables($prefix, &$tables)
{
$tmp = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
'ParentPrefix' => $this->Application->getUnitOption($prefix, 'ParentPrefix'),
'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
'Prefix' => $prefix,
'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
'TableId' => $this->TableIdCounter++,
);
$this->FinalRefs[ $tmp['TableName'] ] = $tmp['TableId'];
$constrain = $this->Application->getUnitOption($prefix,'Constrain');
if ($constrain)
{
$tmp['Constrain'] = $constrain;
$this->FinalRefs[ $tmp['TableName'].$tmp['Constrain'] ] = $tmp['TableId'];
}
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
$same_sub_counter = 1;
if( is_array($SubItems) )
{
foreach($SubItems as $prefix)
{
$this->AddTables($prefix, $tmp);
}
}
if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
$tables['SubTables'] = array();
}
$tables['SubTables'][] = $tmp;
}
function CloneItems($prefix, $special, $ids, $master=null, $foreign_key=null, $parent_prefix = null)
{
if (!isset($master)) $master = $this->Tables;
// recalling by different name, because we may get kDBList, if we recall just by prefix
if (!preg_match('/(.*)-item$/', $special)) {
$special .= '-item';
}
$object =& $this->Application->recallObject($prefix.'.'.$special, $prefix, Array('skip_autoload' => true));
foreach ($ids as $id) {
$mode = 'create';
if ( $cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']) ) {
// if we have already cloned the id, replace it with cloned id and set mode to update
// update mode is needed to update second ForeignKey for items cloned by first ForeignKey
if ( getArrayValue($cloned_ids, $id) ) {
$id = $cloned_ids[$id];
$mode = 'update';
}
}
$object->Load($id);
$original_values = $object->FieldValues;
$object->NameCopy($master, $foreign_key);
if (isset($foreign_key)) {
$master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
$object->SetDBField($master_foreign_key_field, $foreign_key);
}
if ($mode == 'create') {
$this->RaiseEvent('OnBeforeClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key);
}
$res = $mode == 'update' ? $object->Update() : $object->Create();
if ($res)
{
if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
// remember original => clone mapping for dual ForeignKey updating
$this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
}
if($object->mode == 't') $object->setTempID();
if ($mode == 'create') {
$this->RaiseEvent('OnAfterClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key, array('original_id' => $id) );
$this->saveID($master['Prefix'], $special, $object->GetID());
}
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoClone')) continue;
$sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$sub_ids = $this->Conn->GetCol($query);
if ( is_array(getArrayValue($sub_table, 'ForeignKey')) ) {
// $sub_ids could containt newly cloned items, we need to remove it here
// to escape double cloning
$cloned_ids = getArrayValue($this->AlreadyProcessed, $sub_table['TableName']);
if ( !$cloned_ids ) $cloned_ids = Array();
$new_ids = array_values($cloned_ids);
$sub_ids = array_diff($sub_ids, $new_ids);
}
$parent_key = $object->GetDBField($parent_key_field);
$this->CloneItems($sub_table['Prefix'], $special, $sub_ids, $sub_table, $parent_key, $master['Prefix']);
}
}
}
}
if (!$ids) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = Array();
}
return $this->savedIDs[$prefix.($special ? '.' : '').$special];
}
function DeleteItems($prefix, $special, $ids, $master=null, $foreign_key=null)
{
if (!isset($master)) $master = $this->Tables;
if( strpos($prefix,'.') !== false ) list($prefix,$special) = explode('.', $prefix, 2);
$prefix_special = rtrim($prefix.'.'.$special, '.');
//recalling by different name, because we may get kDBList, if we recall just by prefix
$recall_prefix = $prefix_special.($special ? '' : '.').'-item';
$this->Application->setUnitOption($prefix,'AutoLoad',false);
$object =& $this->Application->recallObject($recall_prefix, $prefix);
foreach ($ids as $id)
{
$object->Load($id);
$original_values = $object->FieldValues;
if( !$object->Delete($id) ) continue;
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoDelete')) continue;
$sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? getArrayValue($sub_table, 'ParentTableKey', $master['Prefix']) : $sub_table['ParentTableKey'];
if (!$foreign_key_field || !$parent_key_field) continue;
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
$sub_ids = $this->Conn->GetCol($query);
$parent_key = $object->GetDBField(is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$prefix] : $sub_table['ParentTableKey']);
$this->DeleteItems($sub_table['Prefix'], '', $sub_ids, $sub_table, $parent_key);
}
}
}
}
function DoCopyLiveToTemp($master, $ids, $parent_prefix=null)
{
// when two tables refers the same table as sub-sub-table, and ForeignKey and ParentTableKey are arrays
// the table will be first copied by first sub-table, then dropped and copied over by last ForeignKey in the array
// this should not do any problems :)
if ( !preg_match("/.*\.[0-9]+/", $master['Prefix']) ) {
if( $this->DropTempTable($master['TableName']) )
{
$this->CreateTempTable($master['TableName']);
}
}
if (is_array($ids)) {
$ids = join(',', $ids);
}
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($ids != '' && !in_array($table_sig, $this->CopiedTables)) {
if ( getArrayValue($master, 'ForeignKey') ) {
if ( is_array($master['ForeignKey']) ) {
$key_field = $master['ForeignKey'][$parent_prefix];
}
else {
$key_field = $master['ForeignKey'];
}
}
else {
$key_field = $master['IdField'];
}
$query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
SELECT * FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], '', $this->Conn->GetCol($query) );
}
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
if (!$parent_key) continue;
if ( $ids != '' && $parent_key != $key_field ) {
$query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
$sub_foreign_keys = join(',', $this->Conn->GetCol($query));
}
else {
$sub_foreign_keys = $ids;
}
$this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
}
}
}
function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
{
$mode = 1; //multi
if (!is_array($live_id)) {
$live_id = Array($live_id);
$mode = 2; //single
}
if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
if ( isset($sub_table['ParentTableKey']) ) {
if ( is_array($sub_table['ParentTableKey']) ) {
$parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
}
else {
$parent_key_field = $sub_table['ParentTableKey'];
}
}
else {
$parent_key_field = $master['IdField'];
}
if ( $cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field) ) {
if ( array_key_exists(serialize($live_id), $cached) ) {
list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
}
if ($parent_key_field != $master['IdField']) {
$query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
$live_foreign_key = $this->Conn->GetCol($query);
if (isset($temp_id)) {
$query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' IN ('.join(',', $temp_id).')';
$temp_foreign_key = $this->Conn->GetCol($query);
}
else {
$temp_foreign_key = Array();
}
}
else {
$live_foreign_key = $live_id;
$temp_foreign_key = $temp_id;
}
$this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
function DoCopyTempToOriginal($master, $parent_prefix=null)
{
$query = 'SELECT '.$master['IdField'].' FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$current_ids = $this->Conn->GetCol($query);
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($current_ids) {
// delete all ids from live table - for MasterTable ONLY!
// because items from Sub Tables get deteleted in CopySubTablesToLive !BY ForeignKey!
if ($master['TableName'] == $this->MasterTable) {
$this->RaiseEvent( 'OnBeforeDeleteFromLive', $master['Prefix'], '', $current_ids );
-
- // Do not delete live items with 0 id
- // otherwise home category permissions got deleted when creating new category
- $del_ids = $current_ids;
- array_splice($del_ids, array_search(0, $current_ids), 1);
- if (count($del_ids) >= 1) {
- $query = 'DELETE FROM '.$master['TableName'].' WHERE '.$master['IdField'].' IN ('.join(',', $del_ids).')';
- $this->Conn->Query($query);
- }
+
+ $query = 'DELETE FROM '.$master['TableName'].' WHERE '.$master['IdField'].' IN ('.join(',', $current_ids).')';
+ $this->Conn->Query($query);
}
if ( getArrayValue($master, 'SubTables') ) {
if( in_array($table_sig, $this->CopiedTables) || $this->FinalRefs[$table_sig] != $master['TableId'] ) return;
foreach($current_ids AS $id)
{
$this->RaiseEvent( 'OnBeforeCopyToLive', $master['Prefix'], '', Array($id) );
//reset negative ids to 0, so autoincrement in live table works fine
if($id < 0)
{
$query = 'UPDATE '.$this->GetTempName($master['TableName']).'
SET '.$master['IdField'].' = 0
WHERE '.$master['IdField'].' = '.$id;
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
$id_to_copy = 0;
}
else
{
$id_to_copy = $id;
}
//copy current id_to_copy (0 for new or real id) to live table
$query = 'INSERT INTO '.$master['TableName'].'
SELECT * FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
$this->Conn->Query($query);
$insert_id = $id_to_copy == 0 ? $this->Conn->getInsertID() : $id_to_copy;
$this->RaiseEvent( 'OnAfterCopyToLive', $master['Prefix'], '', Array($insert_id), null, array('temp_id' => $id) );
$this->UpdateForeignKeys($master, $insert_id, $id);
//delete already copied record from master temp table
$query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
}
$this->CopiedTables[] = $table_sig;
// when all of ids in current master has been processed, copy all sub-tables data
$this->CopySubTablesToLive($master, $current_ids);
}
elseif( !in_array($table_sig, $this->CopiedTables) && ($this->FinalRefs[$table_sig] == $master['TableId']) ) { //If current master doesn't have sub-tables - we could use mass operations
// We don't need to delete items from live here, as it get deleted in the beggining of the method for MasterTable
// or in parent table processing for sub-tables
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], '', $current_ids);
// reset ALL negative IDs to 0 so it get inserted into live table with autoincrement
$query = 'UPDATE '.$this->GetTempName($master['TableName']).'
SET '.$master['IdField'].' = 0
WHERE '.$master['IdField'].' < 0';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
// copy ALL records to live table
$query = 'INSERT INTO '.$master['TableName'].'
SELECT * FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
/*
!!! WE NEED TO FIND A WAY TO DETERMINE IF OnAfterCopyToLive is not an empty method, and do on-by-one insert
and pass Ids to OnAfterCopyToLive, otherwise it's not smart to do on-by-one insert for any object
OR WE COULD FIND A WAY TO GET ALL INSERTED IDS as an array and iterate them !!!
$this->RaiseEvent('OnAfterCopyToLive', IDS ??? );
*/
// no need to clear temp table - it will be dropped by next statement
}
}
if ($this->FinalRefs[ $master['TableName'] ] != $master['TableId']) return;
/*if ( is_array(getArrayValue($master, 'ForeignKey')) ) { //if multiple ForeignKeys
if ( $master['ForeignKey'][$parent_prefix] != end($master['ForeignKey']) ) {
return; // Do not delete temp table if not all ForeignKeys have been processed (current is not the last)
}
}*/
$this->DropTempTable($master['TableName']);
}
function UpdateForeignKeys($master, $live_id, $temp_id) {
foreach ($master['SubTables'] as $sub_table) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) return;
list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
//Update ForeignKey in sub TEMP table
if ($live_foreign_key != $temp_foreign_key) {
$query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
SET '.$foreign_key_field.' = '.$live_foreign_key.'
WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
function CopySubTablesToLive($master, $current_ids) {
foreach ($master['SubTables'] as $sub_table) {
$table_sig = $sub_table['TableName'].(isset($sub_table['Constrain']) ? $sub_table['Constrain'] : '');
// delete records from live table by foreign key, so that records deleted from temp table
// get deleted from live
if (count($current_ids) > 0 && !in_array($table_sig, $this->CopiedTables) ) {
- $foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) continue;
$foreign_keys = $this->GetForeignKeys($master, $sub_table, $current_ids);
+ // Do not delete live sub-items with 0 id
+ // otherwise home category permissions got deleted when creating new category
+ $zero_id = array_search(0, $foreign_keys);
+ if ($zero_id !== false) {
+ array_splice($foreign_keys, $zero_id, 1);
+ }
if (count($foreign_keys) > 0) {
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], '', $this->Conn->GetCol($query) );
$query = 'DELETE FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
//sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
$this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
}
}
function RaiseEvent($name, $prefix, $special, $ids, $foreign_key = null, $add_params = null)
{
if ( !is_array($ids) ) return ;
$event_key = $prefix.($special ? '.' : '').$special.':'.$name;
$event = new kEvent($event_key);
if (isset($foreign_key)) {
$event->setEventParam('foreign_key', $foreign_key);
}
foreach($ids as $id)
{
$event->setEventParam('id', $id);
if (is_array($add_params)) {
foreach ($add_params as $name => $val) {
$event->setEventParam($name, $val);
}
}
$this->Application->HandleEvent($event);
}
}
function DropTempTable($table)
{
if( in_array($table, $this->DroppedTables) ) return false;
$query = sprintf("DROP TABLE IF EXISTS %s",
$this->GetTempName($table)
);
array_push($this->DroppedTables, $table);
$this->DroppedTables = array_unique($this->DroppedTables);
$this->Conn->Query($query);
return true;
}
function PrepareEdit()
{
$this->DoCopyLiveToTemp($this->Tables, $this->Tables['IDs']);
}
function SaveEdit($skip_master=0)
{
$this->DoCopyTempToOriginal($this->Tables);
}
function CancelEdit($master=null)
{
if (!isset($master)) $master = $this->Tables;
$this->DropTempTable($master['TableName']);
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$this->CancelEdit($sub_table);
}
}
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/temp_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.23
\ No newline at end of property
+1.24
\ No newline at end of property
Index: trunk/core/units/categories/categories_event_handler.php
===================================================================
--- trunk/core/units/categories/categories_event_handler.php (revision 5175)
+++ trunk/core/units/categories/categories_event_handler.php (revision 5176)
@@ -1,271 +1,287 @@
<?php
class CategoriesEventHandler extends InpDBEventHandler {
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnRebuildCache' => Array('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Apply system filter to categories list
*
* @param kEvent $event
*/
function SetCustomQuery(&$event)
{
parent::SetCustomQuery($event);
$types=$event->getEventParam('types');
$except_types=$event->getEventParam('except');
$object =& $event->getObject();
$type_clauses = Array();
$object =& $event->getObject();
if ( $event->getEventParam('parent_cat_id') ) {
$parent_cat_id = $event->getEventParam('parent_cat_id');
if ($parent_cat_id == 'Root') {
$module_name = $event->getEventParam('module') ? $event->getEventParam('module') : 'In-Commerce';
$module =& $this->Application->recallObject('mod.'.$module_name);
$parent_cat_id = $module->GetDBField('RootCat');
}
}
else {
$parent_cat_id = $this->Application->GetVar('c_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
if ($parent_cat_id != 'any') {
if ($event->getEventParam('recursive')) {
$current_path = $this->Conn->GetOne('SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId='.$parent_cat_id);
$subcats = $this->Conn->GetCol('SELECT CategoryId FROM '.TABLE_PREFIX.'Category WHERE ParentPath LIKE "'.$current_path.'%" ');
$object->addFilter('parent_filter', 'ParentId IN ('.implode(', ', $subcats).')');
}
else {
$object->addFilter('parent_filter', 'ParentId = '.$parent_cat_id);
}
}
$object->addFilter('parent_filter', 'ParentId = '.$parent_cat_id);
$object->addFilter('perm_filter', 'PermId = 1'); // check for CATEGORY.VIEW permission
if ($this->Application->GetVar('u_id') > 0) { // !$this->Application->IsAdmin() ||
// apply permission filters to all users except "root"
$groups = explode(',',$this->Application->RecallVar('UserGroups'));
foreach ($groups as $group) {
$view_filters[] = 'FIND_IN_SET('.$group.', acl) || ((NOT FIND_IN_SET('.$group.',dacl)) AND acl=\'\')';
}
$view_filter = implode(' OR ', $view_filters);
$object->addFilter('perm_filter2', $view_filter);
$object->addFilter('status_filter', $object->TableName.'.Status = 1');
}
if(strpos($types, 'category_related') !== false)
{
$object->removeFilter('parent_filter');
$resource_id = $this->Conn->GetOne('
SELECT ResourceId FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
WHERE CategoryId = '.$parent_cat_id
);
$sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'Relationship
WHERE SourceId = '.$resource_id.' AND SourceType = 1';
$related_cats = $this->Conn->GetCol($sql);
$related_cats = is_array($related_cats) ? $related_cats : Array();
$sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'Relationship
WHERE TargetId = '.$resource_id.' AND TargetType = 1 AND Type = 1';
$related_cats2 = $this->Conn->GetCol($sql);
$related_cats2 = is_array($related_cats2) ? $related_cats2 : Array();
$related_cats = array_unique( array_merge( $related_cats2, $related_cats ) );
if($related_cats)
{
$type_clauses['category_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')';
$type_clauses['category_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')';
}
else
{
$type_clauses['category_related']['include'] = '0';
$type_clauses['category_related']['except'] = '1';
}
$type_clauses['category_related']['having_filter'] = false;
}
if(strpos($types, 'product_related') !== false)
{
$object->removeFilter('parent_filter');
$product_id = $event->getEventParam('product_id') ? $event->getEventParam('product_id') : $this->Application->GetVar('p_id');
$resource_id = $this->Conn->GetOne('
SELECT ResourceId FROM '.$this->Application->getUnitOption('p', 'TableName').'
WHERE ProductId = '.$product_id
);
$sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'Relationship
WHERE SourceId = '.$resource_id.' AND TargetType = 1';
$related_cats = $this->Conn->GetCol($sql);
$related_cats = is_array($related_cats) ? $related_cats : Array();
$sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'Relationship
WHERE TargetId = '.$resource_id.' AND SourceType = 1 AND Type = 1';
$related_cats2 = $this->Conn->GetCol($sql);
$related_cats2 = is_array($related_cats2) ? $related_cats2 : Array();
$related_cats = array_unique( array_merge( $related_cats2, $related_cats ) );
if($related_cats)
{
$type_clauses['product_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')';
$type_clauses['product_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')';
}
else
{
$type_clauses['product_related']['include'] = '0';
$type_clauses['product_related']['except'] = '1';
}
$type_clauses['product_related']['having_filter'] = false;
}
/********************************************/
$includes_or_filter =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter->setType(FLT_TYPE_OR);
$excepts_and_filter =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter->setType(FLT_TYPE_AND);
$includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter');
$includes_or_filter_h->setType(FLT_TYPE_OR);
$excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter');
$excepts_and_filter_h->setType(FLT_TYPE_AND);
$except_types_array=explode(',', $types);
if ($types){
$types_array=explode(',', $types);
for ($i=0; $i<sizeof($types_array); $i++){
$type=trim($types_array[$i]);
if (isset($type_clauses[$type])){
if ($type_clauses[$type]['having_filter']){
$includes_or_filter_h->removeFilter('filter_'.$type);
$includes_or_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}else{
$includes_or_filter->removeFilter('filter_'.$type);
$includes_or_filter->addFilter('filter_'.$type, $type_clauses[$type]['include']);
}
}
}
}
if ($except_types){
$except_types_array=explode(',', $except_types);
for ($i=0; $i<sizeof($except_types_array); $i++){
$type=trim($except_types_array[$i]);
if (isset($type_clauses[$type])){
if ($type_clauses[$type]['having_filter']){
$excepts_and_filter_h->removeFilter('filter_'.$type);
$excepts_and_filter_h->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}else{
$excepts_and_filter->removeFilter('filter_'.$type);
$excepts_and_filter->addFilter('filter_'.$type, $type_clauses[$type]['except']);
}
}
}
}
$object->addFilter('includes_filter', $includes_or_filter);
$object->addFilter('excepts_filter', $excepts_and_filter);
$object->addFilter('includes_filter_h', $includes_or_filter_h, HAVING_FILTER);
$object->addFilter('excepts_filter_h', $excepts_and_filter_h, HAVING_FILTER);
}
function GetPassedId(&$event)
{
if ( $this->Application->IsAdmin() ) return parent::getPassedID($event);
$ret = $this->Application->GetVar('m_cat_id');
if($ret) return $ret;
return parent::getPassedID($event);
}
/**
* Rebuilds category cache
*
* @param kEvent $event
*/
function OnRebuildCache(&$event)
{
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
$event->SetRedirectParam('index_file', 'category/category_maint.php');
}
/**
* Adds calculates fields for item statuses
*
* @param kCatDBItem $object
* @param kEvent $event
*/
function prepareObject(&$object, &$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2,
IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue('Category_DaysNew').
'*3600*24), 1, 0),
%1$s.NewItem
)');
}
/**
* Set cache modification mark if needed
*
* @param kEvent $event
*/
function OnBeforeDeleteFromLive(&$event)
{
$id = $event->getEventParam('id');
if ($id == 0) {
// new category -> update chache
$this->Application->SetVar('require_cache_update', 1);
return ;
}
// existing category was edited, check if in-cache fields are modified
$temp_object =& $event->getObject( Array('skip_autoload' => true) );
$temp_object->Load($id);
$live_object =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('live_table' => true));
$live_object->Load($id);
$cached_fields = Array('Name', 'Filename', 'CategoryTemplate', 'ItemTemplate');
foreach ($cached_fields as $cached_field) {
if ($live_object->GetDBField($cached_field) != $temp_object->GetDBField($cached_field)) {
$this->Application->SetVar('require_cache_update', 1);
break;
}
}
}
+
+ /**
+ * Checks cache update mark and redirect to cache if needed
+ *
+ * @param kEvent $event
+ */
+ function OnSave(&$event)
+ {
+ parent::OnSave($event);
+ if ($event->status == erSUCCESS && $this->Application->GetVar('require_cache_update')) {
+ // "catalog" should be in opener stack by now
+ $opener_stack = unserialize($this->Application->RecallVar('opener_stack'));
+ $opener_stack[0] = str_replace('catalog', 'categories/cache_updater', $opener_stack[0]);
+ $this->Application->StoreVar('opener_stack', serialize($opener_stack));
+ }
+ }
}
?>
\ No newline at end of file
Property changes on: trunk/core/units/categories/categories_event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.15
\ No newline at end of property
+1.16
\ No newline at end of property
Index: trunk/core/units/categories/cache_updater.php
===================================================================
--- trunk/core/units/categories/cache_updater.php (revision 5175)
+++ trunk/core/units/categories/cache_updater.php (revision 5176)
@@ -1,355 +1,355 @@
<?php
class clsRecursionStack
{
var $Stack;
function clsRecursionStack()
{
$this->Stack = Array();
}
function Push($values)
{
array_push($this->Stack, $values);
}
function Pop()
{
if ($this->Count() > 0) {
return array_pop($this->Stack);
}
else {
return false;
}
}
function Get()
{
if ($this->Count() > 0) {
// return end($this->Stack);
return $this->Stack[count($this->Stack)-1];
}
else {
return false;
}
}
function Update($values)
{
$this->Stack[count($this->Stack)-1] = $values;
}
function Count()
{
return count($this->Stack);
}
}
class clsCachedPermissions
{
- var $Allow;
- var $Deny;
+ var $Allow = Array();
+ var $Deny = Array();
var $CatId;
function clsCachedPermissions($CatId)
{
$this->CatId = $CatId;
}
function SetCatId($CatId)
{
$this->CatId = $CatId;
}
function CheckPermArray($Perm)
{
if (!isset($this->Allow[$Perm])) {
$this->Allow[$Perm] = array();
$this->Deny[$Perm] = array();
}
}
function AddAllow($Perm, $GroupId)
{
$this->CheckPermArray($Perm);
if (!in_array($GroupId, $this->Allow[$Perm])) {
array_push($this->Allow[$Perm], $GroupId);
$this->RemoveDeny($Perm, $GroupId);
}
}
function AddDeny($Perm, $GroupId)
{
$this->CheckPermArray($Perm);
if (!in_array($GroupId, $this->Deny[$Perm])) {
array_push($this->Deny[$Perm], $GroupId);
$this->RemoveAllow($Perm, $GroupId);
}
}
function RemoveDeny($Perm, $GroupId)
{
if (in_array($GroupId, $this->Deny[$Perm])) {
array_splice($this->Deny[$Perm], array_search($GroupId, $this->Deny[$Perm]), 1);
}
}
function RemoveAllow($Perm, $GroupId)
{
if (in_array($GroupId, $this->Allow[$Perm])) {
array_splice($this->Allow[$Perm], array_search($GroupId, $this->Allow[$Perm]), 1);
}
}
function GetInsertSQL()
{
$values = array();
$has_deny = array();
foreach ($this->Deny as $perm => $groups) {
if (count($groups) > 0) {
$values[] = '('.$this->CatId.', '.$perm.', "", "'.join(',', $groups).'")';
$has_deny[] = $perm;
}
}
foreach ($this->Allow as $perm => $groups) {
if (in_array($perm, $has_deny)) continue;
if (count($groups) > 0) {
$values[] = '(' .$this->CatId. ', ' .$perm. ', "' .join(',', $groups). '", "")';
}
}
if (!$values) return '';
$sql = 'INSERT INTO '.TABLE_PREFIX.'PermCache (CategoryId, PermId, ACL, DACL) VALUES '.join(',', $values);
return $sql;
}
}
class kPermCacheUpdater extends kHelper
{
var $Stack;
var $iteration;
var $totalCats;
var $doneCats;
var $table;
var $root_prefixes = Array();
function Init($prefix, $special, $event_params = null)
{
parent::Init($prefix, $special, $event_params);
$continuing = $event_params['continue'];
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$this->root_prefixes[ $module_info['RootCat'] ] = $module_info['Var'];
}
$this->iteration = 0;
$this->table = $this->Application->GetTempName('permCacheUpdate');
if ($continuing == 1) {
$this->InitUpdater();
}
elseif ($continuing == 2) {
$this->getData();
}
}
function InitUpdater($continue)
{
$this->Stack =& new clsRecursionStack();
$sql = 'DELETE FROM '.TABLE_PREFIX.'PermCache';
$this->Conn->Query($sql);
$this->initData();
}
function getDonePercent()
{
if(!$this->totalCats)return 0;
return intval( round( $this->doneCats / $this->totalCats * 100 ) );
}
function getData()
{
$tmp = $this->Conn->GetOne('SELECT data FROM '.$this->table);
if ($tmp) $tmp = unserialize($tmp);
$this->totalCats = isset($tmp['totalCats']) ? $tmp['totalCats'] : 0;
$this->doneCats = isset($tmp['doneCats']) ? $tmp['doneCats'] : 0;
if (isset($tmp['stack'])) {
$this->Stack = $tmp['stack'];
}
else {
$this->Stack = & new clsRecursionStack();
}
}
function setData()
{
$tmp = Array (
'totalCats' => $this->totalCats,
'doneCats' => $this->doneCats,
'stack' => $this->Stack,
);
$this->Conn->Query('DELETE FROM '.$this->table);
$fields_hash = Array('data' => serialize($tmp));
$this->Conn->doInsert($fields_hash, $this->table);
}
function initData()
{
$this->clearData(); // drop table before starting anyway
$this->Conn->Query('CREATE TABLE '.$this->table.'(data LONGTEXT)');
$this->totalCats = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Category');
$this->doneCats = 0;
}
function clearData()
{
$this->Conn->Query('DROP TABLE IF EXISTS '.$this->table);
}
function DoTheJob()
{
$data = $this->Stack->Get();
if ($data === false) { //If Stack is empty
$data['current_id'] = 0;
$data['title'] = Array();
$data['named_path'] = Array();
$data['category_template'] = '';
$data['item_template'] = '';
$this->Stack->Push($data);
}
if (!isset($data['queried'])) {
$this->QueryTitle($data);
$this->QueryChildren($data);
$this->QueryPermissions($data);
$data['queried'] = 1;
if ($sql = $data['perms']->GetInsertSQL()) {
$this->Conn->Query($sql);
$this->doneCats++;
}
$this->iteration++;
}
// start with first child if we haven't started yet
if (!isset($data['current_child'])) $data['current_child'] = 0;
// if we have more children
if (isset($data['children'][$data['current_child']])) {
$next_data = Array();
$next_data['title'] = $data['title'];
$next_data['named_path'] = $data['named_path'];
$next_data['category_template'] = $data['category_template'];
$next_data['item_template'] = $data['item_template'];
$next_data['current_id'] = $data['children'][ $data['current_child'] ]; //next iteration should process child
$next_data['perms'] = $data['perms']; //we should copy our permissions to child - inheritance
$next_data['perms']->SetCatId($next_data['current_id']);
$data['current_child']++;
$this->Stack->Update($data); //we need to update ourself for the iteration after the next (or further) return to next child
$this->Stack->Push($next_data); //next iteration should process this child
return true;
}
else {
$this->UpdateCachedPath($data);
$this->Stack->Pop(); //remove ourself from stack if we have finished all the childs (or there are none)
// we are getting here if we finished with current level, so check if it's first level - then bail out.
return $this->Stack->Count() > 0;
}
}
function UpdateCachedPath(&$data)
{
$fields_hash = Array( 'CachedNavbar' => implode('>', $data['title']),
'NamedParentPath' => implode('/', $data['named_path'] ),
'CachedCategoryTemplate'=> $data['category_template'],
'CachedItemTemplate' => $data['item_template'],
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$data['current_id']);
}
function QueryTitle(&$data)
{
$category_id = $data['current_id'];
$sql = 'SELECT Name, Filename, CategoryTemplate, ItemTemplate
FROM '.TABLE_PREFIX.'Category
WHERE CategoryId = '.$category_id;
$record = $this->Conn->GetRow($sql);
if ($record) {
$data['title'][] = $record['Name'];
$data['named_path'][] = $record['Filename'];
// it is one of the modules root category
$root_prefix = isset($this->root_prefixes[$category_id]) ? $this->root_prefixes[$category_id] : false;
if ($root_prefix) {
$fields_hash = Array();
if (!$record['CategoryTemplate']) {
$record['CategoryTemplate'] = $this->Application->ConfigValue($root_prefix.'_CategoryTemplate');
$fields_hash['CategoryTemplate'] = $record['CategoryTemplate'];
}
if (!$record['ItemTemplate']) {
$record['ItemTemplate'] = $this->Application->ConfigValue($root_prefix.'_ItemTemplate');
$fields_hash['ItemTemplate'] = $record['ItemTemplate'];
}
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$category_id);
}
// if explicitly set, then use it; use parent template otherwise
if ($record['CategoryTemplate']) {
$data['category_template'] = $record['CategoryTemplate'];
}
if ($record['ItemTemplate']) {
$data['item_template'] = $record['ItemTemplate'];
}
}
}
function QueryChildren(&$data)
{
$sql = 'SELECT CategoryId
FROM '.TABLE_PREFIX.'Category
WHERE ParentId = '.$data['current_id'];
$data['children'] = $this->Conn->GetCol($sql);
}
function QueryPermissions(&$data)
{
// don't search for section "view" permissions here :)
$sql = 'SELECT ipc.PermissionConfigId, ip.GroupId, ip.PermissionValue
FROM '.TABLE_PREFIX.'Permissions AS ip
LEFT JOIN '.TABLE_PREFIX.'PermissionConfig AS ipc ON ipc.PermissionName = ip.Permission
WHERE (CatId = '.$data['current_id'].') AND (Permission LIKE "%.VIEW") AND (ip.Type = 0)';
$records = $this->Conn->Query($sql);
//create permissions array only if we don't have it yet (set by parent)
if (!isset($data['perms'])) {
$data['perms'] = new clsCachedPermissions($data['current_id']);
}
foreach ($records as $record) {
if ($record['PermissionValue'] == 1) {
$data['perms']->AddAllow($record['PermissionConfigId'], $record['GroupId']);
}
else {
$data['perms']->AddDeny($record['PermissionConfigId'], $record['GroupId']);
}
}
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/units/categories/cache_updater.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
\ No newline at end of property
+1.4
\ No newline at end of property
Index: trunk/core/admin_templates/categories/xml/categories_list.tpl
===================================================================
--- trunk/core/admin_templates/categories/xml/categories_list.tpl (revision 5175)
+++ trunk/core/admin_templates/categories/xml/categories_list.tpl (revision 5176)
@@ -1,72 +1,72 @@
<inp2:m_include t="incs/blocks"/>
<inp2:m_include t="incs/grid_blocks"/>
<inp2:c_InitList no_special="1" per_page="-1"/>
Grids['c'] = new Grid('c', 'table_white_selected', ':original', edit, a_toolbar);
Grids['c'].AddItemsByIdMask('td', /^c_([0-9-]+)/, 'c[$$ID$$][CategoryId]');
Grids['c'].InitItems();
Grids['c'].SetDependantToolbarButtons( new Array('edit','delete','approve','decline','sep3','cut','copy','move_up','move_down','sep6'));
<inp2:c_ViewMenu block="viewmenu_declaration" grid="Default" no_special="1" menu_perpage="no" menu_filters="yes" ajax="1"/>
<!-- substiture form action, like from was created from here -->
document.getElementById('categories_form').action = '<inp2:m_t pass="all" js_escape="1"/>';
$Catalog.setItemCount('c', '<inp2:c_TotalRecords no_special="1"/>');
$Catalog.ParentCategoryID = <inp2:c_GetParentCategory/>;
document.getElementById('c_search_warning').style.display = '<inp2:m_if check="m_RecallEquals" var="c_search_keyword" value="" inverse="inverse">block<inp2:m_else/>none</inp2:m_if>';
document.getElementById('c_search_keyword').value = '<inp2:c_SearchKeyword no_special="1" js_escape="1"/>';
<inp2:m_DefineElement name="root_cat_caption">
<span class="NAV_CURRENT_ITEM">
<inp2:m_if check="m_ParamEquals" name="current" value="1">
<inp2:c_RootCategoryName />
<inp2:m_else/>
<a class="control_link" href="javascript:$Catalog.go_to_cat(0);"><inp2:c_RootCategoryName /></a>
</inp2:m_if>
</span>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="category_caption">
<span class="NAV_CURRENT_ITEM">
<inp2:m_param name="separator"/>
<inp2:m_if check="m_ParamEquals" name="current" value="1" inverse="1">
<a class="control_link" href="javascript:$Catalog.go_to_cat(<inp2:m_param name="cat_id"/>);"><inp2:m_param name="cat_name"/></a>
<inp2:m_else/>
<inp2:m_param name="cat_name"/>
</inp2:m_if>
</span>
</inp2:m_DefineElement>
setInnerHTML('category_path', '<inp2:c_CategoryPath separator="&gt;" rootcatblock="root_cat_caption" rootmoduleblock="category_caption" currentblock="category_caption" block="category_caption" js_escape="1"/>');
<inp2:m_if check="m_GetEquals" name="m_cat_id" value="0">
a_toolbar.DisableButton('upcat');
a_toolbar.DisableButton('homecat');
<inp2:m_else/>
a_toolbar.EnableButton('upcat');
a_toolbar.EnableButton('homecat');
</inp2:m_if>
#separator#
<inp2:c_UpdateLastTemplate template="catalog"/>
<inp2:m_include t="categories/ci_blocks"/>
<br />
<table border="0" width="100%">
<inp2:m_DefineElement name="category_td">
<td valign="top" class="table_white text" id="<inp2:m_param name="PrefixSpecial"/>_<inp2:Field field="CategoryId"/>">
<input type="checkbox" name="<inp2:InputName field="$IdField"/>" id="<inp2:InputName field="$IdField"/>">
<img src="<inp2:ModulePath />img/itemicons/<inp2:ItemIcon grid="Default"/>">&nbsp;<span class="priority"><inp2:m_if check="FieldEquals" field="Priority" value="0" inverse="inverse"><sup><inp2:Field field="Priority"/></sup></inp2:m_if></span>
<a class="link" href="javascript:$Catalog.go_to_cat(<inp2:m_get name="c_id"/>);"><b><inp2:Field name="Name"/></b></a><span class="cat_desc">:</span>
- <span class="cat_pick"><inp2:m_if check="IsPick">Pick</inp2:m_if></span>
- <span class="cat_new"><inp2:m_if check="IsNew">New</inp2:m_if></span>
+ <inp2:m_RenderElement name="status_mark" field="EditorsPick" type="pick" PrefixSpecial="$PrefixSpecial"/>
+ <inp2:m_RenderElement name="status_mark" field="IsNew" type="new" PrefixSpecial="$PrefixSpecial"/>
<span class="cats_stats">(<inp2:SubCatCount/> / <inp2:ItemCount/>)</span><br>
<div style="padding-left: 3px;">
<span class="cat_desc"><inp2:Field field="Description"/></span><br>
<span class="cats_stats">(<inp2:Field field="CreatedOn" format="_regional_DateFormat"/>)</span>
</div>
</td>
</inp2:m_DefineElement>
<inp2:m_if check="c_TotalRecords" no_special="1">
<inp2:c_CategoryList no_special="1" block_main="category_td" per_page="-1" columns="2" direction="V" IdField="CategoryId" />
<inp2:m_else/>
<tr>
<td class="text">
<inp2:m_phrase name="la_text_NoCategories"/>
</td>
</tr>
</inp2:m_if>
</table></br>
Property changes on: trunk/core/admin_templates/categories/xml/categories_list.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14
\ No newline at end of property
+1.15
\ No newline at end of property
Index: trunk/core/admin_templates/categories/cache_updater.tpl
===================================================================
--- trunk/core/admin_templates/categories/cache_updater.tpl (revision 5175)
+++ trunk/core/admin_templates/categories/cache_updater.tpl (revision 5176)
@@ -1,97 +1,87 @@
<inp2:m_RequireLogin permissions="CATEGORY.VIEW"/>
-
-
-<!-- do this from OnSave php event when substitung opener
-<inp2:m_if check="m_RecallEquals" name="PermCache_UpdateRequired" value="1" inverse="inverse">
- <script type="text/javascript">
- window.location.href = '<inp2:m_t t="catalog" pass="all" escape="1"/>';
- </script>
-</inp2:m_if>
--->
-
<inp2:m_include t="incs/header" nobody="yes"/>
<body topmargin="0" leftmargin="8" marginheight="0" marginwidth="8" bgcolor="#FFFFFF">
<inp2:m_ParseBlock name="section_header" prefix="c" icon="icon46_catalog" module="in-portal" title="!la_title_Categories!"/>
<inp2:m_ParseBlock name="blue_bar" prefix="c" title_preset="categories_update" module="in-portal" icon="icon46_catalog"/>
<inp2:m_if check="c_InitCacheUpdater" destination_template="catalog">
<table width="100%" border="0" cellspacing="0" cellpadding="2" class="tableborder">
<tr>
<td align="center" colspan="3" bgcolor="#FFFFFF">
<inp2:m_phrase name="la_confirm_maintenance"/>
</td>
</tr>
<tr>
<td align="center" colspan="3" bgcolor="#FFFFFF">
<inp2:m_phrase name="la_prompt_perform_now"/>
</td>
</tr>
<tr>
<td align="right" width="50%">
<input type="button" name="yes_btn" value="<inp2:m_phrase name="lu_yes"/>" onclick="goto_url('<inp2:m_t continue="1"/>');" class="button" />
</td>
<td>
<img src="img/spacer.gif" width="10" />
</td>
<td align="left" width="50%">
<input type="button" name="yes_btn" value="<inp2:m_phrase name="lu_no"/>" onclick="javascript:goto_url('<inp2:m_t continue="0"/>');" class="button" />
</td>
</tr>
</table>
<inp2:m_else/>
<script type="text/javascript" src="incs/ajax.js"></script>
<table cellspacing="0" cellpadding="2" width="100%" border="0" class="tableborder">
<tr>
<td id="current_percent" bgcolor="#4682B2" style="width: 0%;"></td>
<td id="percents_left" bgcolor="#FFFFFF" style="width: 100%;"><img src="img/spacer.gif" height="15" width="1" alt="" /></td>
</tr>
</table>
<script type="text/javascript">
function CacheUpdater($url) {
this.URL = $url;
this.BusyRequest = false;
this.Query();
}
CacheUpdater.prototype.Query = function() {
Request.makeRequest(this.URL, this.BusyRequest, '', this.successCallback, this.errorCallback, '', this);
}
CacheUpdater.prototype.successCallback = function($request, $params, $object) {
var $responce = $request.responseText;
if ($responce.match(/^#redirect#(.*)/)) {
$object.showProgress(100);
// redirect to external template requested
window.location.href = RegExp.$1;
return false;
}
$object.showProgress($responce);
$object.Query();
}
CacheUpdater.prototype.errorCallback = function($request, $params, $object) {
alert('AJAX ERROR: ' + Request.getErrorHtml($request));
}
CacheUpdater.prototype.showProgress = function ($percent) {
$percent = parseInt($percent);
document.getElementById('percents_done').innerHTML = '(' + $percent + '%)';
document.getElementById('current_percent').style.width = $percent + '%';
document.getElementById('percents_left').style.width = (100 - $percent) + '%';
}
$CacheUpdater = new CacheUpdater('<inp2:m_t t="xml/cache_updater" continue="2" no_amp="1"/>');
</script>
</inp2:m_if>
<script type="text/javascript">
function goto_url($url) {
window.location.href = $url;
}
</script>
<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Property changes on: trunk/core/admin_templates/categories/cache_updater.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property

Event Timeline