User

Difference between revisions of "Rvsjoen/tutorial/Developing an MVC Component/Part 13"

From Joomla! Documentation

< User:Rvsjoen‎ | tutorial/Developing an MVC Component
 
(9 intermediate revisions by the same user not shown)
Line 119: Line 119:
 
'''<tt>admin/views/helloworld/tmpl/edit.php</tt>'''
 
'''<tt>admin/views/helloworld/tmpl/edit.php</tt>'''
 
<source lang="php">
 
<source lang="php">
 +
<?php
 
// No direct access to this file
 
// No direct access to this file
 
defined('_JEXEC') or die;
 
defined('_JEXEC') or die;
Line 165: Line 166:
  
 
== Updating the toolbar ==
 
== Updating the toolbar ==
 +
 +
Now, in order to make the component options available to the user so they can be configured, we need to add an '''Options''' button to the toolbar.
  
 
With your favorite editor, modify the following files to look like this
 
With your favorite editor, modify the following files to look like this
  
<span id="admin/views/helloworld/view.html.php">
+
<span id="admin/views/helloworlds/view.html.php">
'''<tt>admin/views/helloworld/view.html.php</tt>'''
+
'''<tt>admin/views/helloworlds/view.html.php</tt>'''
 
<source lang="php" highlight="34" line>
 
<source lang="php" highlight="34" line>
 
// No direct access to this file
 
// No direct access to this file
Line 216: Line 219:
 
</span>
 
</span>
  
== Updating the frontend view ==
+
== Updating the table to support parameters ==
 
 
With your favorite editor, modify the following files to look like this
 
  
<span id="site/views/helloworld/tmpl/default.php">
+
In the database table, params are stored as JSON-encoded strings, in order to make this transparent to the model, we override the <code>bind()</code> and <code>load()</code> functions of the JTable instance to perform the conversion between a '''JRegistry''' object and a JSON-encoded string automatically.
'''<tt>site/views/helloworld/tmpl/default.php</tt>'''
 
<source lang="php">
 
// No direct access to this file
 
defined('_JEXEC') or die;
 
 
 
?>
 
<h1>
 
        <?php echo $this->item->greeting; ?>
 
        <?php if($this->item->category && $this->item->params->get('show_category')): ?>
 
                <?php echo ' ('.$this->item->category.') '; ?>
 
        <?php endif; ?>
 
</h1>
 
</source>
 
</span>
 
 
 
== Updating the table to support parameters ==
 
  
 
<span id="admin/tables/helloworld.php">
 
<span id="admin/tables/helloworld.php">
Line 284: Line 269:
 
</span>
 
</span>
  
== Updating the model to support parameters ==
+
== Updating the frontend ==
 +
 
 +
Now, at this point, the frontend '''HelloWorldModelHelloWorld''' knows nothing about the parameters in the table, or in the component options, so we have to write some more code to make it aware of this. When loading an item from the database we will also convert the JSON-encoded parameters to a JRegistry object, and merge them with the component options. This ensures that the item-specific options can override the component-wide options if they are set.
 +
 
 +
With your favorite editor, modify the following files to look like this
 +
 
 +
<span id="site/models/helloworld.php">
 +
'''<tt>site/models/helloworld.php</tt>'''
 +
<source lang="php">
 +
<?php
 +
// No direct access to this file
 +
defined('_JEXEC') or die('Restricted access');
 +
 
 +
jimport('joomla.application.component.modelitem');
 +
 
 +
