<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 15156 -->
<!-- Reviewed: no -->
<sect3 id="zend.controller.actionhelpers.autocomplete">
    <title>AutoComplete</title>

    <para>
        Viele AJAX Javascript Bibliotheken bieten Funktionalitäten an für eine automatische
        Vervollständigung wobei eine Auswahlliste von potentiell passenden Ergebnissen angezeigt
        wird wärend der Benutzer tippt. Der <code>AutoComplete</code> Helfer zielt darauf ab
        einfach akzeptierbare Ergebnisse zu solchen Methoden zurückzugeben.
    </para>

    <para>
        Da nicht alle JS Bibliotheken automatische Vervollständigung auf die gleiche Art
        implementieren bietet der <code>AutoComplete</code> Helfer einige grundsätzliche abstrakte
        Funktionalitäten zu vielen Bibliotheken und konkrete Implementierungen für individuelle
        Bibliotheken. Zurückgegebene Typen sind generell entweder JSON Arrays von Strings, JSON
        Arrays von Arrays (mit jedem Mitgliedsarray das ein assoziatives Array von Metadaten ist,
        das verwendet wird um die Auswahlliste zu erstellen), oder HTML.
    </para>

    <para>
        Die grundsätzliche Verwendung ist für jede Implementierung die selbe:
    </para>

    <programlisting role="php"><![CDATA[
class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // etwas Logik durchführen...

        // Verschlüsseln und Antwort senden;
        $this->_helper->autoCompleteDojo($data);

        // oder explizit:
        $response = $this->_helper->autoCompleteDojo
                                  ->sendAutoCompletion($data);

        // oder einfach die Antwort der automatischen
        // Vervollständigung vorbereiten;
        $response = $this->_helper->autoCompleteDojo
                                  ->prepareAutoCompletion($data);
    }
}
]]></programlisting>

    <para>
        Standardmäßig mach die automatische Vervollständigung folgendes:
    </para>

    <itemizedlist>
        <listitem><para>
                Layouts und ViewRenderer ausschalten.
        </para></listitem>

        <listitem><para>
                Die richtigen Antwort Header zu setzen.
        </para></listitem>

        <listitem><para>
                Antwort Body mit verschlüsselten/formatierten automatisch vervollständigten Daten
                setzen.
        </para></listitem>

        <listitem><para>
                Antwort senden.
        </para></listitem>
    </itemizedlist>

    <para>
        Mögliche Methoden des Helfers beinhalten:
    </para>

    <itemizedlist>
        <listitem><para>
                <code>disableLayouts()</code> kann verwendet werden um Layouts und den ViewRenderer
                auszuschalten. Typischerweise wird das innerhalb von
                <code>prepareAutoCompletion()</code> aufgerufen.
        </para></listitem>

        <listitem><para>
                <code>encodeJson($data, $keepLayouts = false)</code> verschlüsselt Daten zu JSON,
                und aktiviert oder deaktiviert Layouts optional. Typischerweise wird das innerhalb
                von <code>prepareAutoCompletion()</code> aufgerufen.
        </para></listitem>

        <listitem><para>
                <code>prepareAutoCompletion($data, $keepLayouts = false)</code> wird verwendet um
                Daten im Antwortformat vorzubereiten wenn das für die konkrete Implementation
                notwendig ist, wobei Layouts optional aktiviert oder deaktiviert werden können.
                Der Rückgabewert variiert basierend auf der Implementierung.
        </para></listitem>

        <listitem><para>
                <code>sendAutoCompletion($data, $keepLayouts = false)</code> wird verwendet um
                Daten im Antwortformat zu senden was für die konkrete Implementierung notendig ist.
                Sie ruft <code>prepareAutoCompletion()</code> und sendet dann die Antwort.
        </para></listitem>

        <listitem><para>
                <code>direct($data, $sendNow = true, $keepLayouts = false)</code> wird verwendet
                wenn der Helfer als Methode des Helfer Brokers aufgerufen wird. Das
                <code>$sendNow</code> Flag wird verwendet um festzustellen ob
                <code>sendAutoCompletion()</code> oder <code>prepareAutoCompletion()</code>
                aufgerufen werden muß.
        </para></listitem>
    </itemizedlist>

    <para>
        Aktuell unterstützt <code>AutoComplete</code> die folgenden Dojo und Scriptaculous AJAX
        Bibliotheken.
    </para>

    <sect4 id="zend.controller.actionhelpers.autocomplete.dojo">
        <title>AutoCompletion mit Dojo</title>

        <para>
            Dojo hat per se keinen AutoCompletion Wizard, hat aber zwei Wizards die AutoCompletion
            ausführen können: ComboBox und FilteringSelect. In beiden Fällen benötigen Sie einen
            Datenspeicher der QueryReadStore implementiert; für mehr Informationen über dieses
            Thema siehe die
            <ulink url="http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/data-retrieval-dojo-data-0">dojo.data</ulink>
            Dokumentation.
        </para>

        <para>
            Im Zend Framework kann ein einfaches indiziertes Array an den AutoCompletionDojo Helfer
            übergeben werden, und er wird eine JSON Antwort zurückgeben die passend für die
            Verwendung in so einem Speicher ist:
        </para>

        <programlisting role="php"><![CDATA[
// In der Controller Aktion:
$this->_helper->autoCompleteDojo($data);
]]></programlisting>

        <example id="zend.controller.actionhelpers.autocomplete.dojo.example1">
            <title>AutoCompletion mit Dojo und der Verwendung von Zend MVC</title>

            <para>
                AutoCompletion mit Dojo, über Zend MVC, benötigt verschiedene Dinge: Erstellung
                eines Form Objekts für die Kombobox bei der man AutoCompletion will, eine
                Kontroller Action für das anbieten der AutoCompletion Ergebnisse, Erstellung eines
                eigenen QueryReadSote um die AutoCompletion Aktion damit zu verbinden, und
                Erstellung des Javascripts das zur Initialisierung der AutoCompletion auf der
                Serverseite zu verwenden ist.
            </para>

            <para>
                Schauen wir uns zuerst das benötigte Javascript an. Dojo bietet ein komplettes
                Framework für die Erstellung von OOP Javascript, so wie Zend Framework für PHP.
                Teile davon sind die Möglichkeit Pseudo-Namespaces zu erstellen indem die
                Verzeichnis Hirarchie verwendet wird. Wir erstellen ein 'custom' Verzeichnis auf
                dem gleichen Level wie das Dojo Verzeichnis das Teil der Distribution von Dojo ist.
                In diesem Verzeichnis, erstellen wir eine Javascript Datei, TestNameReadStore.js,
                mit den folgenden Inhalten:
             </para>

            <programlisting role="javascript"><![CDATA[
dojo.provide("custom.TestNameReadStore");
dojo.declare("custom.TestNameReadStore", dojox.data.QueryReadStore, {
    fetch:function (request) {
        request.serverQuery = { test:request.query.name };
        return this.inherited("fetch", arguments);
    }
});
]]></programlisting>

            <para>
                Diese Klasse ist einfach eine Erweiterung von Dojo's eigenem QueryReadStore,
                welche selbst eine Abstrakte Klasse ist. Wir definieren einfach eine Methode mit
                der angefragt werden soll, und verknüpfen Sie mit dem 'test' Element.
            </para>

            <para>
                Als nächstes, erstellen wir das Form Element für das wir AutoCompletion wollen:
            </para>

            <programlisting role="php"><![CDATA[
class TestController extends Zend_Controller_Action
{
    protected $_form;

    public function getForm()
    {
        if (null === $this->_form) {
            $this->_form = new Zend_Form();
            $this->_form->setMethod('get')
                ->setAction(
                    $this->getRequest()->getBaseUrl() . '/test/process'
                )
                ->addElements(array(
                    'test' => array('type' => 'text', 'options' => array(
                        'filters'        => array('StringTrim'),
                        'dojoType'       => array('dijit.form.ComboBox'),
                        'store'          => 'testStore',
                        'autoComplete'   => 'false',
                        'hasDownArrow'   => 'true',
                        'label' => 'Your input:',
                    )),
                    'go' => array('type' => 'submit',
                                  'options' => array('label' => 'Go!'))
                ));
        }
        return $this->_form;
    }
}
]]></programlisting>

            <para>
                Hier erstellen wir einfach eine Form mit den 'test' und 'go' Methoden. Die 'test'
                Methode fügt verschiedene spezielle, Dojo-spezifische Attribute hinzu: dojoType,
                store, autoComplete, und hasDownArrow. Der dojoType wird verwendet um anzuzeigen
                das wir eine ComboBox erstellen, und wir Sie zum Datenspeicher von 'testStore'
                verbinden wollen (Schlüssel 'store') -- mehr dazu später. Die Spezifizierung von
                'autoComplete' mit false sagt Dojo das der erste passende Eintrag nicht automatisch
                ausgewählt wird, aber stattdessen eine Liste von Entsprechnungen angezeigt wird.
                Letztendlich, erstellt 'hasDownArrow' einen Abwärtspfeil ähnlich einer Selectbox
                sodas Wir die Entsprechnungen zeigen und verstecken können.
            </para>

            <para>
                Fügen wir eine Methode hinzu um die Form anzuzeigen, sowie einen Endpunkt für die
                Bearbeitung der AutoCompletion:
            </para>

            <programlisting role="php"><![CDATA[
class TestController extends Zend_Controller_Action
{
    // ...

    /**
     * Startseite
     */
    public function indexAction()
    {
        $this->view->form = $this->getForm();
    }

    public function autocompleteAction()
    {
        if ('ajax' != $this->_getParam('format', false)) {
            return $this->_helper->redirector('index');
        }
        if ($this->getRequest()->isPost()) {
            return $this->_helper->redirector('index');
        }

        $match = trim($this->getRequest()->getQuery('test', ''));

        $matches = array();
        foreach ($this->getData() as $datum) {
            if (0 === strpos($datum, $match)) {
                $matches[] = $datum;
            }
        }
        $this->_helper->autoCompleteDojo($matches);
    }
}
]]></programlisting>

            <para>
                in unserer <code>autocompleteAction()</code> machen wir eine Anzahl von Dingen.
                Zuerst schauen wir darauf eine Post Anfrage durchzuführen, und das dort ein
                'format' Parameter auf den Wert 'ajax' gesetzt ist; das hilft einfach störende
                Anfragen zur Aktion zu reduzieren. Als nächstes prüfen wir auf den 'test'
                Parameter, und vergleichen Ihn mit unseren Daten. (wir haben absichtlich die
                Implementation von <code>getData()</code> hier ausgelassen -- es können einfach
                jede Art von Datenquelle sein.) Letztendlich senden wir unsere Entsprechungen zum
                AutoCompletion Helfer.
            </para>

            <para>
                Jetzt da wir alle Teile des Backends haben, sehen wir uns an was wir benötigen um
                es in unserem View Skript für die Startseite auszugeben. Zuerst müssen wir unseren
                Datenspeicher einstellen, dann unsere Form darstellen, und letztendlich
                sicherstellen das die richtigen Dojo Bibliotheken -- inklusive unserer eigenen
                Datenspeicher -- geladen werden. Schauen wir uns das View Skript an, das die
                Schritte kommentiert:
            </para>

            <programlisting role="php"><![CDATA[
<?php // Den Datenspeicher einstellen: ?>
<div dojoType="custom.TestNameReadStore" jsId="testStore"
    url="<?php echo $this->baseUrl() ?>/unit-test/autocomplete/format/ajax"
    requestMethod="get"></div>

<?php // Die Form darstellen: ?>
<?php echo $this->form ?>

<?php // Das Dojo-betreffende CSS einstellen das im
      // HTML Head geladen werden soll: ?>
<?php $this->headStyle()->captureStart() ?>
@import "<?php echo $this->baseUrl()
?>/javascript/dijit/themes/tundra/tundra.css";
@import "<?php echo $this->baseUrl() ?>/javascript/dojo/resources/dojo.css";
<?php $this->headStyle()->captureEnd() ?>

<?php // Javascript einstellen das im HTML Head geladen werden soll,
      // inklusive aller benötigten Dojo Bibliotheken: ?>
<?php $this->headScript()
        ->setAllowArbitraryAttributes(true)
        ->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js',
            'text/javascript',
            array('djConfig' => 'parseOnLoad: true'))
        ->captureStart() ?>
djConfig.usePlainJson=true;
dojo.registerModulePath("custom","../custom");
dojo.require("dojo.parser");
dojo.require("dojox.data.QueryReadStore");
dojo.require("dijit.form.ComboBox");
dojo.require("custom.TestNameReadStore");
<?php $this->headScript()->captureEnd() ?>
]]></programlisting>

            <para>
                Beachte die Aufrufe zu den View Helfern wie headStyle und headScript; das sind
                Platzhalter, welche dann in der HTML Head Sektion des Layout View Skripts
                dargestellt werden können.
            </para>

            <para>
                Wir haben jetzt alle Teil um mit Dojo AutoCompletion zu arbeiten.
            </para>
        </example>
    </sect4>

    <sect4 id="zend.controller.actionhelpers.autocomplete.scriptaculous">
        <title>AutoCompletion mit Scriptaculous</title>
        <para>
            <ulink url="http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter">Scriptaculous</ulink>
            erwartet eine HTML Antwort in einem speziellen Format.
        </para>

        <para>
            Der Helfer der mit dieser Bibliothek zu verwenden ist ist 'AutoCompleteScriptaculous'.
            Es muß einfach ein Array von Daten angegeben werden, und der Helfer wird eine HTML
            Antwort erstellen die mit Ajax.Autocompleter kompatibel ist.
        </para>
    </sect4>
</sect3>
<!--
vim:se ts=4 sw=4 et:
-->