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

    <para>
        Viele <acronym>AJAX</acronym> Javascript Bibliotheken bieten Funktionalitäten an für eine
        automatische Vervollständigung wobei eine Auswahlliste von potentiell passenden Ergebnissen
        angezeigt wird während der Benutzer tippt. Der <emphasis>AutoComplete</emphasis> 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 <emphasis>AutoComplete</emphasis> Helfer einige grundsätzliche
        abstrakte Funktionalitäten zu vielen Bibliotheken und konkrete Implementierungen für
        individuelle Bibliotheken. Zurückgegebene Typen sind generell entweder
        <acronym>JSON</acronym> Arrays von Strings, <acronym>JSON</acronym> Arrays von Arrays (mit
        jedem Mitgliedsarray das ein assoziatives Array von Metadaten ist, das verwendet wird um
        die Auswahlliste zu erstellen), oder <acronym>HTML</acronym>.
    </para>

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

    <programlisting language="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 oder 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>
                <methodname>disableLayouts()</methodname> kann verwendet werden um Layouts und den
                ViewRenderer auszuschalten. Typischerweise wird das innerhalb von
                <methodname>prepareAutoCompletion()</methodname> aufgerufen.
            </para>
        </listitem>

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

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

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

    <para>
        Aktuell unterstützt <emphasis>AutoComplete</emphasis> die folgenden Dojo und Scriptaculous
        <acronym>AJAX</acronym> 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/reference-guide/dojo/data.html">dojo.data</ulink>
            Dokumentation.
        </para>

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

        <programlisting language="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 <acronym>MVC</acronym>, benötigt verschiedene
                Dinge: Erstellung eines Form Objekts für die Kombobox bei der man AutoCompletion
                will, eine Controller 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 <acronym>OOP</acronym> Javascript, so wie Zend
                Framework für <acronym>PHP</acronym>. 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, <filename>TestNameReadStore.js</filename>, mit den folgenden
                Inhalten:
             </para>

            <programlisting language="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 language="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 <constant>FALSE</constant> 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 language="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 <methodname>autocompleteAction()</methodname> 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 <methodname>getData()</methodname> 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 language="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 <acronym>HTML</acronym> 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 <acronym>HTML</acronym> Antwort in einem speziellen Format.
        </para>

        <para>
            Der Helfer der mit dieser Bibliothek zu verwenden ist 'AutoCompleteScriptaculous'.
            Es muß einfach ein Array von Daten angegeben werden, und der Helfer wird eine
            <acronym>HTML</acronym> Antwort erstellen die mit Ajax.Autocompleter kompatibel ist.
        </para>
    </sect4>
</sect3>
