fix: rebuild assets after content restore to fix ACL
After restoring content tables, deletes stale content-level assets (articles, categories, modules, contacts, banners) and rebuilds: - Category nested set tree - Menu nested set tree - Asset nested set tree - Re-creates missing asset entries for articles with asset_id=0 Component and extension-level assets are never touched. Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -247,6 +247,9 @@ class DemoResetService
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild assets table to fix ACL after content restore
|
||||
$this->rebuildAssets();
|
||||
|
||||
Log::add(sprintf('Demo site reset (%d tables, media=%s)', $restored, $mediaRestored ? 'yes' : 'no'), Log::WARNING, 'mokowaas');
|
||||
|
||||
return [
|
||||
@@ -276,6 +279,149 @@ class DemoResetService
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the assets table after content restore.
|
||||
*
|
||||
* Deletes content-related asset entries (which now have stale IDs)
|
||||
* and rebuilds them using Joomla's Table classes. Extension and
|
||||
* component-level assets are left untouched.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function rebuildAssets(): void
|
||||
{
|
||||
try
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
// Delete content-level assets (articles, categories, modules, etc.)
|
||||
// Keep component-level and root assets intact
|
||||
$contentAssetPrefixes = [
|
||||
'com_content.article.%',
|
||||
'com_content.category.%',
|
||||
'com_contact.contact.%',
|
||||
'com_banners.banner.%',
|
||||
'com_banners.category.%',
|
||||
'com_modules.module.%',
|
||||
'com_menus.menu.%',
|
||||
'com_users.user.%',
|
||||
];
|
||||
|
||||
foreach ($contentAssetPrefixes as $prefix)
|
||||
{
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__assets'))
|
||||
->where($db->quoteName('name') . ' LIKE ' . $db->quote($prefix))
|
||||
);
|
||||
$db->execute();
|
||||
}
|
||||
|
||||
// Rebuild category tree (also fixes category assets)
|
||||
$catTable = \Joomla\CMS\Table\Table::getInstance('Category');
|
||||
|
||||
if ($catTable)
|
||||
{
|
||||
$catTable->rebuild();
|
||||
}
|
||||
|
||||
// Rebuild menu tree
|
||||
$menuTable = \Joomla\CMS\Table\Table::getInstance('Menu');
|
||||
|
||||
if ($menuTable)
|
||||
{
|
||||
$menuTable->rebuild();
|
||||
}
|
||||
|
||||
// Rebuild asset tree
|
||||
$assetTable = \Joomla\CMS\Table\Table::getInstance('Asset');
|
||||
|
||||
if ($assetTable)
|
||||
{
|
||||
$assetTable->rebuild();
|
||||
}
|
||||
|
||||
// Re-create assets for content items that lost theirs
|
||||
$this->fixContentAssets($db);
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
Log::add('Asset rebuild warning: ' . $e->getMessage(), Log::WARNING, 'mokowaas');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-create missing asset entries for content items.
|
||||
*
|
||||
* After deleting stale assets and restoring content, some items
|
||||
* may reference asset_id=0. This creates new asset rows for them.
|
||||
*
|
||||
* @param \Joomla\Database\DatabaseInterface $db
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function fixContentAssets($db): void
|
||||
{
|
||||
// Fix articles with missing assets
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->quoteName('id'), $db->quoteName('title'), $db->quoteName('alias')])
|
||||
->from($db->quoteName('#__content'))
|
||||
->where($db->quoteName('asset_id') . ' = 0');
|
||||
|
||||
$db->setQuery($query);
|
||||
$articles = $db->loadAssocList() ?: [];
|
||||
|
||||
// Find the com_content component asset as parent
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__assets'))
|
||||
->where($db->quoteName('name') . ' = ' . $db->quote('com_content'))
|
||||
);
|
||||
$contentAssetId = (int) $db->loadResult();
|
||||
|
||||
foreach ($articles as $article)
|
||||
{
|
||||
$assetName = 'com_content.article.' . (int) $article['id'];
|
||||
|
||||
$asset = (object) [
|
||||
'parent_id' => $contentAssetId ?: 1,
|
||||
'lft' => 0,
|
||||
'rgt' => 0,
|
||||
'level' => 0,
|
||||
'name' => $assetName,
|
||||
'title' => $article['title'],
|
||||
'rules' => '{}',
|
||||
];
|
||||
|
||||
$db->insertObject('#__assets', $asset, 'id');
|
||||
|
||||
// Update content row with new asset_id
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->update($db->quoteName('#__content'))
|
||||
->set($db->quoteName('asset_id') . ' = ' . (int) $asset->id)
|
||||
->where($db->quoteName('id') . ' = ' . (int) $article['id'])
|
||||
);
|
||||
$db->execute();
|
||||
}
|
||||
|
||||
// Rebuild asset tree again after inserts
|
||||
try
|
||||
{
|
||||
$assetTable = \Joomla\CMS\Table\Table::getInstance('Asset');
|
||||
|
||||
if ($assetTable)
|
||||
{
|
||||
$assetTable->rebuild();
|
||||
}
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
// Best effort
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Private helpers
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user