diff --git a/modules/mod_articles_popular/mod_articles_popular.php b/modules/mod_articles_popular/mod_articles_popular.php deleted file mode 100644 index 0cca23f3b994f..0000000000000 --- a/modules/mod_articles_popular/mod_articles_popular.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @license GNU General Public License version 2 or later; see LICENSE.txt - */ - -defined('_JEXEC') or die; - -use Joomla\CMS\Component\ComponentHelper; -use Joomla\CMS\Helper\ModuleHelper; -use Joomla\CMS\Language\Text; -use Joomla\Module\ArticlesPopular\Site\Helper\ArticlesPopularHelper; - -// Exit early if hits are disabled. -if (!ComponentHelper::getParams('com_content')->get('record_hits', 1)) { - echo Text::_('JGLOBAL_RECORD_HITS_DISABLED'); - - return; -} - -$list = ArticlesPopularHelper::getList($params); - -require ModuleHelper::getLayoutPath('mod_articles_popular', $params->get('layout', 'default')); diff --git a/modules/mod_articles_popular/mod_articles_popular.xml b/modules/mod_articles_popular/mod_articles_popular.xml index 95e8a9396effb..760ff93f48f4f 100644 --- a/modules/mod_articles_popular/mod_articles_popular.xml +++ b/modules/mod_articles_popular/mod_articles_popular.xml @@ -11,7 +11,7 @@ MOD_POPULAR_XML_DESCRIPTION Joomla\Module\ArticlesPopular - mod_articles_popular.php + services src tmpl diff --git a/modules/mod_articles_popular/services/provider.php b/modules/mod_articles_popular/services/provider.php new file mode 100644 index 0000000000000..870a9bf02c26f --- /dev/null +++ b/modules/mod_articles_popular/services/provider.php @@ -0,0 +1,42 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +defined('_JEXEC') or die; + +use Joomla\CMS\Extension\Service\Provider\HelperFactory; +use Joomla\CMS\Extension\Service\Provider\Module; +use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + +/** + * The popular articles module service provider. + * + * @since __DEPLOY_VERSION__ + */ +return new class implements ServiceProviderInterface +{ + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function register(Container $container) + { + $container->registerServiceProvider(new ModuleDispatcherFactory('\\Joomla\\Module\\ArticlesPopular')); + $container->registerServiceProvider(new HelperFactory('\\Joomla\\Module\\ArticlesPopular\\Site\\Helper')); + + $container->registerServiceProvider(new Module()); + } +}; diff --git a/modules/mod_articles_popular/src/Dispatcher/Dispatcher.php b/modules/mod_articles_popular/src/Dispatcher/Dispatcher.php new file mode 100644 index 0000000000000..551ac0450babb --- /dev/null +++ b/modules/mod_articles_popular/src/Dispatcher/Dispatcher.php @@ -0,0 +1,51 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Module\ArticlesPopular\Site\Dispatcher; + +use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Dispatcher\AbstractModuleDispatcher; +use Joomla\CMS\Helper\HelperFactoryAwareInterface; +use Joomla\CMS\Helper\HelperFactoryAwareTrait; +use Joomla\CMS\Language\Text; + +// phpcs:disable PSR1.Files.SideEffects +\defined('JPATH_PLATFORM') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * Dispatcher class for mod_articles_popular + * + * @since __DEPLOY_VERSION__ + */ +class Dispatcher extends AbstractModuleDispatcher implements HelperFactoryAwareInterface +{ + use HelperFactoryAwareTrait; + + /** + * Returns the layout data. + * + * @return array + * + * @since __DEPLOY_VERSION__ + */ + protected function getLayoutData() + { + $data = parent::getLayoutData(); + + if (!ComponentHelper::getParams('com_content')->get('record_hits', 1)) { + $data['hitsDisabledMessage'] = Text::_('JGLOBAL_RECORD_HITS_DISABLED'); + } else { + $data['list'] = $this->getHelperFactory()->getHelper('ArticlesPopularHelper', $data)->getArticles($data['params'], $data['app']); + } + + return $data; + } +} diff --git a/modules/mod_articles_popular/src/Helper/ArticlesPopularHelper.php b/modules/mod_articles_popular/src/Helper/ArticlesPopularHelper.php index 9ce5657b7bbce..c3a0f83257b34 100644 --- a/modules/mod_articles_popular/src/Helper/ArticlesPopularHelper.php +++ b/modules/mod_articles_popular/src/Helper/ArticlesPopularHelper.php @@ -11,11 +11,18 @@ namespace Joomla\Module\ArticlesPopular\Site\Helper; use Joomla\CMS\Access\Access; +use Joomla\CMS\Application\SiteApplication; +use Joomla\CMS\Cache\CacheControllerFactoryInterface; +use Joomla\CMS\Cache\Controller\OutputController; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Router\Route; use Joomla\Component\Content\Administrator\Extension\ContentComponent; use Joomla\Component\Content\Site\Helper\RouteHelper; +use Joomla\Component\Content\Site\Model\ArticlesModel; +use Joomla\Database\DatabaseAwareInterface; +use Joomla\Database\DatabaseAwareTrait; +use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; @@ -24,78 +31,152 @@ /** * Helper for mod_articles_popular * - * @since 1.6 + * @since __DEPLOY_VERSION__ */ -abstract class ArticlesPopularHelper +class ArticlesPopularHelper { /** - * Get a list of popular articles from the articles model + * The module instance * - * @param \Joomla\Registry\Registry &$params object holding the models parameters + * @var \stdClass * - * @return mixed + * @since __DEPLOY_VERSION__ */ - public static function getList(&$params) + protected $module; + + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * + * @since __DEPLOY_VERSION__ + */ + public function __construct($config = []) + { + $this->module = $config['module']; + } + + /** + * Retrieve a list of months with archived articles + * + * @param Registry $params The module parameters. + * @param SiteApplication $app The current application. + * + * @return object[] + * + * @since __DEPLOY_VERSION__ + */ + public function getArticles(Registry $moduleParams, SiteApplication $app) { - $app = Factory::getApplication(); + $cacheKey = md5(serialize([$moduleParams->toString(), $this->module->module, $this->module->id])); - // Get an instance of the generic articles model - $model = $app->bootComponent('com_content') - ->getMVCFactory()->createModel('Articles', 'Site', ['ignore_request' => true]); + /** @var OutputController $cache */ + $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) + ->createCacheController('output', ['defaultgroup' => 'mod_articles_popular']); - // Set application parameters in model - $appParams = $app->getParams(); - $model->setState('params', $appParams); + if (!$cache->contains($cacheKey)) { + $mvcContentFactory = $app->bootComponent('com_content')->getMVCFactory(); - $model->setState('list.start', 0); - $model->setState('filter.published', ContentComponent::CONDITION_PUBLISHED); + /** @var ArticlesModel $articlesModel */ + $articlesModel = $mvcContentFactory->createModel('Articles', 'Site', ['ignore_request' => true]); - // Set the filters based on the module params - $model->setState('list.limit', (int) $params->get('count', 5)); - $model->setState('filter.featured', $params->get('show_front', 1) == 1 ? 'show' : 'hide'); + // Set application parameters in model + $appParams = $app->getParams(); + $articlesModel->setState('params', $appParams); - // This module does not use tags data - $model->setState('load_tags', false); + $articlesModel->setState('list.start', 0); + $articlesModel->setState('filter.published', ContentComponent::CONDITION_PUBLISHED); - // Access filter - $access = !ComponentHelper::getParams('com_content')->get('show_noauth'); - $authorised = Access::getAuthorisedViewLevels(Factory::getUser()->get('id')); - $model->setState('filter.access', $access); + // Set the filters based on the module params + $articlesModel->setState('list.limit', (int) $moduleParams->get('count', 5)); + $articlesModel->setState('filter.featured', $moduleParams->get('show_front', 1) == 1 ? 'show' : 'hide'); - // Category filter - $model->setState('filter.category_id', $params->get('catid', [])); + // This module does not use tags data + $articlesModel->setState('load_tags', false); - // Date filter - $date_filtering = $params->get('date_filtering', 'off'); + // Access filter + $access = !ComponentHelper::getParams('com_content')->get('show_noauth'); + $articlesModel->setState('filter.access', $access); - if ($date_filtering !== 'off') { - $model->setState('filter.date_filtering', $date_filtering); - $model->setState('filter.date_field', $params->get('date_field', 'a.created')); - $model->setState('filter.start_date_range', $params->get('start_date_range', '1000-01-01 00:00:00')); - $model->setState('filter.end_date_range', $params->get('end_date_range', '9999-12-31 23:59:59')); - $model->setState('filter.relative_date', $params->get('relative_date', 30)); - } + // Category filter + $articlesModel->setState('filter.category_id', $moduleParams->get('catid', [])); - // Filter by language - $model->setState('filter.language', $app->getLanguageFilter()); + // Date filter + $date_filtering = $moduleParams->get('date_filtering', 'off'); - // Ordering - $model->setState('list.ordering', 'a.hits'); - $model->setState('list.direction', 'DESC'); + if ($date_filtering !== 'off') { + $articlesModel->setState('filter.date_filtering', $date_filtering); + $articlesModel->setState('filter.date_field', $moduleParams->get('date_field', 'a.created')); + $articlesModel->setState('filter.start_date_range', $moduleParams->get('start_date_range', '1000-01-01 00:00:00')); + $articlesModel->setState('filter.end_date_range', $moduleParams->get('end_date_range', '9999-12-31 23:59:59')); + $articlesModel->setState('filter.relative_date', $moduleParams->get('relative_date', 30)); + } + + // Filter by language + $articlesModel->setState('filter.language', $app->getLanguageFilter()); + + // Ordering + $articlesModel->setState('list.ordering', 'a.hits'); + $articlesModel->setState('list.direction', 'DESC'); - $items = $model->getItems(); + // Prepare the module output + $items = []; + $itemParams = new \stdClass(); - foreach ($items as &$item) { - $item->slug = $item->id . ':' . $item->alias; + $itemParams->authorised = Access::getAuthorisedViewLevels($app->getIdentity()->get('id')); + $itemParams->access = $access; - if ($access || \in_array($item->access, $authorised)) { - // We know that user has the privilege to view the article - $item->link = Route::_(RouteHelper::getArticleRoute($item->slug, $item->catid, $item->language)); - } else { - $item->link = Route::_('index.php?option=com_users&view=login'); + foreach ($articlesModel->getItems() as $item) { + $items[] = $this->prepareItem($item, $itemParams); } + + // Cache the output and return + $cache->store($items, $cacheKey); + + return $items; } - return $items; + // Return the cached output + return $cache->get($cacheKey); + } + + /** + * Prepare the article before render. + * + * @param object $item The article to prepare + * @param \stdClass $params The model item + * + * @return object + * + * @since __DEPLOY_VERSION__ + */ + private function prepareItem($item, $params): object + { + $item->slug = $item->id . ':' . $item->alias; + + if ($params->access || \in_array($item->access, $params->authorised)) { + // We know that user has the privilege to view the article + $item->link = Route::_(RouteHelper::getArticleRoute($item->slug, $item->catid, $item->language)); + } else { + $item->link = Route::_('index.php?option=com_users&view=login'); + } + + return $item; + } + + /** + * Get a list of popular articles from the articles model + * + * @param \Joomla\Registry\Registry &$params object holding the models parameters + * + * @return mixed + * + * @since __DEPLOY_VERSION__ + * + * @deprecated 5.0 Use the none static function getArticles + */ + public static function getList(&$params) + { + return (new self())->getArticles($params, Factory::getApplication()); } } diff --git a/modules/mod_articles_popular/tmpl/default.php b/modules/mod_articles_popular/tmpl/default.php index 9b00f2e24f2f5..a3cf9ce24ea56 100644 --- a/modules/mod_articles_popular/tmpl/default.php +++ b/modules/mod_articles_popular/tmpl/default.php @@ -10,7 +10,10 @@ defined('_JEXEC') or die; -if (!$list) { +if (!isset($list)) { + if (isset($hitsDisabledMessage)) { + echo $hitsDisabledMessage; + } return; }