/Feed/Builder.php

https://bitbucket.org/gkawka/zend-framework · PHP · 398 lines · 184 code · 16 blank · 198 comment · 41 complexity · 5a9922e89aad6891962a85566f23e886 MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Feed
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Builder.php 24593 2012-01-05 20:35:02Z matthew $
  20. */
  21. /**
  22. * @see Zend_Feed_Builder_Interface
  23. */
  24. require_once 'Zend/Feed/Builder/Interface.php';
  25. /**
  26. * @see Zend_Feed_Builder_Header
  27. */
  28. require_once 'Zend/Feed/Builder/Header.php';
  29. /**
  30. * @see Zend_Feed_Builder_Entry
  31. */
  32. require_once 'Zend/Feed/Builder/Entry.php';
  33. /**
  34. * A simple implementation of Zend_Feed_Builder_Interface.
  35. *
  36. * Users are encouraged to make their own classes to implement Zend_Feed_Builder_Interface
  37. *
  38. * @category Zend
  39. * @package Zend_Feed
  40. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  41. * @license http://framework.zend.com/license/new-bsd New BSD License
  42. */
  43. class Zend_Feed_Builder implements Zend_Feed_Builder_Interface
  44. {
  45. /**
  46. * The data of the feed
  47. *
  48. * @var $_data array
  49. */
  50. private $_data;
  51. /**
  52. * Header of the feed
  53. *
  54. * @var $_header Zend_Feed_Builder_Header
  55. */
  56. private $_header;
  57. /**
  58. * List of the entries of the feed
  59. *
  60. * @var $_entries array
  61. */
  62. private $_entries = array();
  63. /**
  64. * Constructor. The $data array must conform to the following format:
  65. * <code>
  66. * array(
  67. * 'title' => 'title of the feed', //required
  68. * 'link' => 'canonical url to the feed', //required
  69. * 'lastUpdate' => 'timestamp of the update date', // optional
  70. * 'published' => 'timestamp of the publication date', //optional
  71. * 'charset' => 'charset', // required
  72. * 'description' => 'short description of the feed', //optional
  73. * 'author' => 'author/publisher of the feed', //optional
  74. * 'email' => 'email of the author', //optional
  75. * 'webmaster' => 'email address for person responsible for technical issues' // optional, ignored if atom is used
  76. * 'copyright' => 'copyright notice', //optional
  77. * 'image' => 'url to image', //optional
  78. * 'generator' => 'generator', // optional
  79. * 'language' => 'language the feed is written in', // optional
  80. * 'ttl' => 'how long in minutes a feed can be cached before refreshing', // optional, ignored if atom is used
  81. * 'rating' => 'The PICS rating for the channel.', // optional, ignored if atom is used
  82. * 'cloud' => array(
  83. * 'domain' => 'domain of the cloud, e.g. rpc.sys.com' // required
  84. * 'port' => 'port to connect to' // optional, default to 80
  85. * 'path' => 'path of the cloud, e.g. /RPC2 //required
  86. * 'registerProcedure' => 'procedure to call, e.g. myCloud.rssPleaseNotify' // required
  87. * 'protocol' => 'protocol to use, e.g. soap or xml-rpc' // required
  88. * ), a cloud to be notified of updates // optional, ignored if atom is used
  89. * 'textInput' => array(
  90. * 'title' => 'the label of the Submit button in the text input area' // required,
  91. * 'description' => 'explains the text input area' // required
  92. * 'name' => 'the name of the text object in the text input area' // required
  93. * 'link' => 'the URL of the CGI script that processes text input requests' // required
  94. * ) // a text input box that can be displayed with the feed // optional, ignored if atom is used
  95. * 'skipHours' => array(
  96. * 'hour in 24 format', // e.g 13 (1pm)
  97. * // up to 24 rows whose value is a number between 0 and 23
  98. * ) // Hint telling aggregators which hours they can skip // optional, ignored if atom is used
  99. * 'skipDays ' => array(
  100. * 'a day to skip', // e.g Monday
  101. * // up to 7 rows whose value is a Monday, Tuesday, Wednesday, Thursday, Friday, Saturday or Sunday
  102. * ) // Hint telling aggregators which days they can skip // optional, ignored if atom is used
  103. * 'itunes' => array(
  104. * 'author' => 'Artist column' // optional, default to the main author value
  105. * 'owner' => array(
  106. * 'name' => 'name of the owner' // optional, default to main author value
  107. * 'email' => 'email of the owner' // optional, default to main email value
  108. * ) // Owner of the podcast // optional
  109. * 'image' => 'album/podcast art' // optional, default to the main image value
  110. * 'subtitle' => 'short description' // optional, default to the main description value
  111. * 'summary' => 'longer description' // optional, default to the main description value
  112. * 'block' => 'Prevent an episode from appearing (yes|no)' // optional
  113. * 'category' => array(
  114. * array('main' => 'main category', // required
  115. * 'sub' => 'sub category' // optional
  116. * ),
  117. * // up to 3 rows
  118. * ) // 'Category column and in iTunes Music Store Browse' // required
  119. * 'explicit' => 'parental advisory graphic (yes|no|clean)' // optional
  120. * 'keywords' => 'a comma separated list of 12 keywords maximum' // optional
  121. * 'new-feed-url' => 'used to inform iTunes of new feed URL location' // optional
  122. * ) // Itunes extension data // optional, ignored if atom is used
  123. * 'entries' => array(
  124. * array(
  125. * 'title' => 'title of the feed entry', //required
  126. * 'link' => 'url to a feed entry', //required
  127. * 'description' => 'short version of a feed entry', // only text, no html, required
  128. * 'guid' => 'id of the article, if not given link value will used', //optional
  129. * 'content' => 'long version', // can contain html, optional
  130. * 'lastUpdate' => 'timestamp of the publication date', // optional
  131. * 'comments' => 'comments page of the feed entry', // optional
  132. * 'commentRss' => 'the feed url of the associated comments', // optional
  133. * 'source' => array(
  134. * 'title' => 'title of the original source' // required,
  135. * 'url' => 'url of the original source' // required
  136. * ) // original source of the feed entry // optional
  137. * 'category' => array(
  138. * array(
  139. * 'term' => 'first category label' // required,
  140. * 'scheme' => 'url that identifies a categorization scheme' // optional
  141. * ),
  142. * array(
  143. * //data for the second category and so on
  144. * )
  145. * ) // list of the attached categories // optional
  146. * 'enclosure' => array(
  147. * array(
  148. * 'url' => 'url of the linked enclosure' // required
  149. * 'type' => 'mime type of the enclosure' // optional
  150. * 'length' => 'length of the linked content in octets' // optional
  151. * ),
  152. * array(
  153. * //data for the second enclosure and so on
  154. * )
  155. * ) // list of the enclosures of the feed entry // optional
  156. * ),
  157. * array(
  158. * //data for the second entry and so on
  159. * )
  160. * )
  161. * );
  162. * </code>
  163. *
  164. * @param array $data
  165. * @return void
  166. */
  167. public function __construct(array $data)
  168. {
  169. $this->_data = $data;
  170. $this->_createHeader($data);
  171. if (isset($data['entries'])) {
  172. $this->_createEntries($data['entries']);
  173. }
  174. }
  175. /**
  176. * Returns an instance of Zend_Feed_Builder_Header
  177. * describing the header of the feed
  178. *
  179. * @return Zend_Feed_Builder_Header
  180. */
  181. public function getHeader()
  182. {
  183. return $this->_header;
  184. }
  185. /**
  186. * Returns an array of Zend_Feed_Builder_Entry instances
  187. * describing the entries of the feed
  188. *
  189. * @return array of Zend_Feed_Builder_Entry
  190. */
  191. public function getEntries()
  192. {
  193. return $this->_entries;
  194. }
  195. /**
  196. * Create the Zend_Feed_Builder_Header instance
  197. *
  198. * @param array $data
  199. * @throws Zend_Feed_Builder_Exception
  200. * @return void
  201. */
  202. protected function _createHeader(array $data)
  203. {
  204. $mandatories = array('title', 'link', 'charset');
  205. foreach ($mandatories as $mandatory) {
  206. if (!isset($data[$mandatory])) {
  207. /**
  208. * @see Zend_Feed_Builder_Exception
  209. */
  210. require_once 'Zend/Feed/Builder/Exception.php';
  211. throw new Zend_Feed_Builder_Exception("$mandatory key is missing");
  212. }
  213. }
  214. $this->_header = new Zend_Feed_Builder_Header($data['title'], $data['link'], $data['charset']);
  215. if (isset($data['lastUpdate'])) {
  216. $this->_header->setLastUpdate($data['lastUpdate']);
  217. }
  218. if (isset($data['published'])) {
  219. $this->_header->setPublishedDate($data['published']);
  220. }
  221. if (isset($data['description'])) {
  222. $this->_header->setDescription($data['description']);
  223. }
  224. if (isset($data['author'])) {
  225. $this->_header->setAuthor($data['author']);
  226. }
  227. if (isset($data['email'])) {
  228. $this->_header->setEmail($data['email']);
  229. }
  230. if (isset($data['webmaster'])) {
  231. $this->_header->setWebmaster($data['webmaster']);
  232. }
  233. if (isset($data['copyright'])) {
  234. $this->_header->setCopyright($data['copyright']);
  235. }
  236. if (isset($data['image'])) {
  237. $this->_header->setImage($data['image']);
  238. }
  239. if (isset($data['generator'])) {
  240. $this->_header->setGenerator($data['generator']);
  241. }
  242. if (isset($data['language'])) {
  243. $this->_header->setLanguage($data['language']);
  244. }
  245. if (isset($data['ttl'])) {
  246. $this->_header->setTtl($data['ttl']);
  247. }
  248. if (isset($data['rating'])) {
  249. $this->_header->setRating($data['rating']);
  250. }
  251. if (isset($data['cloud'])) {
  252. $mandatories = array('domain', 'path', 'registerProcedure', 'protocol');
  253. foreach ($mandatories as $mandatory) {
  254. if (!isset($data['cloud'][$mandatory])) {
  255. /**
  256. * @see Zend_Feed_Builder_Exception
  257. */
  258. require_once 'Zend/Feed/Builder/Exception.php';
  259. throw new Zend_Feed_Builder_Exception("you have to define $mandatory property of your cloud");
  260. }
  261. }
  262. $uri_str = 'http://' . $data['cloud']['domain'] . $data['cloud']['path'];
  263. $this->_header->setCloud($uri_str, $data['cloud']['registerProcedure'], $data['cloud']['protocol']);
  264. }
  265. if (isset($data['textInput'])) {
  266. $mandatories = array('title', 'description', 'name', 'link');
  267. foreach ($mandatories as $mandatory) {
  268. if (!isset($data['textInput'][$mandatory])) {
  269. /**
  270. * @see Zend_Feed_Builder_Exception
  271. */
  272. require_once 'Zend/Feed/Builder/Exception.php';
  273. throw new Zend_Feed_Builder_Exception("you have to define $mandatory property of your textInput");
  274. }
  275. }
  276. $this->_header->setTextInput($data['textInput']['title'],
  277. $data['textInput']['description'],
  278. $data['textInput']['name'],
  279. $data['textInput']['link']);
  280. }
  281. if (isset($data['skipHours'])) {
  282. $this->_header->setSkipHours($data['skipHours']);
  283. }
  284. if (isset($data['skipDays'])) {
  285. $this->_header->setSkipDays($data['skipDays']);
  286. }
  287. if (isset($data['itunes'])) {
  288. $itunes = new Zend_Feed_Builder_Header_Itunes($data['itunes']['category']);
  289. if (isset($data['itunes']['author'])) {
  290. $itunes->setAuthor($data['itunes']['author']);
  291. }
  292. if (isset($data['itunes']['owner'])) {
  293. $name = isset($data['itunes']['owner']['name']) ? $data['itunes']['owner']['name'] : '';
  294. $email = isset($data['itunes']['owner']['email']) ? $data['itunes']['owner']['email'] : '';
  295. $itunes->setOwner($name, $email);
  296. }
  297. if (isset($data['itunes']['image'])) {
  298. $itunes->setImage($data['itunes']['image']);
  299. }
  300. if (isset($data['itunes']['subtitle'])) {
  301. $itunes->setSubtitle($data['itunes']['subtitle']);
  302. }
  303. if (isset($data['itunes']['summary'])) {
  304. $itunes->setSummary($data['itunes']['summary']);
  305. }
  306. if (isset($data['itunes']['block'])) {
  307. $itunes->setBlock($data['itunes']['block']);
  308. }
  309. if (isset($data['itunes']['explicit'])) {
  310. $itunes->setExplicit($data['itunes']['explicit']);
  311. }
  312. if (isset($data['itunes']['keywords'])) {
  313. $itunes->setKeywords($data['itunes']['keywords']);
  314. }
  315. if (isset($data['itunes']['new-feed-url'])) {
  316. $itunes->setNewFeedUrl($data['itunes']['new-feed-url']);
  317. }
  318. $this->_header->setITunes($itunes);
  319. }
  320. }
  321. /**
  322. * Create the array of article entries
  323. *
  324. * @param array $data
  325. * @throws Zend_Feed_Builder_Exception
  326. * @return void
  327. */
  328. protected function _createEntries(array $data)
  329. {
  330. foreach ($data as $row) {
  331. $mandatories = array('title', 'link', 'description');
  332. foreach ($mandatories as $mandatory) {
  333. if (!isset($row[$mandatory])) {
  334. /**
  335. * @see Zend_Feed_Builder_Exception
  336. */
  337. require_once 'Zend/Feed/Builder/Exception.php';
  338. throw new Zend_Feed_Builder_Exception("$mandatory key is missing");
  339. }
  340. }
  341. $entry = new Zend_Feed_Builder_Entry($row['title'], $row['link'], $row['description']);
  342. if (isset($row['author'])) {
  343. $entry->setAuthor($row['author']);
  344. }
  345. if (isset($row['guid'])) {
  346. $entry->setId($row['guid']);
  347. }
  348. if (isset($row['content'])) {
  349. $entry->setContent($row['content']);
  350. }
  351. if (isset($row['lastUpdate'])) {
  352. $entry->setLastUpdate($row['lastUpdate']);
  353. }
  354. if (isset($row['comments'])) {
  355. $entry->setCommentsUrl($row['comments']);
  356. }
  357. if (isset($row['commentRss'])) {
  358. $entry->setCommentsRssUrl($row['commentRss']);
  359. }
  360. if (isset($row['source'])) {
  361. $mandatories = array('title', 'url');
  362. foreach ($mandatories as $mandatory) {
  363. if (!isset($row['source'][$mandatory])) {
  364. /**
  365. * @see Zend_Feed_Builder_Exception
  366. */
  367. require_once 'Zend/Feed/Builder/Exception.php';
  368. throw new Zend_Feed_Builder_Exception("$mandatory key of source property is missing");
  369. }
  370. }
  371. $entry->setSource($row['source']['title'], $row['source']['url']);
  372. }
  373. if (isset($row['category'])) {
  374. $entry->setCategories($row['category']);
  375. }
  376. if (isset($row['enclosure'])) {
  377. $entry->setEnclosures($row['enclosure']);
  378. }
  379. $this->_entries[] = $entry;
  380. }
  381. }
  382. }