# Zend_Feed_Writer

## Einführung

`Zend_Feed_Writer` ist die Bruderkomponente zu `Zend_Feed_Reader` und verantwortlich für die Erzeugung von Feeds für die Ausgabe. Sie unterstützt die Atom 1.0 Spezifikation (RFC 4287) und RSS 2.0 wie vom RSS Advisory Board (RSS 2.0.11) spezifiziert. Es ist kein Nachkomme dieses Standards. Trotzdem bietet es ein einfaches System der Erweiterung welches es erlaubt jede Erweiterung und jedes Modul für jede der zwei Spezifikationen zu implementieren wenn diese nicht von Haus aus angeboten werden.

Auf vielen Wegen ist `Zend_Feed_Writer` das Gegenteil von `Zend_Feed_Reader`. Wobei `Zend_Feed_Reader` darauf fokusiert ist ein einfach zu verwendendes Architektur Frontend durch Getter Methoden anzubieten, und `Zend_Feed_Writer` durch ähnlich benannte Setter oder Mutatoren. Das stellt sicher das die API keine weitere Lernkurve erfordert wenn jemand bereits mit `Zend_Feed_Reader` bekannt ist.

Als Ergebnis dieses Designs, ist der Rest sogar einleuchtend. Dahinter, wird jedes Datenset eines `Zend_Feed_Reader` Objekts wärend der Darstellungszeit in ein DOMDocument Objekt übersetzt indem die notwendigen Feed Elemente verwendet werden. Für jeden unterstützten Feed Typen gibt es beide, sowohl einen Atom 1.0 als auch einen RSS 2.0 Renderer. Die Verwendung von DOMDocument statt einer Template Lösung hat viele Vorteile. Der offensichtlichste ist die Möglichkeit das DOMDocument zu exportieren um es weiter zu bearbeiten und auf PHP DOM für die Korrakturen und richtige Darstellung zu setzen.

Wie bei `Zend_Feed_Reader` ist `Zend_Feed_Writer` ein alleinstehender Ersatz für `Zend_Feed`'s Builder Architektur und nicht kompatibel mit diesen Klassen.

## Architektur

Die Architektur von `Zend_Feed_Writer` ist sehr einfach. Es hat zwei Kernsets von Klassen: Container und Renderer.

Der Container enthält die Klassen `Zend_Feed_Writer_Feed` und `Zend_Feed_Writer_Entry`. Die Einstiegsklassen können bei jeder Feed Klasse angehängt werden. Der einzige Zweck dieses Containers ist es Daten über den zu erstellenden Feed zu sammelnindem ein einfaches Interface von Setter Methoden verwendet wird. Diese Methode führen einige Test zur Datenprüfung durch. Zum Beispiel prüft er übergebene URIs, Datum, usw. Diese Checks sind nicht an einen der Feed Standards gebunden. Das Container Objekt enthält auch Methoden welche die schnelle Darstellung und den Export des endgültigen Feeds erlauben, und Sie können auf Wunsch wiederverwendet werden.

Wärend es zwei Daten Container gibt, gibt es vier Renderer - zwei passende Container Renderer pro unterstütztem Feed Typ. Der Renderer akzeptiert einen Container, und basierend auf seinem Container versucht er einen gültigen Feed zu erstellen. Wenn der Renderer nicht in der Lage ist einen gültigen Feed zu erstellen, möglicherweise weil dem Container ein obligatorischer Datenpunkt fehlt, dann wird er dies melden indem eine `Exception` geworfen wird. Wärend es möglich ist `Exception`s zu ignorieren, würde das diese alle standardmäßigen Sicherheiten entfernen welche sicherstellen das gültige Daten gesetzt wurden um einen komplett gültigen Feed darzustellen.

