Archived

Developing a MVC Component/Adding verifications

From Joomla! Documentation

< Archived:Developing a MVC Component

This page has been archived. This page contains information for an unsupported Joomla! version or is no longer relevant. It exists only as a historical reference, it will not be improved and its content may be incomplete and/or contain broken links.

Documentation all together tranparent small.png
Under Construction

This article or section is in the process of an expansion or major restructuring. You are welcome to assist in its construction by editing it as well. If this article or section has not been edited in several days, please remove this template.
This article was last edited by Cdemko (talk| contribs) 14 years ago. (Purge)

Template:Future

Articles in this series[edit]

Indroduction[edit]

This tutorial is part of the Developing a Model-View-Controller (MVC) Component for Joomla!1.6 tutorial. You are encouraged to read the previous parts of the tutorial before reading this.

Preventing CSRF attacks[edit]

A way to prevent CSRF attacks is to use tokens in the forms. Joomla!1.6 provides a function to generate tokens and function to check them.

In the admin/views/helloworldlist/tmpl/default.php file put these lines

admin/views/helloworldlist/tmpl/default.php

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted Access');
// load tooltip behavior
JHtml::_('behavior.tooltip');
?>
<form action="<?php echo JRoute::_('index.php?option=com_helloworld'); ?>" method="post" name="adminForm">
	<table class="adminlist">
		<thead><?php echo $this->loadTemplate('head');?></thead>
		<tfoot><?php echo $this->loadTemplate('foot');?></tfoot>
		<tbody><?php echo $this->loadTemplate('body');?></tbody>
	</table>
	<input type="hidden" name="task" value="" />
	<input type="hidden" name="boxchecked" value="0" />
	<?php echo JHtml::_('form.token'); ?>
</form>

The echo JHtml::_('form.token'); generates the token.

Rename the admin/views/helloworld/tmpl/default.php file into admin/views/helloworld/tmpl/edit.php (because we will use a JControllerForm inherited class) and put these lines

admin/views/helloworld/tmpl/edit.php

<?php
// No direct access
defined('_JEXEC') or die('Restricted access');
JHTML::_('behavior.tooltip');
JHTML::_('behavior.formvalidation');
?>
<form action="<?php echo JRoute::_('index.php?option=com_helloworld'); ?>" method="post" name="adminForm" id="adminForm" class="form-validate">
	<fieldset class="adminform">
		<legend><?php echo JText::_( 'com_helloworld_HelloWorld_Details' ); ?></legend>
		<?php foreach($this->form->getFields() as $field): ?>
			<?php if (!$field->hidden): ?>
				<?php echo $field->label; ?>

			<?php endif; ?>
			<?php echo $field->input; ?>

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

Tokens are now generated in the forms. They have to be verified in the controllers.

In the admin/controllers/helloworldlist.php file put these lines

admin/controllers/helloworldlist.php

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla controller library
jimport('joomla.application.component.controller');
/**
 * HelloWorldList Controller
 */
class HelloWorldControllerHelloWorldList extends HelloWorldController
{
	/**
	 * remove record(s)
	 * @return void
	 */
	function remove() 
	{
		JRequest::checkToken() or jexit(JText::_('JInvalid_Token'));
		$model = $this->getModel('HelloWorldList');
		if ($model->remove()) 
		{
			$msg = JText::_('com_helloworld_HelloWorldList_Greetings_removed');
			$type = 'message';
		}
		else
		{
			$msg = JText::sprintf('com_helloworld_HelloWorldList_One_or_more_greetings_could_not_be_deleted', implode("<br />", $model->getErrors()));
			$type = 'error';
		}
		$this->setRedirect('index.php?option=com_helloworld', $msg, $type);
	}
}

The JRequest::checkToken call verifies the generated token.

For the other controller, there is now in Joomla!1.6 a 'JControllerForm class. It is used for managing (editing, saving, ...) item.

In the admin/controllers/helloworld.php file put these lines

admin/controllers/helloworld.php

<?php
/**
 * @version    $Id: helloworld.php 28 2009-11-13 14:47:57Z chdemko $
 * @package    Joomla16.Tutorials
 * @subpackage Components
 * @copyright  Copyright (C) 2005 - 2009 Open Source Matters, Inc. All rights reserved.
 * @author     Christophe Demko
 * @link       http://joomlacode.org/gf/project/helloworld_1_6/
 * @license    GNU/GPL
 */
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla controllerform library
jimport('joomla.application.component.controllerform');
/**
 * HelloWorld Controller
 */
class HelloWorldControllerHelloWorld extends JControllerForm
{
	function __construct ($config=array())
	{
		parent::__construct($config);
		jimport('joomla.form.formvalidator');
		JFormValidator::addRulePath(JPATH_COMPONENT . DS . 'models' . DS . 'rules');
	}
	protected $_view_list = 'HelloWorldList';
}

Verifying the form (client side)[edit]

Forms can be verified on the client side using javascript code. You may have noted that the html form contained in the admin/views/helloworld/edit.php file now has the form-validate class. And that we added a JHTML::_('behavior.formvalidation'); call to tell Joomla!1.6 to use its javascript form validation.

