Passed
Push — templating ( 0cf8c2 )
by Daniel
20:43
created

feeds::iterate_props()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 6
rs 10
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 string */
30
	protected $cache_dir;
31
32
	/** @var array */
33
	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'];
34
35
	/** @var array */
36
	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'];
37
38
	/**
39
	 * Constructor
40
	 *
41
	 * @param \phpbb\language\language				$translator			Language object
42
	 * @param \phpbb\request\request_interface		$request			Request object
43
	 * @param \phpbb\template\twig\environment		$twig				Twig environment
44
	 * @param string 								$cache_dir			Path to cache directory
45
	 */
46
	public function __construct(\phpbb\language\language $translator, \phpbb\request\request_interface $request, \phpbb\template\twig\environment $twig, $cache_dir)
47
	{
48
		$this->translator = $translator;
49
		$this->request = $request;
50
		$this->twig = $twig;
51
		$this->cache_dir = $cache_dir;
52
	}
53
54
	/**
55
	 * {@inheritdoc}
56
	 */
57
	public function get_config(array $settings)
58
	{
59
		$template_default = '<a target="_blank" href="{{ item.link }}">{{ item.title }}</a>';
60
		return array(
61
			'legend1'		=> 'SETTINGS',
62
			'feeds'			=> array('lang' => 'FEED_URLS', 'type' => 'multi_input:0', 'default' => []),
63
			'template'		=> array('type' => 'custom', 'default' => $template_default, 'object' => $this, 'method' => 'get_cfg_feeds_template'),
64
			'max'			=> array('lang' => 'MAX_ITEMS', 'validate' => 'int:1', 'type' => 'number:1', 'default' => 5),
65
			'cache'			=> array('lang' => 'CACHE_DURATION', 'validate' => 'int:1', 'type' => 'number:1', 'default' => 6, 'append' => 'HOURS_SHORT'),
66
		);
67
	}
68
69
	/**
70
	 * {@inheritdoc}
71
	 */
72
	public function display(array $bdata, $edit_mode = false)
73
	{
74
		$content = '';
75
		$settings = $bdata['settings'];
76
		$feed_urls = $this->get_feeds_array($settings['feeds']);
77
78
		if (sizeof($feed_urls))
79
		{
80
			if ($items = $this->get_feed_items($feed_urls, $content, $settings['max'], $settings['cache']))
81
			{
82
				// We try to render block with user-provided trig template
83
				try
84
				{
85
					$template = $this->twig->createTemplate($this->get_feed_template($settings['template']));
86
87
					$content = $template->render([
88
						'items'	=> $items,
89
					]);
90
				}
91
				catch (\Exception $e)
92
				{
93
					$content = $e->getMessage();
94
				}
95
			}
96
		}
97
		else
98
		{
99
			$content = $this->translator->lang('FEED_URL_MISSING');
100
		}
101
102
		return array(
103
			'title'		=> 'FEEDS',
104
			'content'	=> $content,
105
		);
106
	}
107
108
	/**
109
	 * @param string $source
110
	 * @return string
111
	 */
112
	public function get_cfg_feeds_template($source)
113
	{
114
		$template = $this->twig->load('@blitze_sitemaker/cfg_fields/feeds.html');
115
		return $template->render([
116
			'template'	=> $source,
117
		]);
118
	}
119
120
	/**
121
	 * Called when editing feed block to get available rss/atom fields
122
	 * @return array
123
	 */
124
	public function get_fields()
125
	{
126
		$this->translator->add_lang('feed_fields', 'blitze/sitemaker');
127
128
		$feeds = $this->request->variable('feeds', array(0 => ''));
129
		$feeds = $this->get_feeds_array($feeds);
130
131
		$message = '';
132
		$data = array('items' => []);
133
		$fields = array('items' => $this->get_field_defaults('items'));
134
		$feed_items = $this->get_feed_items($feeds, $message, 0, 0, 1);
135
136
		foreach ($feed_items as $feed)
137
		{
138
			$feed_data = $feed_fields = [];
139
			$fields['items']['children'] += $this->get_feed_fields($feed, $feed_data);
140
141
			foreach ($this->item_fields as $field)
142
			{
143
				$value = $feed->{$field};
144
				$feed_data[$field] = $value;
145
				$feed_fields[$field] = $this->build_tags($field, $value);
146
			}
147
148
			$data['items'][] = array_filter($feed_data);
149
			$fields['items']['children'] = array_replace_recursive($fields['items']['children'], array_filter($feed_fields));
150
		}
151
152
		return [
153
			'fields'	=> array_filter($fields),
154
			'data'		=> array_filter($data),
155
			'message'	=> $message,
156
		];
157
	}
