JFishbone - Eine Joomla! Anwendung

Geschrieben von Tom   
Dienstag, 30. Dezember 2008

Was heißt das: Eine Joomla! Applikation?

Nun, Joomla! ist ein bekanntes Content Management System, aber seit Version 1.5 ist es mehr als nur eine schnell einzusetzende CMS-Anwendung. Joomla! stellt ein Framework für PHP-Entwickler bereit, die ihre eigenen Anwendungen mit der ganzen Vielfalt an Features, wie den Einsatz von Templates, einfachen Datenbankzugriff, ein administrations Interface, Komponenten und Module, und Nutzer und Kontakt-Management ausstatten wollen.

Um zu zeigen, wie all das funktioniert, habe ich eine kleine Anwendung names Fishbone entwickelt, welche zeigt, wie man das Framework nutzt und wie man solch eine Anwendung strukturiert. Der gesamte Beispielcode stammt von Joomla!, hauptsächlich aus dem Installations- und Administrationsbereich des CMS.

Der Originalartikel stammt von Wolfgang Disch und wurde im JFoobar Blog veröffentlicht. Die Übersetzung und Veröffentlichung dieses Artikels wurde offiziell genemigt. Für ein besseres Verständnis wurden kleine Anpassungen und ein paar klärende Sätze eingefügt.

In unserem Beispiel nutzen wir ein Template, um einfache Textausgaben und die Unterstützung verschiedener Sprachen zu demonstrieren.

Die Struktur der Anwendung

Der Name der Anwendung ist Fishbone, also ist unsere erste Aufgabe die Erstellung eines Verzeichnisses mit diesem Namen. Das Verzeichnis definiert den Startpunkt der Anwendung und enthält die Hauptdatei index.php, welche die Bibliotheken lädt und das Anwendungsobjekt ausführt.

Wenn Sie Joomla! auf Ihrem lokalen Rechner im Verzeichnis joomla15 installiert haben, können Sie Fishbone über http://localhost/joomla15/fishbone aufrufen.

Schauen wir uns die index.php an:

/**
* Fishbone - a Joomla! Application
* created by Wolfgang Disch
*/
define( '_JEXEC', 1 );
define( 'JPATH_BASE', dirname( __FILE__ ) );
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
// create the mainframe object
$mainframe =& JFactory::getApplication('fishbone');
// initialise the application
$mainframe->initialise();
// render the application
$mainframe->render();
// return the response
echo   JResponse::toString();

Anhand dieser Datei können wir die Struktur einer Joomla! Anwendung sehen: Das Anwendungsverzeichnis beinhaltet ein Verzeichnis mit dem Namen includes, welches die anwendungsbezogenen Dateien defines.php, framework.php,application.php und andere beinhaltet.
Die Datei defines.php spezifiziert die global genutzten Dateipfade:

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
//Joomla framework path definitions
$parts = explode( DS,   JPATH_BASE );
array_pop( $parts );
define( 'JPATH_ROOT', implode( DS, $parts ) );
define( 'JPATH_SITE', JPATH_ROOT );
define( 'JPATH_CONFIGURATION', JPATH_ROOT );
define( 'JPATH_ADMINISTRATOR', JPATH_ROOT.DS.'administrator' );
define( 'JPATH_XMLRPC', JPATH_ROOT.DS.'xmlrpc' );
define( 'JPATH_LIBRARIES', JPATH_ROOT.DS.'libraries' );
define( 'JPATH_PLUGINS', JPATH_ROOT.DS.'plugins' );
define( 'JPATH_INSTALLATION', JPATH_ROOT.DS.'installation' );
define( 'JPATH_THEMES', JPATH_BASE.DS.'templates' );
define( 'JPATH_CACHE', JPATH_ROOT.DS.'cache' );
// the new application
define( 'JPATH_FISHBONE', JPATH_ROOT.DS.'fishbone' );

In framework.php werden die Framework bezogenen Dateien geladen:

// no   direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
/*
* Joomla! system checks
*/
error_reporting( E_ALL );
@set_magic_quotes_runtime( 0 );
@ini_set('zend.ze1_compatibility_mode',   '0');
/*
* Joomla! system startup
*/
// System includes
require_once( JPATH_LIBRARIES.DS.'joomla'.DS.'import.php');
// Installation file includes
define( 'JPATH_INCLUDES', dirname(__FILE__) );
/*
* Joomla! framework loading
*/
// Include object abstract class
require_once(JPATH_SITE.DS.'libraries'.DS.'joomla'.DS.'utilities'.DS.'compat'.DS.'compat.php');
// Joomla!   library imports
jimport( 'joomla.database.table' );
jimport( 'joomla.user.user');
jimport( 'joomla.environment.uri' );
jimport( 'joomla.user.user');
jimport( 'joomla.html.parameter' );
jimport( 'joomla.utilities.utility' );
jimport( 'joomla.language.language');
jimport( 'joomla.utilities.string' );

Zurück in der index.php sehen wir, wie die Anwendung erzeugt wird:

// create the mainframe object
$mainframe =& JFactory::getApplication('fishbone');

Die Factory Klasse sucht im /fishbone/includes Verzeichnis nach einer Datei names application.php. Diese Datei enthält das JFishbone Objekt, welches eine von JApplication erbende Klasse ist. Hier ist der Konstruktor der Klasse:

// no direct access
defined( '_JEXEC' ) or die('Restricted access' );
/**
* Joomla! Application class
*
* @final
*/
class JFishbone extends JApplication
{
/**
* Class constructor
*
* @access protected
* @param array An optional associative array of 
*    configuration settings
* Recognized key values include 'clientId'
* (this list is not meant to be comprehensive).
*/
function __construct($config = array())
{
// OUR APPLICATION ID
$config['clientId'] =   4;
parent::__construct($config);
//Set the root in  the URI based on the application name
JURI::root(null, str_replace('/'.$this->getName(), '',
JURI::base(true)));
}

Er definiert eine client ID für unsere Anwendung. Aber die Erstellung der neuen Instanz wird fehlschlagen! Dies liegt daran, dass tief in der JApplication Klasse ein Aufruf zu einer Helper-Klasse stattfindet:

$info =& JApplicationHelper::getClientInfo($client, true);

Der Sinn dieses Aufrufs ist, Informationen zu registrierten Anwenungen zu erlangen. Grundsätzlich sind vier Anwenungen in der JApplicationHelper Klasse bereits vorhanden, das wären der Website-Client, der Administrations-Client, der Installations-Client und XMLRPC-Client. Wir könnten nun unsere Anwendung einfach hinter die bereits Vorhandenen anhängen. Das wäre allerdings ein Hack der JApplicationHelper Klasse (libraries/joomla/application/helper.php). Um das zu vermeiden, registrieren wir unsere Anwendung einfach in der index.php, indem wir ein weiteres Client-Objekt an das Client-Array anfügen:

/**
* Fishbone - a Joomla! Application
* created by Wolfgang Disch
*/
define( '_JEXEC', 1 );
define( 'JPATH_BASE', dirname( __FILE__ ) );
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
jimport( 'joomla.application.helper' );
$info =& JApplicationHelper::getClientInfo();
$obj = new stdClass();
$obj->id = 4;
$obj->name = 'fishbone';
$obj->path = JPATH_FISHBONE;
$info[4] = $obj;
unset($obj);
// create the mainframe object
$mainframe =& JFactory::getApplication('fishbone');
// initialise the application
$mainframe->initialise(array('language' => 'de-DE'));
// render the application
$mainframe->render();
// return the response
echo JResponse::toString();

Nun kann unsere Anwendung registriert werden, und die Erzeugung des Anwendungsobjekts ist erfolgreich.

Der Anwendungsfluss

Nun wird der Anwendungsfluss ausgeführt: Nach dem Erstellen des Objektes durch die Factory Klasse JFactory werden die Methoden initialise() und render() ausgeführt. Es gibt weitere Methoden für das Routing (Erzeugung von URLs) und Dispatching (Handhabung von Ereignissen), aber wir wollen es einfach halten.

Die Initialisierungsmethode setzt die Sprache der Anwendung:

/**
* Initialise the application.
*
* @access public
*/
function   initialise( $options = array())
{    
// Give the user English
if (!empty($options['language'])) {
$options['language'] = 'en-GB';
}
// One last check to make sure we have something
if ( !   JLanguage::exists($options['language']) ) {
$options['language'] = 'en-GB';
} 
parent::initialise($options);
}

In unserem Beispiel wechseln wir zur Deutschen Sprache, wenn wir die Methode mit einem Sprachparameter aufrufen:

// initialise the application
$mainframe->initialise(array('language' => 'de-DE'));

Nun folgt der Kern der Anwendung. Die $mainframe->render Methode lädt das Template und rendert es. Das Ergebnis wird in den Body des JResponse-Objekts geschrieben. Der Name und Pfad des Templates werden der Render-Methode des Dokuments, welches vom Typ JDocumentHTML ist, übergeben.

$params = array(
'template'  => 'default',
'file'  => 'index.php',
'directory' => JPATH_THEMES
);
$data = $document->render(false, $params);
JResponse::setBody($data);

Das Rendern des Templates ersetzt Ausdrücke durch den Inhalt der genannten Komponente, welche durch die setBuffer Methode gesetzt wird.

$document->setBuffer( $contents, 'component');

Hier sehen wir die Aufteilung in Template auf der einen, und Komponente auf der anderen Seite. Um das Beispiel einfach zu halten, wird der Inhalt direkt von einer Pseudo-Komponente gesetzt, welche wir in die Render-Methode einbeziehen.

Schauen wir uns nun die Render-Methode an:

/**
* Render the application
*
* @access public
*/
function render()
{
$document =& JFactory::getDocument();
$user  =& JFactory::getUser();
$document->setTitle(JText::_('PAGE_TITLE'));
// Define   component path
define('JPATH_COMPONENT', JPATH_BASE.DS.'content');
// Execute the component
ob_start();
require_once(JPATH_COMPONENT.DS.'hello.php');
$contents = ob_get_contents();
ob_end_clean();
$params = array(
'template'  => 'default',
'file'  => 'index.php',
'directory' => JPATH_THEMES
);
$document->setBuffer( $contents, 'component');  
$data = $document->render(false, $params);
JResponse::setBody($data);
}

Die Komponente in hello.php ist nur ein Platzhalter, um zu demonstrieren, wie die Anwendung verschiedene Komponenten einsetzen, kann um Inhalte in das Template zu rendern.

Der Inhalt wird schließlich $contents zugewiesen.

Nach dem Rendern des Inhalts der Seite wird das Ergebnis dem JResponse-Objekt angefügt. In der letzten Zeile wird JResponse ausgegeben.

// return the response
echo JResponse::toString();

Das war's. Das Ergebnis sieht sehr einfach aus, aber Sie sollten daran denken, was wir erreicht haben:

Wir haben eine Anwendung mit voller Unterstützung des Joomla! Frameworks entwickelt