Modify the admin/models/forms/helloworld.xml file to indicate that the greeting field has to be verified:

<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields>
		<field
			id="id"
			name="id"
			type="hidden"
		/>
		<field
			id="greeting"
			name="greeting"
			type="text"
			size="40"
			class="inputbox validate-greeting"
			validate="greeting"
			required="true"
			default=""
			label="com_helloworld_HelloWorld_Greeting"
			description="com_helloworld_HelloWorld_Greeting_Desc"
		/>
	</fields>
</form>

Note for the moment that the css class is now "inputbox validate-greeting" and that the attribute required is set to true. It means that this field is required and has to be verified by an handler of the form validator framework of Joomla

With your favorite file manager and editor put a file admin/models/forms/helloworld.js containing

admin/models/forms/helloworld.js

window.addEvent('domready', function() {
	document.formvalidator.setHandler('greeting',
		function (value) {
			regex=/^[^0-9]+$/;
			return regex.test(value);
	});
});

It adds an handler to the form validator of Joomla for fields having the "validate-greeting" css class. Each time a field the greeting field is modified, the handler will be executed to verify its validaty (no digits).

The final step is to verify the form when the save button is clicked.

With your favorite file manager and editor put a file admin/views/helloworld/submitbutton.js containing

admin/views/helloworld/submitbutton.js

function submitbutton(task)
{
	if (task == '')
	{
		return false;
	}
	else
	{
		var isValid=true;
		if (task != 'helloworld.cancel' && task != 'helloworld.close')
		{
			var forms = $$('form.form-validate');
			for (var i=0;i<forms.length;i++)
			{
				if (!document.formvalidator.isValid(forms[i]))
				{
					isValid = false;
					break;
				}
			}
		}
	
		if (isValid)
		{
			submitform(task);
			return true;
		}
		else
		{
			alert(Joomla.JText._('com_helloworld_HelloWorld_Error_Some_Values_Are_Unacceptable','Some values are unacceptable'));
			return false;
		}
	}
}

This function will verify that all forms which have the "form-validate" css class are valid. Note that it will display an alert message translated by the Joomla!1.6 framework.

The HelloWorldViewHelloWorld view class has to be modified to use these javascript files:

admin/views/helloworld/view.html.php

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla view library
jimport('joomla.application.component.view');
/**
 * HelloWorld View
 */
class HelloWorldViewHelloWorld extends JView
{
	/**
	 * View form
	 *
	 * @var		form
	 */
	protected $form = null;
	/**
	 * View script
	 */
	protected $script = null;
	/**
	 * display method of Hello view
	 * @return void
	 */
	public function display($tpl = null) 
	{
		// get the Form
		$form = & $this->get('Form');
		// get the Data
		$data = & $this->get('Data');
		// get the script
		$script = & $this->get('Script');
		// Check for errors
		if (count($errors = $this->get('Errors'))) 
		{
			JError::raiseError(500, implode("<br />", $errors));
			return;
		}
		// Bind the Data
		$form->bind($data);
		// Assign the form
		$this->form = $form;
		// Assign the script
		$this->script = $script;
		// Set the toolbar
		$this->_setToolBar();
		// Display the template
		parent::display($tpl);
		// Set the document
		$this->_setDocument();
	}
	/**
	 * Setting the toolbar
	 */
	protected function _setToolBar() 
	{
		JRequest::setVar('hidemainmenu', 1);
		$isNew = ($this->form->getValue('id') < 1);
		JToolBarHelper::title(JText::_('com_helloworld_Manager') . ': <small><small>[ ' . ($isNew ? JText::_('JToolBar_New') : JText::_('JToolBar_Edit')) . ' ]</small></small>', 'helloworld');
		JToolBarHelper::save('helloworld.save');
		JToolBarHelper::cancel('helloworld.cancel', $isNew ? 'JToolBar_Cancel' : 'JToolBar_Close');
	}
	/**
	 * Method to set up the document properties
	 *
	 * @return void
	 */
	protected function _setDocument() 
	{
		$isNew = ($this->form->getValue('id') < 1);
		$document = &JFactory::getDocument();
		$document->setTitle(JText::_('com_helloworld_Administration') . ' - ' . ($isNew ? JText::_('com_helloworld_HelloWorld_Creating') : JText::_('com_helloworld_HelloWorld_Editing')));
		$document->addScript(JURI::root() . $this->script);
		$document->addScript(JURI::root() . 'administrator/components/com_helloworld/views/helloworld/submitbutton.js');
		JText::script('com_helloworld_HelloWorld_Error_Some_Values_Are_Unacceptable');
	}
}

This view now

  • verifies if the model has no error;
  • adds two javascript files;
  • injects javascript translation using the Joomla!1.6 JText::script function.

The final step is to implement a getScript function in the HelloWorldModelHelloWorld model:

admin/models/helloworld.php

