3

I want to get the parameters of a module which is not assigned to the the current page. The helper class JModuleHelper has a getModule method but as defined here: http://docs.joomla.org/JModuleHelper/getModule, the module must be assigned to the current menu item or all menu items.

Obviously I can just go into the database and pull out the parameters myself, but I wanted to do it in a neater Joomla way.

What I'm trying to do is write a library, but the library requires some parametrization and its own database tables (two things that libraries cannot do), so I'm trying to use a module to fill the gaps. I need to access the module parameters from the library code (which could be called from any page on the site).

Thanks for any help


The solution I've gone with is to add the following code to my library:

$db = JFactory::getDbo();
$query = $db->getQuery(true);

$query->select('m.params')
    ->from('#__modules AS m')
    ->where('m.module=' . $db->quote('mod_my_module_name'));
$db->setQuery($query);
$module = $db->loadObject();

$module_params = new JRegistry();
$module_params->loadString($module->params);

I've not added this as an answer to this question because I think there should be a better solution which doesn't directly query the core database. However I think that the above is the best solution for now.


Update

Based on an answer to this question on the Joomla! developer group I've implemented a library/plugin solution. Plugins can have parameters which can be pulled from anywhere using the code:

$plugin = JPluginHelper::getPlugin('plugin_type', 'plugin_name');
$parameteres = new JRegistry($plugin->params);
$param =$parameteres->get('parameter');

The advantage of plugins over modules is that there is no requirement to assign the plugin to all item id's as their is with modules.

The more I've looked into it, the more confident I am that no elegant solution to my original question, of getting the parameters of modules not assigned to the current item id. So if you have found this question because you want to do something similar then I would recommend my solution above or cppl's solution below. Both will work and there probably isn't much to choose between them

Dom
  • 2,980
  • 2
  • 28
  • 41
  • You might want to circumvent the problem by assigning the module to all menu items but putting it in a position that doesn't exist in the template. Then getModule would find it, I think. If you need to display it sometimes though this would be a hassle. – David Fritsch May 04 '13 at 21:15

1 Answers1

3

To get around that you can get the current document and then load the module renderer. e.g. if I wanted the Latest news module I had setup with a title of "Sport News" I could use this:

$module    = 'mod_articles_latest';
$title     = 'Sport News';

$document  = JFactory::getDocument();
$renderer  = $document->loadRenderer('module');
$theModule = JModuleHelper::getModule($module, $title);

So, to handle the case where modules aren't assigned to the current or all menu items you could possibly create your own helper that inherits from JModuleHelper and override just the protected function _load().

