Creating a form at backend for making entries to database
Files to create / update
update breed.xml /administrator/models/forms/breed.xml
create filemultiple.php /administrator/models/fields/filemultiple.php
update view.html.php /administrator/views/breed/view.html.php
update edit.php /administrator/views/breed/tmpl/edit.php
update en-GB.com_breed.ini /languages/administrator/en-GB/en-GB.com_breed.ini
File Details
/administrator/models/forms/breed.xml
<?xml version="1.0" encoding="utf-8"?>
<form>
<fieldset>
<field name="id" type="text" default="0" label="COM_BREED_FORM_LBL_BREED_ID"
readonly="true" class="readonly"
description="JGLOBAL_FIELD_ID_DESC" />
<field name="created_by" type="createdby" default=""
label="COM_BREED_FORM_LBL_BREED_CREATED_BY"
description="COM_BREED_FORM_DESC_BREED_CREATED_BY" />
<field name="breedname" type="text"
label="COM_BREED_FORM_LBL_BREED_BREEDNAME"
description="COM_BREED_FORM_DESC_BREED_BREEDNAME"
required="true" />
<field name="pic" type="FileMultiple"
label="COM_BREED_FORM_LBL_BREED_PIC"
description="COM_BREED_FORM_DESC_BREED_PIC"
upload_directory="breedpic"
max_size="10" />
<field name="breedcat" type="radio"
label="COM_BREED_FORM_LBL_BREED_BREEDCAT"
description="COM_BREED_FORM_DESC_BREED_BREEDCAT"
required="true"
option_on="Yes"
option_off="Yes">
<option value="hybrids">Hybrids</option>
<option value="purebreeds">Pure Breeds</option>
</field>
<field name="filter_breedcat" type="list" onchange="this.form.submit();">
<option value="">COM_BREED_BREEDS_BREEDCAT_FILTER</option>
<option value="HYBRIDS">Hybrids</option>
<option value="PUREBREEDS">Pure Breeds</option>
</field>
<field name="shortdesc" type="textarea"
label="COM_BREED_FORM_LBL_BREED_SHORTDESC"
description="COM_BREED_FORM_DESC_BREED_SHORTDESC"
required="true"
width="400"
height="100"
cols="155"
rows="4"
option_on="Yes"
option_off="Yes" />
<field name="desc" type="editor"
label="COM_BREED_FORM_LBL_BREED_DESC"
description="COM_BREED_FORM_DESC_BREED_DESC"
required="true"
menu_published="0"
width="500"
height="400"
filter="safehtml"
directory_stripext="true"
directory_hidenode="true"
directory_hidedefault="true"
alias_generator="2195442"
heading="h4"
close="true"
option_on="Yes"
option_off="Yes" />
<field
name="state"
type="list"
label="JSTATUS"
description="JFIELD_PUBLISHED_DESC"
class="inputbox"
size="1"
default="1">
<option value="1">JPUBLISHED</option>
<option value="0">JUNPUBLISHED</option>
<option value="2">JARCHIVED</option>
<option value="-2">JTRASHED</option>
</field>
<field name="checked_out" type="hidden" filter="unset" />
<field name="checked_out_time" type="hidden" filter="unset" />
</fieldset>
<fieldset
name="accesscontrol">
<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_breed"
section="breed"
/>
</fieldset>
</form>
This is an xml file with form element at root and then there is a nested fieldset element. Fieldset elements could be more than one, but currently in our case, it is one. We are starting up with an id field. Every field would have a name and type, which will uniquely identify it. So, in this form you will notice hidden elements, text elements, lists, radio button etc. After that there would be label and description for every form element. If the element type is not “hidden”, the label will be displayed right before it and description will be displayed, when you mouse over the label. Then there are other parameters like size, default and class and are doing the same as their nmae propose. Elements could also be marked as required. JForm ensures that a value must be set for that element, which is marked as required.
The next field is the “access” field which is given a type of “accesslevel”. This will give us a list of the viewing access levels that are defined in the user manager.
/administrator/views/breed/view.html.php
<?php
// No direct access
defined('_JEXEC') or die;
jimport('joomla.application.component.view');
class BreedViewBreed extends JViewLegacy
{
protected $state;
protected $item;
protected $form;
public function display($tpl = null)
{
$this->state = $this->get('State');
$this->item = $this->get('Item');
$this->form = $this->get('Form');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
throw new Exception(implode("\n", $errors));
}
$this->addToolbar();
parent::display($tpl);
}
protected function addToolbar()
{
JFactory::getApplication()->input->set('hidemainmenu', true);
$user = JFactory::getUser();
$isNew = ($this->item->id == 0);
if (isset($this->item->checked_out))
{
$checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id'));
}
else
{
$checkedOut = false;
}
$canDo = BreedHelper::getActions();
JToolBarHelper::title(JText::_('COM_BREED_TITLE_BREED'), 'breed.png');
// If not checked out, can save the item.
if (!$checkedOut && ($canDo->get('core.edit') || ($canDo->get('core.create'))))
{
JToolBarHelper::apply('breed.apply', 'JTOOLBAR_APPLY');
JToolBarHelper::save('breed.save', 'JTOOLBAR_SAVE');
}
if (!$checkedOut && ($canDo->get('core.create')))
{
JToolBarHelper::custom('breed.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false);
}
if (!$isNew && $canDo->get('core.create'))
{
JToolBarHelper::custom('breed.save2copy', 'save-copy.png', 'save-copy_f2.png', 'JTOOLBAR_SAVE_AS_COPY', false);
}
if (empty($this->item->id))
{
JToolBarHelper::cancel('breed.cancel', 'JTOOLBAR_CANCEL');
}
else
{
JToolBarHelper::cancel('breed.cancel', 'JTOOLBAR_CLOSE');
}
}
}
This is the actual view which will hold the form. In this view.html.php file like other views, first there is a view class in which lot of things are happening. On line 21, we are getting an item from the model. We already have a breed model in place, so we are getting it from there. Next there is exception handling and after that there is a call to addtoolbar method, which will add the toolbar to the form view. In the toolbar method, we have function calls to JToolBarHelper for Apply, Save and Close, Save and New, Save and Copy, Cancel respectively.
On line 22, we are adding a form to the view, by getting a form from the model and sending it to the view. We are assigning this form value to the $form property, we have declared on line 16. Next step is to add that form to layout.
In the toolbar method, the first line at 38, we are trying to hide the main menu, by passing a variable in the request,name as “hidemainmenu”. The main drop down menu in the backend is a module and through “hidemainmenu” it could be disabled. set(‘hidemainmenu’, true) works like we have included this variable in the url and as component code runs first, it provides information to template, to hide a module, otherwise which it is going to display.
Next we take some measures to see which toolbar buttons we can display. Ee add the “apply”, “save” and “save-to-new” buttons, if the record is not checked out, and the user has the “core.edit” permission. Now, if the record already exists, and the user has the “core.create” permission we add the “save-to-copy” button. After that, we add a cancel button to toolbar and if we are editing an existing record, we change the label from “cancel” to “close”.
/administrator/views/breed/tmpl/edit.php
<?php
// No direct access
defined('_JEXEC') or die;
JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
JHtml::_('behavior.tooltip');
JHtml::_('behavior.formvalidation');
JHtml::_('formbehavior.chosen', 'select');
JHtml::_('behavior.keepalive');
?>
<script type="text/javascript">
js = jQuery.noConflict();
js(document).ready(function () {
});
Joomla.submitbutton = function (task) {
if (task == 'breed.cancel') {
Joomla.submitform(task, document.getElementById('breed-form'));
}
else {
js = jQuery.noConflict();
if(js('#jform_pic').val() != ''){
js('#jform_pic_hidden').val(js('#jform_pic').val());
}
if (task != 'breed.cancel' && document.formvalidator.isValid(document.id('breed-form'))) {
Joomla.submitform(task, document.getElementById('breed-form'));
}
else {
alert('<?php echo $this->escape(JText::_('JGLOBAL_VALIDATION_FORM_FAILED')); ?>');
}
}
}
</script>
<form
action="<?php echo JRoute::_('index.php?option=com_breed&layout=edit&id=' . (int) $this->item->id); ?>"
method="post" enctype="multipart/form-data" name="adminForm" id="breed-form" class="form-validate">
<div class="form-horizontal">
<?php echo JHtml::_('bootstrap.startTabSet', 'myTab', array('active' => 'general')); ?>
<?php echo JHtml::_('bootstrap.addTab', 'myTab', 'general', JText::_('COM_BREED_TITLE_BREED', true)); ?>
<div class="row-fluid">
<div class="span10 form-horizontal">
<fieldset class="adminform">
<input type="hidden" name="jform[id]" value="<?php echo $this->item->id; ?>" />
<input type="hidden" name="jform[ordering]" value="<?php echo $this->item->ordering; ?>" />
<input type="hidden" name="jform[state]" value="<?php echo $this->item->state; ?>" />
<input type="hidden" name="jform[checked_out]" value="<?php echo $this->item->checked_out; ?>" />
<input type="hidden" name="jform[checked_out_time]" value="<?php echo $this->item->checked_out_time; ?>" />
<?php if(empty($this->item->created_by)){ ?>
<input type="hidden" name="jform[created_by]" value="<?php echo JFactory::getUser()->id; ?>" />
<?php }
else{ ?>
<input type="hidden" name="jform[created_by]" value="<?php echo $this->item->created_by; ?>" />
<?php } ?> <div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('breedname'); ?></div>
<div class="controls"><?php echo $this->form->getInput('breedname'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('pic'); ?></div>
<div class="controls"><?php echo $this->form->getInput('pic'); ?></div>
</div>
<?php if (!empty($this->item->pic)) : ?>
<?php foreach ((array)$this->item->pic as $fileSingle) : ?>
<?php if (!is_array($fileSingle)) : ?>
<a href="/nomi/<?php echo JRoute::_(JUri::root() . 'components/com_breed/breedpic' . DIRECTORY_SEPARATOR . $fileSingle, false);?>"><?php echo $fileSingle; ?></a> |
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
<input type="hidden" name="jform[pic][]" id="jform_pic_hidden" value="<?php echo implode(',', (array)$this->item->pic); ?>" /> <div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('breedcat'); ?></div>
<div class="controls"><?php echo $this->form->getInput('breedcat'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('shortdesc'); ?></div>
<div class="controls"><?php echo $this->form->getInput('shortdesc'); ?></div>
</div>
<div class="control-group">
<div class="control-label"><?php echo $this->form->getLabel('desc'); ?></div>
<div class="controls"><?php echo $this->form->getInput('desc'); ?></div>
</div>
</fieldset>
</div>
</div>
<?php echo JHtml::_('bootstrap.endTab'); ?>
<?php if (JFactory::getUser()->authorise('core.admin','breed')) : ?>
<?php echo JHtml::_('bootstrap.addTab', 'myTab', 'permissions', JText::_('JGLOBAL_ACTION_PERMISSIONS_LABEL', true)); ?>
<?php echo $this->form->getInput('rules'); ?>
<?php echo JHtml::_('bootstrap.endTab'); ?>
<?php endif; ?>
<?php echo JHtml::_('bootstrap.endTabSet'); ?>
<input type="hidden" name="task" value=""/>
<?php echo JHtml::_('form.token'); ?>
</div>
</form>
Instead of default.php, this file is edit.php and the reason for this is, joomla is using this mechanism as a way of securing this view against unauthorized access to add or edit records.
In this file we have a form, starting from line 40 which is posting back to breed component and we also have a breed item id, embedded into the form which tells joomla that we are dealing with this specific record.
To load three core behaviours, we are using JHtml class here, which will enable us to display tooltips, second will validate the html form and the third will keep the form alove, when we are performing edits to it.
After that, there is a javascript code block which will be triggered when we try to save the page. Joomla maintains a healthy javascript framework architecture and the word “Joomla” in the CMS specific javascript is a master javascript object and in our this code block, we are attaching the “submitbutton” action to it. If the user just wants to cancel the form, the javascript will just submit the form by passing task and the form ID, without taking into account, any form field. And if this is not the case, the form will be valideted first and if all seemed ok, it will be submitted properly. If Joomla found any validation issues, it will show back the issues to the user and form will not be submitted. Joomla picks up the validation rules from the XML file, which we have written before, in this step.
Next, our main html form starts. The edit page url is passed to the action attribute of the form with the id of the record, which is always unique. Its name would be “adminform” and the method should be post. We have given “form-validate” as the class name of the form which will tell the javascript to validate this form.
In the form body, we are using the normal HTML markup structure to create a proper layout and for rendering form elements we are taking help of the Joomla API and loading the form fields and their labels through “getInput” and “getLabel” method by just simply passing the name of the field, that we want to display. We are enclosing our form fields here in proper fieldset tags. At the end of the form, just before the form closing tag, we have added the “task”hidden field, which value will be determined by javascript on the basis of which action user wants to perform and after this we have added a form token through JHtml Helper which ensures that the actual user is submitting the form and not a script. This will protect the form protect against cross site request forgery attacks.
/administrator/models/fields/filemultiple.php
<?php
defined('JPATH_BASE') or die;
jimport('joomla.form.formfield');
class JFormFieldFileMultiple extends JFormField
{
protected $type = 'file';
protected function getInput()
{
$html = '<input type="file" name="' . $this->name . '[]" multiple>';
return $html;
}
}
It is the beauty of Joomla JFormField that you can create any form field type and add it to your Joomla extension, by just extending JFormField base class and providing appropriate field type. In our case here, we are trying to create a multiple select field, through which multiple images could be uploaded. In this file, first we have imported the formfield library and then have created the class “JFormFieldFileMultiple” extending JFormField. In the getInput method, we have declared a multiple form field and passed it to $html variable, which will be returned back. Note that the name of the field is dynamic, as it will be picked from the form XML file, through JFormField class.
/languages/administrator/en-GB/en-GB.com_breed.ini
COM_BREED_TITLE_BREEDS="Breeds"
COM_BREED_TITLE_BREED="Breed"
COM_BREED_FORM_LBL_BREED_BREEDNAME=" Breed Name"
COM_BREED_FORM_DESC_BREED_BREEDNAME=""
COM_BREED_FORM_LBL_BREED_PIC="Pic"
COM_BREED_FORM_DESC_BREED_PIC=""
COM_BREED_FORM_LBL_BREED_BREEDCAT="Breed Category"
COM_BREED_FORM_DESC_BREED_BREEDCAT=""
COM_BREED_FORM_LBL_BREED_SHORTDESC="Short Description"
COM_BREED_FORM_DESC_BREED_SHORTDESC=""
COM_BREED_FORM_LBL_BREED_DESC="Description"
COM_BREED_FORM_DESC_BREED_DESC=""
These are the updates that have to be made to the language file, on the basis of the material we have added to the edit form.