Zend_Feed_Reader.xml 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.feed.reader">
  5. <title>Zend_Feed_Reader</title>
  6. <sect2 id="zend.feed.reader.introduction">
  7. <title>Einführung</title>
  8. <para>
  9. <classname>Zend_Feed_Reader</classname> ist eine Komponente die verwendet wird um
  10. <acronym>RSS</acronym> und Atom Feeds jeder Version zu konsumieren, inklusive
  11. <acronym>RDF</acronym>/<acronym>RSS</acronym> 1.0, <acronym>RSS</acronym> 2.0, Atom 0.3
  12. und Atom 1.0. Die <acronym>API</acronym> für das Empfangen von Feed Daten ist relativ
  13. einfach da <classname>Zend_Feed_Reader</classname> in der Lage ist jeden Feed eines
  14. jeden Typs mit Hilfe der <acronym>API</acronym> nach den angefragten Informationen zu
  15. durchsuchen. Wenn die typischen Elemente die diese Informationen enthalten nicht
  16. vorhanden sind, werden diese adaptiert und statt dessen auf eine Vielzahl von
  17. alternativen Elementen zurück gegriffen. Diese Fähigkeit, von Alternativen auszuwählen,
  18. verhindert das Benutzer Ihren eigenen astrakten Layer über die Komponente legen müssen
  19. damit Sie nützlich ist, oder beliebig tiefes Wissen des zugrundeliegenden Standard,
  20. aktueller alternativen und namespaces Erweiterungen haben müssen.
  21. </para>
  22. <para>
  23. Intern arbeitet <classname>Zend_Feed_Reader</classname> fast komplett auf Basis der
  24. Erstellung von XPath Abfragen gegen das Dokument Objekt Modell des Feed
  25. <acronym>XML</acronym>'s. Das <acronym>DOM</acronym> wird nicht durch eine gekettete
  26. Eigenschaften <acronym>API</acronym> wie bei <classname>Zend_Feed</classname> bekannt
  27. gegeben und durch die darunterliegenden DOMDocument, DOMElement und DOMXPath Objekte für
  28. eine externe Manipulation bekannt gegeben. Dieser Singular Weg des Parsens ist
  29. konsistent und die Komponente bietet ein Plugin System um dem Feed hinzuzufügen und eine
  30. Eintrags Level <acronym>API</acronym> durch das Schreiben von Erweiterungen auf einer
  31. ähnlichen Basis.
  32. </para>
  33. <para>
  34. Geschwindigkeit wird auf drei Wegen bereitgestellt. Erstens unterstützt
  35. <classname>Zend_Feed_Reader</classname> das Cachen durch Verwendung von
  36. <classname>Zend_Cache</classname> um eine Kopie des Originalen Feed
  37. <acronym>XML</acronym> zu halten. Das erlaubt es Netzwerk Anfragen für eine Feed
  38. <acronym>URI</acronym> zu überspringen wenn der Cache gültig ist. Zweitens wird die
  39. Feed und Eintrag- Level <acronym>API</acronym> durch einen internen Cache gesichert
  40. (nicht persistent) damit wiederholte <acronym>API</acronym> Aufrufe für den gleichen
  41. Feed eine zusätzliche Verwendung von <acronym>DOM</acronym> oder XPath verhindert.
  42. Drittens erlaubt das Importieren von Feeds von einer <acronym>URI</acronym> den
  43. Vorteil von konditionellen <acronym>HTTP</acronym> <constant>GET</constant> Anfragen
  44. welche es Servern erlauben eine leere 304 Anfrage auszulösen wenn der angefragte Feed
  45. seit der Zeit zu der er das letzte Mal angefragt wurde, nicht verändert wurde. Im
  46. letzten Fall hält eine Instanz von <classname>Zend_Cache</classname> den zuletzt
  47. empfangenen Feed zusammen mit dem ETag und dem Last-Modified Header Werten die in der
  48. <acronym>HTTP</acronym> Antwort gesendet wurde.
  49. </para>
  50. <para>
  51. Relativ zu <classname>Zend_Feed</classname> wurde
  52. <classname>Zend_Feed_Reader</classname> als frei stehender Ersatz für
  53. <classname>Zend_Feed</classname> formuliert der aber nicht mit
  54. <classname>Zend_Feed</classname> rückwärts kompatibel ist. Aber es ist eine Alternative
  55. die einer anderen Ideologie folgt die darin fokusiert ist einfach verwendbar zu sein,
  56. flexibel, konsistent und durch das Plugin System erweiterbar.
  57. <classname>Zend_Feed_Reader</classname> ist auch nicht dazu fähig Feeds zu erstellen,
  58. delegiert diese Aufgabe aber an <classname>Zend_Feed_Writer</classname>, seinen Bruder.
  59. </para>
  60. </sect2>
  61. <sect2 id="zend.feed.reader.import">
  62. <title>Feeds importieren</title>
  63. <para>
  64. Das importieren eines Feeds mit <classname>Zend_Feed_Reader</classname> ist zu
  65. <classname>Zend_Feed</classname> nicht sehr unterschiedlich. Feeds können von einem
  66. String, einer Datei, <acronym>URI</acronym> oder einer Instanz des Typs
  67. <classname>Zend_Feed_Abstract</classname> importiert werden. Das importieren von einer
  68. <acronym>URI</acronym> kann zusätzlich eine konditionelle <acronym>HTTP</acronym>
  69. <constant>GET</constant> Anfrage benützen. Wenn das importieren fehlschlägt, wird eine
  70. Exception geworfen. Das Endergebnis wird ein Objekt des Typs
  71. <classname>Zend_Feed_Reader_FeedInterface</classname> sein, die Core Implementation
  72. von <classname>Zend_Feed_Reader_Feed_Rss</classname> und
  73. <classname>Zend_Feed_Reader_Feed_Atom</classname> (<classname>Zend_Feed</classname>
  74. hat alle kurzen Namen genommen!). Beide Objekte unterstützen mehrere (alle
  75. existierenden) Versionen dieser breiten Feed Typen.
  76. </para>
  77. <para>
  78. Im folgenden Beispiel importieren wir einen
  79. <acronym>RDF</acronym>/<acronym>RSS</acronym> 1.0 Feed und extrahieren einige
  80. grundsätzliche Information die dann in einer Datenbank oder wo anders gespeichert
  81. werden können.
  82. </para>
  83. <programlisting language="php"><![CDATA[
  84. $feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');
  85. $data = array(
  86. 'title' => $feed->getTitle(),
  87. 'link' => $feed->getLink(),
  88. 'dateModified' => $feed->getDateModified(),
  89. 'description' => $feed->getDescription(),
  90. 'language' => $feed->getLanguage(),
  91. 'entries' => array(),
  92. );
  93. foreach ($feed as $entry) {
  94. $edata = array(
  95. 'title' => $entry->getTitle(),
  96. 'description' => $entry->getDescription(),
  97. 'dateModified' => $entry->getDateModified(),
  98. 'authors' => $entry->getAuthors(),
  99. 'link' => $entry->getLink(),
  100. 'content' => $entry->getContent()
  101. );
  102. $data['entries'][] = $edata;
  103. }
  104. ]]></programlisting>
  105. <para>
  106. Das obige Beispiel demonstriert die <acronym>API</acronym> von
  107. <classname>Zend_Feed_Reader</classname> und es demonstriert auch einige seiner
  108. internen Operationen. In Wirklichkeit hat der ausgewählte <acronym>RDF</acronym> Feed
  109. keine nativen Daten oder Author Elemente, trotzdem verwendet er das Dublin Core 1.1
  110. Modul welches Namespaced Ersteller und Datums Elemente anbietet.
  111. <classname>Zend_Feed_Reader</classname> fällt auf diese und ähnliche Operationen zurück
  112. wenn keine relativ nativen Elemente existieren. Wenn es absolut keine alternative
  113. finden kann wird es <constant>NULL</constant> zurückgeben, was anzeigt das die
  114. Informationen nicht im Feed gefunden werden können. Man sollte beachten das Klassen die
  115. <classname>Zend_Feed_Reader_FeedInterface</classname> implementieren auch
  116. die <acronym>SPL</acronym> Interfaces <classname>Iterator</classname> und
  117. <classname>Countable</classname> implementieren.
  118. </para>
  119. <para>
  120. Feeds können auch von Strings, Dateien und sogar Objekten des Typs
  121. <classname>Zend_Feed_Abstract</classname> importiert werden.
  122. </para>
  123. <programlisting language="php"><![CDATA[
  124. // von einer URI
  125. $feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');
  126. // von einem String
  127. $feed = Zend_Feed_Reader::importString($feedXmlString);
  128. // von einer Datei
  129. $feed = Zend_Feed_Reader::importFile('./feed.xml');
  130. // von einem abstrakten Zend_Feed_Abstract Objekt
  131. $zfeed = Zend_Feed::import('http://www.planet-php.net/atom/');
  132. $feed = Zend_Feed_Reader::importFeed($zfeed);
  133. ]]></programlisting>
  134. </sect2>
  135. <sect2 id="zend.feed.reader.sources">
  136. <title>Empfangen darunterliegender Quellen von Feeds und Einträgen</title>
  137. <para>
  138. <classname>Zend_Feed_Reader</classname> macht sein bestes um Ihnen die Details
  139. abzunehmen. Wenn man an einem Feed ausserhalb von
  140. <classname>Zend_Feed_Reader</classname> arbeiten muß, kann man das grundsätzliche
  141. DOMDocument oder DOMElement von jeder Klasse extrahieren, oder sogar einen
  142. <acronym>XML</acronym> String der sie enthält. Es werden auch Methoden angeboten um das
  143. aktuelle DOMXPath Objekt (mit allen registrierten Kern und Erweiterungs Namespaces) zu
  144. extrahieren, und den richtigen Präfix der in allen XPath Anfragen für den aktuellen Feed
  145. oder Eintrag verwendet wird. Die grundsätzlich zu verwenden Methoden (für jedes Objekt)
  146. sind <methodname>saveXml()</methodname>, <methodname>getDomDocument()</methodname>,
  147. <methodname>getElement()</methodname>, <methodname>getXpath()</methodname> und
  148. <methodname>getXpathPrefix()</methodname>. Diese erlauben es sich von
  149. <classname>Zend_Feed_Reader</classname> zu lösen und das zu tun was man selbst
  150. machen will.
  151. </para>
  152. <itemizedlist>
  153. <listitem>
  154. <para>
  155. <methodname>saveXml()</methodname> gibt einen <acronym>XML</acronym> String
  156. zurück der nur das Element enthält welches das aktuelle Objekt repräsentiert.
  157. </para>
  158. </listitem>
  159. <listitem>
  160. <para>
  161. <methodname>getDomDocument()</methodname> gibt das DOMDocument Objekt zurück das
  162. den kompletten Feed repräsentiert (sogar wenn es von einem Entry Objekt aus
  163. aufgerufen wird).
  164. </para>
  165. </listitem>
  166. <listitem>
  167. <para>
  168. <methodname>getElement()</methodname> gibt das DOMElement
  169. des aktuellen Objekts zurück (z.B. den Feed oder aktuellen Eintrag).
  170. </para>
  171. </listitem>
  172. <listitem>
  173. <para>
  174. <methodname>getXpath()</methodname> gibt das aktuelle DOMXPath Objekt für den
  175. aktuellen Feed zurück (sogar wenn es von einem Entry Objekt aus aufgerufen wird)
  176. mit den Namespaces des aktuellen Feed Typs und allen vor-registrierten geladenen
  177. Erweiterungen.
  178. </para>
  179. </listitem>
  180. <listitem>
  181. <para>
  182. <methodname>getXpathPrefix()</methodname> gibt den Präfix der Abfrage für das
  183. aktuelle Objekt zurück (z.B. den Feed oder den aktuellen Eintrag) welcher den
  184. richtigen XPath Query Pfad für den spezifizierten Feed oder Eintrag enthält.
  185. </para>
  186. </listitem>
  187. </itemizedlist>
  188. <para>
  189. Hier ist ein Beispiel bei dem ein Feed eine <acronym>RSS</acronym> Erweiterung enthalten
  190. können die von <classname>Zend_Feed_Reader</classname> nicht out of the Box unterstützt
  191. wird. Beachtenswert ist, das man eine Erweiterungen schreiben und registrieren könnte
  192. (wird später behandelt) um das zu bewerkstelligen, aber das ist nicht immer eine
  193. Garantie für einen schnellen Check. Man muß jeden neuen Namespace beim DOMXPath Objekt
  194. registrieren bevor es verwendet wird ausser Sie werden vorab von
  195. <classname>Zend_Feed_Reader</classname> oder einer Erweiterung registriert.
  196. </para>
  197. <programlisting language="php"><![CDATA[
  198. $feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');
  199. $xpathPrefix = $feed->getXpathPrefix();
  200. $xpath = $feed->getXpath();
  201. $xpath->registerNamespace('admin', 'http://webns.net/mvcb/');
  202. $reportErrorsTo = $xpath->evaluate('string('
  203. . $xpathPrefix
  204. . '/admin:errorReportsTo)');
  205. ]]></programlisting>
  206. <warning>
  207. <para>
  208. Wenn man einen bereits registrierten Namespace mit einem anderen Präfix Namen
  209. registriert als jenen der von <classname>Zend_Feed_Reader</classname> intern
  210. verwendet wird, zerstört das die Interne Arbeitsweise dieser Komponente.
  211. </para>
  212. </warning>
  213. </sect2>
  214. <sect2 id="zend.feed.reader.cache-request">
  215. <title>Unterstützung für Caches und intelligente Anfragen</title>
  216. <sect3 id="zend.feed.reader.cache-request.cache">
  217. <title>Unterstützung für Caches in Zend_Feed_Reader hinzufügen</title>
  218. <para>
  219. <classname>Zend_Feed_Reader</classname> unterstützt die Verwendung einer Instanz von
  220. <classname>Zend_Cache</classname> um Feeds zu cachen (als <acronym>XML</acronym>)
  221. um unnötige Anfragen im Netzwerk zu vermeiden. Das Hinzufügen eines Caches ist hier
  222. so einfach wie bei anderen Zend Framework Komponenten. Den Cache erstellen und
  223. konfigurieren und dann <classname>Zend_Feed_Reader</classname> mitteilen das er
  224. verwendet werden soll! Der verwendete Cache Schlüssel ist
  225. "<classname>Zend_Feed_Reader_</classname>" gefolgt von dem
  226. <acronym>MD5</acronym> Hash der <acronym>URI</acronym> des Feeds.
  227. </para>
  228. <programlisting language="php"><![CDATA[
  229. $frontendOptions = array(
  230. 'lifetime' => 7200,
  231. 'automatic_serialization' => true
  232. );
  233. $backendOptions = array('cache_dir' => './tmp/');
  234. $cache = Zend_Cache::factory(
  235. 'Core', 'File', $frontendOptions, $backendOptions
  236. );
  237. Zend_Feed_Reader::setCache($cache);
  238. ]]></programlisting>
  239. <note>
  240. <para>
  241. Auch wenn es etwas abseits ist, sollte man daran denken zu
  242. <classname>Zend_Loader_PluginLoader</classname> einen Cache hinzuzufügen der
  243. von <classname>Zend_Feed_Reader</classname> verwendet wird um Erweiterungen zu
  244. laden.
  245. </para>
  246. </note>
  247. </sect3>
  248. <sect3 id="zend.feed.reader.cache-request.http-conditional-get">
  249. <title>Unterstützung für HTTP Conditional GET</title>
  250. <para>
  251. Die große Frage wenn man ofters einen Feed importiert, ist ob er sich geändert hat.
  252. Wenn ein Cache aktiviert ist, kann man die Unterstützung für <acronym>HTTP</acronym>
  253. Conditional <constant>GET</constant> hinzufügen um diese Frage zu beantworten.
  254. </para>
  255. <para>
  256. Durch Verwendung dieser Methode kann man Feeds von <acronym>URI</acronym> anfragen
  257. und deren letzte bekannte Werte der ETag und Last-Modified Antwort Header mit der
  258. Anfrage inkludieren (wobei die If-None-Match und If-Modified-Since Header verwendet
  259. werden). Wenn der Feed auf dem Server unverändert ist, sollte man eine 304 Antwort
  260. empfangen die <classname>Zend_Feed_Reader</classname> mitteilt das die gecachte
  261. Version zu verwenden ist. Wenn ein kompletter Feed in einer Antwort mit einem Status
  262. Code von 200 geschickt wird, bedeutet dieses, das der Feed verändert wurde und
  263. <classname>Zend_Feed_Reader</classname> wird die neue Version parsen und Sie im
  264. Cache abspeichern. Es werden auch die neuen Werte der ETag und Last-Modified Header
  265. für eine zukünftige Verwendung gespeichert.
  266. </para>
  267. <para>
  268. Bei diesen "konditionalen" Abfragen ist nicht garantiert das Sie, vom Server von dem
  269. man eine <acronym>URI</acronym> abfragt, unterstützt werden, können aber trotzdem
  270. angefragt werden. Die meisten Feed Quellen wie Blogs sollten hierfür eine
  271. Unterstützung haben. Um konditionale Anfragen zu erlauben, muss man einen Cache
  272. bei <classname>Zend_Feed_Reader</classname> angeben.
  273. </para>
  274. <programlisting language="php"><![CDATA[
  275. $frontendOptions = array(
  276. 'lifetime' => 86400,
  277. 'automatic_serialization' => true
  278. );
  279. $backendOptions = array('cache_dir' => './tmp/');
  280. $cache = Zend_Cache::factory(
  281. 'Core', 'File', $frontendOptions, $backendOptions
  282. );
  283. Zend_Feed_Reader::setCache($cache);
  284. Zend_Feed_Reader::useHttpConditionalGet();
  285. $feed = Zend_Feed_Reader::import('http://www.planet-php.net/rdf/');
  286. ]]></programlisting>
  287. <para>
  288. Im obige Beispiel werden, bei aktivierten <acronym>HTTP</acronym> Conditional
  289. <constant>GET</constant> Anfragen, die Werte der Antwort Header für ETag und
  290. Last-Modified mit dem Feed gecacht. Für die nächsten 24 Stunden (die Lebenszeit des
  291. Caches) werden Feed am Cache nur dann aktualisiert wenn eine nicht-304 Antwort
  292. empfangen wird, die ein gültiges <acronym>RSS</acronym> oder Atom
  293. <acronym>XML</acronym> Dokument enthält.
  294. </para>
  295. <para>
  296. Wenn man darauf anzielt die Antwort Header ausserhalb von
  297. <classname>Zend_Feed_Reader</classname> zu managen, kann man die relevanten
  298. If-None-Matches und If-Modified-Since Antwort Header über die <acronym>URI</acronym>
  299. Import Methode setzen.
  300. </para>
  301. <programlisting language="php"><![CDATA[
  302. $lastEtagReceived = '5e6cefe7df5a7e95c8b1ba1a2ccaff3d';
  303. $lastModifiedDateReceived = 'Wed, 08 Jul 2009 13:37:22 GMT';
  304. $feed = Zend_Feed_Reader::import(
  305. $uri, $lastEtagReceived, $lastModifiedDateReceived
  306. );
  307. ]]></programlisting>
  308. </sect3>
  309. </sect2>
  310. <sect2 id="zend.feed.reader.locate">
  311. <title>Feed URIs von Webseiten erkennen</title>
  312. <para>
  313. Dieser Tage ist vielen Webseiten bekannt das der Ort Ihrer <acronym>XML</acronym> Feeds
  314. nicht immer eindeutig ist. Eine kleine <acronym>RDF</acronym>, <acronym>RSS</acronym>
  315. oder Atom Grafik hilft wenn der Benutzer die Seite liest, aber was wenn eine Maschine
  316. kommt und versucht herauszufinden So die Feed sind? Um hierbei zu helfen, zeigen viele
  317. Webseiten zu Ihren Feeds indem &lt;link&gt; Tags in der &lt;head&gt; Sektion Ihres
  318. <acronym>HTML</acronym>s verwendet werden. Um diesen Vorteil zu nutzen, kann man
  319. <classname>Zend_Feed_Reader</classname> verwenden diese Feeds zu erkennen, indem die
  320. statische <methodname>findFeedLinks()</methodname> Methode verwendet wird.
  321. </para>
  322. <para>
  323. Diese Methode ruft irgendeine <acronym>URI</acronym> auf und sucht nach dem Ort der
  324. <acronym>RSS</acronym>, <acronym>RDF</acronym> und Atom Feeds mit der Annahme dass das
  325. <acronym>HTML</acronym> der Webseite nur die relevanten Links enthält. Sie gibt dann ein
  326. Wert Objekt zurück indem man die Existenz einer <acronym>RSS</acronym>,
  327. <acronym>RDF</acronym> oder Atom Feed <acronym>URI</acronym> prüfen kann.
  328. </para>
  329. <para>
  330. Das zurückgegebene Objekt ist eine Unterklasse von <classname>ArrayObject</classname>
  331. welche <classname>Zend_Feed_Reader_Collection_FeedLink</classname> heisst, damit es in
  332. ein Array gecastet werden kann, oder damit man es iterieren kann um auf alle erkannten
  333. Links zuzugreifen. Trotzdem kann man, als einfache Abkürzung, den ersten
  334. <acronym>RSS</acronym>, <acronym>RDF</acronym> oder Atom Link holen indem dessen
  335. öffentliche Eigenschaft wie im beiliegenden Beispiel verwendet wird. Andernfalls ist
  336. jedes Element von <classname>ArrayObject</classname> ein einfaches Array mit den
  337. Schlüsseln "type" und "uri" wobei der Typ "rdf", "rss" oder "atom" sein kann.
  338. </para>
  339. <programlisting language="php"><![CDATA[
  340. $links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
  341. if(isset($links->rdf)) {
  342. echo $links->rdf, "\n"; // http://www.planet-php.org/rdf/
  343. }
  344. if(isset($links->rss)) {
  345. echo $links->rss, "\n"; // http://www.planet-php.org/rss/
  346. }
  347. if(isset($links->atom)) {
  348. echo $links->atom, "\n"; // http://www.planet-php.org/atom/
  349. }
  350. ]]></programlisting>
  351. <para>
  352. Basierend auf diesen Links kann man dann, von welchen Quellen man auch immer will,
  353. importieren indem die übliche Vorgehensweise verwendet wird.
  354. </para>
  355. <para>
  356. Diese schnelle Methode gibt nur einen Link für jeden Feed Typ zurück, aber Webseiten
  357. können viele Links von jedem Typ enthalten. Möglicherweise ist es eine News Site mit
  358. einem <acronym>RSS</acronym> Feed für jede News Kategorie. Man kann durch alle Links
  359. iterieren indem der ArrayObject Iterator verwendet wird.
  360. </para>
  361. <programlisting language="php"><![CDATA[
  362. $links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
  363. foreach ($links as $link) {
  364. echo $link['uri'], "\n";
  365. }
  366. ]]></programlisting>
  367. </sect2>
  368. <sect2 id="zend.feed.reader.attribute-collections">
  369. <title>Attribut Sammlungen</title>
  370. <para>
  371. In einem Versuch die Rückgabetypen zu vereinfachen, können Rückgabetypen für die
  372. verschiedenen Feed und Entry Level Methoden ab Zend Framework 1.10 ein Objekt vom Typ
  373. <classname>Zend_Feed_Reader_Collection_CollectionAbstract</classname> enthalten.
  374. Abgesehen vom speziellen Klassennamen der anbei erklärt wird, ist es nur eine einfache
  375. Subklasse von <acronym>SPL</acronym>'s <classname>ArrayObject</classname>.
  376. </para>
  377. <para>
  378. Der Hauptzweck hierbei besteht darin, die Präsentation von so vielen Daten wie möglich
  379. von den angefragten Elementen zu erlauben, während trotzdem der Zugriff auf die meisten
  380. relevanten Daten über ein einfaches Array erlaubt wird. Das erzwingt auch einen
  381. Standardweg um solche Daten zurückzugeben, was vorher zwischen Arrays und Objekten
  382. gewandert ist.
  383. </para>
  384. <para>
  385. Der neue Klassentyp arbeitet identisch zu <classname>ArrayObject</classname>, mit der
  386. gleichen kleinen Änderung dass eine neue Methode <methodname>getValues()</methodname>
  387. existiert welche ein einfaches flaches Array zurückgibt dass die meisten relevanten
  388. Informationen enthält.
  389. </para>
  390. <para>
  391. Ein einfaches Beispiel hiervon ist
  392. <methodname>Zend_Feed_Reader_FeedInterface::getCategories()</methodname>. Wenn es in
  393. irgendeinem <acronym>RSS</acronym> oder Atom Feed verwendet wird, gibt diese Methode
  394. Daten der Kategorie als Container Objekt zurück welches
  395. <classname>Zend_Feed_Reader_Collection_Category</classname> genannt wird. Das Container
  396. Objekt wird, für jede Kategorie, drei Felder an Daten enthalten: term, schema und label.
  397. "term" ist der grundsätzliche Name der Kategorie, oft Maschinen lesbar (normalerweise
  398. ein <acronym>URI</acronym> Identifikator) und in <acronym>RSS</acronym> 2.0 auch bekannt
  399. als "domain". "label" ist ein menschlich lesbarer Kategorie Name welcher
  400. <acronym>HTML</acronym> Entities unterstützt. In <acronym>RSS</acronym> 2.0 gibt es kein
  401. Label Attribut deshalb wird es der Bequemlichkeit halber immer auf den selben Wert
  402. gesetzt wie der Ausdruck.
  403. </para>
  404. <para>
  405. Um auf die Label der Kategorie selbst als einfache Array Werte zuzugreifen könnte man
  406. das folgende verwenden:
  407. </para>
  408. <programlisting language="php"><![CDATA[
  409. $feed = Zend_Feed_Reader::import('http://www.example.com/atom.xml');
  410. $categories = $feed->getCategories();
  411. $labels = array();
  412. foreach ($categories as $cat) {
  413. $labels[] = $cat['label']
  414. }
  415. ]]></programlisting>
  416. <para>
  417. Es ist ein erfundenes Beispiel, aber der Punkt ist, dass Label zusammen mit anderen
  418. Informationen gebunden sind.
  419. </para>
  420. <para>
  421. Trotzdem erlaubt die Container Klasse den Zugriff auf die "relevantesten" Daten als
  422. einfaches Array indem die Methode <methodname>getValues()</methodname> verwendet wird.
  423. Das Konzept der "relevantesten" Daten ist offensichtlich ein beurteilter Aufruf. Für
  424. Kategorien bedeutet es die Label der Kategorien (nicht die Typen oder Schemata) während
  425. es für Autoren der Name des Autors wäre (nicht deren Email Adressen oder die
  426. <acronym>URI</acronym>s). Das einfache Array ist flach (nur Werte) und durchläuft
  427. <methodname>array_unique</methodname> um doppelte Werte zu entfernen.
  428. </para>
  429. <programlisting language="php"><![CDATA[
  430. $feed = Zend_Feed_Reader::import('http://www.example.com/atom.xml');
  431. $categories = $feed->getCategories();
  432. $labels = $categories->getValues();
  433. ]]></programlisting>
  434. <para>
  435. Das obige Beispiel zeigt wie nur die Label und sonst nichts extrahiert wird. Das gibt
  436. einen einfachen Zugriff auf die Label der Kategorie ohne zusätzliche Arbeit die Daten
  437. selbst zu extrahieren.
  438. </para>
  439. </sect2>
  440. <sect2 id="zend.feed.reader.retrieve-info">
  441. <title>Empfangen von Feed Informationen</title>
  442. <para>
  443. Das Empfangen von Informationen von einem Feed (wir reden über Einträge und Elemente in
  444. der nächsten Sektion da Sie identischen Prinzipien folgen) verwendet eine klar
  445. definierte <acronym>API</acronym> welche exakt die gleiche ist, unabhängig davon ob der
  446. angefragte Feed <acronym>RSS</acronym>, <acronym>RDF</acronym> oder Atom ist. Das selbe
  447. gilt für Sub-Versionen dieser Standards da wir jede einzelne <acronym>RSS</acronym> und
  448. Atom Version getestet haben. Wärend sich der darunterliegende <acronym>XML</acronym>
  449. Feed substantiell unterscheiden kann, im Sinne von Tags und Elementen die vorhanden
  450. sind, versuchen trotzdem alle ähnliche Informationen zu geben und um das alles zu
  451. reflektieren werden unterschiede und das Hanteln durch alternative Tags intern von
  452. <classname>Zend_Feed_Reader</classname> behandelt welche einem ein identisches Interface
  453. für jeden anzeigt. Idealerweise sollte man sich nicht darum kümmern ob ein Feed
  454. <acronym>RSS</acronym> oder Atom ist, solange man die Informationen extrahieren kann
  455. die man benötigt.
  456. </para>
  457. <note>
  458. <para>
  459. Wärend die Erkennung von Gemeinsamkeiten zwischen den Feed Typen selbst sehr komplex
  460. ist, sollte erwähnt werden das <acronym>RSS</acronym> selbst eine konstant strittige
  461. "Spezifikation". Das hat seine Wurzeln im originalen <acronym>RSS</acronym> 2.0
  462. Dokument welches Doppeldeutigkeiten enthält und die richtige Behandlung alle
  463. Elemente nicht im Detail erklärt. Als Ergebnis verwendet diese Komponente riguros
  464. die <acronym>RSS</acronym> 2.0.11 Spezifikation welche vom
  465. <acronym>RSS</acronym> Advisory Board veröffentlicht wurde und dessen beigefügtes
  466. <acronym>RSS</acronym> Best Practices Profil. Keine andere Interpretation von
  467. <acronym>RSS</acronym> 2.0 wird unterstützt wobei Ausnahmen erlaubt sein können wo
  468. es die anwendung der zwei vorher erwähnten Dokumente nicht direkt verhindert.
  469. </para>
  470. </note>
  471. <para>
  472. Natürlich leben wir nicht in einer idealen Welt sodas es Zeiten gibt in denen die
  473. <acronym>API</acronym> einfach nicht das bietet wonach man sucht. Um hierbei zu helfen
  474. bietet <classname>Zend_Feed_Reader</classname> ein Plugin System an das es erlaubt
  475. Erweiterungen zu schreiben und die Kern <acronym>API</acronym> zu erweitern sowie
  476. alle zusätzliche Daten abzudecken die man von Feeds extrahieren will. Wenn das schreiben
  477. einer weiteren Erweiterung zu problematisch ist, kann man einfach das darunterliegende
  478. <acronym>DOM</acronym> oder die XPath Objekte holen und das von Hand in der Anwendung
  479. machen. Natürlich sollte wirklich eine Erweiterung geschrieben werden, einfach um es
  480. portabler und wiederverwendbarer zu machen. Und nützliche Erweiterungen können für den
  481. Framework vorgeschlagen werden um Sie formal hinzuzufügen.
  482. </para>
  483. <para>
  484. Hier ist eine Zusammenfassung der Kern <acronym>API</acronym> für Feeds. Man sollte
  485. beachten das es nicht nur die grundsätzlichen <acronym>RSS</acronym> und Atom
  486. Standard abdeckt, sondern das es auch eine Anzahl von mitgelieferten Erweiterungen
  487. gibt die mit <classname>Zend_Feed_Reader</classname> gebündelt sind. Die Benennung
  488. dieser Methoden von Erweiterungen ist recht generisch - alle erweiterten Methoden
  489. arbeiten auf dem gleichen Level wie die Kern <acronym>API</acronym> da wir es
  490. erlauben alle spefizischen Erweiterungs Objekte separat zu empfangen wenn das
  491. notwendig ist.
  492. </para>
  493. <table>
  494. <title>API Methoden auf dem Level des Feeds</title>
  495. <tgroup cols="2">
  496. <tbody>
  497. <row>
  498. <entry><methodname>getId()</methodname></entry>
  499. <entry>
  500. Gibt eine eindeutige ID zurück die mit dem Feed assoziiert ist
  501. </entry>
  502. </row>
  503. <row>
  504. <entry><methodname>getTitle()</methodname></entry>
  505. <entry>Gibt den Titel des Feeds zurück</entry>
  506. </row>
  507. <row>
  508. <entry><methodname>getDescription()</methodname></entry>
  509. <entry>Gibt die textuelle Beschreibung des Feeds zurück</entry>
  510. </row>
  511. <row>
  512. <entry><methodname>getLink()</methodname></entry>
  513. <entry>
  514. Gibt eine <acronym>URI</acronym> zu der <acronym>HTML</acronym> Webseite
  515. zurück welche die gleiche oder ähnliche Informationen wie dieser Feed
  516. enthält (z.B. wenn der Feed von einem Blog ist, sollte die
  517. <acronym>URI</acronym> des Blogs enthalten sein indem die
  518. <acronym>HTML</acronym> Version des Eintrags gelesen werden kann)
  519. </entry>
  520. </row>
  521. <row>
  522. <entry><methodname>getFeedLink()</methodname></entry>
  523. <entry>
  524. Gibt die <acronym>URI</acronym> dieses Feeds zurück, welche die gleiche
  525. sein kann wie die <acronym>URI</acronym> welche verwendet wurde um
  526. den Feed zu importieren. Es gibt wichtige Fälle in denen sich der Feed
  527. Link unterscheiden kann weil die Quell <acronym>URI</acronym>
  528. aktualisiert wird und geplant ist Sie in Zukunft zu entfernen.
  529. </entry>
  530. </row>
  531. <row>
  532. <entry><methodname>getAuthors()</methodname></entry>
  533. <entry>
  534. Gibt ein Objekt vom Typ
  535. <classname>Zend_Feed_Reader_Collection_Author</classname> zurück welches
  536. ein <classname>ArrayObject</classname> ist dessen Elemente einfach
  537. Arrays sind die eine Kombination der Schlüssel "name", "email" und
  538. uri" enthalten. Wo es wegen der Quelldaten irrelevant ist können
  539. einige dieser Schlüssel unterdrückt werden.
  540. </entry>
  541. </row>
  542. <row>
  543. <entry><methodname>getAuthor(integer $index = 0)</methodname></entry>
  544. <entry>
  545. Gibt entweder den ersten bekannten Author zurück, oder mit dem
  546. optionalen Parameter <varname>$index</varname> jeden spezifischen
  547. Index des Arrays von Authoren wie vorher beschrieben (gibt
  548. <constant>NULL</constant> bei einem ungültigen Index zurück).
  549. </entry>
  550. </row>
  551. <row>
  552. <entry><methodname>getDateCreated()</methodname></entry>
  553. <entry>
  554. Gibt das Datum zurück zu dem dieser Feed erstellt wurde. Generell nur
  555. anwendbar bei Atom da es das Datum repräsentiert zu der das Atom 1.0
  556. Dokument erstellt wurde das die Ressource beschreibt. Das zurückgegebene
  557. Datum ist ein <classname>Zend_Date</classname> Objekt.
  558. </entry>
  559. </row>
  560. <row>
  561. <entry><methodname>getDateModified()</methodname></entry>
  562. <entry>
  563. Gibt das Datum zurück zu dem der Feed das letzte mal geändert wurde. Das
  564. zurückgegebene Datum ist ein <classname>Zend_Date</classname> Objekt.
  565. </entry>
  566. </row>
  567. <row>
  568. <entry><methodname>getLastBuildDate()</methodname></entry>
  569. <entry>
  570. Gibt das Datum zurück an dem der Feed das letzte Mal erstellt wurde. Das
  571. zurückgegebene Datum ist ein <classname>Zend_Date</classname> Objekt.
  572. Das wird nur von <acronym>RSS</acronym> unterstützt - Atom Feeds geben
  573. immer <constant>NULL</constant> zurück.
  574. </entry>
  575. </row>
  576. <row>
  577. <entry><methodname>getLanguage()</methodname></entry>
  578. <entry>
  579. Gibt die Sprache des Feeds zurüc (wenn definiert) oder einfach die
  580. Sprache die im <acronym>XML</acronym> Dokument notiert wurde
  581. </entry>
  582. </row>
  583. <row>
  584. <entry><methodname>getGenerator()</methodname></entry>
  585. <entry>
  586. Gibt den Erzeuger des Feeds zurück, z.B. die Software die Ihn erzeugt
  587. hat. Das kann sich zwischen <acronym>RSS</acronym> und Atom
  588. unterscheiden, da Atom eine andere Schreibweise definiert.
  589. </entry>
  590. </row>
  591. <row>
  592. <entry><methodname>getCopyright()</methodname></entry>
  593. <entry>
  594. Gibt alle Copyright Notizen zurück die mit dem Feed assoziiert sind
  595. </entry>
  596. </row>
  597. <row>
  598. <entry><methodname>getHubs()</methodname></entry>
  599. <entry>
  600. Gibt ein Array der <acronym>URI</acronym> Endpunkte aller Hub Server
  601. zurück welche vom Feed für die Berwendung mit dem Pubsubhubbub
  602. Protokoll bekanntgegeben werden, und erlaubt damit das Einschreiben
  603. für Feeds für Real-Time Updates.
  604. </entry>
  605. </row>
  606. <row>
  607. <entry><methodname>getCategories()</methodname></entry>
  608. <entry>
  609. Gibt ein <classname>Zend_Feed_Reader_Collection_Category</classname>
  610. Objekt zurück welches die Details aller Kategorien enthält die im
  611. kompletten Feed enthalten sind. Die unterstützten Felder enthalten
  612. "term" (den Maschinen lesbaren Namen der Kategorie), "scheme"
  613. (dem Schema der Kategorisierung für diese Kategorie), und "label" (ein
  614. <acronym>HTML</acronym> dekodierter menschlich lesbarer Kategoriename).
  615. Wenn irgendeines der drei Felder abwesend ist, werden Sie entweder auf
  616. die näheste vorhandene Alternative gesetzt, oder im Fall von "scheme",
  617. auf <constant>NULL</constant> gesetzt.
  618. </entry>
  619. </row>
  620. <row>
  621. <entry><methodname>getImage()</methodname></entry>
  622. <entry>
  623. Gibt ein Array zurück welches Daten enthält die jedem Feed Bild oder
  624. Logo angehören oder <constant>NULL</constant> wenn kein Bild gefunden
  625. wurde. Das resultierende Array kann die folgenden Schlüssel enthalten:
  626. <property>uri</property>, <property>link</property>,
  627. <property>title</property>, <property>description</property>,
  628. <property>height</property>, und <property>width</property>. Nur Atom
  629. Logos enthalten eine <acronym>URI</acronym> so dass die anderen
  630. Metadaten nur von <acronym>RSS</acronym> Feeds angehören.
  631. </entry>
  632. </row>
  633. </tbody>
  634. </tgroup>
  635. </table>
  636. <para>
  637. Angehend von der Vielzahl von Feeds in der Wildnis, werden einige dieser Methoden
  638. erwartungsgemäßg <constant>NULL</constant> zurückgeben, was anzeigt das die relevanten
  639. Informationen nicht gefunden wurden. Wo es möglich ist wird
  640. <classname>Zend_Feed_Reader</classname> während der Suche auf alternative Elemente
  641. zurück greifen. Zum Beispiel ist das Durchsuchen eines <acronym>RSS</acronym> Feeds
  642. nach einem Modifikations Datum komplizierter als es aussieht. <acronym>RSS</acronym>
  643. Feeds sollten ein <command>&lt;lastBuildDate&gt;</command> Tag und (oder) ein
  644. <command>&lt;pubDate&gt;</command> Element enthalten. Aber was wenn Sie es nicht tun,
  645. weil es z.B. ein <acronym>RSS</acronym> 1.0 Feed ist? Vielleicht ist stattdessen ein
  646. <command>&lt;atom:updated&gt;</command> Element mit identischen Informationen vorhanden
  647. (Atom kann verwendet werden um die <acronym>RSS</acronym> Syntax anzubieten)? Bei einem
  648. Fehlschlag können wir einfach auf die Einträge sehen, den aktuellsten herausholen, und
  649. sein <command>&lt;pubDate&gt;</command> Element verwenden. In der Annahme das es
  650. existiert... viele Feeds verwenden auch Dublin Core 1.0 oder 1.1
  651. <command>&lt;dc:date&gt;</command> Elemente für Feeds und Einträge. Oder wir können
  652. wieder ein Atom finden das herumliegt.
  653. </para>
  654. <para>
  655. Der Punkt ist, das <classname>Zend_Feed_Reader</classname> entwickelt wurde um das zu
  656. wissen. Wenn man nach dem Änderungsdatum fragt (oder irgendwas anderes), wird er
  657. starten und alle diese Alternativen suchen bis er entweder aufgibt und
  658. <constant>NULL</constant> zurückgibt, oder eine Alternative findet welche die richtige
  659. Antwort hat.
  660. </para>
  661. <para>
  662. Zusätzlich zu den obigen Methoden, implementieren alle Feed Objekte Methoden für das
  663. empfangen der <acronym>DOM</acronym> und XPath Objekte für die aktuellen Feeds wie
  664. vorher beschrieben. Feed Objekte implementieren auch die Interfaces für
  665. <acronym>SPL</acronym> Iterator und Countable. Die erweiterte <acronym>API</acronym>
  666. wird anbei zusammengefasst.
  667. </para>
  668. <table>
  669. <title>Erweiterte API Methoden auf Level des Feeds</title>
  670. <tgroup cols="2">
  671. <tbody>
  672. <row>
  673. <entry><methodname>getDomDocument()</methodname></entry>
  674. <entry>
  675. Gibt das elterliche DOMDocument Objekt für das
  676. komplette <acronym>XML</acronym> Quelldokument zurück
  677. </entry>
  678. </row>
  679. <row>
  680. <entry><methodname>getElement()</methodname></entry>
  681. <entry>
  682. Gibt das aktuelle DOMElement Objekt des Feed Levels zurück
  683. </entry>
  684. </row>
  685. <row>
  686. <entry><methodname>saveXml()</methodname></entry>
  687. <entry>
  688. Gibt einen String zurück der ein <acronym>XML</acronym> Dokument
  689. zurück welches das komplette Feed Element enthält (das ist nicht das
  690. originale Dokument sondern eine nachgebaute Version)
  691. </entry>
  692. </row>
  693. <row>
  694. <entry><methodname>getXpath()</methodname></entry>
  695. <entry>
  696. Gibt das intern verwendete DOMXPath Objekt zurück mit dem Abfragen auf
  697. das DOMDocument Objekt durchgeführt werden (das enthält die Kern und
  698. Erweiterungs Namespaces die vor-registriert sind)
  699. </entry>
  700. </row>
  701. <row>
  702. <entry><methodname>getXpathPrefix()</methodname></entry>
  703. <entry>
  704. Gibt den gültigen <acronym>DOM</acronym> Pfad Präfix zurück der bei
  705. allen XPath Abfragen passt die dem Feed entsprechen der abgefragt wird.
  706. </entry>
  707. </row>
  708. <row>
  709. <entry><methodname>getEncoding()</methodname></entry>
  710. <entry>
  711. Gibt die Kodierung des <acronym>XML</acronym> Quelldokuments zurück
  712. (Beachte: Das kann nicht verwendet werden für Fehler wie einen
  713. Server der Dokumente in einer anderen Kodierung verschickt). Wo diese
  714. nicht definiert ist, wird die Standardkodierung <acronym>UTF-8</acronym>
  715. von Unicode angewendet.
  716. </entry>
  717. </row>
  718. <row>
  719. <entry><methodname>count()</methodname></entry>
  720. <entry>
  721. Gibt eine Zahl von Einträgen oder Elementen zurück welche dieser Feed
  722. enthält (implementiert das <acronym>SPL</acronym> Interface
  723. <classname>Countable</classname>)
  724. </entry>
  725. </row>
  726. <row>
  727. <entry><methodname>current()</methodname></entry>
  728. <entry>
  729. Gibt nur den aktuellen Eintrag zurück (verwendet den aktuellen
  730. Index von <methodname>key()</methodname>)
  731. </entry>
  732. </row>
  733. <row>
  734. <entry><methodname>key()</methodname></entry>
  735. <entry>Gibt den aktuellen Index für Einträge zurück</entry>
  736. </row>
  737. <row>
  738. <entry><methodname>next()</methodname></entry>
  739. <entry>Addiert den Wert des Index für Einträge um Eins</entry>
  740. </row>
  741. <row>
  742. <entry><methodname>rewind()</methodname></entry>
  743. <entry>Setzt den Index für Einträge auf 0 zurück</entry>
  744. </row>
  745. <row>
  746. <entry><methodname>valid()</methodname></entry>
  747. <entry>
  748. Prüft ob der aktuelle Index für Einträge gültig ist, z.B. ob er nicht
  749. unter 0 fällt und die Anzahl der existierenden Einträge nicht
  750. übersteigt.
  751. </entry>
  752. </row>
  753. <row>
  754. <entry><methodname>getExtensions()</methodname></entry>
  755. <entry>
  756. Gibt ein Array aller Erweiterungs Objekte zurück die für den aktuellen
  757. Feed geladen sind (Beachte: sowohl Feel-Level als auch Element-Level
  758. Erweiterungen exstieren, aber nur Feed-Level Erweiterungen werden hier
  759. zurückgegeben). Die Array Schlüssel sind in der Form
  760. (ErweiterungsName)_Feed.
  761. </entry>
  762. </row>
  763. <row>
  764. <entry><methodname>getExtension(string $name)</methodname></entry>
  765. <entry>
  766. Gibt ein Erweiterungs Objekt für den Feed zurück der unter dem
  767. angegebenen Namen registriert ist. Das erlaubt einen feiner
  768. gestaffelten Zugriff auf Erweiterungen welche andernfalls in der
  769. Implementation der standardmäßigen <acronym>API</acronym> Methoden
  770. versteckt wären.
  771. </entry>
  772. </row>
  773. <row>
  774. <entry><methodname>getType()</methodname></entry>
  775. <entry>
  776. Gibt eine statische Klassenkonstante zurück (z.B.
  777. <constant>Zend_Feed_Reader::TYPE_ATOM_03</constant>, z.B. Atom 0.3)
  778. welche exakt anzeigt welche Art von Feed gerade konsumiert wird.
  779. </entry>
  780. </row>
  781. </tbody>
  782. </tgroup>
  783. </table>
  784. </sect2>
  785. <sect2 id="zend.feed.reader.entry">
  786. <title>Empfangen von Informationen aus Einträgen/Elementen</title>
  787. <para>
  788. Das Empfangen von Informationen für spezifische Einträge oder Elemente (abhängig davon
  789. ob man Atom oder <acronym>RSS</acronym> spricht) ist identisch wie bei den Daten auf
  790. Feed Level. Der Zugriff auf Einträge ist einfach ein Fall von Iteration über ein Feed
  791. Objekt oder durch Verwendung des <acronym>SPL</acronym> Interfaces
  792. <classname>Iterator</classname> welches Feed Objekte implementieren und durch
  793. Aufruf der betreffenden Methoden auf Ihnen.
  794. </para>
  795. <table>
  796. <title>API Methoden auf Level des Eintrags</title>
  797. <tgroup cols="2">
  798. <tbody>
  799. <row>
  800. <entry><methodname>getId()</methodname></entry>
  801. <entry>Gibt eine eindeutige ID für den aktuellen Eintrag zurück.</entry>
  802. </row>
  803. <row>
  804. <entry><methodname>getTitle()</methodname></entry>
  805. <entry>Gibt den Titel des aktuellen Eintrags zurück.</entry>
  806. </row>
  807. <row>
  808. <entry><methodname>getDescription()</methodname></entry>
  809. <entry>Gibt eine Beschreibung des aktuellen Eintrags zurück.</entry>
  810. </row>
  811. <row>
  812. <entry><methodname>getLink()</methodname></entry>
  813. <entry>
  814. Gibt eine <acronym>URI</acronym> zur <acronym>HTML</acronym> Version des
  815. aktuellen Eintrags zurück.
  816. </entry>
  817. </row>
  818. <row>
  819. <entry><methodname>getPermaLink()</methodname></entry>
  820. <entry>
  821. Gibt einen permanenten Link zum aktuellen Eintrag zurück. In den meisten
  822. Fällen ist dies das selbe wie die Verwendung von
  823. <methodname>getLink()</methodname>.
  824. </entry>
  825. </row>
  826. <row>
  827. <entry><methodname>getAuthors()</methodname></entry>
  828. <entry>
  829. Gibt ein Objekt vom Typ
  830. <classname>Zend_Feed_Reader_Collection_Author</classname> zurück welches
  831. ein <classname>ArrayObject</classname> ist, dessen Elemente alle
  832. einfache Array sind welche beliebige Kombinationen der Schlüssel "name",
  833. "email" und "uri" enthalten können. Wo es für die Quelldaten irrelevant
  834. ist können einige dieser Schlüssel unterdrückt sein.
  835. </entry>
  836. </row>
  837. <row>
  838. <entry><methodname>getAuthor(integer $index = 0)</methodname></entry>
  839. <entry>
  840. Gibt entweder den ersten bekannten Autor zurück, oder mit dem
  841. optionalen Parameter <varname>$index</varname> jeden spezifischen Index
  842. aus dem Array der Authoren wie vorher beschrieben (gibt
  843. <constant>NULL</constant> zurück wenn der Index ungültig ist).
  844. </entry>
  845. </row>
  846. <row>
  847. <entry><methodname>getDateCreated()</methodname></entry>
  848. <entry>
  849. Gibt das Datum zurück an dem der aktuelle Eintrag erstellt wurde.
  850. Generell kann das nur auf Atom angewendet werden wo es das Datum der
  851. Ressource beschreibt zu welche das Atom 1.0 Dokument erstellt wurde.
  852. </entry>
  853. </row>
  854. <row>
  855. <entry><methodname>getDateModified()</methodname></entry>
  856. <entry>
  857. Gibt das Datum zurück an welchem der aktuelle Eintrag zuletzt geändert
  858. wurde.
  859. </entry>
  860. </row>
  861. <row>
  862. <entry><methodname>getContent()</methodname></entry>
  863. <entry>
  864. Gibt den Inhalt des aktuellen Eintrags zurück (das retourniert alle
  865. Entities wenn das möglich ist, mit der Annahme das der Content Type
  866. <acronym>HTML</acronym> ist). Die Beschreibung wird zurückgegeben wenn
  867. ein kein seperates Content Element existiert.
  868. </entry>
  869. </row>
  870. <row>
  871. <entry><methodname>getEnclosure()</methodname></entry>
  872. <entry>
  873. Gibt ein Array zurück welches die Werte aller Attribute eines
  874. Multimedia &lt;enclosure&gt; Elements enthält, inklusive der Array
  875. Schlüssel: <emphasis>url</emphasis>, <emphasis>length</emphasis>,
  876. <emphasis>type</emphasis>. Basierend auf dem <acronym>RSS</acronym> Best
  877. Practices Profile des <acronym>RSS</acronym> Advisory Boards, wird keine
  878. Unterstützung für mehrere Enclosures angeboten da so eine Unterstützung
  879. kein Teil der <acronym>RSS</acronym> Spezifikation ist.
  880. </entry>
  881. </row>
  882. <row>
  883. <entry><methodname>getCommentCount()</methodname></entry>
  884. <entry>
  885. Gibt die Anzahl der Kommentare zurück die auf diesen Eintrag gemacht
  886. wurden seit der Zeit an welcher der Feed erstellt wurde
  887. </entry>
  888. </row>
  889. <row>
  890. <entry><methodname>getCommentLink()</methodname></entry>
  891. <entry>
  892. Gibt eine <acronym>URI</acronym> zurück welche auf die
  893. <acronym>HTML</acronym> Seite zeigt, auf der Kommentare zu diesem
  894. Eintrag gemacht werden können
  895. </entry>
  896. </row>
  897. <row>
  898. <entry>
  899. <methodname>getCommentFeedLink([string $type =
  900. 'atom'|'rss'])</methodname>
  901. </entry>
  902. <entry>
  903. Gibt eine <acronym>URI</acronym> zurück die auf einen Feed zeigt welcher
  904. vom angegebenen Typ ist, und alle Kommentare für diesen Eintrag enthält
  905. (Der Typ ist standardmäßig Atom/<acronym>RSS</acronym> abhängig vom
  906. aktuellen Feed Typ).
  907. </entry>
  908. </row>
  909. <row>
  910. <entry><methodname>getCategories()</methodname></entry>
  911. <entry>
  912. Gibt ein <classname>Zend_Feed_Reader_Collection_Category</classname>
  913. Objekt zurück welches die Details jeder Kategorie enthält welche mit dem
  914. Eintrag assoziiert ist. Die unterstützten Felder sind "term" (der
  915. Maschinen lesbare Name der Kategorie), "scheme" (der Name des Schemas
  916. der Kategorisierung für diese Kategorie), und "label" (ein
  917. <acronym>HTML</acronym> dekodierter menschlich lesbarer Name der
  918. Kategorie). Wenn eines der drei Felder nicht vorhanden ist, werden Sie
  919. entweder auf den näheste vorhandene Alternative, oder im Fall von
  920. "scheme", auf <constant>NULL</constant> gesetzt.
  921. </entry>
  922. </row>
  923. </tbody>
  924. </tgroup>
  925. </table>
  926. <para>
  927. Die erweiterte <acronym>API</acronym> für Einträge ist identisch zu der für die Feed
  928. mit der Aufnahme der Iterator Methoden die hier nicht benötigt werden.
  929. </para>
  930. <caution>
  931. <para>
  932. Es gibt oft Missverständnisse über die Konzepte vom Zeitpunkt der Änderung und des
  933. Erstellungsdatums. In Atom, sind diese zwei klar definierte Konzepte aber in
  934. <acronym>RSS</acronym> sind Sie vage. <acronym>RSS</acronym> 2.0 definiert ein
  935. einzelnes <emphasis>&lt;pubDate&gt;</emphasis> Element das typischerweise auf das
  936. Datum referiert an dem dieser Eintrag veröffentlicht wurde, z.B. etwas in der Art
  937. eines Erstellungsdatums. Das ist nicht immer das gleiche, und kann sich durch
  938. Updates ändern oder auch nicht. Als Resultat sollte man sich, wenn man wirklich
  939. prüfen will ob der Eintrag geändert wurde oder nicht, nicht auf das Ergebnis von
  940. <methodname>getDateModified()</methodname> verlassen. Stattdessen sollte man
  941. Erwägen den <acronym>MD5</acronym> Hash von drei anderen verknpüften Elementen
  942. zu beobachten, z.B. durch Verwendung von <methodname>getTitle()</methodname>,
  943. <methodname>getDescription()</methodname> und
  944. <methodname>getContent()</methodname>. Wenn der Eintrag wirklich geändert wurde,
  945. gibt diese Hash Berechnung ein anderes Ergebnis als die vorher gespeicherten Hashs
  946. für den gleichen Eintrag. Das ist natürlich Inhalts-Orientiert und hilft nicht
  947. bei der Erkennung von anderen relevanten Elementen. Atom Feeds sollten solche
  948. Schritte nicht benötigen.
  949. </para>
  950. <para>
  951. Weitere Schritte in diesen Wassern zeigen das die Daten
  952. von Feeds unterschiedlichen Standards folgen. Atom und Dublin Core Daten sollten
  953. <acronym>ISO</acronym> 86001 folgen und <acronym>RSS</acronym> Daten sollten
  954. <acronym>RFC</acronym> 822 oder <acronym>RFC</acronym> 2822 folgen welche auch
  955. üblicherweise verwendet werden. Datumsmethoden werfen eine Exception wenn
  956. <classname>Zend_Date</classname>, oder die <acronym>PHP</acronym> basierenden
  957. Möglichkeiten für <acronym>RSS</acronym> Daten, das Datum durch Verwendung der
  958. obigen Standards nicht laden kann.
  959. </para>
  960. </caution>
  961. <warning>
  962. <para>
  963. Die Werte die von diesen Methoden zurückgegeben werden, sind nicht geprüft. Das
  964. bedeutet das der Benutzer Prüfungen auf allen empfangenen Daten durchführen muss
  965. inklusive filtern von jeglichem <acronym>HTML</acronym> wie von
  966. <methodname>getContent()</methodname> bevor es von der eigenen Anwendung ausgegeben
  967. wird. Es ist zu beachten das die meisten Feeds von externen Quellen kommen, und
  968. deshalb die normale Annahme sein sollte das man Ihnen nicht trauen kann.
  969. </para>
  970. </warning>
  971. <table>
  972. <title>Erweiterte API Methoden auf Level des Eintrags</title>
  973. <tgroup cols="2">
  974. <tbody>
  975. <row>
  976. <entry><methodname>getDomDocument()</methodname></entry>
  977. <entry>
  978. Gibt das elterliche DOMDocument Objekt für den kompletten Feed zurück
  979. (nicht nur den aktuellen Eintrag)
  980. </entry>
  981. </row>
  982. <row>
  983. <entry><methodname>getElement()</methodname></entry>
  984. <entry>
  985. Gibt das DOMDocument Objekt für den aktuellen Level des Eintrags zurück
  986. </entry>
  987. </row>
  988. <row>
  989. <entry><methodname>getXpath()</methodname></entry>
  990. <entry>
  991. Gibt das DOMXPath Objekt zurück welches intern verwendet wird um
  992. Abfragen auf dem DOMDocument Objekt durchzuführen (es enthält
  993. auch die vorregistrierten Kern und Erweiterungs Namespaces)
  994. </entry>
  995. </row>
  996. <row>
  997. <entry><methodname>getXpathPrefix()</methodname></entry>
  998. <entry>
  999. Gibt einen gültigen <acronym>DOM</acronym> Pfad Präfix zurück der allen
  1000. XPath Abfrage vorangestellt wird, welche dem Eintrag entsprechen der
  1001. abgefragt wird.
  1002. </entry>
  1003. </row>
  1004. <row>
  1005. <entry><methodname>getEncoding()</methodname></entry>
  1006. <entry>
  1007. Gibt die Kodierung des <acronym>XML</acronym> Quelldokuments zurück
  1008. (Achtung: Das kann nicht für Fehler genommen werden bei denen der
  1009. Server eine andere Kodierung sendet als die Dokumente). Die Standard
  1010. Kodierung welche bei Abwesenheit jeglicher anderen Kodierung angewendet
  1011. wird, ist die <acronym>UTF-8</acronym> Kodierung von Unicode.
  1012. </entry>
  1013. </row>
  1014. <row>
  1015. <entry><methodname>getExtensions()</methodname></entry>
  1016. <entry>
  1017. Gibt ein Array aller Erweiterungsobjekte zurück die für den aktuellen
  1018. Eintrag geladen wurden (Achtung: Sowohl Erweiterung auf Level von Feeds
  1019. als auch auf Level von Einträgen existieren, und nur Erweiterungen auf
  1020. Level von Einträgen werden hier zurückgegeben). Die Arrayschlüssel sind
  1021. im Format {ErweiterungsName}_Entry.
  1022. </entry>
  1023. </row>
  1024. <row>
  1025. <entry><methodname>getExtension(string $name)</methodname></entry>
  1026. <entry>
  1027. Gibt das Erweiterungsobjekt zurück für das der Eintrag mit dem
  1028. angegebenen Namen registriert wurde. Das erlaubt einen feineren
  1029. Zugriff auf Erweiterungen welche andernfalls innerhalb der
  1030. Implementierung der standardmäßigen <acronym>API</acronym> Methoden
  1031. versteckt wären.
  1032. </entry>
  1033. </row>
  1034. <row>
  1035. <entry><methodname>getType()</methodname></entry>
  1036. <entry>
  1037. Gibt eine statische Klassenkonstante zurück (z.B.
  1038. <constant>Zend_Feed_Reader::TYPE_ATOM_03</constant>, z.B. Atom 0.3)
  1039. die exakt anzeigt von welcher Art der Feed ist der gerade konsumiert
  1040. wird.
  1041. </entry>
  1042. </row>
  1043. </tbody>
  1044. </tgroup>
  1045. </table>
  1046. </sect2>
  1047. <sect2 id="zend.feed.reader.extending">
  1048. <title>Erweitern der APIs für Feeds und Einträge</title>
  1049. <para>
  1050. Die Erweiterung von <classname>Zend_Feed_Reader</classname> erlaubt es Methoden sowohl
  1051. auf Level von Feeds als auch auf Level von Einträgen hinzuzufügen, welche das Empfangen
  1052. von Informationen abdecken die nicht bereits von <classname>Zend_Feed_Reader</classname>
  1053. unterstützt werden. Bei der Anzahl an <acronym>RSS</acronym> und Atom Erweiterungen die
  1054. existieren, ist das ein guter Weg da <classname>Zend_Feed_Reader</classname> einfach
  1055. nicht alles hinzufügen kann.
  1056. </para>
  1057. <para>
  1058. Es gibt zwei Typen von Erweiterungen, jene welche Informationen von Elementen empfangen
  1059. die unmittelbare Kunder des Root Elements sind (z.B. <command>&lt;channel&gt;</command>
  1060. für <acronym>RSS</acronym> oder <command>&lt;feed&gt;</command> für Atom), und jene die
  1061. Informationen von Kind-Elementen eines Eintrags empfangen (z.B.
  1062. <command>&lt;item&gt;</command> für <acronym>RSS</acronym> oder
  1063. <command>&lt;entry&gt;</command> für Atom). Auf dem Filesystem sind Sie als Klassen in
  1064. einem Namespace gruppiert, basierend auf dem Standardnamen der Erweiterung. Zum Beispiel
  1065. haben wir intern <classname>Zend_Feed_Reader_Extension_DublinCore_Feed</classname> und
  1066. <classname>Zend_Feed_Reader_Extension_DublinCore_Entry</classname> Klassen welche zwei
  1067. Klassen sind welche die Unterstützung für Dublin Core 1.0/1.1 implementieren.
  1068. </para>
  1069. <para>
  1070. Erweiterungen werden in <classname>Zend_Feed_Reader</classname> durch Verwendung von
  1071. <classname>Zend_Loader_PluginLoader</classname> geladen, sodas dessen Operationen
  1072. ähnlich denen anderer Zend Framework Komponenten ist.
  1073. <classname>Zend_Feed_Reader</classname> kommt bereits mit einer Anzahl dieser
  1074. Erweiterungen. Trotzdem müssen jene, die nicht intern verwendet und standardmäßig
  1075. registriert werden (sogenannte Core Erweiterungen), bei
  1076. <classname>Zend_Feed_Reader</classname> registriert werden bevor Sie verwendet werden.
  1077. Die gebündelten Erweiterungen sind:
  1078. </para>
  1079. <table>
  1080. <title>Core Extensions (pre-registered)</title>
  1081. <tgroup cols="2">
  1082. <tbody>
  1083. <row>
  1084. <entry>DublinCore (Feed und Eintrag)</entry>
  1085. <entry>
  1086. Implementiert die Unterstützung für das Dublin Core Metadata Element
  1087. Set 1.0 und 1.1
  1088. </entry>
  1089. </row>
  1090. <row>
  1091. <entry>Content (nur Eintrag)</entry>
  1092. <entry>Implementiert Unterstützung für Content 1.0</entry>
  1093. </row>
  1094. <row>
  1095. <entry>Atom (Feed und Eintrag)</entry>
  1096. <entry>Implementiert Unterstützung für Atom 0.3 und Atom 1.0</entry>
  1097. </row>
  1098. <row>
  1099. <entry>Slash</entry>
  1100. <entry>
  1101. Implementiert Unterstützung für das Slash <acronym>RSS</acronym> 1.0
  1102. Modul
  1103. </entry>
  1104. </row>
  1105. <row>
  1106. <entry>WellFormedWeb</entry>
  1107. <entry>
  1108. Implementiert Unterstützung für das Well Formed Web CommentAPI 1.0
  1109. </entry>
  1110. </row>
  1111. <row>
  1112. <entry>Thread</entry>
  1113. <entry>
  1114. Implementiert Unterstützung für Atom Threading Erweiterungen wie in
  1115. <acronym>RFC</acronym> 4685 beschrieben
  1116. </entry>
  1117. </row>
  1118. <row>
  1119. <entry>Podcast</entry>
  1120. <entry>
  1121. Implementiert Unterstützung für das Podcast 1.0 <constant>DTD</constant>
  1122. von Apple
  1123. </entry>
  1124. </row>
  1125. </tbody>
  1126. </tgroup>
  1127. </table>
  1128. <para>
  1129. Die Core Erweiterungen sind irgendwie speziell da Sie extrem allgemein sind und viele
  1130. Facetten haben. Zum Beispiel haben wir eine Core Erweiterung für Atom. Atom ist als
  1131. Erweiterung (und nicht nur als Basis Klasse) implementiert weil es ein gültiges
  1132. <acronym>RSS</acronym> Modul dupliziert - so kann man Atom Elemente in
  1133. <acronym>RSS</acronym> Feeds einfügen. Wir haben sogar <acronym>RDF</acronym> Feeds
  1134. gesehen die viel von Atom verwenden statt den üblicheren Erweiterungen wie Dublin Core.
  1135. </para>
  1136. <table>
  1137. <title>Nicht-Core Erweiterungen (müssen per Hand registriert werden)</title>
  1138. <tgroup cols="2">
  1139. <tbody>
  1140. <row>
  1141. <entry>Syndication</entry>
  1142. <entry>
  1143. Implementiert Unterstützung für Syndication 1.0 <acronym>RSS</acronym>
  1144. Feeds
  1145. </entry>
  1146. </row>
  1147. <row>
  1148. <entry>CreativeCommons</entry>
  1149. <entry>
  1150. Ein <acronym>RSS</acronym> Modul das ein Element auf &lt;channel&gt;
  1151. oder &lt;item&gt; Level hinzufügt welches spezifiziert welche
  1152. Creative Commons Lizenz anzuwenden ist.
  1153. </entry>
  1154. </row>
  1155. </tbody>
  1156. </tgroup>
  1157. </table>
  1158. <para>
  1159. Die zusätzlichen nicht-Core Erweiterungen werden angeboten aber standardmäßig bei
  1160. <classname>Zend_Feed_Reader</classname> nicht registriert. Wenn man Sie verwenden will,
  1161. muß man <classname>Zend_Feed_Reader</classname> sagen dass Sie diese zusätzlich zum
  1162. Importieren eines Feeds laden soll. Zusätzliche nicht-Core Erweiterungen werden in
  1163. zukünftigen Releases dieser Komponente enthalten sein.
  1164. </para>
  1165. <para>
  1166. Das Registrieren einer Erweiterung bei <classname>Zend_Feed_Reader</classname>, so dass
  1167. diese geladen wird und dessen <acronym>API</acronym> für Feed und Entry Objekte zur
  1168. Verfügung steht, ist eine einfache Sache wenn der
  1169. <classname>Zend_Loader_PluginLoader</classname> verwendet wird. Hier registrieren wir
  1170. die optionale Slash Erweiterung und finden heraus das Sie direkt von der Entry Level
  1171. <acronym>API</acronym> heraus aufgerufen werden kann, ohne große Dinge notwendig sind.
  1172. Es ist zu beachten das die Namen der Erweiterungen von der Schreibweise abhängig sind
  1173. und Camel Casing für mehrere Ausdrücke verwenden.
  1174. </para>
  1175. <programlisting language="php"><![CDATA[
  1176. Zend_Feed_Reader::registerExtension('Syndication');
  1177. $feed = Zend_Feed_Reader::import('http://rss.slashdot.org/Slashdot/slashdot');
  1178. $updatePeriod = $feed->current()->getUpdatePeriod();
  1179. ]]></programlisting>
  1180. <para>
  1181. Im obigen Beispiel haben wir geprüft wie oft ein Feed aktualisiert wurde indem wir die
  1182. <methodname>getUpdatePeriod()</methodname> Methode verwendet haben. Da das nicht Teil
  1183. der Kern <acronym>API</acronym> von <classname>Zend_Feed_Reader</classname> ist, kann es
  1184. nur eine Methode sein die von der neu registrieren Syndication Erweiterung unterstützt
  1185. wird.
  1186. </para>
  1187. <para>
  1188. Wie man auch sieht, kann man auf die neuen Methoden vlon Erweiterungen aus der Haupt
  1189. <acronym>API</acronym> heraus zugreifen indem <acronym>PHP</acronym>'s magische
  1190. Methoden verwendet werden. Als Alternative kann man, für ein ähnliches Ergebnis, auf
  1191. jedes Erweiterungs Objekt auch direkt zugreifen, wie anbei gezeigt.
  1192. </para>
  1193. <programlisting language="php"><![CDATA[
  1194. Zend_Feed_Reader::registerExtension('Syndication');
  1195. $feed = Zend_Feed_Reader::import('http://rss.slashdot.org/Slashdot/slashdot');
  1196. $syndication = $feed->getExtension('Syndication');
  1197. $updatePeriod = $syndication->getUpdatePeriod();
  1198. ]]></programlisting>
  1199. <sect3 id="zend.feed.reader.extending.feed">
  1200. <title>Erweiterungen für Zend_Feed_Reader schreiben</title>
  1201. <para>
  1202. Unweigerlich gibt es Zeiten in denen die <acronym>API</acronym> von
  1203. <classname>Zend_Feed_Reader</classname> einfach nicht in der Lage ist etwas das man
  1204. von einem Feed oder Eintrag benötigt zu erhalten. Man kann die darunterliegenden
  1205. Quell Objekte, wie ein DOMDocument, verwenden um Sie von Hand zu erhalten. Trotzdem
  1206. sind weitere wiederverwendbare Methoden vorhanden indem man Erweiterungen schreibt
  1207. die diese neuen Abfragen unterstützen.
  1208. </para>
  1209. <para>
  1210. Als Beispiel nehmen wir den Fall eine komplett fiktiven Firma an die Jungle Books
  1211. heißt. Jungle Books hat eine Vielzahl an Reviews für Bücher veröffentlicht die Sie
  1212. verkaufen (von externen Quellen und Kunden), welche als <acronym>RSS</acronym> 2.0
  1213. Feed verteilt werden. Die Marketing Abteilung realisiert das Web Anwendungen welche
  1214. diesen Feed verwenden, aktuell nicht herausfinden können welches Buch exakt
  1215. betrachtet wird. Um jedem das Leben leichter zu machen entscheiden Sie dass die
  1216. Streber Abteilung <acronym>RSS</acronym> 2.0 erweitern muß um ein neues Element
  1217. pro Eintrag hinzuzufügen das die <acronym>ISBN</acronym>-10 oder
  1218. <acronym>ISBN</acronym>-13 Zahl der Veröffentlichung die der Eintrag betrifft
  1219. unterstützt. Sie definieren das neue <command>&lt;isbn&gt;</command> Element recht
  1220. einfach mit dem standardmäßigen Namen und Namespace <acronym>URI</acronym>:
  1221. </para>
  1222. <programlisting language="php"><![CDATA[
  1223. JungleBooks 1.0:
  1224. http://example.com/junglebooks/rss/module/1.0/
  1225. ]]></programlisting>
  1226. <para>
  1227. Ein Teil des <acronym>RSS</acronym> das diese Erweiterung in der Praxis enthält
  1228. könnte in etwa so aussehen:
  1229. </para>
  1230. <programlisting language="php"><![CDATA[
  1231. <?xml version="1.0" encoding="utf-8" ?>
  1232. <rss version="2.0"
  1233. xmlns:content="http://purl.org/rss/1.0/modules/content/"
  1234. xmlns:jungle="http://example.com/junglebooks/rss/module/1.0/">
  1235. <channel>
  1236. <title>Jungle Books Customer Reviews</title>
  1237. <link>http://example.com/junglebooks</link>
  1238. <description>Many book reviews!</description>
  1239. <pubDate>Fri, 26 Jun 2009 19:15:10 GMT</pubDate>
  1240. <jungle:dayPopular>
  1241. http://example.com/junglebooks/book/938
  1242. </jungle:dayPopular>
  1243. <item>
  1244. <title>Review Of Flatland: A Romance of Many Dimensions</title>
  1245. <link>http://example.com/junglebooks/review/987</link>
  1246. <author>Confused Physics Student</author>
  1247. <content:encoded>
  1248. A romantic square?!
  1249. </content:encoded>
  1250. <pubDate>Thu, 25 Jun 2009 20:03:28 -0700</pubDate>
  1251. <jungle:isbn>048627263X</jungle:isbn>
  1252. </item>
  1253. </channel>
  1254. </rss>
  1255. ]]></programlisting>
  1256. <para>
  1257. Die Implementierung dieses neuen <acronym>ISBN</acronym> Elements als eine einfache
  1258. Eintrags Level Erweiterung wird die folgende Klasse benötigen (und die Verwendung
  1259. des eigenen Klassen Namespaces ausserhalb von Zend).
  1260. </para>
  1261. <programlisting language="php"><![CDATA[
  1262. class My_FeedReader_Extension_JungleBooks_Entry
  1263. extends Zend_Feed_Reader_Extension_EntryAbstract
  1264. {
  1265. public function getIsbn()
  1266. {
  1267. if (isset($this->_data['isbn'])) {
  1268. return $this->_data['isbn'];
  1269. }
  1270. $isbn = $this->_xpath->evaluate(
  1271. 'string(' . $this->getXpathPrefix() . '/jungle:isbn)'
  1272. );
  1273. if (!$isbn) {
  1274. $isbn = null;
  1275. }
  1276. $this->_data['isbn'] = $isbn;
  1277. return $this->_data['isbn'];
  1278. }
  1279. protected function _registerNamespaces()
  1280. {
  1281. $this->_xpath->registerNamespace(
  1282. 'jungle', 'http://example.com/junglebooks/rss/module/1.0/'
  1283. );
  1284. }
  1285. }
  1286. ]]></programlisting>
  1287. <para>
  1288. Diese Erweiterung ist einfach genug um Ihr zu folgen. Sie erstellt eine neue Methode
  1289. <methodname>getIsbn()</methodname>, welche eine XPath Abfrage auf dem aktuellen
  1290. Eintrag durchführt, um die <acronym>ISBN</acronym> Nummer welche vom
  1291. <command>&lt;jungle:isbn&gt;</command> Element umhüllt ist, zu extrahieren. Das kann
  1292. optional auch im internen nicht-persistenten Cache gespeichert werden (keine
  1293. Notwendigkeit den <acronym>DOM</acronym> abzufragen wenn es auf dem gleichen
  1294. Eintrag nochmals aufgerufen wird). Der Wert wird dem Anrufer zurückgegeben.
  1295. Am Ende haben wir eine geschützte Methode (Sie ist abstrakt, muss also existieren)
  1296. welche den Jungle Books Namespace für Ihre eigenen <acronym>RSS</acronym> Module
  1297. registriert. Wärend wir das ein <acronym>RSS</acronym> Modul nennen, gibt es nichts
  1298. das verhindert dass das gleiche Element in Atom Feeds verwendet wird - und alle
  1299. Erweiterungen welche den Prefix verwenden der von
  1300. <methodname>getXpathPrefix()</methodname> angeboten wird, sind aktuell neutral und
  1301. arbeiten auf <acronym>RSS</acronym> oder Atom Feeds ohne zusätzlichen Code.
  1302. </para>
  1303. <para>
  1304. Da die Erweiterung ausserhalb vom Zend Framework gespeichert ist, muss man den Pfad
  1305. Prefix für die eigenen Erweiterungen registrieren damit
  1306. <classname>Zend_Loader_PluginLoader</classname> diese finden kann. Danach ist es
  1307. einfach ein Problem der Registrierung der Erweiterung, wenn diese nicht bereits
  1308. geladen wurde, und deren Verwendung in der Praxis.
  1309. </para>
  1310. <programlisting language="php"><![CDATA[
  1311. if(!Zend_Feed_Reader::isRegistered('JungleBooks')) {
  1312. Zend_Feed_Reader::addPrefixPath(
  1313. 'My_FeedReader_Extension', '/path/to/My/FeedReader/Extension'
  1314. );
  1315. Zend_Feed_Reader::registerExtension('JungleBooks');
  1316. }
  1317. $feed = Zend_Feed_Reader::import('http://example.com/junglebooks/rss');
  1318. // ISBN für irgendein Buch dem der erste Eintrag im Feed gewidmet war
  1319. $firstIsbn = $feed->current()->getIsbn();
  1320. ]]></programlisting>
  1321. <para>
  1322. Das Schreiben einer Feed Level Erweiterung unterscheidet sich nicht sehr. Der
  1323. Beispiel Feed von vorher enthält ein nicht erwähntes
  1324. <command>&lt;jungle:dayPopular&gt;</command> Element das Jungle Books bei Ihrem
  1325. Standard hinzugefügt haben um einen Link zum beliebtesten Buch des Tages
  1326. hinzuzufügen (im Sinne von Verkehr der Besucher). Hier ist eine Erweiterung welche
  1327. eine <methodname>getDaysPopularBookLink()</methodname> Methode bei der Feed Level
  1328. <acronym>API</acronym> hinzufügt.
  1329. </para>
  1330. <programlisting language="php"><![CDATA[
  1331. class My_FeedReader_Extension_JungleBooks_Feed
  1332. extends Zend_Feed_Reader_Extension_FeedAbstract
  1333. {
  1334. public function getDaysPopularBookLink()
  1335. {
  1336. if (isset($this->_data['dayPopular'])) {
  1337. return $this->_data['dayPopular'];
  1338. }
  1339. $dayPopular = $this->_xpath->evaluate(
  1340. 'string(' . $this->getXpathPrefix() . '/jungle:dayPopular)'
  1341. );
  1342. if (!$dayPopular) {
  1343. $dayPopular = null;
  1344. }
  1345. $this->_data['dayPopular'] = $dayPopular;
  1346. return $this->_data['dayPopular'];
  1347. }
  1348. protected function _registerNamespaces()
  1349. {
  1350. $this->_xpath->registerNamespace(
  1351. 'jungle', 'http://example.com/junglebooks/rss/module/1.0/'
  1352. );
  1353. }
  1354. }
  1355. ]]></programlisting>
  1356. <para>
  1357. Wiederholen wir das letzte Beispiel der Verwendung einer eigenen Erweiterung um zu
  1358. zeigen wie die Methode verwendet wird.
  1359. </para>
  1360. <programlisting language="php"><![CDATA[
  1361. if(!Zend_Feed_Reader::isRegistered('JungleBooks')) {
  1362. Zend_Feed_Reader::addPrefixPath(
  1363. 'My_FeedReader_Extension', '/path/to/My/FeedReader/Extension'
  1364. );
  1365. Zend_Feed_Reader::registerExtension('JungleBooks');
  1366. }
  1367. $feed = Zend_Feed_Reader::import('http://example.com/junglebooks/rss');
  1368. // URI zur Informations Seite des populärsten Buchs des Tages mit Besuchern
  1369. $daysPopularBookLink = $feed->getDaysPopularBookLink();
  1370. // ISBN für irgendein Buch dem der erste Eintrag im Feed gewidmet war
  1371. $firstIsbn = $feed->current()->getIsbn();
  1372. ]]></programlisting>
  1373. <para>
  1374. Beim Betrachten dieser Beispiele, konnte man sehen das wir Feed und Eintrags
  1375. Erweiterungen nicht separat registriert haben. Erweiterungen im selben Standard
  1376. können sowohl eine Feed und Entry Klasse enthalten oder auch nicht, sodas
  1377. <classname>Zend_Feed_Reader</classname> nur die Registrierung des darüberliegenden
  1378. Eltern Namens benötigt, z.B. JungleBooks, DublinCore, Slash. Intern kann sie
  1379. prüfen für welchen Level Erweiterungen existieren und und diese Laden wenn Sie
  1380. gefunden werden. In unserem Fall haben wir jetzt ein komplettes Set von
  1381. Erweiterungen: <classname>JungleBooks_Feed</classname> und
  1382. <classname>JungleBooks_Entry</classname>.
  1383. </para>
  1384. </sect3>
  1385. </sect2>
  1386. </sect1>