class MyModuleHelper extends JModuleHelper
{
    protected static function &_load()
    {
        static $clean;

        if (isset($clean))
        {
            return $clean;
        }

        $Itemid = JRequest::getInt('Itemid');
        $app = JFactory::getApplication();
        $user = JFactory::getUser();
        $groups = implode(',', $user->getAuthorisedViewLevels());
        $lang = JFactory::getLanguage()->getTag();
        $clientId = (int) $app->getClientId();

        $cache = JFactory::getCache('com_modules', '');
        $cacheid = md5(serialize(array($Itemid, $groups, $clientId, $lang)));

        if (!($clean = $cache->get($cacheid)))
        {
            $db = JFactory::getDbo();

            $query = $db->getQuery(true);
            $query->select('m.id, m.title, m.module, m.position,    m.content, m.showtitle, m.params, mm.menuid');
            $query->from('#__modules AS m');
            $query->join('LEFT', '#__modules_menu AS mm ON mm.moduleid =    m.id');
            $query->where('m.published = 1');

            $query->join('LEFT', '#__extensions AS e ON e.element =     m.module AND e.client_id = m.client_id');
            $query->where('e.enabled = 1');

            $date = JFactory::getDate();
            $now = $date->toSql();
            $nullDate = $db->getNullDate();
            $query->where('(m.publish_up = ' . $db->Quote($nullDate) . '    OR m.publish_up <= ' . $db->Quote($now) . ')');
            $query->where('(m.publish_down = ' . $db->Quote($nullDate) . '  OR m.publish_down >= ' . $db->Quote($now) . ')');

            $query->where('m.access IN (' . $groups . ')');
            $query->where('m.client_id = ' . $clientId);
            // Disable this line in your override class's _load()...
            // $query->where('(mm.menuid = ' . (int) $Itemid . ' OR     mm.menuid <= 0)');

            // Filter by language
            if ($app->isSite() && $app->getLanguageFilter())
            {
                $query->where('m.language IN (' . $db->Quote($lang) .   ',' . $db->Quote('*') . ')');
            }

            $query->order('m.position, m.ordering');

            // Set the query
            $db->setQuery($query);
            $modules = $db->loadObjectList();
            $clean = array();

            if ($db->getErrorNum())
            {
                JError::raiseWarning(500,   JText::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $db->getErrorMsg()));
                return $clean;
            }

            // Apply negative selections and eliminate duplicates
            $negId = $Itemid ? -(int) $Itemid : false;
            $dupes = array();
            for ($i = 0, $n = count($modules); $i < $n; $i++)
            {
                $module = &$modules[$i];

                // The module is excluded if there is an explicit   prohibition
                $negHit = ($negId === (int) $module->menuid);

                if (isset($dupes[$module->id]))
                {
                    // If this item has been excluded, keep the     duplicate flag set,
                    // but remove any item from the cleaned array.
                    if ($negHit)
                    {
                        unset($clean[$module->id]);
                    }
                    continue;
                }

                $dupes[$module->id] = true;

                // Only accept modules without explicit exclusions.
                if (!$negHit)
                {
                    // Determine if this is a 1.0 style custom  module (no mod_ prefix)
                    // This should be eliminated when the class is  refactored.
                    // $module->user is deprecated.
                    $file = $module->module;
                    $custom = substr($file, 0, 4) == 'mod_' ?  0 :  1;
                    $module->user = $custom;
                    // 1.0 style custom module name is given by     the title field, otherwise strip off "mod_"
                    $module->name = $custom ? $module->module :     substr($file, 4);
                    $module->style = null;
                    $module->position = strtolower($module- >position);
                    $clean[$module->id] = $module;
                }
            }

            unset($dupes);

            // Return to simple indexing that matches the query order.
            $clean = array_values($clean);

            $cache->store($clean, $cacheid);
        }

        return $clean;
    }
}
Craig
  • 9,335
  • 2
  • 34
  • 38
  • Thanks for trying but your code doesn't work me. Also I can't see how it ever could work because at no point are you loading the missing module, you're just loading the renderer. Are you missing a line such as $renderer->render($module) ? – Dom May 04 '13 at 08:48
  • I think I've just understood the problem you were trying to solve, but that isn't the problem I have. You were trying to solve the problem that no modules were loaded into the document at the time I was trying to access them, but the problem I have is that the module I want to get at is not assigned to the current menu item. I've stated this a couple of times now JModuleHelper::getModule cannot retrieve modules which are not assigned to the current menu item. – Dom May 04 '13 at 09:00
  • Well yes, I did miss that, `JModuleHelper`'s protected `_load()` function will only get **published** modules assigned to the current or all menu items. It wouldn't be very efficient to load all the possible modules (so sites have hundreds, half of which are unplaced or unpublished) - you can probably make your own helper class and over-ride the it. See my updated answer. – Craig May 04 '13 at 23:34
  • Creating my own subclass seems like a really heavy way round the problem. I think the better solution is to just get the module data straight from the database. I know it's not elegant, but I think its the best of the available solutions. – Dom May 05 '13 at 16:53
  • I'm not sure I understand what's "heavy" about it given all you have to do is copy that code into a helper file and then load it. Anyway at least the SQL is there for you. – Craig May 06 '13 at 00:19
  • I think it's 'heavy' for the following reasons: You're adding over 100 lines of code; the code pulls in all modules, not just the one you need; the code is duplicating core code, which creates a maintenance headache if that core code is updated in a security patch; your code is tightly coupled with the core tables in the database, rather than using an API call. I think the solution shown in my question edit is slightly better, but I still don't think my solution is particularly good, but it the options I'm going to have to go with. – Dom May 06 '13 at 13:16