1

I am writing an integration module for our product to go into any Joomla 1.6 page. I need some help with getting custom data (from the API) into the basic settings part but can't seem to find a way to get it.

If you look at the documentation for the creation of a module, the settings for your module you set up in an XML format. That leaves you to hard code any values or selections without any dynamic options whatsoever. Basically what I want to do is setup a very basic module that takes three basic properties: URL (used to define the path to the API) API key (The API key) List selection (Connects to the API and gets list names from your account.)

The list selection would change for every user's API key naturally but because you setup the module with an XML file I see no way around the hard coding of list selection options.

Please tell me if you can build a dynamic <select> with options in a Joomla 1.6 module.

NOTE: I say 1.6 because there is a major difference between 1.5 and 1.6 development in Joomla.

Etienne Marais
  • 1,660
  • 1
  • 22
  • 40

2 Answers2

4

Well after a hell of a struggle and no help here whatsoever I can finally say that I have done it. Here is the process for any googlers in the future:

To build a dynamic dropdown you have to do a bunch of thing right for it to be pulled together by Joomla finally.

Also remember to read the documentation carefully, This answer's methods are not contained in it but maybe someone will wake up and put it there someday.

So after inspection of how the 1.6 architecture puts module variables together using the XML build file here we go.

The XML will look something like this :

<?xml version="1.0" encoding="UTF-8"?>
<extension type="module" version="1.6.0" client="site">
    <name>...</name>
    <author>...</author>
    <creationDate>April 2011</creationDate>
    <copyright>Copyright (C) 2011 ... All rights reserved.</copyright>
    <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
    <authorEmail>...</authorEmail>
    <authorUrl>...</authorUrl>
    <version>1.6.0</version>
    <description>
        ...
    </description>
    <files>
        <filename module="mod_your_mod">mod_your_mod.php</filename>
        <filename>helper.php</filename>
        <filename>index.html</filename>
        <folder>tmpl</folder>
        <folder>elements</folder>
        <folder>lib</folder>
    </files>
    <languages />
    <help />
    <config>
        <fields name="params">
            <fieldset name="basic">
                <!-- Custom field, list selection from API -->
                <!-- Path to module external parameters -->
                <field addfieldpath="/modules/mod_your_mod/elements" 
                    name="mod_your_mod_id_selection" <!-- Name of variable -->
                    type="lists" <!-- New variable type -->
                    default="" 
                    label="Select lists" 
                    description="This is the list selection, where you select the list a contact can subscribe to." />
            </fieldset>
            <fieldset
                name="advanced">
                <field
                    name="layout"
                    type="modulelayout"
                    label="JFIELD_ALT_LAYOUT_LABEL"
                    description="JFIELD_ALT_MODULE_LAYOUT_DESC" />
                <field
                    name="moduleclass_sfx"
                    type="text"
                    label="COM_MODULES_FIELD_MODULECLASS_SFX_LABEL"
                    description="COM_MODULES_FIELD_MODULECLASS_SFX_DESC" />
                <field
                    name="cache"
                    type="list"
                    default="1"
                    label="COM_MODULES_FIELD_CACHING_LABEL"
                    description="COM_MODULES_FIELD_CACHING_DESC">
                    <option
                        value="1">JGLOBAL_USE_GLOBAL</option>
                    <option
                        value="0">COM_MODULES_FIELD_VALUE_NOCACHING</option>
                </field>
                <field
                    name="cache_time"
                    type="text"
                    default="900"
                    label="COM_MODULES_FIELD_CACHE_TIME_LABEL"
                    description="COM_MODULES_FIELD_CACHE_TIME_DESC" />
                <field
                    name="cachemode"
                    type="hidden"
                    default="itemid">
                    <option value="itemid"></option>
                </field>
            </fieldset>
        </fields>
    </config>
</extension>

So after following the Joomla way of implementing a module here and here, I added the new parameter variable type into the elements folder as lists.php, see the name is the same as the type you declared in the XML file.

The class inside of this file looks like this :

<?php
// No direct access
defined('_JEXEC') or die('Direct Access to this location is not allowed.');
jimport('joomla.html.html');
//import the necessary class definition for formfield
jimport('joomla.form.formfield');

