In this days Nick Savov started a discussion in the Joomla! Platform Development google group about improving the Joomla! override system. I really think that Joomla! has to improve the way that developers can override core or third components classes. But it's true that this is a debate concerning to Joomla! CMS, not to the Joomla! Platform.

What is an override?

Core and third part overrides allow you to replace/extend any component default models, views and controllers without having to edit the source file directly.

They are useful for example when you just need to add a functionallity to a already existent component but you don't want to lose that changes when component is updated or stopping the system to keep updateable.

Most times they are fast changes/patches that solve issues or doesn't worth to lose time (and money if you are a developer) with a better solution.

If you have already developed online stores with Magento or Prestashop you probably know the way that overrides work on that systems. You only need to copy a core file into an override folder to safely start hacking it.

Actually the best solution to override controllers, models or views in Joomla! is the Override Plugin developed by Julio Pontes. I've been trying to get some time to test it and finally got it this week.

How the plugin works?

The only documentation about the plugin seems to be at the Joomla! Documentation wiki. Just one page to explain how to override model, view and controller files? Yes, its enough!! Although I still miss better documentation.

The plugin uses almost the same override method than Magento or Prestashop:

  1. Copy the class to be overriden into a specific folder (you can see the override folder options in the Joomla! Documentation page).
  2. Edit the class in the override folder to extend the Default standard class.

You can also replace the original class instead of extending it but most times it's preferable to extend it. This way you only have to override the methods that you want to customize.

The test challenge

So why don't test the Override Plugin in a real challenge? :)

I've been some time trying to modify the K2 item model to allow its use externally (without being in the K2 component itself). Using the model to create items has some advantages:

  • Avoid SQL queries.
  • Plugins are applied into the item as when you create it from the k2 component.
  • Create items in about 10 lines of code.

We are going to face some problems in the default K2 item model:

  • It uses the JPATH_COMPONENT and JPATH_COMPONENT_ADMINISTRATOR constants to require files. When you call it from a different component all requires are broken.
  • The save method uses POST data to automatically receive the data from the K2 forms. You cannot use it as the content article save method that accepts a $data array as parameter. The controller should retrieve the POST data and the call the save method with the data as parameter.
  • Each item saved redirects you to the itemlist view. Save should return boolean. The controller should do the redirections.

Create the K2 item model override file

First of all we need to create the override file. As the model that we want to override is in the backend we are going to use the override folder:

administrator/code

We are going to copy the original K2 item model from:

administrator/components/com_k2/models/item.php

To:

administrator/code/com_k2/models/item.php

Patch and install the Override Plugin

In my tests the plugin was unable to recognize the original K2ModelItem class using the regular expressions method included. It showed me the error:

Fatal error: Class 'K2ModelItemDefault' not found in /var/www/joomla256/administrator/code/com_k2/models/item.php on line 18

I've patched it to use the PHP token_get_all function to parse and find original classes. I've sent a pull request on Github's project page but that version seems in development and does not work in Joomla 2.5.6.

Download the patched 2.5.4 plugin version

After installing the plugin go to the plugin management, activate it and set it to extend classes. Settings will be like:

mvc-settings

Customize the override file

Next step will be editing the override file to extend the original K2ModelItem. Find:

class K2ModelItem extends JModel
{

The original class definition extends JModel. The Override Plugin renames the original class from K2ModelItem to K2ModelItemDefault. Our override is going to extend that Default class. That will allow us to only modify/create needed methods.

Replace the class definition with:

class K2ModelItem extends K2ModelItemDefault
{

Now if we load K2 we will receive a warning about the use of component based constants:

Your override file use constants, please replace code constants
JPATH_COMPONENT -> JPATH_SOURCE_COMPONENT,
JPATH_COMPONENT_SITE -> JPATH_SOURCE_COMPONENT_SITE and
JPATH_COMPONENT_ADMINISTRATOR -> JPATH_SOURCE_COMPONENT_ADMINISTRATOR

The plugin suggest us to replace the component based constants with the replacement constants that it defines. But as we want to use the model from outside the k2 component we are going to use different constant replacements. Every model should use this kind of constants to allow its use externally.

Find and replace the following constants with the value after "->":

JPATH_COMPONENT -> JPATH_ADMINISTRATOR . '/components/com_k2'
JPATH_COMPONENT_SITE -> JPATH_SITE . '/components/com_k2'
JPATH_COMPONENT_ADMINISTRATOR -> JPATH_ADMINISTRATOR . '/components/com_k2'

We are going to empty our extension class to start adding content from scratch.

So the current override content is:

<?php
// no direct access
defined('_JEXEC') or die('Restricted access');
JLoader::import('joomla.application.component.model');
JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_k2/tables');
class K2ModelItem extends K2ModelItemDefault
{
}

We finally have our override ready to start using it. Reload the K2 item administration and it should load normally.

- "Hey!! But this does nothing!!"

You are wrong. This already does the hard stuff. We have patched and installed the plugin, learned where to store overrides and how to extend the default classes avoiding errors.

Override test

Ok ok. We are going to do a small override test overriding the getData method. We will add a method in our override class like:

<?php
// no direct access
defined('_JEXEC') or die('Restricted access');
JLoader::import('joomla.application.component.model');
JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_k2/tables');
class K2ModelItem extends K2ModelItemDefault
{
	function getData()
	{
		$row = parent::getData();
		$row->title .= ' (override = ON)';
		return $row;
	}
}

Now if you edit any K2 item you will see that the string "(override = ON)" string is added to the title.

Overriden getData() method

 

Remember to delete the getData method after testing the override! :)

 

What's next

In the next article we will modify our K2 item model to create a method that saves items externally.

Feel free to comment any question.