Da das System in Datencontainer und Renderer geteilt ist, kann es Erweiterungen interessant machen. Eine typische Erweiterung welche namespaced Feeds und Entry Level Elemente bietet, muss selbst exakt die gleiche Atchitektur reflektieren, z.B. anbieten von Feed und Entry Level Daten Containern, und passenden Renderern. Das ist, glücklicherweise, keine komplexe Integrationsarbeit da alle Erweiterungsklassen einfach registriert und automatisch von den Kern Klassen verwendet werden. Wir kommen später in diesem Kapitel im Detail zu den Erweiterungen.

## Beginnen

Die Verwendung von `Zend_Feed_Reader` ist so einfach wie das Setzen von Daten und dem Ausführen des Renderers. Hier ist ein Beispiel um einen minimalen Atom 1.0 Feed zu erstellen.

    /**
     * Den Eltern Feed erstellen
     */
    $feed = new Zend_Feed_Writer_Feed;
    $feed->setTitle('Paddy\'s Blog');
    $feed->setLink('http://www.example.com');
    $feed->setFeedLink('http://www.example.com/atom', 'atom');
    $feed->addAuthor(array(
        'name'  => 'Paddy',
        'email' => 'paddy@example.com',
        'uri'   => 'http://www.example.com',
    ));
    $feed->setDateModified(time());
    $feed->addHub('http://pubsubhubbub.appspot.com/');

    /**
     * Einen oder mehrere Einträge hinzufügen. Beachten das Einträge
     * manuell hinzugefügt werden müssen sobald Sie erstellt wurden
     */
    $entry = $feed->createEntry();
    $entry->setTitle('All Your Base Are Belong To Us');
    $entry->setLink('http://www.example.com/all-your-base-are-belong-to-us');
    $entry->addAuthor(array(
        'name'  => 'Paddy',
        'email' => 'paddy@example.com',
        'uri'   => 'http://www.example.com',
    ));
    $entry->setDateModified(time());
    $entry->setDateCreated(time());
    $entry->setDescription(
        'Die Schwierigkeiten erklären Spiele ins englische zu portieren.'
    );
    $entry->setContent(
        'Ich schreibe diesen Artikel nicht. Das Beispiel ist lang genug ;).');
    $feed->addEntry($entry);

    /**
     * Den ergebenden Feed in Atom 1.0 darstellen und $out zuordnen. Man kann
     * "atom" mit "rss" ersetzen um einen RSS 2.0 feed zu erstellen
     */
    $out = $feed->export('atom');

Die dargestellt Ausgabe sollte folgende sein:

    <?xml version="1.0" encoding="utf-8"?>
    <feed xmlns="http://www.w3.org/2005/Atom">
        <title type="text">Paddy's Blog</title>
        <subtitle type="text">Writing about PC Games since 176 BC.</subtitle>
        <updated>2009-12-14T20:28:18+00:00</updated>
        <generator uri="http://framework.zend.com" version="1.10.0alpha">
            Zend_Feed_Writer
        </generator>
        <link rel="alternate" type="text/html" href="http://www.example.com"/>
        <link rel="self" type="application/atom+xml"
            href="http://www.example.com/atom"/>
        <id>http://www.example.com</id>
        <author>
            <name>Paddy</name>
            <email>paddy@example.com</email>
            <uri>http://www.example.com</uri>
        </author>
        <link rel="hub" href="http://pubsubhubbub.appspot.com/"/>
        <entry>
            <title type="html"><![CDATA[All Your Base Are Belong To Us

                Die Schwierigkeiten erklären Spiele ins englische zu
                         portieren.

            2009-12-14T20:28:18+00:00
            2009-12-14T20:28:18+00:00

            http://www.example.com/all-your-base-are-belong-to-us

                Paddy
                paddy@example.com
                http://www.example.com

                Ich schreibe diesen Artikel nicht.
                         Das Beispiel ist lang genug ;).

    ]]>