// Include API utility file
require_once(dirname(__FILE__) . '/../lib/your_api.php');

class JFormFieldLists extends JFormField
{
    /**
     * The form field type.
     *
     * @var  string
     * @since 1.6
     */
    protected $type = 'lists'; //the form field type see the name is the same

    /**
     * Method to retrieve the lists that resides in your application using the API.
     *
     * @return array The field option objects.
     * @since 1.6
     */
    protected function getInput()
    {
        $options = array();
        $attr = '';

        $attr .= ' multiple="multiple"';
        $attr .= ' style="width:220px;height:220px;"';

        // Get the database instance
        $db = JFactory::getDbo();
        // Build the select query
        $query = 'SELECT params FROM jos_modules'
            . ' WHERE module="mod_your_mod"';
        $db->setQuery($query);
        $params = $db->loadObjectList();

        // Decode the options to get thje api key and url
        $options = json_decode($params[0]->params, true);

        // Gracefully catch empty fields
        if ( empty($options['api_key']) === true )
        {
            $tmp = JHtml::_(
                'select.option',
                0,
                'No lists available, please add an API key'
            );

            $lists[] = $tmp;

            // The dropdown output, return empty list if no API key specified
            return JHTML::_(
                'select.genericlist',
                $lists,
                $this->name,
                trim($attr),
                'value',
                'text',
                $this->value,
                $this->id
            );
        }
        if ( empty($options['url']) === true )
        {
            $tmp = JHtml::_(
                'select.option',
                0,
                'No lists available, please add the enterprise URL'
            );

            $lists[] = $tmp;

            // The dropdown output, return empty list if no API key specified
            return JHTML::_(
                'select.genericlist',
                $lists,
                $this->name,
                trim($attr),
                'value',
                'text',
                $this->value,
                $this->id
            );

        }

        // Create a new API utility class
        $api = new APIClass(
            $options['url'],
            $options['api_key']
        );

        try
        {
            // Get the lists needed for subscription
            $response = $api->getLists();
        }
        catch ( Exception $e )
        {
            $tmp = JHtml::_(
                'select.option',
                0,
                'Could not connect to the API'
            );

            $lists[] = $tmp;

            // The dropdown output, return empty list if no API key specified
            return JHTML::_(
                'select.genericlist',
                $lists,
                $this->name,
                trim($attr),
                'value',
                'text',
                $this->value,
                $this->id
            );
        }

        $lists = array();

        // Builds the options for the dropdown
        foreach ( $response['data'] as $list )
        {
            // Build options object here
            $tmp = JHtml::_(
                'select.option',
                $list['list_id'],
                $list['list_name']
            );

            $lists[] = $tmp;
        }

        // The dropdown output

        /* The name of the select box MUST be the same as in the XML file otherwise 
         * saving your selection using Joomla will NOT work. Also if you want to make it 
         * multiple selects don't forget the [].
         */
        return JHTML::_(
            'select.genericlist',
            $lists,
            'jform[params][mod_your_mod_id_selection][]',
            trim($attr),
            'value',
            'text',
            $this->value,
            $this->id
        );

    }

}

?>

So you will know when everything is working because your selection of the drop down list, built by the API(hence completely dynamic), will save into the module database entry with the name of the select box which you can easily retrieve by calling:

$api_key = $params->get('api_key', '');

in your module file. In this case its called mod_your_mod.php.

I really hope that this helps you when defining customized parameters in the back end of your Joomla 1.6 modules. This allows for extreme customizations and integrates tightly with whatever application you like to use's API.

The only downside is that it might be slow, but using a bunch of checks it fails gracefully when the API is down or not pulling data through correctly. All in all a very unpleasant CMS to work with but that is only my opinion.

Etienne Marais
  • 1,660
  • 1
  • 22
  • 40
3

There is also a much simpler solution if your needs are basic: http://docs.joomla.org/SQL_form_field_type

There is an "sql" form field type:

<field name="title" type="sql" default="10" label="Select an article" query="SELECT id AS value, title FROM #__content" />

(I sympathize with your frustration - the documentation is terrible, scattered and hard to find)