Setting action tabs at frontend of Joomla 3.x component

In this step of Joomla extension development tutorial, we are going to create edit and delete functionality for frontend records so that user would be able to edit or delete a record that he has created.

Files to create / update

create: breedform.php   /site/controllers/breedform.php

create: breed.php   /site/helpers/breed.php

create: breedform.php   /site/models/breedform.php

update: default.php   /site/views/breeds/tmpl/default.php

update: en-GB.com_breed.ini   /languages/site/en-GB/en-GB.com_breed.ini

File Details

/site/controllers/breedform.php 

<?php

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

require_once JPATH_COMPONENT . '/controller.php';


class BreedControllerBreedForm extends BreedController
{

	public function edit()
	{
		$app = JFactory::getApplication();

		// Get the previous edit id (if any) and the current edit id.
		$previousId = (int) $app->getUserState('com_breed.edit.breed.id');
		$editId     = $app->input->getInt('id', 0);

		$app->setUserState('com_breed.edit.breed.id', $editId);

		$model = $this->getModel('BreedForm', 'BreedModel');

		// Check out the item
		if ($editId)
		{
			$model->checkout($editId);
		}

		if ($previousId)
		{
			$model->checkin($previousId);
		}

		$this->setRedirect(JRoute::_('index.php?option=com_breed&view=breedform&layout=edit', false));
	}

In this step, first we have created a new controller file, called breedform.php in the controller folder. This controller will be processing our edit or delete requests and will also handle the form that we will create in the next steps of this tutorial.

So, in this file, we have created a class named, “BreedControllerBreedForm” which is extending our base controller.In this class, our first method is, edit() which purpose is to handle the edit requests coming from breeds listing page. First we have created an $app object as we have done in previous several steps. On line 17, we are getting the id of the record through getUserState() method and this would be the id of the record that is previously stored in Joomla user state object. Next on line 18, we are trying to get a fresh id of the record that user wants to edit and assigning its value to $editId. After this on line 20, we are updating the user state through a fresh id we are getting from $editId and then we are getting the BreedForm model. What we have done till yet here in this file is just getting and setting but our major work in this method will start from here.

On line 25, we are checking that whether a fresh record id exists, and if it does, model will checkout the record first and the userstate will also be updated with this id and if the userstate already holds a record id, the record will be checked in and the user will be redirected to the edit page through setRedirect method. The checkin process is necessary as it indicates other users, specially administrators of the site, that this specific user is editing the record. 

	public function remove()
	{
		// Initialise variables.
		$app   = JFactory::getApplication();
		$model = $this->getModel('BreedForm', 'BreedModel');

		$data       = array();
		$data['id'] = $app->input->getInt('id');


		if (empty($data['id']))
		{
			// Get the validation messages.
			$errors = $model->getErrors();

			for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++)
			{
				if ($errors[$i] instanceof Exception)
				{
					$app->enqueueMessage($errors[$i]->getMessage(), 'warning');
				}
				else
				{
					$app->enqueueMessage($errors[$i], 'warning');
				}
			}

			// Save the data in the session.
			$app->setUserState('com_breed.edit.breed.data', $data);

			$id = (int) $app->getUserState('com_breed.edit.breed.id');
			$this->setRedirect(JRoute::_('index.php?option=com_breed&view=breed&layout=edit&id=' . $id, false));
		}


		$return = $model->delete($data);

		// Check for errors.
		if ($return === false)
		{
			$app->setUserState('com_breed.edit.breed.data', $data);

			$id = (int) $app->getUserState('com_breed.edit.breed.id');
			$this->setMessage(JText::sprintf('Delete failed', $model->getError()), 'warning');
			$this->setRedirect(JRoute::_('index.php?option=com_breed&view=breed&layout=edit&id=' . $id, false));
		}

		// Check in the profile.
		if ($return)
		{
			$model->checkin($return);
		}

		$app->setUserState('com_breed.edit.breed.id', null);