Das ist ein perfekt gültiges Beispiel für Atom 1.0. Es sollte erwähnt sein das die Unterdrückung von obligatorischen Datenpunkten, wie dem Titel, eine `Exception` werfen wenn diese als Atom 1.0 dargestellt werden. Das unterscheidet sich für RSS 2.0 wo ein Titel unterdrückt werden kann solange eine Beschreibung vorhanden ist. Dadurch werden Exceptions geworfen die sich zwischen beiden Standards unterscheiden abhängig vom Renderer der Verwendet wird. Vom Design her wird `Zend_Feed_Writer` einen ungültigen Feed für keinen Standard darstellen solange der End-Benutzer nicht definiert das alle Exceptions ignoriert werden sollen.

## Die Datenpunkte eines Feeds setzen

Bevor ein Feed dargestellt werden kann, müssen zuerst die notwendigen Daten, für den Feed der dargestellt werden soll, gesetzt werden. Hierbei wird eine einfache Setter artige API verwendet welche auch als initiale Methode für die Prüfung von Daten herhält wenn diese gesetzt werden. Vom Design her entspricht die API stark der von `Zend_Feed_Reader` um Unklarheiten und Unsicherheiten zu vermeiden.

`Zend_Feed_Writer` bietet diese API über seine Datencontainer Klassen `Zend_Feed_Writer_Feed` und `Zend_Feed_Writer_Entry` an. Diese Klassen speichern nahezu alle Feed Daten in einer vom Typ unabhängigen Art, was bedeutet das man jeden Datencontainer mit jedem Renderer wiederverwenden kann ohne das zusätzliche Arbeit notwendig ist. Beide Klassen sind auch offen für Erweiterungen, was bedeutet das eine Erweiterung seine eigenen Containerklassen definieren kann welche bei den Basis Containerklassen als Erweiterung registriert sind, und geprüft werden sobald irgendein Methodenaufruf die `__call()` Methode des Basiscontainers auslöst.

Hier ist eine Zusammenfassung der Kern API für Feeds. Man sollte beachten das Sie nicht nur die Standards für RSS und Atom umfasst, sondern auch eine Anzahl von Erweiterungen welche in `Zend_Feed_Writer` enthalten sind. Die Benamung dieser Erweiterungs Methoden ist recht generisch - alle Erweiterungs Methoden arbeiten auf dem gleichen Level wie die Kern API da wir es erlauben jedes Erweiterungs Objekt seperat zu empfangen wenn das notwendig ist.

### API Methoden auf Feed Level

`setId()` | Setzt eine eindeutige ID die mit diesem Feed assoziiert ist. Für Atom 1.0 ist das ein atom:id Element, und für RSS 2.0 wird es als guid Element hinzugefügt. Diese sind optional solange ein Link hinzugefügt wird, wenn z.B. der Link als ID gesetzt ist.
`setTitle()` | Setzt den Titel des Feeds.
`setDescription()` | Setzt die textuelle Beschreibung des Feeds.
`setLink()` | Setzt eine URI zur HTML Website welche die gleichen oder ähnliche Informationen wie dieser Feed enthält (z.B. wenn der Feed von einem Blog ist, sollte er die URI des Blogs anbieten unter welche die HTML Version der Einträge gelesen werden können).

`setFeedLinks()`

Fügt einen Link zu einem XML Feed hinzu, entweder der erzeugte Feed oder eine alternative URI zeigen auf den gleichen Feed, aber in einem anderen Format. Es ist mindestens notwendig einen Link zum erstellten Feed zu inkludieren damit dieser eine identifizierbare endgültige URI hat, welche es dem Client erlaubt Änderungen des Orts mitzubekommen ohne das dauernde Umleitungen notwendig sind. Dieser Parameter ist ein Array von Arrays, wobei jedes Unter-Array die Schlüssel "type" und "uri" enthält. Der Type sollte "atom", "rss" oder "rdf" sein. Wenn ein Typ unterdrückt wird, ist er standardmäßig mit dem Typ identisch mit dem der Feed dargestellt wird.

`setAuthors()`

