I have been struggling with a problem with Joomla!, lately, and figured out a nifty solution I wanted to share and see if others had ideas. Joomla!'s standard Components, Modules, and Plugins just didn't fit the requirements of this Intranet application I am building. I created a very flexible architecture of Portals->Themes->Positions->Portlets->Layouts->Resources with nice customization on the frontend by users, the ability to create groups and share resources easily, and a standard data model and set of processing that is used for all content, whether it's images, or text, or private messages.

To output the Portlet Layouts, I created a series of classes that use "JDoc-like" statements in the Template to drive processing. The application collects resource requirements (JS, CSS) from the Template and Portlets during processing and combines/minifies the files at the end. I have my own head process where output is available via layouts and easier to adjust, as needed.

The problem I ended up having was that Joomla! was unaware of the Portlet processing since it only handles normal Modules, Components and Plugins. For that reason, some times, Joomla! would finish before all of the portlets were processed, and before the resources were combined and minified.

Today, I realized that what I needed was two new HTML Renderers, one for my position/portlet output, and the other for my head replacement. After some hacking around, I figured out a way to load a custom Renderer, and then use my own JDoc statements to get Joomla! to drive the Portlet and Head processes, just like it does with Modules, Components, and Plugins.

1. loadRenderer Function
I had to copy the loadRenderer Function from the JDocument class since the path was unfortunately hardcoded and I didn't want to add any files to the core libraries. This function can be added to any appropriate class. As you can see, my class is named TamkaDocumentHTML.

Note how I changed the path to my library location (I could have made that more flexible by passing in the folder location.) Also, it is important to note that the JDocumentRenderer.$type class must be followed.

class TamkaDocumentHTML
{
function __construct( ) {}
/**
* Load a renderer
*
* @access public
* @param string The renderer type
* @return object
* @since 1.5
*/
function loadRenderer( $type )
{
$null = null;
$class = 'JDocumentRenderer'.$type;

if( !class_exists( $class ) ) {
// $path = dirname(__FILE__).DS.$this->_type.DS.'renderer'.DS.$type.'.php';
$path = dirname(__FILE__).DS.'renderer'.DS.$type.'.php';
if(file_exists($path)) {
require_once($path);
} else {
JError::raiseError(500,JText::_('Unable to load renderer class'));
}
}
if ( !class_exists( $class ) ) {
return $null;
}
$instance = new $class($this);
return $instance;
}
}

2. Create the Renderers and place into the position specified, above.
Next, I created a Renderer for the production of the Position Portlets and also a Renderer for the Head Statement. The name of the class must be JDocumentRenderer + the value you will use as your JDoc Type statement. Also, the name of the Renderer file must be the same as the Type Value.
class JDocumentRendererTamkaPosition 
{
/**
* render
* @param object $module
* @param object $params [optional]
* @param object $content [optional]
* @return
*/
function render( $module, $params = array(), $content = null )
{
$_SESSION['TAMKA_RENDER_POSITION'] = '';
require_once TAMKA_CONSTANT_INCLUDE_THEMES.'position.php';
$tamkaPosition = new TamkaPosition($module);
return $_SESSION['TAMKA_RENDER_POSITION'];
}
}

