Application->getUnitOption($prefix, 'IDField'); $table_name = $this->Application->getUnitOption($prefix, 'TableName'); $sql = 'SELECT '.$id_field.' FROM '.$table_name.' WHERE ParentId = '.$category_id; $sub_categories = $this->Conn->GetCol($sql); if ($sub_categories) { foreach ($sub_categories as $sub_category_id) { $this->DeleteCategory($sub_category_id); } } $ci_table = $this->Application->getUnitOption('ci', 'TableName'); // 1. remove category items from this category if it is supplemental (non-primary) category to them $sql = 'DELETE FROM '.$ci_table.' WHERE ('.$id_field.' = '.$category_id.') AND (PrimaryCat = 0)'; $this->Conn->Query($sql); /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($prefix.'_TempHandler', 'kTempTablesHandler'); // 2. delete items this have this category as primary $delete_ids = $this->getCategoryItems($category_id, true); foreach ($delete_ids as $item_prefix => $resource_ids) { if (!$item_prefix) { // not ItemPrefix filled -> old categoryitem linking continue; } $item_ids = $this->GetItemIDs($item_prefix, $resource_ids); $temp_handler->BuildTables($item_prefix, $item_ids); $temp_handler->DeleteItems($item_prefix, '', $item_ids); } // 3. delete this category $temp_handler->BuildTables($prefix, Array($category_id)); $temp_handler->DeleteItems($prefix, '', Array($category_id)); } /** * Converts resource ids list to id field list for given prefix * * @param string $prefix * @param Array $resource_ids * @return Array */ function GetItemIDs($prefix, $resource_ids) { if (!$resource_ids) { return Array(); } $id_field = $this->Application->getUnitOption($prefix, 'IDField'); $table_name = $this->Application->getUnitOption($prefix, 'TableName'); $sql = 'SELECT '.$id_field.' FROM '.$table_name.' WHERE ResourceId IN ('.implode(',', $resource_ids).')'; return $this->Conn->GetCol($sql); } // moves selected categories to destination category function MoveCategories($category_ids, $dest_category_id) { if (!$category_ids) return ; $id_field = $this->Application->getUnitOption('c', 'IDField'); $table_name = $this->Application->getUnitOption('c', 'TableName'); // do not move categories into their children $sql = 'SELECT ParentPath FROM '.$table_name.' WHERE '.$id_field.' = '.$dest_category_id; $dest_parent_path = explode('|', substr($this->Conn->GetOne($sql), 1, -1)); $child_categories = array_intersect($dest_parent_path, $category_ids); // get categories, then can't be moved $category_ids = array_diff($category_ids, $child_categories); // remove them from movable categories list if ($category_ids) { $sql = 'UPDATE '.$table_name.' SET ParentId = '.$dest_category_id.' WHERE '.$id_field.' IN ('.implode(',', $category_ids).')'; $this->Conn->Query($sql); } } /** * Complete cloning or category with subcategories and sub-items * * @param int $category_id * @param string $prefix */ function PasteCategory($category_id, $prefix = 'c') { $backup_category_id = $this->Application->GetVar('m_cat_id'); $src_parent_path = $this->_getParentPath($category_id); $dst_parent_path = $this->_getParentPath($backup_category_id); if ( substr($dst_parent_path, 0, strlen($src_parent_path)) == $src_parent_path ) { // target path contains source path -> recursion return; } // 1. clone category /** @var kTempTablesHandler $temp_handler */ $temp_handler = $this->Application->recallObject($prefix . '_TempHandler', 'kTempTablesHandler'); $temp_handler->BuildTables($prefix, Array ($category_id)); $new_category_id = array_pop($temp_handler->CloneItems($prefix, '', Array ($category_id))); $this->Application->SetVar('m_cat_id', $new_category_id); $id_field = $this->Application->getUnitOption($prefix, 'IDField'); $table_name = $this->Application->getUnitOption($prefix, 'TableName'); // 2. assign supplemental items to current category to new category $paste_ids = $this->getCategoryItems($category_id, false); foreach ($paste_ids as $item_prefix => $resource_ids) { if ( !$item_prefix ) { // not ItemPrefix filled -> old categoryitem linking continue; } /** @var kCatDBItem $item_object */ $item_object = $this->Application->recallObject($item_prefix . '.-item', null, Array ('skip_autoload' => true)); foreach ($resource_ids as $item_resource_id) { $item_object->Load($item_resource_id, 'ResourceId'); $item_object->assignToCategory($new_category_id, false); } } // 3. clone items that have current category as primary $paste_ids = $this->getCategoryItems($category_id, true); foreach ($paste_ids as $item_prefix => $resource_ids) { if ( !$item_prefix ) { // not ItemPrefix filled -> old categoryitem linking continue; } // 2. clone items from current category (for each prefix separately) $item_ids = $this->GetItemIDs($item_prefix, $resource_ids); $temp_handler->BuildTables($item_prefix, $item_ids); $temp_handler->CloneItems($item_prefix, '', $item_ids); } // 4. do same stuff for each subcategory $sql = 'SELECT ' . $id_field . ' FROM ' . $table_name . ' WHERE ParentId = ' . $category_id; $sub_categories = $this->Conn->GetCol($sql); if ( $sub_categories ) { foreach ($sub_categories as $sub_category_id) { $this->PasteCategory($sub_category_id, $prefix); } } $this->Application->SetVar('m_cat_id', $backup_category_id); } /** * Returns grouped category items * * @param int $category_id * @param bool $item_primary_category * @return Array */ function getCategoryItems($category_id, $item_primary_category = true) { $ci_table = $this->Application->getUnitOption('ci', 'TableName'); $sql = 'SELECT ItemPrefix, ItemResourceId FROM '.$ci_table.' WHERE (CategoryId = '.$category_id.') AND (PrimaryCat = '.($item_primary_category ? 1 : 0).')'; $category_items = $this->Conn->GetCol($sql, 'ItemResourceId'); $item_ids = Array(); foreach ($category_items as $resource_id => $item_prefix) { $item_ids[$item_prefix][] = $resource_id; } return $item_ids; } /** * Returns parent path for given category * * @param int $category_id * @return Array */ function _getParentPath($category_id) { static $cache = Array (); if (!array_key_exists($category_id, $cache)) { $sql = 'SELECT ParentPath FROM ' . TABLE_PREFIX . 'Categories WHERE CategoryId = ' . $category_id; $cache[$category_id] = $this->Conn->GetOne($sql); } return $cache[$category_id]; } }