158
159
	/**
160
	 * @param array $feed_urls
161
	 * @param string $message
162
	 * @param int $max
163
	 * @param int $cache
164
	 * @return array
165
	 */
166
	protected function get_feed_items(array $feed_urls, &$message, $max, $cache = 0, $items_per_feed = 0)
167
	{
168
		$items = [];
169
170
		if (sizeof($feed_urls))
171
		{
172
			try
173
			{
174
				/**
175
				 * The below class cannot be added as a non-shared service using DI
176
				 * as it does not follow best practises for class contructs.
177
				 * It contains logic and method calls in the contructor for one thing.
178
				 * Passing it as a non-shared service does not work
179
				 */
180
				$feed = new \blitze\sitemaker\services\simplepie\feed;
181
				$feed->set_feed_url($feed_urls);
182
				$feed->enable_cache((bool) $cache);
183
				$feed->set_cache_location($this->cache_dir);
184
				$feed->set_cache_duration($cache * 3600);
185
186
				if ($items_per_feed)
187
				{
188
					$feed->set_item_limit($items_per_feed);
189
				}
190
191
				$feed->init();
192
				$feed->handle_content_type();
193
194
				if (!($items = $feed->get_items(0, $max)))
195
				{
196
					$message = $this->translator->lang('FEED_PROBLEMS');
197
				}
198
			}
199
			catch (\Exception $e)
200
			{
201
				$message = $e->getMessage();
202
			}
203
		}
204
205
		return array_filter((array) $items);
206
	}
207
208
	/**
209
	 * @param \blitze\sitemaker\services\simplepie\item $feed
210
	 * @return array
211
	 */
212
	protected function get_feed_fields(\blitze\sitemaker\services\simplepie\item $item, array &$data)
213
	{
214
		$feed_props = [];
215
		foreach ($this->feed_fields as $field)
216
		{
217
			$feed_props[$field] = $this->build_tags($field, $item->feed->{$field});
218
			$data['feed'][$field] = $item->feed->{$field};
219
		}
220
221
		$feed_props = array_filter($feed_props);
222
		$data['feed'] = array_filter($data['feed']);
223
224
		$fields = [];
225
		if (sizeof($feed_props))
226
		{
227
			$fields['feed'] = $this->get_field_defaults('feed');
228
			$fields['feed']['children'] = $feed_props;
229
		}
230
231
		return $fields;
232
	}
233
234
	/**
235
	 * @param string $field
236
	 * @param mixed $value
237
	 * @return array|string
238
	 */
239
	protected function build_tags($field, $value)
240
	{
241
		if (empty($value))
242
		{
243
			return '';
244
		}
245
246
		$data = $this->get_field_defaults($field);
247
248
		if ($this->is_array_of_objects($value))
249
		{
250
			$value = array_slice($value, 0, 1);
251
			$this->iterate_props($value, $data);
252
		}
253
		else if (gettype($value) === 'object')
254
		{
255
			$props = array_filter(get_object_vars($value));
256
			$this->iterate_props($props, $data);
257
		}
258
259
		return $data;
260
	}
261
262
	/**
263
	 * @param array $props
264
	 * @param array $data
265
	 * @return void
266
	 */
267
	protected function iterate_props(array $props, array &$data)
268
	{
269
		ksort($props);
270
		foreach ($props as $prop => $value)
271
		{
272
			$data['children'][$prop] = $this->build_tags($prop, $value);
273
		}
274
	}
275
276
	/**
277
	 * @param mixed $value
278
	 * @return bool
279
	 */
280
	protected function is_array_of_objects($value)
281
	{
282
		return (is_array($value) && gettype($value[0]) === 'object');
283
	}
284
285
	/**
286
	 * @param string $field
287
	 * @return array
288
	 */
289
	protected function get_field_defaults($field)
290
	{
291
		$field = (string) $field;
292
		return [
293
			'text'			=> $field,
294
			'displayText'	=> $this->translator->lang(strtoupper($field)),
295
			'children'		=> [],
296
		];
297
	}
298
299
	/**
300
	 * @param string $tpl
301
	 * @return string
302
	 */
303
	protected function get_feed_template($item_tpl)
304
	{
305
		$item_tpl = html_entity_decode(trim($item_tpl));
306
		return "<ul class=\"sm-list\">
307
			{% for item in items %}
308
			<li>
309
				$item_tpl
310
			</li>
311
			{% endfor %}
312
		</ul>";
313
	}
314
315
	/**
316
	 * @param mixed $feeds
317
	 * @return array
318
	 */
319
	protected function get_feeds_array($feeds)
320
	{
321
		return array_map('trim', array_filter((array) $feeds));
322
	}
323
}
324