Completed
Push — master ( 8995ac...f2dc1d )
by Matt
03:30 queued 02:11
created

factory   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 0
dl 0
loc 181
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A update_row_data() 0 15 4
A update_tpl_data() 0 11 5
B query_images() 0 40 7
A extract_images() 0 17 2
A forum_allowed() 0 4 1
A user_allowed() 0 4 1
A has_images() 0 4 3
1
<?php
2
/**
3
 *
4
 * Topic Image Preview. An extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2017, 2020, Matt Friedman
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace vse\topicimagepreview;
12
13
use phpbb\auth\auth;
14
use phpbb\config\config;
15
use phpbb\db\driver\driver_interface;
16
use phpbb\user;
17
18
/**
19
 * Topic Image Preview Factory.
20
 */
21
class factory
22
{
23
	/** @var auth */
24
	protected $auth;
25
26
	/** @var config */
27
	protected $config;
28
29
	/** @var driver_interface */
30
	protected $db;
31
32
	/** @var user */
33
	protected $user;
34
35
	/**
36
	 * Constructor
37
	 *
38
	 * @param auth             $auth
39
	 * @param config           $config
40
	 * @param driver_interface $db
41
	 * @param user             $user
42
	 */
43
	public function __construct(auth $auth, config $config, driver_interface $db, user $user)
44
	{
45
		$this->auth = $auth;
46
		$this->config = $config;
47
		$this->db = $db;
48
		$this->user = $user;
49
	}
50
51
	/**
52
	 * Add post text containing images to topic row data.
53
	 *
54
	 * @param \phpbb\event\data $event The event object
55
	 *
56
	 * @return void
57
	 */
58
	public function update_row_data($event)
59
	{
60
		if (!$this->user_allowed())
61
		{
62
			return;
63
		}
64
65
		// Use topic_list from event, otherwise create one based on the rowset
66
		$topic_list = $event->offsetExists('topic_list') ? $event['topic_list'] : array_keys($event['rowset']);
67
68
		if (count($topic_list))
69
		{
70
			$event['rowset'] = $this->query_images($topic_list, $event['rowset']);
71
		}
72
	}
73
74
	/**
75
	 * Add image previews to the template data.
76
	 *
77
	 * @param \phpbb\event\data $event The event object
78
	 *
79
	 * @return void
80
	 */
81
	public function update_tpl_data($event)
82
	{
83
		if (!$this->user_allowed() || !$this->forum_allowed($event['row']['forum_id']) || !$this->has_images($event))
84
		{
85
			return;
86
		}
87
88
		// Send the image string to the template
89
		$block = $event->offsetExists('topic_row') ? 'topic_row' : 'tpl_ary';
90
		$event[$block] = array_merge($event[$block], ['TOPIC_IMAGES' => $this->extract_images($event['row']['post_text'])]);
91
	}
92
93
	/**
94
	 * Run an SQL query on a group of topics, and find the newest (or oldest)
95
	 * post with [IMG] images. Then update the topic's row set array to include
96
	 * the post's text in the cases where images were found.
97
	 *
98
	 * @param array $topic_list An array of topic ids
99
	 * @param array $rowset     The row set of topic data
100
	 *
101
	 * @return array The updated row set of topic data which now includes
102
	 *               the post_text of a post containing images.
103
	 */
104
	protected function query_images(array $topic_list, array $rowset)
105
	{
106
		$sql_array = [];
107
		foreach ($topic_list as $topic_id)
108
		{
109
			if (!$this->forum_allowed($rowset[$topic_id]['forum_id']))
110
			{
111
				continue;
112
			}
113
114
			$stmt = '(SELECT topic_id, post_text
115
				FROM ' . POSTS_TABLE . '
116
				WHERE topic_id = ' . (int) $topic_id . '
117
					AND post_visibility = ' . ITEM_APPROVED . '
118
					AND post_text ' . $this->db->sql_like_expression('<r>' . $this->db->get_any_char() . '<IMG ' . $this->db->get_any_char()) . '
119
				ORDER BY post_time ' . ($this->config->offsetGet('vse_tip_new') ? 'DESC' : 'ASC') . '
120
				LIMIT 1)';
121
122
			// SQLite3 doesn't like ORDER BY with UNION ALL, so treat $stmt as derived table
123
			if ($this->db->get_sql_layer() === 'sqlite3')
124
			{
125
				$stmt = "SELECT * FROM $stmt AS d";
126
			}
127
128
			$sql_array[] = $stmt;
129
		}
130
131
		if (count($sql_array))
132
		{
133
			$sql = implode(' UNION ALL ', $sql_array);
134
			$result = $this->db->sql_query($sql);
135
			while ($row = $this->db->sql_fetchrow($result))
136
			{
137
				$rowset[$row['topic_id']]['post_text'] = $row['post_text'];
138
			}
139
			$this->db->sql_freeresult($result);
140
		}
141
142
		return $rowset;
143
	}
144
145
	/**
146
	 * Extract images from a post and return them as HTML image tags.
147
	 *
148
	 * @param string $post Post text from the database.
149
	 *
150
	 * @return string An string of HTML IMG tags.
151
	 */
152
	protected function extract_images($post)
153
	{
154
		// Extract the images
155
		$images = [];
156
		$dom = new \DOMDocument;
157
		$dom->loadXML($post);
158
		$xpath = new \DOMXPath($dom);
159
		foreach ($xpath->query('//IMG[not(ancestor::IMG)]/@src') as $image)
160
		{
161
			$images[] = $image->textContent;
162
		}
163
164
		// Create a string of images
165
		return implode(' ', array_map(function ($image) {
166
			return "<img src='{$image}' alt='' style='max-width:{$this->config['vse_tip_dim']}px; max-height:{$this->config['vse_tip_dim']}px;' />";
167
		}, array_slice($images, 0, (int) $this->config['vse_tip_num'], true)));
168
	}
169
170
	/**
171
	 * Is the forum allowed to show topic image previews
172
	 *
173
	 * @param int $forum_id Forum identifier
174
	 * @return bool True if allowed, false if not
175
	 */
176
	protected function forum_allowed($forum_id)
177
	{
178
		return (bool) $this->auth->acl_get('f_vse_tip', $forum_id);
179
	}
180
181
	/**
182
	 * Does the user allow topic image previews?
183
	 *
184
	 * @return bool True if allowed, false if not
185
	 */
186
	protected function user_allowed()
187
	{
188
		return (bool) $this->user->data['user_vse_tip'];
189
	}
190
191
	/**
192
	 * Check if we have post with images
193
	 *
194
	 * @param \phpbb\event\data $event The event object
195
	 * @return bool True if images found in post text, false if not
196
	 */
197
	protected function has_images($event)
198
	{
199
		return !empty($event['row']['post_text']) && preg_match('/^<[r][ >]/', $event['row']['post_text']) && strpos($event['row']['post_text'], '<IMG ') !== false;
200
	}
201
}
202