Grundlage biete die Erweiterung [simple_ajax]1 von Leo Unglaub. Diese installiert eine einzelne PHP-Dateie im Rootverzeichnis der Contao-Installation.

<?php

/**
 * Contao Open Source CMS
 * Copyright (C) 2005-2011 Leo Feyer
 *
 * Formerly known as TYPOlight Open Source CMS.
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program. If not, please visit the Free
 * Software Foundation website at <http://www.gnu.org/licenses/>.
 *
 * PHP version 5
 * @copyright	Leo Unglaub 2012
 * @author		Leo Unglaub <leo@leo-unglaub.net>
 * @package		simple_ajax
 * @license		LGPL
 */

// simple trick for Contao < 2.10
$arrPost = $_POST;
unset($_POST);

// inizialize the contao framework
define('TL_MODE', 'FE');
require('system/initialize.php');

// write the post data back into the array
$_POST = $arrPost;

/**
 * Class SimpleAjax
 * Contain methods to catch ajax requests and send responses back to the client.
 *
 * Description
 * ```````````
 *
 * The usage of the SimpleAjax extensions is very easy. The extension provides
 * the hook $GLOBALS['TL_HOOKS']['simpleAjax'] for extension developers. You
 * simply have to register your class/method and the extension will call
 * your class if there is an incomming ajax request.
 *
 * You simply have to deside if it's an ajax request for your module and return
 * the data you want.
 *
 * There are a few thinks you should know about the extension:
 * 	* YOU have the full controll over the response. That also means
 * 	  that you have to set the correct header.
 *  * YOU have to terminate the request after you have send the response.
 * 	* If the ajax request is not for your method you simply have nothing to
 * 	* return.
 *
 *
 * Usage
 * `````
 * // config.php
 * $GLOBALS['TL_HOOKS']['simpleAjax'][] = array('MyClass', 'myMethod');
 *
 * // MyClass.php
 * class MyClass extends System
 * {
 * 	public function myMethod()
 * 	{
 * 		if ($this->Input->get('acid' == 'myrequest'))
 * 		{
 * 			$arrReturn = array('foo', 'bar', 'foobar');
 *
 * 			header('Content-Type: application/json');
 * 			echo json_encode($arrReturn);
 * 			exit;
 * 		}
 * 	}
 * }
 */
class SimpleAjax extends Controller
{
	/**
	 * Call the parent constructor.
	 *
	 * !!! DON'T REMOVE THIS !!!
	 *
	 * If you remove this you get the following error message:
	 * Fatal error: Call to protected System::__construct() from invalid
	 * context
	 *
	 * @param	void
	 * @return	void
	 */
	public function __construct()
	{
		parent::__construct();
	}

	/**
	 * Get the ajax request and call all hooks
	 *
	 * @param	void
	 * @return	void
	 */
	public function run()
	{
		// check if a hook is registered
		if (is_array($GLOBALS['TL_HOOKS']['simpleAjax']) && count($GLOBALS['TL_HOOKS']['simpleAjax']) > 0)
		{
			// execute every registered callback
			foreach ($GLOBALS['TL_HOOKS']['simpleAjax'] as $callback)
			{
				$this->import($callback[0]);
				$this->$callback[0]->$callback[1]();
			}
		}

		// if there is no other output, we generate a 412 error response
		header('HTTP/1.1 412 Precondition Failed');
		die('Simple Ajax: Invalid AJAX call.');
	}
}

// create a SimpleAjax instance and run it
$objSimpleAjax = new SimpleAjax();
$objSimpleAjax->run();

?>

Die Datei dient aber nur als “Brücke” zu einem System-Modul, welches selber erstellt werden muss. Folgendes Modul gemäss der im Source Code enthaltenen Dokumentation kann die Basis für ein umfangreiches Modul bieten.

 

Neues Modul anlegen

Im Contao Ordner system/modules wird ein neuer Ordner erzeugt. In unserem Fall ajaxRequest.

ACHTUNG: Contao lädt Module in alphabetischer Reihenfolge gemäss der Ordnerbezeichnung. Dies kann unter Umständen zu unerwarteten Ergebnissen führen.

Im eben erstellten Ordner wird noch ein Unterordner config angelegt. Anschliessend wird noch eine Datei config.php im Unterverzeichnis config und eine Datei ajaxRequest.php im Modul-Verzeichnis selber erzeugt.

 

ajaxRequest.php

Die Datei im Hauptverzeichnis des Moduls enthält die Klasse, welche von der Erweiterung [simple_ajax] aufgerufen werden soll. In diesem einfachen Beispiel wird geprüft, ob eine GET-Variable zur Kontrolle übergeben wurde. Ist dies der Fall wird ein vordefiniertes Array zurück gegeben.

<?php if (!defined('TL_ROOT')) die('You cannot access this file directly!');
// MyClass.php
class ajaxRequest extends System {
  public function compile() {

    if ($this->Input->get('acid') == 'ajaxrequest') {
      $arrReturn = array('foo', 'bar', 'foobar');

        // JSON Header
        header('Content-Type: application/json');

        // Cross domain settings
        header('Access-Control-Allow-Origin: *');

        // JSON
        echo json_encode($arrReturn);

        // Exit to prefent contao output
        exit;
      }
    }
}
?>
Über die GET-Variable könnte zum Beispiel auch ein Zugriffsschlüssel oder die ID eines gewünschten Inhalt übergeben werden.
Cross Domain Ajax-Zugriffe werden üblicherweise unterbunden. Um den Zugriff von einer externen Quelle zu erlauben muss dem Header der Wert Access-Control-Allow-Origin hinzugefügt werden. Ein gutes Tutorial2 hat Phil Leggetter von leggetter.co.uk erstellt.

