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.
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.
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)
Related
I need to be able to use different layouts for different categories, selected on the Custom Design tab on the category and Page Layout field.
I'm using Magento 1.9.1.0.
In my config.xml I have:
<global>
<page>
<layouts>
<module_home module="page" translate="label">
<label>Module Home</label>
<template>page/base.phtml</template>
<layout_handle>module_home</layout_handle>
</module_home>
<module_categories module="page" translate="label">
<label>Module Categories</label>
<template>page/base.phtml</template>
<layout_handle>module_categories</layout_handle>
</module_categories>
</layouts>
</page>
...
And in my layouts.xml file I have:
<default>
<reference name="root">...</reference>
</default>
<module_home translate="label">...</module_home>
<module_categories translate="label">...</module_categories>
When I select Module Categories layout from the admin of the category I don't get the changes for module_categories handler, only the ones set on <default>.
If I force it like this:
<catalog_category_view>
<update handle="module_categories" />
</catalog_category_view>
I do get the changes, but I want multiple handlers, selected as Layouts on the admin.
Maybe I'm doing something wrong? Could not find an example for how to do this, maybe you can point somewhere? Thanks!
You've got the right idea with the <update /> directive. Just put it in your category's Custom Layout Update field in the admin, and that category should apply that layout handle. You can still set the page template with the Page Layout field.
The reason you need to explicitly specify the layout handle with the <update /> directive is because Magento's category controller does not use the layout_handle node, whereas other parts of Magento, like Magento's CMS page controller, do use it.
For example, let's look at Mage_Cms_PageController, which is responsible for rendering a CMS page:
public function viewAction()
{
$pageId = $this->getRequest()
->getParam('page_id', $this->getRequest()->getParam('id', false));
if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
$this->_forward('noRoute');
}
}
Let's dig deeper and look at Mage_Cms_Helper_Page::renderPage(), which calls Mage_Cms_Helper_Page::_renderPage():
protected function _renderPage(Mage_Core_Controller_Varien_Action $action, $pageId = null, $renderLayout = true)
{
$page = Mage::getSingleton('cms/page');
/* ... */
if ($page->getRootTemplate()) {
$handle = ($page->getCustomRootTemplate()
&& $page->getCustomRootTemplate() != 'empty'
&& $inRange) ? $page->getCustomRootTemplate() : $page->getRootTemplate();
$action->getLayout()->helper('page/layout')->applyHandle($handle);
}
/* ... */
if ($page->getRootTemplate()) {
$action->getLayout()->helper('page/layout')
->applyTemplate($page->getRootTemplate());
}
/* ... */
}
We see two important pieces of logic here.
First, _renderPage() calls $action->getLayout()->helper('page/layout')->applyHandle($handle). If you dig even deeper, you'll see that Mage_Page_Helper_Layout::applyHandle() is responsible for applying the appropriate layout_handle as defined by the configuration XML:
public function applyHandle($pageLayout)
{
$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
if (!$pageLayout) {
return $this;
}
$this->getLayout()
->getUpdate()
->addHandle($pageLayout->getLayoutHandle());
return $this;
}
Second, _renderPage() calls $action->getLayout()->helper('page/layout')->applyTemplate($page->getRootTemplate()). Similar to applyHandle(), applyTemplate() applies the actual page template.
So, this explains why you can depend on the layout_handle as defined in the configuration XML when it comes to CMS pages. Now, let's find out why it's not dependable for categories.
Let's look at Mage_Catalog_CategoryController::viewAction(), which is responsible for displaying a category page:
public function viewAction()
{
if ($category = $this->_initCatagory()) {
$design = Mage::getSingleton('catalog/design');
$settings = $design->getDesignSettings($category);
/* ... */
// apply custom layout update once layout is loaded
if ($layoutUpdates = $settings->getLayoutUpdates()) {
if (is_array($layoutUpdates)) {
foreach($layoutUpdates as $layoutUpdate) {
$update->addUpdate($layoutUpdate);
}
}
}
/* ... */
// apply custom layout (page) template once the blocks are generated
if ($settings->getPageLayout()) {
$this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}
/* ... */
}
elseif (!$this->getResponse()->isRedirect()) {
$this->_forward('noRoute');
}
}
Stripping out all of the default layout logic, we're left with two pieces:
// apply custom layout update once layout is loaded
if ($layoutUpdates = $settings->getLayoutUpdates()) {
if (is_array($layoutUpdates)) {
foreach($layoutUpdates as $layoutUpdate) {
$update->addUpdate($layoutUpdate);
}
}
}
This goes through the category's layout updates (as defined in the Custom Layout Update field in the admin) and applies them. This is why using <update handle="some_handle" /> works.
And...
// apply custom layout (page) template once the blocks are generated
if ($settings->getPageLayout()) {
$this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}
This applies the custom page template, similar to how the CMS page logic did it, using Mage_Page_Helper_Layout::applyTemplate().
Now, notice something missing?
Yup, the category controller does not call Mage_Page_Helper_Layout::applyHandle() to apply the layout_handle as defined in the configuration XML. This means that you can use the Page Layout field to give the category a particular page template, but your layout_update that accompanies the template won't get applied!
Hope this clears up why your layout_update node isn't getting used on the category page the way you would expect it to. Magento is full of odd behavior and inconsistencies like this :)
I have followed the Joomla Docs tutorial on how to add ACL to my custom component.
While I had success to add the component wide permission management I am struggeling to get the item level ACL to work.
I am trying to implement an ACL for the table books. I have added an asset_id column there as described in the tutorial.
I added a file book.xml in admin/models/forms/ - this is the content:
<?xml version="1.0" encoding="utf-8"?>
<form>
<field name="asset_id" type="hidden" filter="unset" />
<field name="rules"
type="rules"
label="JFIELD_RULES_LABEL"
translate_label="false"
filter="rules"
validate="rules"
class="inputbox"
component="com_mytest"
section="book"
/>
</form>
This is how my access.xml looks like:
<?xml version="1.0" encoding="utf-8" ?>
<access component="com_mytest">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" description="JACTION_ADMIN_COMPONENT_DESC" />
<action name="core.manage" title="JACTION_MANAGE" description="JACTION_MANAGE_COMPONENT_DESC" />
<action name="core.edit" title="JACTION_EDIT_BOOK" description="COM_MYTEST_ACCESS_EDIT_BOOK_DESC" />
<action name="core.delete" title="JACTION_DELETE_BOOK" description="COM_MYTEST_ACCESS_DELETE_BOOK_DESC" />
</section>
<section name="book">
<action name="core.edit" title="JACTION_EDIT_BOOK" description="COM_MYTEST_ACCESS_EDIT_BOOK_DESC" />
<action name="core.delete" title="JACTION_DELETE_BOOK" description="COM_MYTEST_ACCESS_DELETE_BOOK_DESC" />
</section>
</access>
In my JTable variant in admin/tables/mytest_books.php I have added this methods:
public function bind($array, $ignore = '')
{
if (isset($array['jform']) && isset($array['jform']['rules']) && is_array($array['jform']['rules']))
{
$rules = new JAccessRules($array['jform']['rules']);
$this->setRules($rules);
}
return parent::bind($array, $ignore);
}
protected function _getAssetName()
{
return 'com_mytest.book.'.(int) $this->id;
}
protected function _getAssetTitle()
{
return $this->name;
}
protected function _getAssetParentId()
{
$asset = JTable::getInstance('Asset');
$asset->loadByName('com_mytest');
return $asset->id;
}
As you might notice in the bind() method above I have to extract the rules array from with in the jform array. In all tutorials I saw they simply reference $array['rules'] and not $array['jform']['rules'].
Maybe this is my issue?
This is my book model admin/models/book.php:
public function getForm($data = array(), $loadData = true)
{
$form = $this->loadForm('com_mytest.book', 'book', array('control' => 'jform', 'load_data' => $loadData));
if (empty($form)){
return false;
}
return $form;
}
protected function loadFormData()
{
$data = JFactory::getApplication()->getUserState('com_mytest.edit.book.data', array());
if (empty($data))
{
$data = $this->getItem($this->_id);
}
return $data;
}
Here is what I added at the bottom in the book editing screen admin/views/book/tmpl/default.php:
<?php echo JHtml::_('sliders.start', 'permissions-sliders-'.$this->row->id, array('useCookie'=>1)); ?>
<?php echo JHtml::_('sliders.panel', JText::_('COM_MYTEST_FIELDSET_RULES'), 'access-rules'); ?>
<fieldset class="panelform">
<?php echo $this->form->getLabel('rules'); ?>
<?php echo $this->form->getInput('rules'); ?>
</fieldset>
<?php echo JHtml::_('sliders.end'); ?>
Here is what is working:
When I save a book after editing the book level ACL for a group the settings save correctly. My asset table looks good, showing entries like:
id | name | title | rules
198 | com_mytest.book.2 | The guide to something | {"core.edit":{"1":0,"6":1,"7":1,"2":0,"3":0,"4":1,"5":0,"10":0,"12":0,"8":0},"core.delete":{"1":0,"6":1,"7":0,"2":0,"3":0,"4":0,"5":0,"10":0,"12":0,"8":0}}
And yes, the book with ID 2 has 198 in the asset_id column.
Here is my problem
When I save the book ACL by setting Allowed for all actions for the Administrator user group the dialog shows Conflict beside the permission. Setting everything to Denied does not show this message.
For the Allowed case (and the Conflict-situation):
When I use a second browser to login as an Administrator user group user this condition always returns false (yes, $row->id does contain a valid ID):
$canEdit = JFactory::getUser()->authorise('core.edit',
'com_mytest.book.'.$row->id);
Can you help me solving this puzzle?
Thank you very much!
Are your book assets getting the correct parent id in the asset table?
Any time you use ACL when not using categories you need to be extremely careful about parenting. Usually you want to ensure that the items are getting the component as the parent.
This is something that is a bit messy in the classes, but you can look at com_modules and see how this can work.
A conflict situation exists when a group has a hard deny somewhere between the item and the the start of the branch. Usually that might be denied on a component but allowed for a category of that component, as one example. You can get into a conflict situation if your parenting is not done correctly.
I have a problem and I'm new to Joomla and K2, so any help will be highly appreciated.
I'm developing a simple joomla plugin based on Example K2 Plugin (http://getk2.org/extend/extensions/90-example-k2-plugin-for-developers).
What i'm trying to create is a K2 extension for Categories, so i'll be able to add extra content to categories. I already did a search and there is not plugin or extension to cover my needs for this project with Joomal 3.x.
For each category I set information in the backend as currency, language, country , etc. I added this fields to the backend via the xml file.
I have tried several ways, but I haven't been able to access this information on my k2 template. When i dump parameters I get the default value from the xml, but not the one already saved for the category.
So i'm being able to easily display the content with a plugin template but by defect the only function available for categories will be onK2CategoryDisplay, but what i'm trying to achieve here is to call the fields values from the K2 template, next to the title for example, or below a gallery.
I found this lines, but it only displays the default text saved on the xml file, and not the new content. If i'm not being clear, please let me know and i'll update this post. Thanks in advance.
$plugin = JPluginHelper::getPlugin('k2', 'categories');
$pluginParams = new JRegistry();
$pluginParams->loadString($plugin->params);
$param = $pluginParams->get('localCountry_cat');
var_dump($param);
Here is the categories.xml:
<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="k2" method="upgrade">
<name>Categories K2 Plugin</name>
<files>
<filename plugin="categories">categories.php</filename>
<folder>categories</folder>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field name="localCountry_cat" type="text" size="80" default="test" label="Country local name" description="" />
<field name="capital_cat" type="text" size="80" default="test" label="Capital" description="" />
<field name="languages_cat" type="text" size="80" default="test" label="Official Languages" description="" />
</fieldset>
</fields>
</config>
<!-- K2 backend field parameters -->
<fields group="category">
<field name="localCountry_cat" type="text" size="80" default="" label="Country local name" description="" />
<field name="capital_cat" type="text" size="80" default="" label="Capital" description="" />
<field name="languages_cat" type="text" size="80" default="" label="Official Languages" description="" />
</fields>
Here is the categories.php
// no direct access
defined('_JEXEC') or die('Restricted access');
// Load the K2 plugin API
JLoader::register('K2Plugin', JPATH_ADMINISTRATOR.DS.'components'.DS.'com_k2'.DS.'lib'.DS.'k2plugin.php');
class plgK2categories extends K2Plugin {
// Required global reference parameters
var $pluginName = 'categories';
var $pluginNameHumanReadable = 'Categories K2 Plugin';
var $plgCopyrightsStart = " "
var $plgCopyrightsEnd = " ";
function plgK2categories( & $subject, $params) {
parent::__construct($subject, $params);
}
function onK2CategoryDisplay( & $category, & $params, $limitstart) {
// API
$mainframe = JFactory::getApplication();
$document = JFactory::getDocument();
// ---------- Get plugin parameters ---------------
// Global plugin params
$plugin = JPluginHelper::getPlugin('k2', $this->pluginName);
$pluginGlobalParams = new JRegistry( $plugin->params );
// K2 Category plugin specific params
$pluginParams = new K2Parameter($category->plugins, '', $this->pluginName);
$local = $pluginParams->get('localCountry_cat');
$capital = $pluginParams->get('capital_cat');
$languages = $pluginParams->get('languages_cat');
$currency = $pluginParams->get('currency_cat');
// --------- Requirements -------
require_once(dirname(__FILE__).DS.$this->pluginName.DS.'includes'.DS.'helper.php');
// ---------- Fetch the template -------
ob_start();
$getTemplatePath = categoriesHelper::getTemplatePath($this->pluginName,'default.php');
$getTemplatePath = $getTemplatePath->file;
include($getTemplatePath);
$getTemplate = $this->plgCopyrightsStart.ob_get_contents().$this->plgCopyrightsEnd;
ob_end_clean();
// ----- Output -----
return $getTemplate;
}
} // END CLASS
I already solved it. It was easier than I thought, but took me a while to discover it. The lack of documentation for K2 and it's developers is a huge pain.
Retrieved from the database the information with $this->params->get('itemK2Plugins'), but also with: $this->category->plugins
<?php if($this->params->get('itemK2Plugins')): ?>
<?php
$array = json_decode($this->category->plugins, true);
foreach($array as $key => $value) {
$keys[$key] = $value;
}
$countryL = $keys['categorieslocalCountry_cat'];
$MottoL = $keys['categorieslocalMotto_cat'];
?>
<?php endif; ?>
If there is a different and correct way to do it, please let me know!
Thanks :)
The Question: How do I insert values from a database table (#__mytable) into form text fields (motitle and modescription) which have been rendered from an XML file within the Joomla 3.0 platform?
-
I've been trying for days to solve this "easy" Joomla! based undocumented challenge.
I have followed Joomla!'s guide for Developing an MVC, read most of their out-of-date documentation and torn apart the com_content component but have still no idea how to populate my fields.
I've been playing with $this->form->bind($this->item);.
Below I have included some of my code to show the structure I am using. Please feel free to point out any issues you spot along the way.
Models\Forms\item.xml
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="groupOPTIONS">
<fieldset name="Options">
<field
type="text"
name="motitle"
id="motitle"
label="Title"
description="MY TEXT FIELD DESCRIPTION"
maxLength="255" />
<field
type="textarea"
name="modescription"
id="modescription"
label="Description"
description="MY TEXT FIELD DESCRIPTION"
rows="15"
cols="5"
maxLength="255" />
</fieldset>
</fields>
</form>
Models\item.php
jimport('joomla.application.component.modelitem');
class MagicObjectsModelItem extends JModelForm {
public function getForm($data = array(), $loadData = true) {
// Get the form 'items'
$form = $this->loadForm('com_magicobjects.item', 'item',
array('control' => 'jform', 'load_data' => $loadData));
if (empty($form)) {
return false;
}
return $form;
}
protected function loadFormData() {
// Check the session for previously entered form data.
$data = JFactory::getApplication()->getUserState('com_magicobjects.item.edit.data', array());
if (empty($data)) {
$data = $this->getDBItem(1);
}
return $data;
}
public function getDBItem($pk) {
//Obtain JDatabase static connection
$oDb = JFactory::getDbo();
$oQuery = $oDb->getQuery(true);
$sValueToMatch = $pk;
$oQuery
->select(array('mid', 'name', 'keyword', 'description'))
->from('#__mytable')
->where('mid = "' . $sValueToMatch . '"')
->order('mid ASC');
$oDb->setQuery($oQuery);
return $oDb->loadObjectList();
}
views\item\view.html.php
jimport('joomla.application.component.view');
function display($tpl = null) {
// Initialise variables.
$this->form = $this->get('Form');
$this->item = $this->get('Item');
//Display the view
parent::display($tpl);
}
Views\item\tmpl\default.php
foreach ($this->form->getFieldset('Options') as $field) {
echo $field->label;
echo $field->input;
}
By performing a print_r() on item I can see I have the data, but I need to insert the data into the fields shown.
In case this it's still a problem because the form definition is defining a <fields /> group.
This mean that the form fields will be output as follows:
input type="text" name="[groupOPTIONS][motitle]"
based on the example you give above. If you remove the fields grouping it will probably work. It's annoying though as certain JForm methods only work on groups...
You would probably need to change the way in which the data was being passed into the form if you wanted to keep the fields grouping (e.g. by overloading getItem).
Hope that makes sense...
In Joomla 3, the JForm::bind() method appears to accept either an object or associative array as a parameter. All of the object/array fields are then stored in a protected JRegistry type data member called JForm::$data.
When you're trying to display a form field (by calling JForm::getInput()), the call stack is as follows
JForm::getInput() -> JForm::getField() -> JForm::loadField() -> JForm::getValue()
JForm::getValue() returns a value from the (aforementioned JRegistry) JForm::$data data member. The JForm::loadField() method also passes the default value (defined by the form) to the JForm::getValue() method in case a value in the JForm::$data variable doesn't exist.
In terms of doing this inside a model, you might want to generate a object or assoc array from a database query or table (ensuring that the field names correspond with the field names defined in the form xml) and then pass it to JForm::bind() as a parameter. However, if you are using JModelForm, I think you should only override JModelForm::loadFormData() to pass the object/assoc array to the loaded form.
See : libraries/joomla/form/form.php
Hope that helps :)
Instead of $oDb->loadObjectList(); use $oDb->loadAssoc(); in your getDBItem() function.
Check this - http://docs.joomla.org/Accessing_the_database_using_JDatabase/1.5
Check this also - joomla loadformdata
Hope this will work.
Making a simple component. If I save a new record with the box checked, it saves fine. If I go back and uncheck a previously checked item it reverts back to checked. I thought it had something to do with a hidden field, played with putting one of those in manually but that didn't fix it either so took it out.
Here's where I'm at:
An xml snippet:
<fieldset name="checks">
<field name="checkbox1"
type="checkbox"
label="First Checkbox"
value="1"
filter="intval"
/>
<field name="checkbox2"
type="checkbox"
label="Second Checkbox"
value="1"
filter="intval"
/>
...
</fieldset>
The edit.php file:
<div class="width-45 fltlft">
<fieldset class="adminform">
<legend>Checkboxes</legend>
<ul class="adminformlist">
<?php foreach ($this->form->getFieldset('checks') as $field): ?>
<li>
<?php echo $field->label; ?>
<?php echo $field->input; ?>
</li>
<?php endforeach ?>
</ul>
</fieldset>
</div>
Also added this towards the end before the form.token:
<input type="hidden" name="task" id="task" value="completion.edit" />
I tried deleting the value="1" in the xml but then I had the opposite problem where the check wouldn't save at all.
Any ideas?
Thanks!
=============================
Edit:
Model:
<?php
defined( '_JEXEC' ) or die;
jimport('joomla.application.component.modeladmin');
class AssessModelCompletion extends JModelAdmin
{
//tells it what kind of record and the prefix
public function getTable($type = 'Completion', $prefix = 'AssessTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
//Load the data into the edit form
protected function loadFormData()
{
$data = JFactory::getApplication()->getUserState('com_assess.edit.completion.data', array()); //first try to get the data from the session, not db
if (empty($data)) {
$data = $this->getItem(); //this gets the data
}
return $data;
}
//Stores data in a session in case a field is missed
public function getForm($data = array(), $loadData = true)
{
$form = $this->loadForm('com_assess.completion', 'completion', array('control' => 'jform', 'load_data' => $loadData));
return $form;
}
}
And table:
<?php
defined ( '_JEXEC' ) or die;
class AssessTableCompletion extends JTable
{
public function __construct(&$db)
{
parent::__construct('#__tablename_completions', 'completion_id', $db);
}
}
======================================
References:
https://stackoverflow.com/questions/6964333/joomla-1-6-admin-form-processing-grouped-checkboxes-in-form
Tutorial code is not working any more in Joomla 2.5
http://docs.joomla.org/Developing_a_Model-View-Controller_%28MVC%29_Component_for_Joomla!1.7_-_Part_09#Adding_a_toolbar
So this is a kind of odd situation in that the documentation you list makes it seem that you would have to write no code to handle the checkbox (because as you point out a checkbox is different then checkboxes). But this does not seem to be the case because of the way that html checkboxes are submitted.
A quick overview of this issue and one solution can be found here: http://planetozh.com/blog/2008/09/posting-unchecked-checkboxes-in-html-forms/.
To use this, you would need to get the field's name out of the $field variable (which I'm not sure if it will be easy to access) and then place the <input type=hidden name='name' value=0> before <?php echo $field->input; ?>.
The other method to fix this would be to process the form data during save and override elements. Joomla has a prepareTable function that you could add to your model to edit data as necessary during save. The following example assumes that your form elements are wrapped in a jform array. (Confirm this by looking at the name fields in the html generated and they should be 'jform[checkbox1]')
protected function prepareTable(&$table)
{
$jform = JRequest::getVar('jform'); // load all submitted data
if (!isset($jform['checkbox1'])) { // see if the checkbox has been submitted
$table->checkbox1 = 0; // if it has not been submitted, mark the field unchecked
}
if (!isset($jform['checkbox2'])) { // likewise for other checkboxes
$table->checkbox2 = 0;
}
}
In this case, you would want to keep "value=1" in your xml fields file.
The problem ultimately is that Joomla loads the current data from the database during saving and then binds the posted data over the top of it. Because an unchecked box is not submitted in the post data, it does not overwrite the databases information and is thus not saved.
Although the documentation states that you do not have to do any manual handeling of the checkbox this is not true.
As no value is sent in the $_POST array when a checkbox is not checked the value is not overwritten and thus not saved which makes it impossible to uncheck the checkbox. To fix this you have to write special handling for your checkboxes in your table bind() function like this:
class YourcomponentTableYourview extends JTable
{
/**
* Constructor
*
* #param JDatabase A database connector object
*/
public function __construct(&$db)
{
parent::__construct('#__your_table_name', 'id', $db);
}
public function bind($array, $ignore = '')
{
if (!isset($array['name_of_field']))
$array['name_of_field'] = 0 ;
return parent::bind($array, $ignore);
}
}
As you don't have any model/table code showing, I think you may be mistaking JForm's purpose - it is purely for rendering of the form. You still have to have in your model/table something to handle the array that is returned for multivalued fields.
As Sam Moffat put it:
there is no coupling between the form definitions used to render the data and the models and table structures used to persist them
So I had a lot of fields and wanted to simply loop through them in my edit.php field to keep it clean. While all the answers offered were right they weren't easy to implement - got really messy really quickly, had trouble getting it to work, or couldn't figure out a cleaner way around it. I chewed on this for awhile and then today came across what is basically a field override.
The key:
The standard form field types are located in
joomla/libraries/joomla/form/fields/. You should not store custom
fields there, nor should you have to use this path in your own code,
but the standard types are usually good examples.
The custom field types that belong to your component are usually
located in administrator/components//models/fields. You can specify this or another path in your
code
So, I copied checkbox.php to models/fields. Then, towards the end of the file I added the empty field before the checkbox tag:
<input type="hidden" name="'.$this->name.'" id="'.$this->id.'" value="0" /><input type="checkbox" .....
Now, whenever I need a checkbox the empty field is also written. May not be the most efficient solution but simple to implement and can hopefully help someone else.
[Edit]
As a note, with every Joomla update you would probably need to compare the versions in the core in case there was a change.
I know this is an old question, but the official answer is long winded and I think I have a better solution.
Try setting the default value for the checkbox to 0 rather than 1 in your xml like so:
<fieldset name="checks">
<field name="checkbox1"
type="checkbox"
label="First Checkbox"
value="0"
filter="intval"
/>
<field name="checkbox2"
type="checkbox"
label="Second Checkbox"
value="0"
filter="intval"
/>
...
</fieldset>
I just came across your question and tried setting it to 0 as I didn't want to tamper with the core and hey presto it works.
My guess is that Joomla sees no value and thus sets the default instead.