Completed
Push — master ( a960f0...783e4f )
by Matt
02:41 queued 13s
created

preview   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 0
dl 0
loc 154
rs 10
c 0
b 0
f 0

6 Methods

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