class HelloWorldModelHelloWorld extends JModelItem
 +
{
 +
        protected $item;
 +
 
 +
        protected function populateState()
 +
        {
 +
                $app = JFactory::getApplication();
 +
                // Get the message id
 +
                $id = JRequest::getInt('id');
 +
                $this->setState('message.id', $id);
 +
 
 +
                // Load the parameters.
 +
                $params = $app->getParams();
 +
                $this->setState('params', $params);
 +
                parent::populateState();
 +
        }
 +
 
 +
        /**
 +
        * Get the message
 +
        * @return string The message to be displayed to the user
 +
        */
 +
        public function getItem()
 +
        {
 +
                if (!isset($this->item)) {
 +
                        $id = $this->getState('message.id');
 +
                        $this->_db->setQuery($this->_db->getQuery(true)
 +
                                ->from('#__helloworld as h')
 +
                                ->leftJoin('#__categories as c ON h.catid = c.id')
 +
                                ->select('h.greeting, h.params, c.title as category')
 +
                                ->where('h.id=' . (int)$id));
 +
                        if (!$this->item = $this->_db->loadObject()) {
 +
                                $this->setError($this->_db->getError());
 +
                        } else {
 +
                                // Load the JSON string
 +
                                $params = new JRegistry;
 +
                                $params->loadJSON($this->item->params);
 +
                                $this->item->params = $params;
 +
 
 +
                                // Merge global params with item params
 +
                                $params = clone $this->getState('params');
 +
                                $params->merge($this->item->params);
 +
                                $this->item->params = $params;
 +
                        }
 +
                }
 +
                return $this->item;
 +
        }
 +
}
 +
</source>
 +
</span>
 +
 
 +
The frontend view also needs to be updated in order to support only displaying the category if the item is configured to show the category.
 +
 
 +
With your favorite editor, modify the following files to look like this
 +
 
 +
<span id="site/views/helloworld/tmpl/default.php">
 +
'''<tt>site/views/helloworld/tmpl/default.php</tt>'''
 +
<source lang="php">
 +
// No direct access to this file
 +
defined('_JEXEC') or die;
 +
 
 +
?>
 +
<h1>
 +
        <?php echo $this->item->greeting; ?>
 +
        <?php if($this->item->category && $this->item->params->get('show_category')): ?>
 +
                <?php echo ' ('.$this->item->category.') '; ?>
 +
        <?php endif; ?>
 +
</h1>
 +
</source>
 +
</span>
  
 
== Update the language files ==
 
== Update the language files ==
Line 327: Line 395:
 
<source lang="xml">
 
<source lang="xml">
 
<?xml version="1.0" encoding="utf-8"?>
 
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="1.6.0" method="upgrade">
+
<extension type="component" version="2.5.0" method="upgrade">
  
 
         <name>COM_HELLOWORLD</name>
 
         <name>COM_HELLOWORLD</name>
Line 470: Line 538:
  
 
== Download this part ==
 
== Download this part ==
 +
 +