Setzt die Daten für Autoren. Der Parameter ist ein Array von Arrays wobei jedes Unter-Array die Schlüssel "name", "email" und "uri" enthalten kann. Der Wert "uri ist nur für Atom Feeds anwendbar da RSS keine Möglichkeit enthält Ihn anzuzeigen. Für RSS 2.0 werden bei der Darstellung zwei Elemente erzeugt - ein Autor Element welches die Referenz zur Email enthält und dem Namen in Klammern, und ein Dublin Core Creator Element welches nur den Namen enthält.

`setAuthor()` | Setzt die Daten für einen einzelnen Autor und folgt dem selben Format wie vorher für ein einzelnes Unter-Array beschrieben.
`setDateCreated()` | Setzt das Datum an dem dieser Feed erstellt wurde. Generell nur für Atom anwendbar wo es das Datum beschreibt zu der die Ressource, die von dem Atom 1.0 Dokument beschrieben wird, erstellt wurde. Der erwartete Parameter muss ein UNIX Timestamp oder ein `Zend_Date` Objekt sein.
`getDateModified()` | Setzt das Datum zu dem dieser Feed das letzte Mal geändert wurde. Der erwartete Parameter muss ein UNIX Timestamp oder ein `Zend_Date` Objekt sein.
`setLanguage()` | Setzt die Sprache des Feeds. Diese wird unterdrückt solange Sie nicht gesetzt ist.
`getGenerator()` | Erlaubt es einen Generator zu setzen. Der Parameter sollte ein Array sein welche die Schlüssel "name", "version" und "uri" enthält. Wenn er unterdrückt wird, wird ein standardmäßiger Generator hinzugefügt welcher auf `Zend_Feed_Writer`, die aktuelle Version vom Zend Framework und die URI des Frameworks verweist.
`setCopyright()` | Setzt eine Copyright Notiz die mit dem Feed assoziiert ist.
`setHubs()` | Akzeptiert ein Array von Pubsubhubbub Hub Endpunkten die im Feed als Atom Links dargestellt werden damit PuSH Abonnenten den eigenen Feed abbonieren können. Es ist zu beachten das man einen Pubsubhubbub Herausgeber implementieren muss damit Real-Time Updates ermöglicht werden. Ein Herausgeber kann implementiert werden indem `Zend_Feed_Pubsubhubbub_Publisher` verwendet wird.

`setCategories()`

Akzepziert ein Array an Kategorien für die Darstellung, wobei jedes Element selbst ein Array ist dessen möglich Schlüssel "term", "label" und "scheme" enthalten. "term" ist typischerweise der Name einer Kategorie welche für die Aufnahme in einer URI passen. "label" kann ein menschlich lesbarer Name einer Kategorie sein der spezielle Zeichen unterstützt (er wird wärend der Darstellung kodiert) und ist ein benötigter Schlüssel. "scheme" (im RSS auch die Domain genannt) ist optional muss aber eine gültige URI sein.

## Setzen der Datenpunkt für Einträge

Hier ist eine Zusammenfassung der Kern API für Einträge und Elemente. Man sollte beachten das Sie nicht nur die Standards für RSS und Atom umfasst, sondern auch eine Anzahl von Erweiterungen welche in `Zend_Feed_Writer` enthalten sind. Die Benamung dieser Erweiterungs Methoden ist recht generisch - alle Erweiterungs Methoden arbeiten auf dem gleichen Level wie die Kern API da wir es erlauben jedes Erweiterungs Objekt seperat zu empfangen wenn das notwendig ist.

### API Methoden auf Eintrags Level

`setId()` | Setzt eine eindeutige ID die mit diesem Feed assoziiert ist. Für Atom 1.0 ist das ein atom:id Element, und für RSS 2.0 wird es als guid Element hinzugefügt. Diese sind optional solange ein Link hinzugefügt wird, wenn z.B. der Link als ID gesetzt ist.
`setTitle()` | Setzt den Titel des Feeds.
`setDescription()` | Setzt die textuelle Beschreibung des Feeds.
`setLink()` | Setzt eine URI zur HTML Website welche die gleichen oder ähnliche Informationen wie dieser Feed enthält (z.B. wenn der Feed von einem Blog ist, sollte er die URI des Blogs anbieten unter welche die HTML Version der Einträge gelesen werden können).

