Benutzer:Elkuku/Proyektz/EVI2/JFishbone

Aus Joomla! Dokumentation
Wechseln zu: Navigation, Suche

230px-elkuku-proyektz-evi3-jfishbone-dirtree.png

Abb. 1.1 Die Applikation fishbone in einer
Joomla! Installation

Inhaltsverzeichnis

[Bearbeiten] JFishbone - Eine Joomla! Anwendung

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, eine Verwaltungsschnittstelle, 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.

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

[Bearbeiten] 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 File php.png index.php, welche die Bibliotheken lädt und das Anwendungsobjekt ausführt.

Wenn Sie Joomla! auf Ihrem lokalen Rechner im Verzeichnis Folder blue.png joomla15 installiert haben, können Sie Fishbone folgendermassen aufrufen.

http://localhost/joomla15/fishbone

[Bearbeiten] index.php

Schauen wir uns die File php.png 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 Folder blue.png includes, welches die anwendungsbezogenen Dateien File php.png defines.php, File php.png framework.php, File php.png application.php und andere beinhaltet.

[Bearbeiten] defines.php

Die Datei File php.png 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' );

[Bearbeiten] framework.php

In der File php.png 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 File php.png index.php sehen wir, wie die Anwendung erzeugt wird:

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

[Bearbeiten] application.php

Die Factory Klasse sucht im Folder blue.png /fishbone/includes Verzeichnis nach einer Datei names File php.png application.php. Diese Datei enthält das JFishbone Objekt, das die Klasse JApplication erweitert. 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. Um das zu vermeiden, registrieren wir unsere Anwendung einfach in der File php.png 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.

[Bearbeiten] 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 ('component'), 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 File php.png 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. Die kompletten Dateien finden sie im Download (siehe unten). Dort sind dann auch die Verzeichnisse "content", "templates" und "language" enhalten, die fishbone erst anwenden lassen.

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.

[Bearbeiten] Quellen

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.

Die deutsche Übersetzung stammt von Tom Bohaĉek und wurde hier nach freundlicher Genehmigung von Ihm übernommen.

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Sonstiges
Team Navigation
Werkzeuge