|
1 <?php |
|
2 |
|
3 /** |
|
4 * Zend Framework |
|
5 * |
|
6 * LICENSE |
|
7 * |
|
8 * This source file is subject to the new BSD license that is bundled |
|
9 * with this package in the file LICENSE.txt. |
|
10 * It is also available through the world-wide-web at this URL: |
|
11 * http://framework.zend.com/license/new-bsd |
|
12 * If you did not receive a copy of the license and are unable to |
|
13 * obtain it through the world-wide-web, please send an email |
|
14 * to license@zend.com so we can send you a copy immediately. |
|
15 * |
|
16 * @category Zend |
|
17 * @package Zend_Feed |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Atom.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 |
|
24 /** |
|
25 * @see Zend_Feed_Abstract |
|
26 */ |
|
27 require_once 'Zend/Feed/Abstract.php'; |
|
28 |
|
29 /** |
|
30 * @see Zend_Feed_Entry_Atom |
|
31 */ |
|
32 require_once 'Zend/Feed/Entry/Atom.php'; |
|
33 |
|
34 |
|
35 /** |
|
36 * Atom feed class |
|
37 * |
|
38 * The Zend_Feed_Atom class is a concrete subclass of the general |
|
39 * Zend_Feed_Abstract class, tailored for representing an Atom |
|
40 * feed. It shares all of the same methods with its abstract |
|
41 * parent. The distinction is made in the format of data that |
|
42 * Zend_Feed_Atom expects, and as a further pointer for users as to |
|
43 * what kind of feed object they have been passed. |
|
44 * |
|
45 * @category Zend |
|
46 * @package Zend_Feed |
|
47 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
48 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
49 */ |
|
50 class Zend_Feed_Atom extends Zend_Feed_Abstract |
|
51 { |
|
52 |
|
53 /** |
|
54 * The classname for individual feed elements. |
|
55 * |
|
56 * @var string |
|
57 */ |
|
58 protected $_entryClassName = 'Zend_Feed_Entry_Atom'; |
|
59 |
|
60 /** |
|
61 * The element name for individual feed elements (Atom <entry> |
|
62 * elements). |
|
63 * |
|
64 * @var string |
|
65 */ |
|
66 protected $_entryElementName = 'entry'; |
|
67 |
|
68 /** |
|
69 * The default namespace for Atom feeds. |
|
70 * |
|
71 * @var string |
|
72 */ |
|
73 protected $_defaultNamespace = 'atom'; |
|
74 |
|
75 |
|
76 /** |
|
77 * Override Zend_Feed_Abstract to set up the $_element and $_entries aliases. |
|
78 * |
|
79 * @return void |
|
80 * @throws Zend_Feed_Exception |
|
81 */ |
|
82 public function __wakeup() |
|
83 { |
|
84 parent::__wakeup(); |
|
85 |
|
86 // Find the base feed element and create an alias to it. |
|
87 $element = $this->_element->getElementsByTagName('feed')->item(0); |
|
88 if (!$element) { |
|
89 // Try to find a single <entry> instead. |
|
90 $element = $this->_element->getElementsByTagName($this->_entryElementName)->item(0); |
|
91 if (!$element) { |
|
92 /** |
|
93 * @see Zend_Feed_Exception |
|
94 */ |
|
95 require_once 'Zend/Feed/Exception.php'; |
|
96 throw new Zend_Feed_Exception('No root <feed> or <' . $this->_entryElementName |
|
97 . '> element found, cannot parse feed.'); |
|
98 } |
|
99 |
|
100 $doc = new DOMDocument($this->_element->version, |
|
101 $this->_element->actualEncoding); |
|
102 $feed = $doc->appendChild($doc->createElement('feed')); |
|
103 $feed->appendChild($doc->importNode($element, true)); |
|
104 $element = $feed; |
|
105 } |
|
106 |
|
107 $this->_element = $element; |
|
108 |
|
109 // Find the entries and save a pointer to them for speed and |
|
110 // simplicity. |
|
111 $this->_buildEntryCache(); |
|
112 } |
|
113 |
|
114 |
|
115 /** |
|
116 * Easy access to <link> tags keyed by "rel" attributes. |
|
117 * |
|
118 * If $elt->link() is called with no arguments, we will attempt to |
|
119 * return the value of the <link> tag(s) like all other |
|
120 * method-syntax attribute access. If an argument is passed to |
|
121 * link(), however, then we will return the "href" value of the |
|
122 * first <link> tag that has a "rel" attribute matching $rel: |
|
123 * |
|
124 * $elt->link(): returns the value of the link tag. |
|
125 * $elt->link('self'): returns the href from the first <link rel="self"> in the entry. |
|
126 * |
|
127 * @param string $rel The "rel" attribute to look for. |
|
128 * @return mixed |
|
129 */ |
|
130 public function link($rel = null) |
|
131 { |
|
132 if ($rel === null) { |
|
133 return parent::__call('link', null); |
|
134 } |
|
135 |
|
136 // index link tags by their "rel" attribute. |
|
137 $links = parent::__get('link'); |
|
138 if (!is_array($links)) { |
|
139 if ($links instanceof Zend_Feed_Element) { |
|
140 $links = array($links); |
|
141 } else { |
|
142 return $links; |
|
143 } |
|
144 } |
|
145 |
|
146 foreach ($links as $link) { |
|
147 if (empty($link['rel'])) { |
|
148 continue; |
|
149 } |
|
150 if ($rel == $link['rel']) { |
|
151 return $link['href']; |
|
152 } |
|
153 } |
|
154 |
|
155 return null; |
|
156 } |
|
157 |
|
158 |
|
159 /** |
|
160 * Make accessing some individual elements of the feed easier. |
|
161 * |
|
162 * Special accessors 'entry' and 'entries' are provided so that if |
|
163 * you wish to iterate over an Atom feed's entries, you can do so |
|
164 * using foreach ($feed->entries as $entry) or foreach |
|
165 * ($feed->entry as $entry). |
|
166 * |
|
167 * @param string $var The property to access. |
|
168 * @return mixed |
|
169 */ |
|
170 public function __get($var) |
|
171 { |
|
172 switch ($var) { |
|
173 case 'entry': |
|
174 // fall through to the next case |
|
175 case 'entries': |
|
176 return $this; |
|
177 |
|
178 default: |
|
179 return parent::__get($var); |
|
180 } |
|
181 } |
|
182 |
|
183 /** |
|
184 * Generate the header of the feed when working in write mode |
|
185 * |
|
186 * @param array $array the data to use |
|
187 * @return DOMElement root node |
|
188 */ |
|
189 protected function _mapFeedHeaders($array) |
|
190 { |
|
191 $feed = $this->_element->createElement('feed'); |
|
192 $feed->setAttribute('xmlns', 'http://www.w3.org/2005/Atom'); |
|
193 |
|
194 $id = $this->_element->createElement('id', $array->link); |
|
195 $feed->appendChild($id); |
|
196 |
|
197 $title = $this->_element->createElement('title'); |
|
198 $title->appendChild($this->_element->createCDATASection($array->title)); |
|
199 $feed->appendChild($title); |
|
200 |
|
201 if (isset($array->author)) { |
|
202 $author = $this->_element->createElement('author'); |
|
203 $name = $this->_element->createElement('name', $array->author); |
|
204 $author->appendChild($name); |
|
205 if (isset($array->email)) { |
|
206 $email = $this->_element->createElement('email', $array->email); |
|
207 $author->appendChild($email); |
|
208 } |
|
209 $feed->appendChild($author); |
|
210 } |
|
211 |
|
212 $updated = isset($array->lastUpdate) ? $array->lastUpdate : time(); |
|
213 $updated = $this->_element->createElement('updated', date(DATE_ATOM, $updated)); |
|
214 $feed->appendChild($updated); |
|
215 |
|
216 if (isset($array->published)) { |
|
217 $published = $this->_element->createElement('published', date(DATE_ATOM, $array->published)); |
|
218 $feed->appendChild($published); |
|
219 } |
|
220 |
|
221 $link = $this->_element->createElement('link'); |
|
222 $link->setAttribute('rel', 'self'); |
|
223 $link->setAttribute('href', $array->link); |
|
224 if (isset($array->language)) { |
|
225 $link->setAttribute('hreflang', $array->language); |
|
226 } |
|
227 $feed->appendChild($link); |
|
228 |
|
229 if (isset($array->description)) { |
|
230 $subtitle = $this->_element->createElement('subtitle'); |
|
231 $subtitle->appendChild($this->_element->createCDATASection($array->description)); |
|
232 $feed->appendChild($subtitle); |
|
233 } |
|
234 |
|
235 if (isset($array->copyright)) { |
|
236 $copyright = $this->_element->createElement('rights', $array->copyright); |
|
237 $feed->appendChild($copyright); |
|
238 } |
|
239 |
|
240 if (isset($array->image)) { |
|
241 $image = $this->_element->createElement('logo', $array->image); |
|
242 $feed->appendChild($image); |
|
243 } |
|
244 |
|
245 $generator = !empty($array->generator) ? $array->generator : 'Zend_Feed'; |
|
246 $generator = $this->_element->createElement('generator', $generator); |
|
247 $feed->appendChild($generator); |
|
248 |
|
249 return $feed; |
|
250 } |
|
251 |
|
252 /** |
|
253 * Generate the entries of the feed when working in write mode |
|
254 * |
|
255 * The following nodes are constructed for each feed entry |
|
256 * <entry> |
|
257 * <id>url to feed entry</id> |
|
258 * <title>entry title</title> |
|
259 * <updated>last update</updated> |
|
260 * <link rel="alternate" href="url to feed entry" /> |
|
261 * <summary>short text</summary> |
|
262 * <content>long version, can contain html</content> |
|
263 * </entry> |
|
264 * |
|
265 * @param array $array the data to use |
|
266 * @param DOMElement $root the root node to use |
|
267 * @return void |
|
268 */ |
|
269 protected function _mapFeedEntries(DOMElement $root, $array) |
|
270 { |
|
271 foreach ($array as $dataentry) { |
|
272 $entry = $this->_element->createElement('entry'); |
|
273 |
|
274 $id = $this->_element->createElement('id', isset($dataentry->guid) ? $dataentry->guid : $dataentry->link); |
|
275 $entry->appendChild($id); |
|
276 |
|
277 $title = $this->_element->createElement('title'); |
|
278 $title->appendChild($this->_element->createCDATASection($dataentry->title)); |
|
279 $entry->appendChild($title); |
|
280 |
|
281 $updated = isset($dataentry->lastUpdate) ? $dataentry->lastUpdate : time(); |
|
282 $updated = $this->_element->createElement('updated', date(DATE_ATOM, $updated)); |
|
283 $entry->appendChild($updated); |
|
284 |
|
285 $link = $this->_element->createElement('link'); |
|
286 $link->setAttribute('rel', 'alternate'); |
|
287 $link->setAttribute('href', $dataentry->link); |
|
288 $entry->appendChild($link); |
|
289 |
|
290 $summary = $this->_element->createElement('summary'); |
|
291 $summary->appendChild($this->_element->createCDATASection($dataentry->description)); |
|
292 $entry->appendChild($summary); |
|
293 |
|
294 if (isset($dataentry->content)) { |
|
295 $content = $this->_element->createElement('content'); |
|
296 $content->setAttribute('type', 'html'); |
|
297 $content->appendChild($this->_element->createCDATASection($dataentry->content)); |
|
298 $entry->appendChild($content); |
|
299 } |
|
300 |
|
301 if (isset($dataentry->category)) { |
|
302 foreach ($dataentry->category as $category) { |
|
303 $node = $this->_element->createElement('category'); |
|
304 $node->setAttribute('term', $category['term']); |
|
305 if (isset($category['scheme'])) { |
|
306 $node->setAttribute('scheme', $category['scheme']); |
|
307 } |
|
308 $entry->appendChild($node); |
|
309 } |
|
310 } |
|
311 |
|
312 if (isset($dataentry->source)) { |
|
313 $source = $this->_element->createElement('source'); |
|
314 $title = $this->_element->createElement('title', $dataentry->source['title']); |
|
315 $source->appendChild($title); |
|
316 $link = $this->_element->createElement('link', $dataentry->source['title']); |
|
317 $link->setAttribute('rel', 'alternate'); |
|
318 $link->setAttribute('href', $dataentry->source['url']); |
|
319 $source->appendChild($link); |
|
320 } |
|
321 |
|
322 if (isset($dataentry->enclosure)) { |
|
323 foreach ($dataentry->enclosure as $enclosure) { |
|
324 $node = $this->_element->createElement('link'); |
|
325 $node->setAttribute('rel', 'enclosure'); |
|
326 $node->setAttribute('href', $enclosure['url']); |
|
327 if (isset($enclosure['type'])) { |
|
328 $node->setAttribute('type', $enclosure['type']); |
|
329 } |
|
330 if (isset($enclosure['length'])) { |
|
331 $node->setAttribute('length', $enclosure['length']); |
|
332 } |
|
333 $entry->appendChild($node); |
|
334 } |
|
335 } |
|
336 |
|
337 if (isset($dataentry->comments)) { |
|
338 $comments = $this->_element->createElementNS('http://wellformedweb.org/CommentAPI/', |
|
339 'wfw:comment', |
|
340 $dataentry->comments); |
|
341 $entry->appendChild($comments); |
|
342 } |
|
343 if (isset($dataentry->commentRss)) { |
|
344 $comments = $this->_element->createElementNS('http://wellformedweb.org/CommentAPI/', |
|
345 'wfw:commentRss', |
|
346 $dataentry->commentRss); |
|
347 $entry->appendChild($comments); |
|
348 } |
|
349 |
|
350 $root->appendChild($entry); |
|
351 } |
|
352 } |
|
353 |
|
354 /** |
|
355 * Override Zend_Feed_Element to allow formated feeds |
|
356 * |
|
357 * @return string |
|
358 */ |
|
359 public function saveXml() |
|
360 { |
|
361 // Return a complete document including XML prologue. |
|
362 $doc = new DOMDocument($this->_element->ownerDocument->version, |
|
363 $this->_element->ownerDocument->actualEncoding); |
|
364 $doc->appendChild($doc->importNode($this->_element, true)); |
|
365 $doc->formatOutput = true; |
|
366 |
|
367 return $doc->saveXML(); |
|
368 } |
|
369 |
|
370 /** |
|
371 * Send feed to a http client with the correct header |
|
372 * |
|
373 * @return void |
|
374 * @throws Zend_Feed_Exception if headers have already been sent |
|
375 */ |
|
376 public function send() |
|
377 { |
|
378 if (headers_sent()) { |
|
379 /** |
|
380 * @see Zend_Feed_Exception |
|
381 */ |
|
382 require_once 'Zend/Feed/Exception.php'; |
|
383 throw new Zend_Feed_Exception('Cannot send ATOM because headers have already been sent.'); |
|
384 } |
|
385 |
|
386 header('Content-Type: application/atom+xml; charset=' . $this->_element->ownerDocument->actualEncoding); |
|
387 |
|
388 echo $this->saveXML(); |
|
389 } |
|
390 } |