`setFeedLinks()`

Fügt einen Link zu einem XML Feed hinzu, entweder der erzeugte Feed oder eine alternative URI zeigen auf den gleichen Feed, aber in einem anderen Format. Es ist mindestens notwendig einen Link zum erstellten Feed zu inkludieren damit dieser eine identifizierbare endgültige URI hat, welche es dem Client erlaubt Änderungen des Orts mitzubekommen ohne das dauernde Umleitungen notwendig sind. Dieser Parameter ist ein Array von Arrays, wobei jedes Unter-Array die Schlüssel "type" und "uri" enthält. Der Type sollte "atom", "rss" oder "rdf" sein. Wenn ein Typ unterdrückt wird, ist er standardmäßig mit dem Typ identisch mit dem der Feed dargestellt wird.

`setAuthors()`

Setzt die Daten für Autoren. Der Parameter ist ein Array von Arrays wobei jedes Unter-Array die Schlüssel "name", "email" und "uri" enthalten kann. Der Wert "uri ist nur für Atom Feeds anwendbar da RSS keine Möglichkeit enthält Ihn anzuzeigen. Für RSS 2.0 werden bei der Darstellung zwei Elemente erzeugt - ein Autor Element welches die Referenz zur Email enthält und dem Namen in Klammern, und ein Dublin Core Creator Element welches nur den Namen enthält.

`setAuthor()` | Setzt die Daten für einen einzelnen Autor und folgt dem selben Format wie vorher für ein einzelnes Unter-Array beschrieben.
`setDateCreated()` | Setzt das Datum an dem dieser Feed erstellt wurde. Generell nur für Atom anwendbar wo es das Datum beschreibt zu der die Ressource, die von dem Atom 1.0 Dokument beschrieben wird, erstellt wurde. Der erwartete Parameter muss ein UNIX Timestamp oder ein `Zend_Date` Objekt sein.
`getDateModified()` | Setzt das Datum zu dem dieser Feed das letzte Mal geändert wurde. Der erwartete Parameter muss ein UNIX Timestamp oder ein `Zend_Date` Objekt sein.
`setLanguage()` | Setzt die Sprache des Feeds. Diese wird unterdrückt solange Sie nicht gesetzt ist.
`getGenerator()` | Erlaubt es einen Generator zu setzen. Der Parameter sollte ein Array sein welche die Schlüssel "name", "version" und "uri" enthält. Wenn er unterdrückt wird, wird ein standardmäßiger Generator hinzugefügt welcher auf `Zend_Feed_Writer`, die aktuelle Version vom Zend Framework und die URI des Frameworks verweist.
`setCopyright()` | Setzt eine Copyright Notiz die mit dem Feed assoziiert ist.
`setHubs()` | Akzeptiert ein Array von Pubsubhubbub Hub Endpunkten die im Feed als Atom Links dargestellt werden damit PuSH Abonnenten den eigenen Feed abbonieren können. Es ist zu beachten das man einen Pubsubhubbub Herausgeber implementieren muss damit Real-Time Updates ermöglicht werden. Ein Herausgeber kann implementiert werden indem `Zend_Feed_Pubsubhubbub_Publisher` verwendet wird.

`setCategories()`

Akzepziert ein Array an Kategorien für die Darstellung, wobei jedes Element selbst ein Array ist dessen möglich Schlüssel "term", "label" und "scheme" enthalten. "term" ist typischerweise der Name einer Kategorie welche für die Aufnahme in einer URI passen. "label" kann ein menschlich lesbarer Name einer Kategorie sein der spezielle Zeichen unterstützt (er wird wärend der Darstellung kodiert) und ist ein benötigter Schlüssel. "scheme" (im RSS auch die Domain genannt) ist optional muss aber eine gültige URI sein.