  • Wir nutzen JDocument, JDocumentHTML und deren verwandte Methoden, um das Dokument zu rendern.
  • Wir nutzen ein Template, welches einfach verändert werden kann, ohne den Code anzufassen.
  • Wir haben bereits eine Unterstützung für Mehrsprachigkeit, welche erweitert werden kann, um zwischen den Sprachen umzuschalten.
  • Wir haben das Komponenten-Konzept eingeführt.

Falls Sie interessiert sind, können sie den Inhalt des Fishbone-Verzeichnisses hier herunterladen.

Hier ist ein Screenshot unserer Anwendung:

JFishbone Joomla! Anwendung
feed1 Kommentare
foto
Juni 24, 2011
Stimmen: +0

Sehr schöne Anleitung für eine Komponente. Habe sie in das Stammverzeichnis von Joomla eingefügt und über den Browser geöffnet. Funktioniert sehr gut.
Allerdings glaubte ich, beim durchlesen verstanden zu haben, dass sich die Komponente bei Joomla registriert und dass sie dann im Backend unter Komponenten zu sehen sein würde. Dort ist sie aber nicht aufzufinden.
Deswegen frage ich mich. Was fehlt bei der Komponente?
Sie hat keine XML-Datei die die Installation automatisieren würde, aber kann man Sie auch manuell installieren und wie?
Gruss foto

report abuse
vote down
vote up

Kommentar schreiben
 
  kleiner | groesser
 

security image
Bitte den folgenden Code eintragen


busy
 

B01 realisiert zeitgenössische Online-Kommunikationsmittel.
Wir sind spezialisiert auf OSCMS und unterstützen unsere Kunden vom Konzept bis zum Launch mit Erfahrung und exklusiven Komponenten zur Umsetzung von Communitys, Shops, Portalen und Webseiten.

B01 Kunden

Unsere Ideen, unsere Produkte, unsere Kunden.

B01 empfiehlt:

ZOO Content Construktion Kit

ZOO CCK

Virtuemart Shopsystem

E-Commerce

Joomla SEO

SEO

Joomla Content Editor

Content Editor

Joomla Social Networking

JomSocial