		$this->setMessage(JText::_('COM_BREED_ITEM_DELETED_SUCCESSFULLY'));
		$menu = JFactory::getApplication()->getMenu();
		$item = $menu->getActive();
		$url  = (empty($item->link) ? 'index.php?option=com_breed&view=breeds' : $item->link);
		$this->setRedirect(JRoute::_($url, false));

		$app->setUserState('com_breed.edit.breed.data', null);
	}
	
}

Next we have create the remove() method and this is also very easy to understand, as edit method is. First we have initialized the $app variable to hold Joomla application object and then have called the BreedForm model. Then,we would require the id of the record, which the user wants to delete. So, online 46, we are first creating an array and after that, assigning the ID(s) of the records that we will receive from breeds listing page, when user will perform a delete operation and then assign it to the id key of the array. The reason why we are using array here is, user may select more than one record to delete at a time and array would be the thing that will hold the values of every record ids. 

Then from line 50 to 53, we are making a check that whether the ID(s) array is empty or not and if it is, Joomla system will throw an exception with appropriate error messages which will guide the user to the exact issue and also will redirect him to the same breeds listing page.

Now if the array hold some values, we are attempting to delete that records by calling by calling our models delete method and passing the array as an argument. IF for some reason model is unable to delete the records, it will return false and on basis of this, proper error message will be sent to user along with indicating that his operation was unsuccessful.

IF the delete operation is successful, a success message will be sent to user and it will be redirected to appropriate page but the success page could also be created separately and a redirection to that page could also be made easily by editing the $url variable on line 109.

 

/site/helpers/breed.php

<?php

defined('_JEXEC') or die;

class BreedFrontendHelper
{

	public static function getModel($name)
	{
		$model = null;

		if (file_exists(JPATH_SITE . '/components/com_breed/models/' . strtolower($name) . '.php'))
		{
			require_once JPATH_SITE . '/components/com_breed/models/' . strtolower($name) . '.php';
			$model = JModelLegacy::getInstance($name, 'BreedModel');
		}

		return $model;
	}
}

This helper class is pretty much straight forward as you can see that we are trying to create a method through which we can access the appropriate model and its functions by passing model name and method as arguments. In this helper file, first we have created a class named, BreedFrontendHelper and then have made a static method called getModel() which will try to get the name of the model as an argument. Next on line 10, we are flushing out the existing value of $model property  and then making a check that the model which the user tries to access in controller or view file, actually exists, by checking the existing of that model file in models folder. If it exists, we are picking that model through require_once and then immediately creating its instance on next line and after that we are returning this model property back. 

 

/site/models/breedform.php

<?php

// No direct access.
defined('_JEXEC') or die;

jimport('joomla.application.component.modelform');
jimport('joomla.event.dispatcher');

use Joomla\Utilities\ArrayHelper;

class BreedModelBreedForm extends JModelForm
{
	private $item = null;

	
	public function getTable($type = 'Breed', $prefix = 'BreedTable', $config = array())
	{
		$this->addTablePath(JPATH_ADMINISTRATOR . '/components/com_breed/tables');

		return JTable::getInstance($type, $prefix, $config);
	}


	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_breed.breed', 'breedform', array(
			'control'   => 'jform',
			'load_data' => $loadData
			)
		);

		if (empty($form))
		{
			return false;
		}

		return $form;
	}

The getTable() method is used to get a table object, so that Joomla could know that which table is associated with this model. In the arguments of this method, we are passing the name of table class, tbale class prefix and an optional configuration array. What we are doing in this method is, we are just allocating our table class file and returning back an instance of JTable class to the model.

On line 24, we are trying to get an instance of form object belonging to JForm class, through getForm method. We normally override the default getForm method if we want to customize the form in a way we want. In the supplied arguments, $data holds the form field values in the form of an array and $loadData represents whether or not the default form values should be loaded. In our case it is set to true. Then in this method, we are loading our required form, through loadForm() method and the supplied arguments are , path to the form, form name and the options array indicating which control should be used and whether the default values should be loaded or not and if yes, from which resource. Next there is a simple check that whether our function has returned a form in response or not, and if not operation will be terminated by returning false and if all is ok, we will return the $form back to the model for further processing. 

