Joomla 5.2.3自定义插件报错:Class 'Factory' not found
Joomla插件报错:Class "Factory" not found 排查方案
我开发了一个自定义Joomla内容插件,功能是指定艺术家/专辑目录后,读取目录中的MP3文件,解析ID3标签并以表格形式展示播放、下载入口及统计数据。运行时Joomla抛出错误:0 Class "Factory" not found,环境为Joomla 5.2.3、PHP 8.2、Linux服务器。
错误日志
2025-01-27T10:39:44+00:00 CRITICAL xxx.xx.xxx.xx error Uncaught Throwable of type Error thrown with message "Class "Factory" not found". Stack trace: #0 [ROOT]/plugins/content/mp3streaming/mp3streaming.php(29): PlgContentMp3StreamingHelper::getTracksFromFolder('media/mp3/New...') #1 [ROOT]/libraries/src/Plugin/CMSPlugin.php(289): PlgContentMp3Streaming->onContentPrepare('com_content.art...', Object(stdClass), Object(Joomla\Registry\Registry), 0) #2 [ROOT]/libraries/vendor/joomla/event/src/Dispatcher.php(454):
插件主文件(mp3streaming.php)
<?php defined('_JEXEC') or die; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Factory; use Joomla\CMS\Router\Route; use Joomla\CMS\Uri\Uri; // 补充缺失的Uri命名空间 // Load the helper file require_once __DIR__ . '/helper.php'; class PlgContentMp3Streaming extends CMSPlugin { protected $autoloadLanguage = true; public function onContentPrepare($context, &$article, &$params, $limitstart) { // Regex to match the shortcode $regex = '/\{mp3streaming\s+artist="([^"]+)"(?:\s+album="([^"]+)")?\}/'; if (preg_match($regex, $article->text, $matches)) { $artist = $matches[1]; $album = isset($matches[2]) ? $matches[2] : null; $folderPath = 'media/mp3/' . $artist; if ($album) { $folderPath .= '/' . $album; } // Fetch and display tracks $tracks = PlgContentMp3StreamingHelper::getTracksFromFolder($folderPath); $html = '<div class="mp3-streaming">'; $html .= '<h3>Artist: ' . htmlspecialchars($artist) . '</h3>'; if ($album) { $html .= '<h4>Album: ' . htmlspecialchars($album) . '</h4>'; } $html .= '<table class="table table-striped table-hover">'; $html .= '<thead><tr> <th>Title</th> <th>Player</th> <th>Download</th> <th>Plays</th> <th>Downloads</th> </tr></thead><tbody>'; foreach ($tracks as $track) { $playUrl = Route::_('index.php?option=com_ajax&plugin=mp3streaming&format=raw&task=play&id=' . $track->id); $downloadUrl = Route::_('index.php?option=com_ajax&plugin=mp3streaming&format=raw&task=download&id=' . $track->id); $html .= '<tr> <td>' . htmlspecialchars($track->title) . '</td> <td> <audio controls preload="none" onplay="fetch(\'' . $playUrl . '\')"> <source src="' . Uri::root() . $folderPath . '/' . $track->filename . '" type="audio/mpeg"> </audio> </td> <td> <a href="' . $downloadUrl . '" class="btn btn-success btn-sm" download>Download</a> </td> <td>' . $track->play_count . '</td> <td>' . $track->download_count . '</td> </tr>'; } $html .= '</tbody></table></div>'; $article->text = preg_replace($regex, $html, $article->text); } } }
辅助类文件(helper.php)
<?php defined('_JEXEC') or die; use Joomla\CMS\Factory; // 补充缺失的Factory命名空间 require_once __DIR__ . '/getid3/getid3.php'; class PlgContentMp3StreamingHelper { public static function getTracksFromFolder($folderPath) { $folderPath = rtrim($folderPath, '/'); $fullPath = JPATH_ROOT . '/' . $folderPath; if (!is_dir($fullPath)) { return []; } $files = array_diff(scandir($fullPath), ['.', '..']); $db = Factory::getDbo(); $getID3 = new getID3; $tracks = []; foreach ($files as $file) { if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'mp3') { $filePath = $fullPath . '/' . $file; $fileInfo = $getID3->analyze($filePath); $title = $fileInfo['tags']['id3v2']['title'][0] ?? pathinfo($file, PATHINFO_FILENAME); $artist = $fileInfo['tags']['id3v2']['artist'][0] ?? ''; $album = $fileInfo['tags']['id3v2']['album'][0] ?? ''; $track = $fileInfo['tags']['id3v2']['track_number'][0] ?? ''; $size = filesize($filePath); $playtime = $fileInfo['playtime_seconds'] ?? 0; $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__mp3_tracks')) ->where($db->quoteName('filename') . ' = ' . $db->quote($file)); $db->setQuery($query); $trackRecord = $db->loadObject(); if (!$trackRecord) { $query = $db->getQuery(true) ->insert($db->quoteName('#__mp3_tracks')) ->columns($db->quoteName(['filename', 'album', 'artist', 'title', 'track', 'size', 'playtime', 'play_count', 'download_count', 'upload_date'])) ->values(implode(',', [ $db->quote($file), $db->quote($album), $db->quote($artist), $db->quote($title), $db->quote($track), $db->quote($size), $db->quote($playtime), 0, 0, $db->quote(date('Y-m-d H:i:s')) ])); $db->setQuery($query); $db->execute(); $trackRecord = (object)[ 'id' => $db->insertid(), 'filename' => $file, 'album' => $album, 'artist' => $artist, 'title' => $title, 'track' => $track, 'size' => $size, 'playtime' => $playtime, 'play_count' => 0, 'download_count' => 0, ]; } $tracks[] = $trackRecord; } } return $tracks; } }
问题原因及解决说明
核心错误原因:
helper.php中直接调用Factory::getDbo(),但未导入Joomla\CMS\Factory命名空间。Joomla 4+版本全面采用PSR-4命名空间规范,非继承自CMS核心类的文件(如独立helper类)必须手动声明所需类的命名空间,否则PHP无法找到对应类。修复步骤:
- 在
helper.php开头添加use Joomla\CMS\Factory;语句,导入Factory类 - 额外修复:
mp3streaming.php中使用了JUri::root(),该别名在Joomla 5中虽仍可用,但建议使用官方推荐的命名空间use Joomla\CMS\Uri\Uri;,并将JUri::root()改为Uri::root(),避免潜在兼容问题
- 在
验证方法:修改后重新启用插件,测试短代码渲染,确认错误消失且MP3表格正常展示。
内容的提问来源于stack exchange,提问作者9944990
相关产品推荐
相关产品推荐

