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 AnwendungDer 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. // 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 AnwendungsflussNun 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
Falls Sie interessiert sind, können sie den Inhalt des Fishbone-Verzeichnisses hier herunterladen. Hier ist ein Screenshot unserer Anwendung: Lesezeichen setzen Hits: 25305 Kommentar schreiben
|