Erweitertes Beispiel mit Datenbankzugriff und expliziter Seiten oder Inhalts Selektion.

<?php if (!defined('TL_ROOT')) die('You cannot access this file directly!');

// MyClass.php
class ajaxRequest extends System {

	public function compile() {

		$this->import('Database');

		if ($this->Input->get('acid') == 'ajaxrequest' && $this->Input->get('action') && is_numeric($this->Input->get('id'))) {				
			// Check type of content-request
			switch($this->Input->get('action')) {
				case 'page':
					$selectByRow = 'pid';
					break;
				case 'content':
					$selectByRow = 'id';
					break;
				default:
					// Exit request if none of the above
					return;
			}
			// Get id of target and make database select
			$targetID = $this->Input->get('id');
			$objAjax = $this->Database->prepare('SELECT * FROM tl_content WHERE ' . $selectByRow . '=? ORDER BY sorting')->execute($targetID);

			// If content was found convet to array and return JSON
			if ($objAjax->numRows > 0) {			
				for($i=0, $arrAjax = array(); $objAjax->next(); $i++) {
					foreach($objAjax->row() as $key => $value) {
						$arrAjax[$i][$key] = deserialize($value);
					}
				}

				// JSON Header
				header('Content-Type: application/json');

				// Cross domain settings
				header('Access-Control-Allow-Origin: *');

				// JSON
				echo json_encode($arrAjax);

				// Exit to prefent contao output
				exit;
			}
		}
	}
}

?>

 

 

config.php

Das eben erstellte Objekt muss nun noch im System von Contao registriert werden. Dies geschieht über die Datei config.php im Unterordner config. Für den Hook simpleAjax wird hier unser Objekt und die darin enthalten Funktion angelegt. Dieser Hook wiederum wird von der Datei simpleAjax.php beim laden aufgerufen und ausgeführt.

<?php

// SimpleAjax Hook
$GLOBALS['TL_HOOKS']['simpleAjax'][] = array(ajaxRequest, compile);

?>

 

Ajax-Abfrage

Mit folgendem JavaScript kann die Abfrage über das SimpleAjax ausgeführt werden.

<script>
  $xmlhttp = new XMLHttpRequest();

  $xmlhttp.open("GET","http://myhost.com/SimpleAjax.php?acid=ajaxrequest",true);
  $xmlhttp.send();

  $xmlhttp.onreadystatechange = function() {
    if ($xmlhttp.readyState==4 && $xmlhttp.status==200) {
      $result = $.parseJSON($xmlhttp.responseText);
      $('#container').html($result[2]);
    }
  }
</script>
ACHTUNG: Dieses Script funktioniert nur für IE 8+. Bei älteren Browsern muss auf das entsprechende ActiveX Objekt ausgewichen werden.
Das aufgeführte Script verwendet die jQuery Funktion .parseJSON um den JSON-String wieder in ein JavaScript-Objekt umzuwandeln.

Ajax-Zugriff für das erweiterte Beispiel.

<script>
  $xmlhttp = new XMLHttpRequest();

  $xmlhttp.open("GET","http://myhost.com/SimpleAjax.php?acid=ajaxrequest&action=content&id=1",true);
  $xmlhttp.send();

  $xmlhttp.onreadystatechange = function() {
    if ($xmlhttp.readyState==4 && $xmlhttp.status==200) {
      $result = $.parseJSON($xmlhttp.responseText);
      $('#container').html($result[0]['type']);
    }
  }
</script>

content=page Abfrage

xmlhttp = new XMLHttpRequest();

xmlhttp.open("GET", "http://www.mydomain.com/SimpleAjax.php?acid=ajaxrequest&action=page&id=28", true);
xmlhttp.send();

xmlhttp.onreadystatechange = function () {
    // If success
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        var result = $.parseJSON(xmlhttp.responseText);
        // Loop articles
        for (var article in result) {
            // Loop content
            for (var $content in result[article]) {
                if (result[article].hasOwnProperty($content)) {

                    var entry = '<div class="entry">';
                    entry += result[article][$content].text.replace('[nbsp]', ' ');
                    entry += '<a class="photo" href="#about.html" onClick="javascript:localStorage.personID=';
                    entry += result[article][$content].imageUrl.replace(/\{\{link_url::([0-9]+)\}\}/, '$1');
                    entry += '">';
                    entry += '<img src="http://www.gyselroth.com/' + result[article][$content].singleSRC + '">'
                    entry += '</a>'
                    entry += '</div>';

                    $('#home-content').html($('#home-content').html() + entry);
                }
            }
        }
    // If error
    } else if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
        $('#home-content').html('Beim Zugriff auf die Serverdaten ist ein Fehler aufgetreten.')
    }
}

 

 

Todo

  • Sicherheits-Token System einbauen
  • Das Abrufen von Inhalten ermöglichen
  • Backend-Oberfläche zur Definition von Parametern erstellen (Sicherheits-Token, Zugriffs-Domains, Zugriffs-Optionen)

 

Weitere Quellen

  • Contao 3 Erweiterung [rest] – Bietet Ajax Calls mit Backend-Oberfläche. Leider keine Cross-Domain-Unterstützung3
  1. https://contao.org/de/extension-list/view/simple_ajax.10000009.de.html []
  2. http://www.leggetter.co.uk/2010/03/12/making-cross-domain-javascript-requests-using-xmlhttprequest-or-xdomainrequest.html []
  3. https://contao.org/de/extension-list/view/rest.13.de.html []

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht.