Сообщение напрашивается в раздел "Баги Joomla", но создавать там темы у меня прав нет.
Недавно понадобилось импортировать большой объём данных (категорий и материалов) из другой системы в Joomla! 3.4.5.
Сгенерировать нужные значения для полей `parent_id` и `level` таблиц `#__assets` и `#__categories` труда не составило, а для полей `lft` и `rgt` установил -1 в надежде после импорта перестроить штатными средствами Joomla.
Для таблицы категорий такой инструмент имеется (кнопка "Перестроить" в менеджере категорий), а вот для таблицы `#__assets` пришлось написать свой модуль (бесплатного в сети не нашёл, да и платного тоже). В ходе написания обнаружил, что класс JTableAsset наследуется от класса JTableNested, в котором есть "магический" метод rebuild, который собственно и делает то, что мне нужно. Но в этом методе также перестраиваются пути (поле `path`) используя значения поля `alias`. Ни поля `alias`, ни поля `path` в таблице `#__assets` нет, соответственно, вызов метода rebuild для объекта класса JTableAsset вызывает ошибку.
Для решения данной проблемы написал класс JTableAssetRebuild, наследующий от JTableAsset и переопределяющий метод rebuild. Правильней конечно было бы либо переопределить указанный метод непосредственно в классе JTableAsset, либо переписать всю иерархию классов в части JTableNested и JTableAsset, например, добавить в иерархию класс перед JTableNested с "правильным" rebuild (и другими полями/методами) и наследовать JTableAsset уже от него. [upd] Либо в классе JTableNested имеющийся rebuild переименовать, например, в _rebuildWithAlias и сделать его protected, добавить protected метод _rebuildWithoutAlias с аналогичным кодом, но без обновления путей (код ниже), а также добавить вызывающий их public метод rebuild (код ниже) [/upd]. Однако влезать в код ядра Joomla не хотел, чтобы не потерять изменения при обновлении. Если у кого-нибудь есть возможность сообщить о данной ошибке разработчикам Joomla!, прошу сделать это.
Вот собственно код метода ([upd]если добавлять его как protected в класс JTableNested, то переименовать в _rebuildWithoutAlias и не забыть про рекурсивный вызов [/upd]):
/**
* Method to recursively rebuild the whole nested set tree.
*
* @param integer $parentId The root of the tree to rebuild.
* @param integer $leftId The left id to start with in building the tree.
* @param integer $level The level to assign to the current nodes.
*
* @return integer 1 + value of root rgt on success, false on failure
*
* @throws RuntimeException on database error.
*/
public function rebuild($parentId = null, $leftId = 0, $level = 0)
{
// If no parent is provided, try to find it.
if ($parentId === null)
{
// Get the root item.
$parentId = $this->getRootId();
if ($parentId === false)
{
return false;
}
}
$query = $this->_db->getQuery(true);
// Build the structure of the recursive query.
if (!isset($this->_cache['rebuild.sql']))
{
$query->clear()
->select($this->_tbl_key)
->from($this->_tbl)
->where('parent_id = %d')
->order('parent_id, lft');
$this->_cache['rebuild.sql'] = (string) $query;
}
// Make a shortcut to database object.
// Assemble the query to find all children of this node.
$this->_db->setQuery(sprintf($this->_cache['rebuild.sql'], (int) $parentId));
$children = $this->_db->loadObjectList();
// The right value of this node is the left value + 1
$rightId = $leftId + 1;
// Execute this function recursively over all children
foreach ($children as $node)
{
/*
* $rightId is the current right value, which is incremented on recursion return.
* Increment the level for the children.
*/
$rightId = $this->rebuild($node->{$this->_tbl_key}, $rightId, $level + 1); //в классе JTableNested заменить на _rebuildWithoutAlias !
// If there is an update failure, return false to break out of the recursion.
if ($rightId === false)
{
return false;
}
}
// We've got the left value, and now that we've processed
// the children of this node we also know the right value.
$query->clear()
->update($this->_tbl)
->set('lft = ' . (int) $leftId)
->set('rgt = ' . (int) $rightId)
->set('level = ' . (int) $level)
->where($this->_tbl_key . ' = ' . (int) $parentId);
$this->_db->setQuery($query)->execute();
// Return the right value of this node + 1.
return $rightId + 1;
}
/**
* код метода rebuild для класса JTableNested
*/
public function rebuild($parentId = null, $leftId = 0, $level = 0, $path = '') {
$fields = $this->getFields();
if (isset($fields['alias'])) {
return $this->_rebuildWithAlias($parentId, $leftId, $level, $path);
} else {
return $this->_rebuildWithoutAlias($parentId, $leftId, $level);
}
}