1<?php
2class ReutersBridge extends BridgeAbstract
3{
4	const MAINTAINER = 'hollowleviathan, spraynard, csisoap';
5	const NAME = 'Reuters Bridge';
6	const URI = 'https://reuters.com/';
7	const CACHE_TIMEOUT = 1800; // 30min
8	const DESCRIPTION = 'Returns news from Reuters';
9
10	private $feedName = self::NAME;
11
12	/**
13	 * Wireitem types allowed in the final story output
14	 */
15	const ALLOWED_WIREITEM_TYPES = array(
16		'story',
17		'headlines'
18	);
19
20	/**
21	 * Wireitem template types allowed in the final story output
22	 */
23	const ALLOWED_TEMPLATE_TYPES = array(
24		'story',
25		'headlines'
26	);
27
28	const PARAMETERS = array(
29		array(
30			'feed' => array(
31				'name' => 'News Feed',
32				'type' => 'list',
33				'title' => 'Feeds from Reuters U.S/International edition',
34				'values' => array(
35					'Aerospace and Defense' => 'aerospace',
36					'Business' => 'business',
37					'China' => 'china',
38					'Energy' => 'energy',
39					'Entertainment' => 'chan:8ym8q8dl',
40					'Environment' => 'chan:6u4f0jgs',
41					'Health' => 'chan:8hw7807a',
42					'Lifestyle' => 'life',
43					'Markets' => 'markets',
44					'Politics' => 'politics',
45					'Science' => 'science',
46					'Special Reports' => 'special-reports',
47					'Sports' => 'sports',
48					'Tech' => 'tech',
49					'Top News' => 'home/topnews',
50					'UK' => 'chan:61leiu7j',
51					'USA News' => 'us',
52					'Wire' => 'wire',
53					'World' => 'world',
54				)
55			)
56		)
57	);
58
59	/**
60	 * Performs an HTTP request to the Reuters API and returns decoded JSON
61	 * in the form of an associative array
62	 * @param string $feed_uri Parameter string to the Reuters API
63	 * @return array
64	 */
65	private function getJson($feed_uri)
66	{
67		$uri = "https://wireapi.reuters.com/v8$feed_uri";
68		$returned_data = getContents($uri);
69		return json_decode($returned_data, true);
70	}
71
72	/**
73	 * Takes in data from Reuters Wire API and
74	 * creates structured data in the form of a list
75	 * of story information.
76	 * @param array $data JSON collected from the Reuters Wire API
77	 */
78	private function processData($data)
79	{
80		/**
81		 * Gets a list of wire items which are groups of templates
82		 */
83		$reuters_allowed_wireitems = array_filter(
84			$data, function ($wireitem) {
85				return in_array(
86					$wireitem['wireitem_type'],
87					self::ALLOWED_WIREITEM_TYPES
88				);
89			}
90		);
91
92		/*
93		* Gets a list of "Templates", which is data containing a story
94		*/
95		$reuters_wireitem_templates = array_reduce(
96			$reuters_allowed_wireitems,
97			function (array $carry, array $wireitem) {
98				$wireitem_templates = $wireitem['templates'];
99				return array_merge(
100					$carry,
101					array_filter(
102						$wireitem_templates, function (
103							array $template_data
104						) {
105							return in_array(
106								$template_data['type'],
107								self::ALLOWED_TEMPLATE_TYPES
108							);
109						}
110					)
111				);
112			},
113			array()
114		);
115
116		return $reuters_wireitem_templates;
117	}
118
119	private function getArticle($feed_uri)
120	{
121		// This will make another request to API to get full detail of article and author's name.
122		$rawData = $this->getJson($feed_uri);
123		$reuters_wireitems = $rawData['wireitems'];
124		$processedData = $this->processData($reuters_wireitems);
125
126		$first = reset($processedData);
127		$article_content = $first['story']['body_items'];
128		$authorlist = $first['story']['authors'];
129		$category = $first['story']['channel']['name'];
130		$image_list = $first['story']['images'];
131
132		$content_detail = array(
133			'content' => $this->handleArticleContent($article_content),
134			'author' => $this->handleAuthorName($authorlist),
135			'category' => $category,
136			'images' => $this->handleImage($image_list),
137		);
138		return $content_detail;
139	}
140
141	private function handleImage($images) {
142		$img_placeholder = '';
143
144		foreach($images as $image) { // Add more image to article.
145			$image_url = $image['url'];
146			$image_caption = $image['caption'];
147			$img = "<img src=\"$image_url\">";
148			$img_caption = "<figcaption style=\"text-align: center;\"><i>$image_caption</i></figcaption>";
149			$figure = "<figure>$img \t $img_caption</figure>";
150			$img_placeholder = $img_placeholder . $figure;
151		}
152
153		return $img_placeholder;
154	}
155
156	private function handleAuthorName($authors) {
157		$author = '';
158		$counter = 0;
159		foreach ($authors as $data) {
160			//Formatting author's name.
161			$counter++;
162			$name = $data['name'];
163			if ($counter == count($authors)) {
164				$author = $author . $name;
165			} else {
166				$author = $author . "$name, ";
167			}
168		}
169
170		return $author;
171	}
172
173	private function handleArticleContent($contents) {
174		$description = '';
175		foreach ($contents as $content) {
176			$data;
177			if(isset($content['content'])) {
178				$data = $content['content'];
179			}
180			switch($content['type']) {
181				case 'paragraph':
182					$description = $description . "<p>$data</p>";
183					break;
184				case 'heading':
185					$description = $description . "<h3>$data</h3>";
186					break;
187				case 'infographics':
188					$description = $description . "<img src=\"$data\">";
189					break;
190				case 'inline_items':
191					$item_list = $content['items'];
192					$description = $description . '<p>';
193					foreach ($item_list as $item) {
194						if($item['type'] == 'text') {
195							$description = $description . $item['content'];
196						} else {
197							$description = $description . $item['symbol'];
198						}
199					}
200					$description = $description . '</p>';
201					break;
202				case 'p_table':
203					$description = $description . $content['content'];
204					break;
205			}
206		}
207
208		return $description;
209	}
210
211	public function getName() {
212		return $this->feedName;
213	}
214
215	public function collectData()
216	{
217		$reuters_feed_name = $this->getInput('feed');
218
219		if(strpos($reuters_feed_name, 'chan:') !== false) {
220			// Now checking whether that feed has unique ID or not.
221			$feed_uri = "/feed/rapp/us/wirefeed/$reuters_feed_name";
222		} else {
223			$feed_uri = "/feed/rapp/us/tabbar/feeds/$reuters_feed_name";
224		}
225
226		$data = $this->getJson($feed_uri);
227
228		$reuters_wireitems = $data['wireitems'];
229		$this->feedName = $data['wire_name'] . ' | Reuters';
230		$processedData = $this->processData($reuters_wireitems);
231
232		// Merge all articles from Editor's Highlight section into existing array of templates.
233		$top_section = reset($processedData);
234		if ($top_section['type'] == 'headlines') {
235			$top_section = array_shift($processedData);
236			$articles = $top_section['headlines'];
237			$processedData = array_merge($articles, $processedData);
238		}
239
240		foreach ($processedData as $story) {
241			$item['uid'] = $story['story']['usn'];
242			$article_uri = $story['template_action']['api_path'];
243			$content_detail = $this->getArticle($article_uri);
244			$description = $content_detail['content'];
245			$author = $content_detail['author'];
246			$images = $content_detail['images'];
247			$item['categories'] = array($content_detail['category']);
248			$item['author'] = $author;
249			if (!(bool) $description) {
250				$description = $story['story']['lede']; // Just in case the content doesn't have anything.
251			} else {
252				$item['content'] = "$description  $images";
253			}
254
255			$item['title'] = $story['story']['hed'];
256			$item['timestamp'] = $story['story']['updated_at'];
257			$item['uri'] = $story['template_action']['url'];
258			$this->items[] = $item;
259		}
260	}
261}
262