[https://github.com/downloads/rvsjoen/joomla-tutorials/com_helloworld-part13.zip Download example package]
  
 
== Articles in this series ==
 
== Articles in this series ==

Latest revision as of 09:34, 26 January 2012

Adding component options[edit]

If we want our component to be configurable, then we have to go ahead and add some options, we can add options on several levels. Menu items may have options, the component may have options or the individual items (greetings in our case) may have their own set of options. In this part we will cover how to implement global component options, and how to be able to override them with item-specific options for more granularity. Options are also knows as parameters.

Adding the configuration XML[edit]

The component-wide options are defined in their own XML file in the administrator part of your component, so in order to implement these features we need a config.xml file with at least one field in it.

With your favorite editor, create the following file

admin/config.xml

<?xml version="1.0" encoding="utf-8"?>
<config>
        <fieldset
                name="greetings"
                label="COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_LABEL"
                description="COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_DESC">
                <field
                        name="show_category"
                        type="radio"
                        label="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL"
                        description="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC"
                        default="0">
                        <option value="0">JHIDE</option>
                        <option value="1">JSHOW</option>
                </field>
        </fieldset>
</config>

Adding parameters to the database[edit]

While the previous XML configuration file pretty much takes care of the "global" component options, in order to support a bit more granularity and use the parameters in Joomla! on a per-item basis we need to add a field to our table in the database.

With your favorite editor, modify the following file to look like this

admin/sql/install.mysql.utf8.sql

DROP TABLE IF EXISTS `#__helloworld`;

CREATE TABLE `#__helloworld` (
  `id` int(11) NOT NULL auto_increment,
  `greeting` varchar(25) NOT NULL,
  `catid` int(11) NOT NULL DEFAULT '0',
  `params` TEXT NOT NULL DEFAULT '',
   PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

INSERT INTO `#__helloworld` (`greeting`) VALUES
        ('Hello World!'),
        ('Good bye World!');

NOTE: You WILL need to completely uninstall and reinstall the component for these changes to take effect if you have any of the previous parts installed.

Update the editing view[edit]

We are going to have to modify our helloworld form in order to add a fieldset for the parameters so they can be edited by the user when editing the items. And afterwards we have to update the edit view template so that the newly added fieldset is displayed to the user.

With your favorite editor, modify the following filer to look like this

admin/models/forms/helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<form addrulepath="/administrator/components/com_helloworld/models/rules">
        <fieldset name="details">
                <field
                        name="id"
                        type="hidden"
                />
                <field
                        name="greeting"
                        type="text"
                        label="COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_LABEL"
                        description="COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_DESC"
                        size="40"
                        class="inputbox validate-greeting"
                        validate="greeting"
                        required="true"
                        default=""
                />
                <field
                        name="catid"
                        type="category"
                        extension="com_helloworld"
                        class="inputbox"
                        default=""
                        label="COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_LABEL"
                        description="COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_DESC"
                        required="true">
                        <option value="0">JOPTION_SELECT_CATEGORY</option>
                </field>
        </fieldset>
        <fields name="params">
                <fieldset name="params" label="JGLOBAL_FIELDSET_DISPLAY_OPTIONS">
                        <field
                                name="show_category"
                                type="list"
                                label="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL"
                                description="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC"
                                default="">
                                <option value="">JGLOBAL_USE_GLOBAL</option>
                                <option value="0">JHIDE</option>
                                <option value="1">JSHOW</option>
                        </field>
                </fieldset>
        </fields>
</form>

admin/views/helloworld/tmpl/edit.php

<?php
// No direct access to this file
defined('_JEXEC') or die;

JHtml::_('behavior.tooltip');
JHtml::_('behavior.formvalidation');
$params = $this->form->getFieldsets('params');
?>
<form action="<?php echo JRoute::_('index.php?option=com_helloworld&layout=edit&id='.(int) $this->item->id); ?>" 
        method="post" name="adminForm" id="helloworld-form" class="form-validate">
        <div class="width-60 fltlft">
                <fieldset class="adminform">
                <legend><?php echo JText::_( 'COM_HELLOWORLD_HELLOWORLD_DETAILS' ); ?></legend>
                <ul class="adminformlist">
                        <?php foreach($this->form->getFieldset('details') as $field): ?>
                                <li><?php echo $field->label;echo $field->input;?></li>
                        <?php endforeach; ?>
                </ul>
                </fieldset>
        </div>
        <div class="width-40 fltrt">
                <?php echo JHtml::_('sliders.start', 'helloworld-slider'); ?>
                <?php foreach ($params as $name => $fieldset): ?>
                        <?php echo JHtml::_('sliders.panel', JText::_($fieldset->label), $name.'-params');?>
                        <?php if (isset($fieldset->description) && trim($fieldset->description)): ?>
                                <p class="tip"><?php echo $this->escape(JText::_($fieldset->description));?></p>
                        <?php endif;?>
                        <fieldset class="panelform" >
                                <ul class="adminformlist">
                                        <?php foreach ($this->form->getFieldset($name) as $field) : ?>
                                                <li><?php echo $field->label; ?><?php echo $field->input; ?></li>
                                        <?php endforeach; ?>
                                </ul>
                        </fieldset>
                <?php endforeach; ?>
                <?php echo JHtml::_('sliders.end'); ?>
        </div>

        <div>
                <input type="hidden" name="task" value="helloworld.edit" />
                <?php echo JHtml::_('form.token'); ?>
        </div>
</form>

Updating the toolbar[edit]

Now, in order to make the component options available to the user so they can be configured, we need to add an Options button to the toolbar.

With your favorite editor, modify the following files to look like this

admin/views/helloworlds/view.html.php

// No direct access to this file
defined('_JEXEC') or die;

jimport('joomla.application.component.view');

class HelloWorldViewHelloWorlds extends JView
{
        function display($tpl = null) 
        {
                // Get data from the model
                $items = $this->get('Items');
                $pagination = $this->get('Pagination');

                // Assign data to the view
                $this->items = $items;
                $this->pagination = $pagination;

                // Set the toolbar
                $this->addToolBar();

                // Display the template
                parent::display($tpl);

                // Set the document
                $this->setDocument();
        }

        protected function addToolBar() 
        {
                JToolBarHelper::title(JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS'), 'helloworld');
                JToolBarHelper::deleteListX('', 'helloworlds.delete');
                JToolBarHelper::editListX('helloworld.edit');
                JToolBarHelper::addNewX('helloworld.add');
                JToolBarHelper::preferences('com_helloworld');
        }

        protected function setDocument() 
        {
                $document = JFactory::getDocument();
                $document->setTitle(JText::_('COM_HELLOWORLD_ADMINISTRATION'));
        }
}

Updating the table to support parameters[edit]

In the database table, params are stored as JSON-encoded strings, in order to make this transparent to the model, we override the bind() and load() functions of the JTable instance to perform the conversion between a JRegistry object and a JSON-encoded string automatically.

admin/tables/helloworld.php

// No direct access to this file
defined('_JEXEC') or die;

jimport('joomla.database.table');

class HelloWorldTableHelloWorld extends JTable
{
        function __construct(&$db) 
        {
                parent::__construct('#__helloworld', 'id', $db);
        }

        public function bind($array, $ignore = '') 
        {
                if (isset($array['params']) && is_array($array['params'])) 
                {
                        // Convert the params field to a string.
                        $parameter = new JRegistry;
                        $parameter->loadArray($array['params']);
                        $array['params'] = (string)$parameter;
                }
                return parent::bind($array, $ignore);
        }

        public function load($pk = null, $reset = true) 
        {
                if (parent::load($pk, $reset)) 
                {
                        // Convert the params field to a registry.
                        $params = new JRegistry;
                        $params->loadJSON($this->params);
                        $this->params = $params;
                        return true;
                }
                else
                {
                        return false;
                }
        }
}

Updating the frontend[edit]

Now, at this point, the frontend HelloWorldModelHelloWorld knows nothing about the parameters in the table, or in the component options, so we have to write some more code to make it aware of this. When loading an item from the database we will also convert the JSON-encoded parameters to a JRegistry object, and merge them with the component options. This ensures that the item-specific options can override the component-wide options if they are set.

With your favorite editor, modify the following files to look like this

site/models/helloworld.php

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

jimport('joomla.application.component.modelitem');

class HelloWorldModelHelloWorld extends JModelItem
{
        protected $item;

        protected function populateState() 
        {
                $app = JFactory::getApplication();
                // Get the message id
                $id = JRequest::getInt('id');
                $this->setState('message.id', $id);

                // Load the parameters.
                $params = $app->getParams();
                $this->setState('params', $params);
                parent::populateState();
        }

        /**
         * Get the message
         * @return string The message to be displayed to the user
         */
        public function getItem() 
        {
                if (!isset($this->item)) {
                        $id = $this->getState('message.id');
                        $this->_db->setQuery($this->_db->getQuery(true)
                                ->from('#__helloworld as h')
                                ->leftJoin('#__categories as c ON h.catid = c.id')
                                ->select('h.greeting, h.params, c.title as category')
                                ->where('h.id=' . (int)$id));
                        if (!$this->item = $this->_db->loadObject()) {
                                $this->setError($this->_db->getError());
                        } else {
                                // Load the JSON string
                                $params = new JRegistry;
                                $params->loadJSON($this->item->params);
                                $this->item->params = $params;

                                // Merge global params with item params
                                $params = clone $this->getState('params');
                                $params->merge($this->item->params);
                                $this->item->params = $params;
                        }
                }
                return $this->item;
        }
}

The frontend view also needs to be updated in order to support only displaying the category if the item is configured to show the category.

With your favorite editor, modify the following files to look like this

site/views/helloworld/tmpl/default.php

// No direct access to this file
defined('_JEXEC') or die;

?>
<h1>
        <?php echo $this->item->greeting; ?>
        <?php if($this->item->category && $this->item->params->get('show_category')): ?>
                <?php echo ' ('.$this->item->category.') '; ?>
        <?php endif; ?>
</h1>

Update the language files[edit]

With your favorite editor, modify the following files to look like this

admin/language/en-GB/en-GB.com_helloworld.ini

COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_DESC="This message will be displayed"
COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_LABEL="Message"
COM_HELLOWORLD_HELLOWORLD_HEADING_GREETING="Greeting"
COM_HELLOWORLD_HELLOWORLD_HEADING_ID="ID"
COM_HELLOWORLD_HELLOWORLD_DETAILS="Details"
COM_HELLOWORLD_MANAGER_HELLOWORLDS="HelloWorld manager"
COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW="HelloWorld manager: New Message"
COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT="HelloWorld manager: Edit Message"
COM_HELLOWORLD_N_ITEMS_DELETED_1="One message deleted"
COM_HELLOWORLD_N_ITEMS_DELETED_MORE="%d messages deleted"
COM_HELLOWORLD_ADMINISTRATION="HelloWorld - Administration"
COM_HELLOWORLD_HELLOWORLD_CREATING="HelloWorld - Creating"
COM_HELLOWORLD_HELLOWORLD_EDITING="HelloWorld - Editing"
COM_HELLOWORLD_SUBMENU_MESSAGES="Messages"
COM_HELLOWORLD_SUBMENU_CATEGORIES="Categories"
COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_DESC="The category the messages belongs to"
COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_LABEL="Category"
COM_HELLOWORLD_ADMINISTRATION_CATEGORIES="HelloWorld - Categories"
COM_HELLOWORLD_CONFIGURATION="HelloWorld Configuration"
COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_LABEL="Messages settings"
COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_DESC="Settings that will be applied to all messages by default"
COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL="Show category"
COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC="If set to Show, the title of the message&rsquo;s category will show."

Installation manifest[edit]

In the installation manifest, we have updated the version number and added config.xml

helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="2.5.0" method="upgrade">

        <name>COM_HELLOWORLD</name>
        <!-- The following elements are optional and free of formatting constraints -->
        <creationDate>June 2011</creationDate>
        <author>John Doe</author>
        <authorEmail>john.doe@example.org</authorEmail>
        <authorUrl>http://www.example.org</authorUrl>
        <copyright>Copyright Info</copyright>
        <license>License Info</license>
        <!--  The version string is stored in the components table -->
        <version>0.0.13</version>
        <!-- The description is optional and defaults to the name -->
        <description>COM_HELLOWORLD_DESCRIPTION</description>

        <install>
                <sql>
                        <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
                </sql>
        </install>
        <uninstall>
                <sql>
                        <file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
                </sql>
        </uninstall>

        <!-- Note the folder attribute: This attribute describes the folder
                to copy FROM in the package to install therefore files copied
                in this section are copied from "site/" in the package -->
        <files folder="site">
                <filename>index.html</filename>
                <filename>helloworld.php</filename>
                <filename>controller.php</filename>
                <folder>views</folder>
                <folder>models</folder>
                <folder>language</folder>
        </files>

        <media destination="com_helloworld" folder="media">
                <filename>index.html</filename>
                <folder>images</folder>
                <folder>js</folder>
        </media>

        <administration>
                <menu img="../media/com_helloworld/images/tux-16x16.png">COM_HELLOWORLD_MENU</menu>
                <submenu>
                        <menu view="helloworlds">COM_HELLOWORLD_SUBMENU_MESSAGES</menu>
                        <menu link="option=com_categories&amp;view=categories&amp;extension=com_helloworld">COM_HELLOWORLD_SUBMENU_CATEGORIES</menu>
                </submenu>
                <!-- Note the folder attribute: This attribute describes the folder
                        to copy FROM in the package to install therefore files copied
                        in this section are copied from "admin/" in the package -->
                <files folder="admin">
                        <filename>index.html</filename>
                        <filename>helloworld.php</filename>
                        <filename>controller.php</filename>
                        <filename>config.xml</filename>
                        <folder>sql</folder>
                        <folder>tables</folder>
                        <folder>models</folder>
                        <folder>views</folder>
                        <folder>language</folder>
                        <folder>controllers</folder>
                        <folder>helpers</folder>
                </files>
        </administration>

</extension>

Testing your component[edit]

For details on how to install the component into your Joomla! site, refer to the information provided in Part 01.


File listing[edit]

Download this part[edit]

Download example package

Articles in this series[edit]

This tutorial is supported by the following versions of Joomla!

Joomla 2.5