<?php
/**
 * @version    $Id: helloworld.php 27 2009-11-13 09:47:50Z chdemko $
 * @package    Joomla16.Tutorials
 * @subpackage Components
 * @copyright  Copyright (C) 2005 - 2009 Open Source Matters, Inc. All rights reserved.
 * @author     Christophe Demko
 * @link       http://joomlacode.org/gf/project/helloworld_1_6/
 * @license    GNU/GPL
 */
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla modelform library
jimport('joomla.application.component.modelform');
/**
 * HelloWorld Model
 */
class HelloWorldModelHelloWorld extends JModelForm
{
	/**
	 * @var array data
	 */
	protected $data = null;
	/**
	 * Method to auto-populate the model state.
	 */
	protected function _populateState()
	{
		$app = JFactory::getApplication('administrator');

		// Load the User state.
		if (!($pk = (int) $app->getUserState('com_helloworld.edit.helloworld.id'))) {
			$pk = (int) JRequest::getInt('id');
		}
		$this->setState('helloworld.id', $pk);
	}
	/**
	 * Method to get the data.
	 *
	 * @access	public
	 * @return	array of string
	 * @since	1.0
	 */
	public function &getData() 
	{
		if (empty($this->data)) 
		{
			$app = & JFactory::getApplication();
			$data = & JRequest::getVar('jform');
			if (empty($data)) 
			{
				$selected = $this->getState('helloworld.id');
				$query = new JQuery;
				// Select all fields from the hello table.
				$query->select('*');
				$query->from('`#__helloworld`');
				$query->where('id = ' . (int)$selected);
				$this->_db->setQuery((string)$query);
				$data = & $this->_db->loadAssoc();
			}
			if (empty($data)) 
			{
				// Check the session for previously entered form data.
				$data = $app->getUserState('com_helloworld.edit.helloworld.data', array());
				unset($data['id']);
			}
			$app->setUserState('com_helloworld.edit.helloworld.data', $data);
			$this->data = $data;
		}
		return $this->data;
	}
	/**
	 * Method to get the HelloWorld form.
	 *
	 * @access	public
	 * @return	mixed	JForm object on success, false on failure.
	 * @since	1.0
	 */
	public function &getForm() 
	{
		$form = & parent::getForm('helloworld', 'form', array('array' => 'jform') , false);
		return $form;
	}
	/**
	 * Method to get the javascript attached to the form
	 *
	 * @return string URL to the script.
	 */
	function getScript() 
	{
		return 'administrator/components/com_helloworld/models/forms/helloworld.js';
	}
	/**
	 * Method to save a record
	 *
	 * @param array $data array of data
	 * @access	public
	 * @return	boolean	True on success
	 */
	function save($data) 
	{
		// Database processing
		$row = & $this->getTable();
		// Bind the form fields to the hello table
		if (!$row->save($data)) 
		{
			$this->setError($row->getErrorMsg());
			return false;
		}
		return true;
	}
}

Verifying the form (server side)[edit]

Verifying the form on the server side is done by inheritance of JControllerForm class. We have specified in the admin/models/forms/helloworld.xml file that the validate server function will used a greeting.php file. With the JFormValidator::addRulePath(JPATH_COMPONENT . DS . 'models' . DS . 'rules'); line in the admin/controllers/helloworld.php, we specify that this file can be found by the form validator in the rules folder.

With your favorite file manager and editor, put a admin/models/rules/greeting.php file containing:

admin/models/rules/greeting.php

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla formrule library
jimport('joomla.form.formrule');
/**
 * Form Rule class for the Joomla Framework.
 */
class JFormRuleGreeting extends JFormRule
{
	/**
	 * The regular expression.
	 *
	 * @access	protected
	 * @var		string
	 * @since	1.6
	 */
	protected $_regex = '^[^0-9]+$';
}

Packaging the component[edit]

Content of your code directory

Create a compressed file of this directory or directly download the archive and install it using the extension manager of Joomla!1.6. You can add a menu item of this component using the menu manager in the backend.

helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="1.6.0" method="upgrade">
	<name>Hello World!</name>
	<creationDate>November 2009</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>
	<version>0.0.11</version>
	<description>com_helloworld_Description</description>

	<install> <!-- Runs on install -->
		<sql>
			<file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
		</sql>
	</install>
	<uninstall> <!-- Runs on uninstall -->
		<sql>
			<file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
		</sql>
	</uninstall>
	<update> <!-- Runs on update -->
		<sql>
			<file driver="mysql" charset="utf8">sql/update.mysql.utf8.sql</file>
		</sql>
	</update>

	<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>
	</media>
	
	<administration>
		<menu img="../media/com_helloworld/images/tux-16x16.png">Hello World!</menu>
		<files folder="admin">
			<filename>index.html</filename>
			<filename>helloworld.php</filename>
			<filename>controller.php</filename>
			<folder>sql</folder>
			<folder>tables</folder>
			<folder>models</folder>
			<folder>views</folder>
			<folder>controllers</folder>
		</files>		
		<languages folder="admin">
			<language tag="en-GB">language/en-GB/en-GB.com_helloworld.ini</language>
			<language tag="en-GB">language/en-GB/en-GB.com_helloworld.menu.ini</language>
		</languages>
	</administration>
</extension>

Contributors[edit]