public function delete($data)
	{
		$id = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('breed.id');

		if (JFactory::getUser()->authorise('core.delete', 'com_breed.breed.' . $id) !== true)
		{
			throw new Exception(403, JText::_('JERROR_ALERTNOAUTHOR'));
		}

		$table = $this->getTable();

		if ($table->delete($data['id']) === true)
		{
			return $id;
		}
		else
		{
			return false;
		}
	}

 Then delete() is the method where we are actually deleting an item from the database. First we are getting the id of the record(s) to be deleted from $data array and if this vale is empty then we are trying to get the id from the getState() method. I have gone through in detail about what the getState() method is, how it works and why we use it. Then we are deleting the item on the basis of id, through $table->delete() method.

 

/site/views/breeds/tmpl/default.php

JHtml::addIncludePath(JPATH_COMPONENT . '/helpers/html');
JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.multiselect');
JHtml::_('formbehavior.chosen', 'select');

$user       = JFactory::getUser();
$userId     = $user->get('id');

We are including some Joomla jHtml behaviours here to call the javascript for the features like tooltip, multi select etc. Then we are trying to get the id of the loggedin user.

<?php
      echo JLayoutHelper::render('joomla.searchtools.default', array('view' => $this));
?>

Code for rendering search bar.

<td>
	<a href="/nomi/<?php echo JRoute::_('index.php?option=com_breed&view=breed&id='.(int) $item->id); ?>">
	<?php echo $this->escape($item->breedname); ?></a>
	</td>

Here we are rendering the name of the breed from the database, with its link to the detail page.

<td class="center">
 	<a href="/nomi/<?php echo JRoute::_('index.php?option=com_breed&task=breedform.edit&id=' . $item->id, false, 2); ?>" class="btn btn-mini" type="button"><i class="icon-edit" ></i></a>

					<button data-item-id="<?php echo $item->id; ?>" class="btn btn-mini delete-button" type="button"><i class="icon-trash" ></i></button>
					
					</td>

In this step, the first code snippet we have added in the breeds default.php file is, from 94 to 100, where we are displaying an anchor tag pointing to the edit page of that specific record. The addition is displaying a button for deleting a specific record. I have already discussed in detail how the edit and delete requests will be handled in model and controller associated to this specific view.

<script type="text/javascript">

	jQuery(document).ready(function () {
		jQuery('.delete-button').click(deleteItem);
	});

	function deleteItem() {
		var item_id = jQuery(this).attr('data-item-id');

		if (confirm("<?php echo JText::_('COM_BREED_DELETE_MESSAGE'); ?>")) {
			window.location.href = '<?php echo JRoute::_('index.php?option=com_breed&task=breedform.remove&id=', false, 2) ?>' + item_id;
		}

	}
</script>

The second addition is from line 123 to 137, which is indeed a Javascript code. The reason why we are writing this code is, we want a confirmation message popup, when someone try to delete a record, so that a record could not be deleted by an accidental click on the delete button. In the delete item function, first we are getting the id of the record, which the user is trying to delete. Then we send him a confirmation dialog and if he confirms, we send a delete request to the controller. Next we bind this function to the click event of delete button.

 

/languages/site/en-GB/en-GB.com_breed.ini

COM_BREED_BREEDS_ACTIONS="Actions"

COM_BREED_ADD_ITEM="Add Entry"

COM_BREED_ITEM_DELETED_SUCCESSFULLY="Item deleted successfully"

COM_BREED_DELETE_MESSAGE="Are you sure that you want delete this item?"

 We have to update the language file accordingly with respect to the additions that we made in this step.

Download Code

Add a Comment

Your email address will not be published. Required fields are marked *

Enjoy best web development services at an affordable price. Looking forward to build a good relationship and serve you better...

ABOUT CODINGACE

My name is Nohman Habib and I am a web developer with over 10 years of experience, programming in Joomla, Wordpress, WHMCS, vTiger and Hybrid Apps. My plan to start codingace.com is to share my experience and expertise with others. Here my basic area of focus is to post tutorials primarily on Joomla development, HTML5, CSS3 and PHP.

Nohman Habib

CEO: codingace.com

Request a Quote