Passed
Push — develop ( b3eda6...9f2d35 )
by Daniel
03:59 queued 40s
created

feeds::render_feeds()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 3
dl 0
loc 15
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * @package sitemaker
6
 * @copyright (c) 2019 Daniel A. (blitze)
7
 * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
8
 *
9
 */
10
11
namespace blitze\sitemaker\blocks;
12
13
use blitze\sitemaker\services\blocks\driver\block;
14
15
/**
16
 * Feeds Block
17
 */
18
class feeds extends block
19
{
20
	/** @var \phpbb\language\language */
21
	protected $translator;
22
23
	/** @var \phpbb\request\request_interface */
24
	protected $request;
25
26
	/** @var \phpbb\template\twig\environment */
27
	protected $twig;
28
29
	/** @var \blitze\sitemaker\services\simplepie\feed */
30
	protected $simplepie;
31
32
	/** @var string */
33
	protected $cache_dir;
34
35
	/** @var array */
36
	protected $feed_fields = ['title', 'description', 'category', 'categories', 'author', 'authors', 'contributor', 'contributors', 'copyright', 'image_url', 'image_title', 'image_link', 'image_width', 'image_height', 'permalink', 'link', 'links'];
37
38
	/** @var array */
39
	protected $item_fields = ['id', 'title', 'description', 'content', 'category', 'categories', 'author', 'authors', 'contributor', 'contributors', 'copyright', 'date', 'updated_date', 'gmdate', 'updated_gmdate', 'permalink', 'link', 'links', 'enclosure', 'enclosures', 'latitude', 'longitude', 'source'];
40
41
	/**
42
	 * Constructor
43
	 *
44
	 * @param \phpbb\language\language						$translator			Language object
45
	 * @param \phpbb\request\request_interface				$request			Request object
46
	 * @param \phpbb\template\twig\environment				$twig				Twig environment
47
	 * @param \blitze\sitemaker\services\simplepie\feed		$simplepie			An extension of simple pie
48
	 * @param string 										$cache_dir			Path to cache directory
49
	 */
50
	public function __construct(\phpbb\language\language $translator, \phpbb\request\request_interface $request, \phpbb\template\twig\environment $twig, \blitze\sitemaker\services\simplepie\feed $simplepie, $cache_dir)
51
	{
52
		$this->translator = $translator;
53
		$this->request = $request;
54
		$this->twig = $twig;
55
		$this->simplepie = $simplepie;
56
		$this->cache_dir = $cache_dir;
57
	}
58
59
	/**
60
	 * {@inheritdoc}
61
	 */
62
	public function get_config(array $settings)
63
	{
64
		$template_default = '<a target="_blank" href="{{ item.link }}">{{ item.title }}</a>';
65
		return array(
66
			'legend1'		=> 'SETTINGS',
67
			'feeds'			=> array('lang' => 'FEED_URLS', 'type' => 'multi_input:0', 'default' => []),
68
			'template'		=> array('type' => 'custom', 'default' => $template_default, 'object' => $this, 'method' => 'get_cfg_feeds_template'),
69
			'max'			=> array('lang' => 'MAX_ITEMS', 'validate' => 'int:1', 'type' => 'number:1', 'default' => 5),
70
			'cache'			=> array('lang' => 'CACHE_DURATION', 'validate' => 'int:1', 'type' => 'number:1', 'default' => 6, 'append' => 'HOURS_SHORT'),
71
		);
72
	}
73
74
	/**
75
	 * {@inheritdoc}
76
	 */
77
	public function display(array $bdata, $edit_mode = false)
78
	{
79
		$settings = $bdata['settings'];
80
		$feed_urls = $this->get_feeds_array($settings['feeds']);
81
		$status = 0;
82
83
		try
84
		{
85
			$content = $this->render_feeds($feed_urls, $settings, $status);
86
			$status = 1;
87
		}
88
		catch (\Exception $e)
89
		{
90
			$content = $e->getMessage();
91
		}
92
93
		return array(
94
			'title'		=> 'FEEDS',
95
			'content'	=> $status || $edit_mode ? $content : '',
96
			'status'	=> $status,
97
		);
98
	}
99
100
	/**
101
	 * @param array $feeds_url
102
	 * @param array $settings
103
	 * @param int $status
104
	 * @return string
105
	 */
106
	protected function render_feeds(array $feed_urls, array $settings, &$status)
107
	{
108
		$content = '';
109
		if ($items = $this->get_feed_items($feed_urls, $content, $settings['max'], $settings['cache']))
110
		{
111
			// We try to render block with user-provided trig template
112
			$template = $this->twig->createTemplate($this->get_feed_template($settings['template']));
113
114
			$status = 1;
115
			$content = $template->render([
116
				'items'	=> $items,
117
			]);
118
		}
119
120
		return $content;
121
	}
122
123
	/**
124
	 * @param string $source
125
	 * @return string
126
	 */
127
	public function get_cfg_feeds_template($source)
128
	{
129
		$template = $this->twig->load('@blitze_sitemaker/cfg_fields/feeds.html');
130
		return $template->render([
131
			'template'	=> $source,
132
		]);
133
	}
134
135
	/**
136
	 * Called when editing feed block to get available rss/atom fields
137
	 * @return array
138
	 */
139
	public function get_fields()
140
	{
141
		$this->translator->add_lang('feed_fields', 'blitze/sitemaker');
142
143
		$feeds = $this->request->variable('feeds', array(0 => ''));
144
		$feeds = $this->get_feeds_array($feeds);
145
146
		$message = '';
147
		$data = array('items' => []);
148
		$fields = array('items' => $this->get_field_defaults('items'));
149
150
		$feed_items = $this->get_feed_items($feeds, $message, 0, 0, 1, true);
151
152
		foreach ($feed_items as $feed)
153
		{
154
			$feed_data = $feed_fields = [];
155
			$fields['items']['children'] += $this->get_feed_fields($feed, $feed_data);
156
157
			foreach ($this->item_fields as $field)
158
			{
159
				$value = $feed->{$field};
160
				$feed_data[$field] = $value;
161
				$feed_fields[$field] = $this->build_tags($field, $value);
162
			}
163
164
			$data['items'][] = array_filter($feed_data);
165
			$fields['items']['children'] = array_replace_recursive($fields['items']['children'], array_filter($feed_fields));
166
		}
167
168
		return [
169
			'fields'	=> array_filter($fields),
170
			'data'		=> array_filter($data),
171
			'message'	=> $message,
172
		];
173
	}
174
175
	/**
176
	 * @param array $feed_urls
177
	 * @param string $message
178
	 * @param int $max
179
	 * @param int $cache
180
	 * @param bool $quiet
181
	 * @return array
182
	 */
183
	protected function get_feed_items(array $feed_urls, &$message, $max, $cache = 0, $items_per_feed = 0, $quiet = false)
184
	{
185
		if (!sizeof($feed_urls))
186
		{
187
			if (!$quiet)
188
			{
189
				throw new \Exception($this->translator->lang('FEED_URL_MISSING'));
190
			}
191
			return [];
192
		}
193
194
		$items = [];
195
196
		try
197
		{
198
			$this->simplepie->set_feed_url($feed_urls);
199
			$this->simplepie->enable_cache((bool) $cache);
200
			$this->simplepie->set_cache_location($this->cache_dir);
201
			$this->simplepie->set_cache_duration($cache * 3600);
202
203
			if ($items_per_feed)
204
			{
205
				$this->simplepie->set_item_limit($items_per_feed);
206
			}
207
208
			$this->simplepie->init();
209
			$this->simplepie->handle_content_type();
210
211
			if (!($items = $this->simplepie->get_items(0, $max)))
212
			{
213
				$message = $this->translator->lang('FEED_PROBLEMS');
214
			}
215
		}
216
		catch (\Exception $e)
217
		{
218
			$message = $e->getMessage();
219
		}
220
221
		return array_filter((array) $items);
222
	}
223
224
	/**
225
	 * @param \blitze\sitemaker\services\simplepie\item $feed
226
	 * @return array
227
	 */
228
	protected function get_feed_fields(\blitze\sitemaker\services\simplepie\item $item, array &$data)
229
	{
230
		$feed_props = [];
231
		foreach ($this->feed_fields as $field)
232
		{
233
			$feed_props[$field] = $this->build_tags($field, $item->feed->{$field});
234
			$data['feed'][$field] = $item->feed->{$field};
235
		}
236
237
		$feed_props = array_filter($feed_props);
238
		$data['feed'] = array_filter($data['feed']);
239
240
		$fields = [];
241
		if (sizeof($feed_props))
242
		{
243
			$fields['feed'] = $this->get_field_defaults('feed');
244
			$fields['feed']['children'] = $feed_props;
245
		}
246
247
		return $fields;
248
	}
249
250
	/**
251
	 * @param string $field
252
	 * @param mixed $value
253
	 * @return array|string
254
	 */
255
	protected function build_tags($field, $value)
256
	{
257
		if (empty($value))
258
		{
259
			return '';
260
		}
261
262
		$data = $this->get_field_defaults($field);
263
264
		if ($this->is_array_of_objects($value))
265
		{
266
			$value = array_slice($value, 0, 1);
267
			$this->iterate_props($value, $data);
268
		}
269
		else if (gettype($value) === 'object')
270
		{
271
			$props = array_filter(get_object_vars($value));
272
			$this->iterate_props($props, $data);
273
		}
274
275
		return $data;
276
	}
277
278
	/**
279
	 * @param array $props
280
	 * @param array $data
281
	 * @return void
282
	 */
283
	protected function iterate_props(array $props, array &$data)
284
	{
285
		ksort($props);
286
		foreach ($props as $prop => $value)
287
		{
288
			$data['children'][$prop] = $this->build_tags($prop, $value);
289
		}
290
	}
291
292
	/**
293
	 * @param mixed $value
294
	 * @return bool
295
	 */
296
	protected function is_array_of_objects($value)
297
	{
298
		return (is_array($value) && gettype($value[0]) === 'object');
299
	}
300
301
	/**
302
	 * @param string $field
303
	 * @return array
304
	 */
305
	protected function get_field_defaults($field)
306
	{
307
		$field = (string) $field;
308
		return [
309
			'text'			=> $field,
310
			'displayText'	=> $this->translator->lang(strtoupper($field)),
311
			'children'		=> [],
312
		];
313
	}
314
315
	/**
316
	 * @param string $tpl
317
	 * @return string
318
	 */
319
	protected function get_feed_template($item_tpl)
320
	{
321
		$item_tpl = html_entity_decode(trim($item_tpl));
322
		return "<ul class=\"sm-list\">
323
			{% for item in items %}
324
			<li>
325
				$item_tpl
326
			</li>
327
			{% endfor %}
328
		</ul>";
329
	}
330
331
	/**
332
	 * @param mixed $feeds
333
	 * @return array
334
	 */
335
	protected function get_feeds_array($feeds)
336
	{
337
		return array_map('trim', array_filter((array) $feeds));
338
	}
339
}
340