The Header Renderer Class:
class JDocumentRendererTamkaHead 
{
public function render( $head, array $params = array(), $content = null ) {

/**
* Create Resource File Includes and possible minification
*/
require_once TAMKA_CONSTANT_INCLUDE_THEMES.'resources.php';
$tamkaResources = new TamkaResources();
$tamkaResources->addDocumentResources();

/**
* Create Head and begin outputting buffer
*/
ob_start();

echo $_SESSION['TAMKA_LAYOUT_OUTPUT_SITE_HEAD'].
$_SESSION['TAMKA_RESOURCES_DOCUMENT_HEAD_CSS'].
$_SESSION['TAMKA_RESOURCES_DOCUMENT_HEAD_JS'].
$_SESSION['TAMKA_RESOURCES_DOCUMENT_HEAD_JS_INLINE'].
'</head>.;

unset($_SESSION['TAMKA_LAYOUT_OUTPUT_SITE_HEAD']);
unset($_SESSION['TAMKA_RESOURCES_DOCUMENT_HEAD_CSS']);
unset($_SESSION['TAMKA_RESOURCES_DOCUMENT_HEAD_JS']);
unset($_SESSION['TAMKA_RESOURCES_DOCUMENT_HEAD_JS_INLINE']);

$contents = ob_get_contents();

ob_end_clean();

require_once TAMKA_CONSTANT_INCLUDE_THEMES.'meta.php';

$tamkaMeta = new TamkaMeta();
$tamkaMeta->unsetMeta ();

return $contents;
}
}
3. Added a System Plugin that fires on onAfterInitialise to load the new Renderers
 require_once TAMKA_CONSTANT_INCLUDE_LIBRARY_BASE.'utilities'.DIRECTORY_SEPARATOR.'html'.DIRECTORY_SEPARATOR.'html.php';
$tamkaDocument = new TamkaDocumentHTML ();
$tamkaDocument->loadRenderer( 'TamkaHead' );
$tamkaDocument->loadRenderer( 'TamkaPosition' )


4. Custom JDoc Statements in your Template index.php file to drive the new Renderers.

The following two JDoc statements are now available to my application. It's very much like normal JDoc Statements, except these statements drive my architectural elements *and* do so in a way that Joomla! is aware, and listening for completion before continuing to the next step.

<jdoc:include type="tamkaposition" name="6" />

<jdoc:include type="tamkahead" />

This could be useful anytime you want to integrate an application of any nature that doesn't fit the normal architecture. I think it has a lot of potential.

I looked at nooku, as well, and it has the same inflexibility with the loadRenderer function. Much of nooku is still the standard Joomla! framework, with many improvements. In both Joomla! and nooku, it would be nice to make it possible to use JDocument::loadRenderer to extend this capability by simply using the class.

Hope this helps someone. If you have done something similar, or know a better way, I am very interested in hearing about it.!

Views: 74

Tags: joomla

Ajmal Afif Comment by Ajmal Afif on March 5, 2010 at 12:45am
Hi Amy,

Although this is waaaay over my head, I wonder how this Renderer functions in practical example (if you dont mind elaborate it for newbies like myself, that is).

Thanks again for sharing!
Amy Stephen Comment by Amy Stephen on March 5, 2010 at 8:08am
One of the more practical (and yet, still very much developer-y) applications could be creating JSON output easily. Joomla!'s Renderers create HTML, PDF, RSS, and RAW output. If someone wanted to offer a different type of output, this would be an approach to extending the Renderers.

Also, anytime you have an application that would be easier to tap into than to completely recode in Joomla!'s architecture, you could write little interface files - like JDocumentRendererTamkaPosition to spawn off the process and receive the output, passing the output to Joomla! for insertion into the template position.

If you wanted to play with it to see it's potential, follow the instructions and place an "echo "Hello!" statement within the JDocumentRendererTamkaPosition function. Then, place that JDoc statement in a Template and run the page. You should see the "Hello!" present at that location.

In a very practical sense, it can be used to interface to existing applications for retrieving and displaying HTML. It might be useful in cases where IFrames were thought to be the only alternative. It might be useful to interface with a WordPress application -- if you are familiar with that class structure.

It's probably not something most people will ever need. But if you are doing funky stuff, it could come in handy.
Klas Comment by Klas on March 5, 2010 at 8:35am
Just a little side note - JSON work fine with RAW

Otherwise nice tutorial, I wish more of this kind will appear in the future. Would be nice if we would have some repository for such texts (like wiki)

Comment

You need to be a member of All Together, As A Whole to add comments!

Join All Together, As A Whole

Badge

Loading…

© 2012   Created by Amy Stephen.

Badges  |  Report an Issue  |  Terms of Service