<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 22745 -->
<!-- Reviewed: no -->
<sect1 id="zend.tool.extending">
    <title>Zend_Tool erweitern</title>

    <sect2 id="zend.tool.extending.overview">
        <title>Übersicht über Zend_Tool</title>

        <para>
            <classname>Zend_Tool_Framework</classname> ist ein Framework für die Bereitstellung
            gemeinsamer Funktionalitäten wie die Erstellung von Projekthüllen, Code Erzeugung,
            Erstellung von Suchindezes, und noch mehr. Funktionalitäten können geschrieben und über
            <acronym>PHP</acronym> Klassen in den <acronym>PHP</acronym>
            <property>include_path</property> geworfen werden, was eine immense Flexibilität der
            Implementation liefert. Die Funktionalität kann dann verwendet werden indem eine
            Implementation geschrieben wird oder durch protokoll-spezifische Clients -- wie Konsolen
            Clients, <acronym>XML-RPC</acronym>, <acronym>SOAP</acronym>, und andere.
        </para>

        <para>
            <classname>Zend_Tool_Project</classname> baut auf die Möglichkeiten von
            <classname>Zend_Tool_Framework</classname> auf und erweitert diese um ein "Projekt" zu
            managen. Generell ist ein "Projekt" ein geplantes Ereignis oder eine Initiative. In der
            Computerwelt sind Projekte generell Sammlungen von Ressourcen. Diese Ressourcen können
            Dateien, Verzeichnisse, Datenbanken, Schematas, Bilder, Stile und anderes sein.
        </para>
    </sect2>

    <sect2 id="zend.tool.extending.zend-tool-framework">
        <title>Erweiterungen von Zend_Tool_Framework</title>

        <sect3 id="zend.tool.extending.zend-tool-framework.architecture">
            <title>Überblick der Architektur</title>

            <para>
                <classname>Zend_Tool_Framework</classname> bietet das folgende:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        <emphasis>Gemeinsame Interfaces und Abstraktes</emphasis> welche es
                        Entwicklern erlauben Funktionalitäten und Möglichkeiten zu erstellen welche
                        durch Tooling Clients verwendbar sind.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Grundsätzliche Client Funktionalität</emphasis> und eine konkrete
                        Konsolenimplementation welche externe Tools und Interfaces mit
                        <classname>Zend_Tool_Framework</classname> verbindet. Der Konsolenclient
                        kann in <acronym>CLI</acronym> Umgebungen verwendet werden, wie Unix Shells
                        und der Windows Konsole.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>"Provider" und "Manifest" Interfaces</emphasis> welche vom
                        Toolingsystem verwendet werden können. "Provider" repräsentieren den
                        funktionalen Aspekt des Frameworks, und definieren die Aktionen welche
                        Tooling Clients aufrufen können. "Manifests" agieren als Metadaten
                        Registrierungen welche zusätzlichen Kontext für die verschiedenen
                        definierten Provider bieten.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Ein introspektives Ladesystem</emphasis> welches die Umgebung auf
                        Provider scannt und erkennt was benötigt wird um Sie auszuführen.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Ein Standardset von System Provider</emphasis> welche dem System
                        erlauben zu melden was die kompletten Möglichkeiten des Systems sind, und
                        ein nützliches Feedback bieten. Das beinhaltet auch ein ausführliches
                        "Hilfe System".
                    </para>
                </listitem>
            </itemizedlist>

            <para>
                Definitionen welche man in diesem Handbuch in Bezug auf
                <classname>Zend_Tool_Framework</classname> beachten sollte sind:
            </para>

            <itemizedlist>

                <listitem>
                    <para>
                        <classname>Zend_Tool_Framework</classname> - Der Framework welche die
                        Tooling Möglichkeiten bereitstellt.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Tooling Client</emphasis> - Ein Entwickler-Tool welches sich zum
                        <classname>Zend_Tool_Framework</classname> verbindet und Ihn verwendet.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Client</emphasis> - Das Subsystem von
                        <classname>Zend_Tool_Framework</classname> welches ein Interface
                        bereitstellt so das sich Tooling-Clienten verbinden, und Kommandos abfragen
                        und ausführen können.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Konsolen Client / Kommandozeilen Interface /
                        <filename>zf.php</filename></emphasis> - Der Tooling Client für die
                        Kommandozeile.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Provider</emphasis> - Ein Subsystem und eine Sammlung von
                        eingebauten Funktionalitäten welche der Framework exportiert.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <emphasis>Manifest</emphasis> - Ein Subsystem für die Definition,
                        Organisation, und Verbreitung von Daten welche Provider benötigen.
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <classname>Zend_Tool_Project</classname> Provider - Ein Set von Providern
                        speziell für die Erstellung und die Wartung von Zend Framework basierenden
                        Projekten.
                    </para>
                </listitem>
            </itemizedlist>
        </sect3>

        <sect3 id="zend.tool.extending.zend-tool-framework.cli-client">
            <title>Verstehen des CLI Clients</title>

            <para>
                Das <acronym>CLI</acronym>, oder Kommandozeilen-Tool (intern als das Konsolen-Tool
                bekannt) ist aktuell das primäre Interface für die Bearbeitung von
                <classname>Zend_Tool</classname> Anfragen. Mit dem <acronym>CLI</acronym> Tool
                können Entwickler Tooling-Anfragen im "Kommandozeilen-Fenster" behandeln,
                üblicherweise auch als "Terminal" Fenster bekannt. Diese Umgebung ist in einer *nix
                Umgebung vorherrschend, hat aber auch eine übliche Implementation in Windows mit
                <filename>cmd.exe</filename>, Console2 und mit dem Cygwin Projekt.
            </para>

            <sect4 id="zend.tool.extending.zend-tool-framework.cli-client.setup-general">
                <title>Das CLI Tool vorbereiten</title>

                <para>
                    Um Tooling-Anfragen über den Kommandozeilen-Client auszuführen, muss man zuerst
                    den Client vorbereiten so dass das System den "zf" Befehl ausführen kann. Der
                    Kommandozeilen-Client ist, für alle Wünsche und Zwecke, die Datei
                    <filename>.sh</filename> oder <filename>.bat</filename> welche mit der Zend
                    Framework Distribution bereitgestellt wird. Im Trunk kann er hier gefunden
                    werden: <ulink
                        url="http://framework.zend.com/svn/framework/standard/trunk/bin/">http://framework.zend.com/svn/framework/standard/trunk/bin/</ulink>.
                </para>

                <para>
                    Wie man sehen kann, gibt es 3 Dateien im <filename>/bin/</filename> Verzeichnis:
                    <filename>zf.php</filename>, <filename>zf.sh</filename>, und
                    <filename>zf.bat</filename>. <filename>zf.sh</filename> und
                    <filename>zf.bat</filename> sind Betriebssystem-spezifische Client-Wrapper:
                    <filename>zf.sh</filename> für die *nix Umgebung, und
                    <filename>zf.bat</filename> für die Win32 Umgebung. Diese Client-Wrapper sind
                    für das Finden der richtigen <filename>php.exe</filename>, das finden der
                    <filename>zf.php</filename>, und die Übergabe an die Anfrage des Clients
                    zuständig. Die <filename>zf.php</filename> ist verantwortlich für die
                    Behandlung der Umgebung, die Erstellung des richtigen include_path, und der
                    Übergabe von dem was auf der Kommandozeile angegeben wurde an die richtige
                    Bibliothekskomponente für die Bearbeitung.
                </para>

                <para>
                    Ultimativ, muss man zwei Dinge sicherstellen damit alles funktioniert,
                    unabhängig vom Betriebssystem auf dem man arbeitet:
                </para>

                <orderedlist>
                    <listitem>
                        <para>
                            <filename>zf.sh/zf.bat</filename> ist vom Systempfad aus erreichbar.
                            Das ist die Fähigkeit <command>zf</command> von überall aus aufzurufen,
                            unabhängig von aktuellen Arbeitsverzeichnisses.
                        </para>
                    </listitem>

                    <listitem>
                        <para>
                            <filename>ZendFramework/library</filename> ist im
                            <property>include_path</property>.
                        </para>
                    </listitem>
                </orderedlist>

                <note>
                    <para>
                        Zu beachten: Wärend das oben stehende sind die idealsten Notwendigkeiten
                        sind, kann man einfach Zend Framework herunterladen und erwarten das es
                        mit <filename>./path/to/zf.php</filename> und einem Kommando funktioniert.
                    </para>
                </note>
            </sect4>

            <sect4 id="zend.tool.extending.zend-tool-framework.cli-client.setup-starnix">
                <title>Das CLI Tool auf Unix-artigen Systemen einrichten</title>

                <para>
                    Das üblichste Setup in einer *nix Umgebung ist es, <filename>zf.sh</filename>
                    und <filename>zf.sh</filename> in das selbe Verzeichnis wie die
                    <acronym>PHP</acronym> Installation zu kopieren. Diese kann normalerweise in
                    einem der folgenden Plätze gefunden werden:
                </para>

                <programlisting language="text"><![CDATA[
/usr/bin
/usr/local/bin
/usr/local/ZendServer/bin/
/Applications/ZendServer/bin/
]]></programlisting>

                <para>
                    Um den Ort der eigenen <acronym>PHP</acronym> Installation zu finden kann man
                    'which php' auf der Kommandozeile ausführen. Das gibt den Ort der
                    <acronym>PHP</acronym> Installation zurück welche verwendet wird um in dieser
                    Umgebung <acronym>PHP</acronym> Skripte auszuführen.
                </para>

                <para>
                    Der nächste Schritt ist es sicherzustellen das die Zend Framework Bibliothek
                    korrekt im <acronym>PHP</acronym> <property>include_path</property> eingestellt
                    wurde. Um herauszufinden wo der <property>include_path</property> ist, kann man
                    <command>php -i</command> ausführen und nach der
                    <property>include_path</property> Variable sehen, oder kompakter
                    <command>php -i | grep include_path</command> ausführen. Sobald man
                    herausgefunden hat wo der <property>include_path</property> ist (er ist
                    normalerweise etwas wie <filename>/usr/lib/php</filename>,
                    <filename>/usr/share/php</filename>, <filename>/usr/local/lib/php</filename>,
                    oder so ähnlich), sollte man sicherstellen das der Inhalt des Verzeichnisses
                    <filename>/library/</filename> in einem der in <property>include_path</property>
                    spezifizierten Verzeichnisse ist.
                </para>

                <para>
                    Sobald man diese zwei Dinge getan hat, sollte man in der Lage sein ein Kommando
                    auszuführen und die richtige Antwort zurück zu erhalten, wie zum Beispiel:
                </para>

                <para>
                    <inlinegraphic scale="100" align="center" valign="middle"
                        fileref="figures/zend.tool.framework.cliversionunix.png" format="PNG" />
                </para>

                <para>
                    Wenn man diese Art der Ausgabe nicht sieht, sollte man zurückgeben und die
                    eigenen Einstellungen prüfen um sicherzustellen das man alle notwendigen Teile
                    am richtigen Ort vorhanden sind.
                </para>

                <para>
                    Es gibt eine Anzahl an alternativen Einstellungen die man erstellen kann,
                    abhängig von der Konfiguration des Servers, dem Zugriffslevel, oder aus anderen
                    Gründen.
                </para>

                <para>
                    Das <emphasis>alternative Setup</emphasis> enthält das man den Download vom Zend
                    Framework zusammenbehält wie er ist, und einen Link von einem
                    <constant>PATH</constant> Ort zur <filename>zf.sh</filename> erstellt. Was dies
                    bedeutet ist, dass man den Inhalt des Zend Framework Downloads in einem Ort wie
                    <filename>/usr/local/share/ZendFramework</filename> platzieren kann, oder
                    lokaler unter <filename>/home/username/lib/ZendFramework</filename> und einen
                    symbolischen Link zu <filename>zf.sh</filename> erstellt.
                </para>

                <para>
                    Angenommen man will den Link in <filename>/usr/local/bin</filename> platzieren
                    (dies könnte zum Beispiel auch für die Platzierung des Links unter
                    <filename>/home/username/bin/</filename> funktionieren), dan würde man ein
                    Kommando wie das folgende platzieren:
                </para>

                <programlisting language="sh"><![CDATA[
ln -s /usr/local/share/ZendFramework/bin/zf.sh /usr/local/bin/zf

# ODER (zum Beispiel)
ln -s /home/username/lib/ZendFramework/bin/zf.sh /home/username/bin/zf
]]></programlisting>

                <para>
                    Das erstellt einen Link auf den man global von der Kommandozeile aus zugreifen
                    kann.
                </para>
            </sect4>

            <sect4 id="zend.tool.extending.zend-tool-framework.cli-client.setup-windows">
                <title>Das CLI Tool unter Windows einrichten</title>

                <para>
                    Das üblichste Setup in einer Windows Win32 Umgebung ist es
                    <filename>zf.bat</filename> und <filename>zf.php</filename> in das selbe
                    Verzeichnis wie die <acronym>PHP</acronym> Bibliothek zu kopieren. Diese kann
                    generell an einem der folgenden Plätze gefunden werden:
                </para>

                <programlisting language="text"><![CDATA[
C:\PHP
C:\Program Files\ZendServer\bin\
C:\WAMP\PHP\bin
]]></programlisting>

                <para>
                    Man sollte in der Lage sein <filename>php.exe</filename> von der Kommandozeile
                    aus auszuführen. Wenn man dazu nicht in der Lage ist, sollte man zuerst die
                    Dokumentation prüfen welche mit der <acronym>PHP</acronym> Bibliothek
                    mitgeliefert wird, um sicherzustellen dass der Pfad zu
                    <filename>php.exe</filename> in der Windows Umgebungsvariable
                    <constant>PATH</constant> zu finden ist.
                </para>

                <para>
                    Der nächste Schritt besteht darin sicherzustellen das die Zend Framework
                    Bibliothek richtig auf dem <acronym>PHP</acronym>
                    <property>include_path</property> des Systems eingerichtet ist. Um
                    herauszufinden wo der <property>include_path</property> ist, kann man
                    <command>php -i</command> eingeben und nach der Variable
                    <property>include_path</property> sehen, oder kompakter
                    <command>php -i | grep include_path</command> ausführen wenn man ein Cygwin
                    Setup mit vorhandenem grep hat. Sobald man herausgefunden hat wo der
                    <property>include_path</property> liegt (das ist normalerweise etwas wie
                    <filename>C:\PHP\pear</filename>, <filename>C:\PHP\share</filename>,
                    <filename>C:\Program%20Files\ZendServer\share</filename>, oder ähnlich), sollte
                    man sicherstellen das der Inhalt des Verzeichnisses library/ in einem vom
                    <property>include_path</property> spezifizierten Verzeichnis ist.
                </para>

                <para>
                    Sobald man diese zwei Dinge getan hat, sollte man in der Lage sein ein Kommando
                    auszuführen und die richtige Antwort, so ähnlich wie die folgende, zu erhalten:
                </para>

                <para>
                    <inlinegraphic scale="100" align="center" valign="middle"
                        fileref="figures/zend.tool.framework.cliversionwin32.png" format="PNG" />
                </para>

                <para>
                    Wenn man diese Art der Ausgabe nicht sieht, sollte man zurückgehen und die
                    Einstellungen prüfen um sicherzustellen das man alle notwendigen Teile an den
                    richtigen Orten hat.
                </para>

                <para>
                    Es gibt eine Anzahl an alternativen Einstellungen die man erstellen kann,
                    abhängig von der Konfiguration des Servers, dem Zugriffslevel, oder aus anderen
                    Gründen.
                </para>

                <para>
                    Das <emphasis>alternative Setup</emphasis> enthält das man den Download vom Zend
                    Framework zusammenbehält wie er ist, und sowohl den System
                    <constant>PATH</constant>, als auch die <filename>php.ini</filename> Datei
                    verändert. In der Umgebung des Benutzers muss man
                    <filename>C:\Path\To\ZendFramework\bin</filename> hinzufügen damit die Datei
                    <filename>zf.bat</filename> ausführbar ist. Auch die Datei
                    <filename>php.ini</filename> ist zu verändern um sicherzustellen das
                    <filename>C:\Path\To\ZendFramework\library</filename> im
                    <property>include_path</property> liegt.
                </para>
            </sect4>

            <sect4 id="zend.tool.extending.zend-tool-framework.cli-client.setup-othernotes">
                <title>Andere Einstellungs-Möglichkeiten</title>

                <para>
                    Wenn man aus bestimmten Gründen die Zend Framework Bibliothek nicht im
                    <property>include_path</property> haben will, gibt es andere Optionen. Es gibt
                    zwei spezielle Umgebungsvariablen welche <filename>zf.php</filename> verwendet
                    um den Ort der Zend Framework Installation zu erkennen.
                </para>

                <para>
                    Die erste ist <constant>ZEND_TOOL_INCLUDE_PATH_PREPEND</constant>, welche den
                    Wert der Umgebungsvariable dem <property>include_path</property> des Systems
                    (<filename>php.ini</filename>) voranstellt bevor der Client geladen wird.
                </para>

                <para>
                    Alternativ kann man <constant>ZEND_TOOL_INCLUDE_PATH</constant> verwenden um den
                    <property>include_path</property> des System komplett zu
                    <emphasis>ersetzen</emphasis> für jene bei denen es Sinn macht, speziell für das
                    <command>zf</command> Kommandozeilen-Tool.
                </para>
            </sect4>
        </sect3>

        <sect3 id="zend.tool.extending.zend-tool-framework.providers-and-manifests">
            <title>Erstellen von Providern</title>

            <para>
                Generell, ist ein Provider für sich selbst gesehen, nichts weiter als eine Shell für
                einen Entwickler um einige Möglichkeiten zu bündeln welche er mit den Kommandozeilen
                (oder anderen) Clients ausführen will. Das ist eine Analogie für das was der
                "Controller" in der <acronym>MVC</acronym> Anwendung ist.
            </para>

            <sect4 id="zend.tool.extending.zend-tool-framework.providers-and-manifests.loading">
                <title>Wie Zend_Tool eigene Provider findet</title>

                <para>
                    Standardmäßig verwendet <classname>Zend_Tool</classname> den BasicLoader um alle
                    Provider zu finden die es ausführen kann. Er durchsucht alle Verzeichnisse des
                    Include Pfades rekursiv und öffnet alle Dateien welche mit "Manifest.php" oder
                    "Provider.php" enden. Alle Klassen in diesen Dateien werden darauf durchsucht ob
                    Sie entweder <classname>Zend_Tool_Framework_Provider_Interface</classname> oder
                    <classname>Zend_Tool_Framework_Manifest_ProviderManifestable</classname>
                    implementieren. Instanzen des Provider Interfaces sind für die echte
                    Funktionalität zuständig und alle Ihre öffentlichen Methoden kann als Provider
                    Aktionen zugegriffen werden. Das ProviderManifestable Interface benötigt
                    trotzdem die Implementation einer <methodname>getProviders()</methodname>
                    Methode welche ein Array an instanzierten Provider Interface Instanzen
                    zurückgibt.
                </para>

                <para>
                    Die folgenden Namensregeln sind darauf anzuwenden, wie man auf die Provider
                    zugreifen kann welche vom IncludePathLoader gefunden werden:
                </para>

                <itemizedlist>
                    <listitem>
                        <para>
                            Der letzte Teil des eigenen Klassennamens welcher von einem Unterstrich
                            getrennt ist, wird für den Providernamen verwendet, zum Beispiel führt
                            "My_Provider_Hello" zum Provider auf welchen mit dem Namen "hello"
                            zugegriffen werden kann.
                        </para>
                    </listitem>

                    <listitem>
                        <para>
                            Wenn der Provider eine Methode <methodname>getName()</methodname> hat,
                            dann wird diese verwendet statt der vorherigen Methode um den Namen zu
                            erkennen.
                        </para>
                    </listitem>

                    <listitem>
                        <para>
                            Wenn der Provider den Präfix "Provider" hat, zum Beispiel wenn er
                            <classname>My_HelloProvider</classname> heißt, dann wird er vom Namen
                            entfernt so dass der Provider "hello" heißt.
                        </para>
                    </listitem>
                </itemizedlist>

                <note>
                    <para>
                        Der IncludePathLoader folgt Symlinks nicht, was bedeutet das man Provider
                        Funktionalitäten nicht in den Include Pfaden verlinken kann, sondern dass
                        Sie physikalisch in den Include Pfaden vorhanden sein müssen.
                    </para>
                </note>

                <example
                    id="zend.tool.extending.zend-tool-framework.providers-and-manifests.loading.example">
                    <title>Provider mit einem Manifest bekanntmachen</title>

                    <para>
                        Man kann eigene Provider bei <classname>Zend_Tool</classname> bekannt machen
                        indem man ein Manifest anbietet, mit einer speziellen Endung des Dateinamens
                        von "Manifest.php". Ein Provider-Manifest ist eine Implementation von
                        <interface>Zend_Tool_Framework_Manifest_ProviderManifestable</interface> und
                        benötigt die <methodname>getProviders()</methodname> Methode um ein Array
                        von instanziierten Providern zurückzugeben. Anders als unser erster eigener
                        Provider <classname>My_Component_HelloProvider</classname> erstellen wir das
                        folgende Manifest:
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_Manifest
    implements Zend_Tool_Framework_Manifest_ProviderManifestable
{
    public function getProviders()
    {
        return array(
            new My_Component_HelloProvider()
        );
    }
}
]]></programlisting>
                </example>
            </sect4>

            <sect4 id="zend.tool.extending.zend-tool-framework.providers-and-manifests.basic">
                <title>Grundsätzliche Instruktionen für die Erstellung von Providern</title>

                <para>
                    Wenn, als Beispiel, ein Entwickler die Fähigkeit, eine Version einer Datendatei
                    anzuzeigen, hinzufügen will mit der seine 3rd Party Komponente arbeitet, gibt es
                    nur eine Klasse welche der Entwickler implementieren muss. Angenommen die
                    Komponente wird <classname>My_Component</classname> genannt, dann würde er eine
                    Klasse erstellen welche <classname>My_Component_HelloProvider</classname> heißt
                    in einer Datei wleche <filename>HelloProvider.php</filename> genannt ist und
                    irgendwo in seinem <property>include_path</property> liegt. Diese Klasse würde
                    <classname>Zend_Tool_Framework_Provider_Interface</classname> implementieren und
                    diese Datei würde etwa wie folgt auszusehen haben:
                </para>

                <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    implements Zend_Tool_Framework_Provider_Interface
{
    public function say()
    {
        echo 'Hallo von meinem Provider!';
    }
}
]]></programlisting>

                <para>
                    Bei dem obigen Code und der Annahme das der Entwickler Zugriff auf diese
                    Funktionalität über den Konsolen-Client haben will, würde der Aufruf wie folgt
                    aussehen:
                </para>

                <programlisting language="sh"><![CDATA[
% zf say hello
Hallo von meinem Provider!
]]></programlisting>
            </sect4>

            <sect4 id="zend.tool.extending.zend-tool-framework.providers-and-manifests.response">
                <title>Das Antwort-Objekt</title>

                <para>
                    Wie im Architektur-Abschnitt diskutiert erlaubt es
                    <classname>Zend_Tool</classname> andere Clients für die Verwendung eigener
                    <classname>Zend_Tool</classname> Provider zu verknüpfen. Um den
                    unterschiedlichen Clients zu entsprechen sollte man das Antwort-Objekt verwenden
                    um Rückgabe-Meldungen von Providern zurückzugeben anstatt
                    <methodname>echo()</methodname> oder ähnliche Ausgabe-Mechanismen zu verwenden.
                    Nach dem Umschreiben des Hello-Providers mit diesen Erkenntnissen sieht er wie
                    folgt aus:
                </para>

                <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say()
    {
        $this->_registry->getResponse
                        ->appendContent("Hallo von meinem Provider!");
    }
}
]]></programlisting>

                <para>
                    Wie man sieht muss <classname>Zend_Tool_Framework_Provider_Abstract</classname>
                    erweitert werden um Zugriff auf die Registry zu erhalten welche die
                    <classname>Zend_Tool_Framework_Client_Response</classname> Instanz enthält.
                </para>
            </sect4>

            <sect4 id="zend.tool.extending.zend-tool-framework.providers-and-manifests.advanced">
                <title>Fortgeschrittene Informationen für die Entwicklung</title>

                <sect5
                    id="zend.tool.extending.zend-tool-framework.providers-and-manifests.advanced.variables">
                    <title>Variablen an einen Provider übergeben</title>

                    <para>
                        Das obige "Hello World" Beispiel ist großartig für einfache Befehle, aber
                        was ist mit etwas komplizierterem? Wenn die eigenen Skripting- und
                        Tooling-Bedürfnisse wachsen kann man die Notwendigkeit sehen dass man
                        Variablen akzeptiert. So wie Funktions-Signaturen Parameter haben, so können
                        eigene Tooling-Anfragen auch Parmeter akzeptieren.
                    </para>

                    <para>
                        So wie jede Tooling-Anfrage isoliert von einer Methode in einer Klasse sein
                        kann, können auch die Parameter einer Tooling-Anfrage in einem sehr
                        bekanntem Platz isoliert sein. Parameter einer Aktions-Methode eines
                        Providers können die selben Parameter enthalten welche der eigene Client
                        verwenden soll wenn diese Provider und Aktions-Methode aufgerufen wird.
                        Wenn man zum Beispiel einen Namen im oben stehenden Beispiel akzeptieren
                        will, würde man möglicherweise folgendes in OO Code machen:
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    implements Zend_Tool_Framework_Provider_Interface
{
    public function say($name = 'Ralph')
    {
        echo 'Hallo' . $name . ', von meinem Provider!';
    }
}
]]></programlisting>

                    <para>
                        Das obige Beispiel kann dann über die Kommandozeile
                        <command>zf say hello Joe</command> aufgerufen werden. "Joe" wird dem
                        Provider bereitgestellt so wie ein Parameter eines Methodenaufrufs. Es ist
                        auch zu beachten das der Parameter optional ist, was bedeutet das er auch
                        in der Kommandozeile optional ist, so dass
                        <command>zf say hello</command> trotzdem noch funktioniert, und auf den
                        Standardwert "Ralph" zeigt.
                    </para>
                </sect5>

                <sect5
                    id="zend.tool.extending.zend-tool-framework.providers-and-manifests.advanced.prompt">
                    <title>Den Benutzer nach einer Eingabe fragen</title>

                    <para>
                        Es gibt Fälle in denen der Workflow des eigenen Providers es notwendig macht
                        den Benutzer nach einer Eingabe zu fragen. Dies kann getan werden indem der
                        Client nach einer zusätzlich benötigten Eingabe gefragt wird indem folgendes
                        aufgerufen wird:
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say($name = 'Ralph')
    {
        $nameResponse = $this->_registry
                             ->getClient()
                             ->promptInteractiveInput("Wie ist dein Name?");
        $name = $name->getContent();

        echo 'Hallo' . $name . ', von meinem Provider!';
    }
}
]]></programlisting>

                    <para>
                        Dieses Kommando wirft eine Ausnahme wenn der aktuelle Client nicht in der
                        Lage ist interaktive Anfragen zu behandeln. Im Falle des standardmäßigen
                        Konsolen-Clients wird man aber danach gefragt den Namen einzugeben.
                    </para>
                </sect5>

                <sect5
                    id="zend.tool.extending.zend-tool-framework.providers-and-manifests.advanced.pretendable">
                    <title>Die Ausführung einer Provider-Aktion vorbereiten</title>

                    <para>
                        Ein anderes interessantes Feature das man möglicherweise implementieren will
                        ist die <emphasis>Vorbereitung</emphasis>. Vorbereitung ist die Fähigkeit
                        des eigenen Providers sich "vorzubereiten", wie wenn er die angefragte
                        Kombination von Aktion und Provider  durchführt und dem Benutzer so viele
                        Informationen wie möglich darüber zu geben was er tun
                        <emphasis>würde</emphasis> ohne es wirklich zu tun. Das kann ein wichtiger
                        Hinweis sein wenn große Änderungen in der Datenbank oder auf dem Dateisystem
                        durchgeführt werden welche der Benutzer andernfalls nicht durchführen wollen
                        würde.
                    </para>

                    <para>
                        Voranstellbarkeit ist einfach zu implementieren. Es gibt zwei Teile zu
                        diesem Feature: 1) Den Provider markieren, das er die Fähigkeit hat
                        "vorzubereiten", und 2) die Anfrage prüfen und sicherstellen das die
                        aktuelle Anfrage wirklich als "vorzubereiten" angefragt wurde. Dieses
                        Feature wird im folgenden Code-Beispiel demonstriert.
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    extends    Zend_Tool_Framework_Provider_Abstract
    implements Zend_Tool_Framework_Provider_Pretendable
{
    public function say($name = 'Ralph')
    {
        if ($this->_registry->getRequest()->isPretend()) {
            echo 'Ich würde Hallo zu ' . $name . ' sagen.';
        } else {
            echo 'Hallo' . $name . ', von meinem Provider!';
        }
    }
}
]]></programlisting>

                    <para>
                        Um den Provider im vorbereiteten Modus auszuführen muss nur folgendes
                        aufgerufen werden:
                    </para>

                    <programlisting language="sh"><![CDATA[
% zf --pretend say hello Ralph
Ich würde Hallo zu Ralph sagen.
]]></programlisting>
                </sect5>

                <sect5
                    id="zend.tool.extending.zend-tool-framework.providers-and-manifests.advanced.verbosedebug">
                    <title>Verbose und Debug Modi</title>

                    <para>
                        Man kann Provider Aktionen auch in den Modi "verbose" oder "debug" laufen
                        lassen. Die Semantik bezüglich dieser Aktionen muss man im Kontext des
                        Providers implementieren. Man kann auf die Modi Debug oder Verbose wie
                        folgt zugreifen:
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    implements Zend_Tool_Framework_Provider_Interface
{
    public function say($name = 'Ralph')
    {
        if($this->_registry->getRequest()->isVerbose()) {
            echo "Hello::say wurde aufgerufen\n";
        }
        if($this->_registry->getRequest()->isDebug()) {
            syslog(LOG_INFO, "Hello::say wurde aufgerufen\n");
        }
    }
}
]]></programlisting>
                </sect5>

                <sect5
                    id="zend.tool.extending.zend-tool-framework.providers-and-manifests.advanced.configstorage">
                    <title>Auf die Benutzerkonfiguration und den Speicher zugreifen</title>

                    <para>
                        Bei Verwendung der Umgebungsvariable <property>ZF_CONFIG_FILE</property>
                        oder von .zf.ini im Heimverzeichnis können Konfigurationsparameter in jeden
                        <classname>Zend_Tool</classname> Provider eingefügt werden. Der Zugriff auf
                        diese Konfiguration ist über die Registry möglich welche dem Provider
                        übergeben wird wenn man
                        <classname>Zend_Tool_Framework_Provider_Abstract</classname> erweitert.
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say()
    {
        $username = $this->_registry->getConfig()->username;
        if(!empty($username)) {
            echo "Hallo $username!";
        } else {
            echo "Hallo!";
        }
    }
}
]]></programlisting>

                    <para>
                        Die zurückgegebene Konfiguration ist vom Typ
                        <classname>Zend_Tool_Framework_Client_Config</classname> allerdings
                        verweisen die magischen Methoden <methodname>__get()</methodname> und
                        <methodname>__set()</methodname> intern auf eine
                        <classname>Zend_Config</classname> oder den angegebenen Konfigurationstyp.
                    </para>

                    <para>
                        Der Speicher erlaubt es notwendige Daten für eine spätere Referenz zu
                        speichern. Das kann für Aufgaben bei der Ausführung von Batches nützlich
                        sein oder für das wiederausführen von Aufgaben. Man kann auf den Speicher
                        auf dem gleichen Weg zugreifen wie auf die Konfiguration:
                    </para>

                    <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    extends Zend_Tool_Framework_Provider_Abstract
{
    public function say()
    {
        $aValue = $this->_registry->getStorage()->get("myUsername");
        echo "Hallo $aValue!";
    }
}
]]></programlisting>

                    <para>
                        Die <acronym>API</acronym> des Speichers ist sehr einfach:
                    </para>

                    <programlisting language="php"><![CDATA[
class Zend_Tool_Framework_Client_Storage
{
    public function setAdapter($adapter);
    public function isEnabled();
    public function put($name, $value);
    public function get($name, $defaultValue=null);
    public function has($name);
    public function remove($name);
    public function getStreamUri($name);
}
]]></programlisting>

                    <important>
                        <para>
                            Wenn man Provider erstellt welche Konfigurations-fähig oder
                            Speicher-fähig sind muss man daran denken dass man prüfen muss ob die
                            notwendigen Benutzerkonfigurations- oder Speicher-Schlüssel wirklich
                            für diesen Benutzer existieren. Man wird keine fatalen Fehler erhalten
                            wenn keiner von Ihnen angegeben wurde, da leere Schlüssel bei der
                            Anfrage erstellt werden.
                        </para>
                    </important>
                </sect5>
            </sect4>
        </sect3>
    </sect2>

    <sect2 id="zend.tool.extending.zend-tool-project">
        <title>Zend_Tool_Project Erweiterungen</title>

        <para>
            <classname>Zend_Tool_Project</classname> bietet ein reiches Set an Funktionalitäten
            und Möglichkeiten welche die Aufgabe der Erstellung neuer Provider, speziell jener
            welche auf ein Projekt abzielen, einfacher und besser managebar.
        </para>

        <sect3 id="zend.tool.extending.zend-tool-project.architecture">
            <title>Architektur-Übersicht</title>

            <para>
                Das selbe Konzept gilt auch für Zend Framework Projekte. In Zend Framework Projekten
                hat man Controller, Aktionen, Views, Modelle, Datenbanken und so weiter. Im Sinn
                von <classname>Zend_Tool</classname> benötigen wir einen Weg um diese Arten von
                Ressourcen zu verfolgen -- deshalb <classname>Zend_Tool_Project</classname>.
            </para>

            <para>
                <classname>Zend_Tool_Project</classname> ist in der Lage Projektressourcen während
                der Entwicklung eines Projekts zu verfolgen. Wenn man, zum Beispiel, in einem
                Kommando einen Controller erstellt, und im nächsten Kommando eine Aktion in diesem
                Controller erstellen will, muss <classname>Zend_Tool_Project</classname> über die
                Controllerdatei bescheid <emphasis>wissen</emphasis> die man erstellt hat, damit
                man (in der nächsten Aktion) in der Lage ist diese Aktion daran anzuhängen. Das ist
                was das Projekt aktuell hält und <emphasis>zustandsbehaftet</emphasis>.
            </para>

            <para>
                Ein andere wichtiger Punkt den man über Projekte verstehen sollte ist, dass
                Ressourcen typischerweise in einer hierarchischen Art orgainisiert sind. Dies zu
                wissen bedeutet das <classname>Zend_Tool_Project</classname> in der Lage ist das
                aktuelle Projekt in eine interne Repräsentation zu serialisieren welche es erlaubt
                nicht nur jederzeit festzustellen <emphasis>welche</emphasis> Ressourcen Teil eines
                Projekts sind, sondern auch <emphasis>wo</emphasis> Sie in Relation zu anderen
                stehen.
            </para>
        </sect3>

        <sect3 id="zend.tool.extending.zend-tool-project.providers">
            <title>Provider erstellen</title>

            <para>
                Projektspezifische Provider werden auf dem selben Weg erstellt wie reine Framework
                Provider, mit einer Ausnahme: Projektprovider müssen
                <classname>Zend_Tool_Project_Provider_Abstract</classname> erweitern. Diese Klasse
                kommt mit einigen signifikanten Funktionalitäten welche Entwicklern helfen
                existierende Projekte zu laden, das Profilobjekt zu erhalten, und in der Lage zu
                sein das Profil zu suchen, und später dann alle Änderungen im aktuellen
                Projektprofil zu speichern.
            </para>

            <programlisting language="php"><![CDATA[
class My_Component_HelloProvider
    extends Zend_Tool_Project_Provider_Abstract
{
    public function say()
    {
        $profile = $this->_loadExistingProfile();

        /* ... Projektarbeiten hier durchführen */

        $this->_storeProfile();
    }
}
]]></programlisting>
        </sect3>

        <!--
        <sect3 id="zend.tool.extending.zend-tool-project.resources-and-contexts">
            <title>Creating Resources &amp; Contexts</title>

        </sect3>
        -->
    </sect2>
</sect1>
