Completed
Pull Request — master (#25)
by Matt
02:01
created

mysqli::is_supported()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.2
c 0
b 0
f 0
cc 4
eloc 2
nc 4
nop 0
1
<?php
2
/**
3
 *
4
 * Precise Similar Topics
5
 *
6
 * @copyright (c) 2018 Matt Friedman
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace vse\similartopics\driver;
12
13
class mysqli implements driver_interface
14
{
15
	/** @var \phpbb\db\driver\driver_interface */
16
	protected $db;
17
18
	/** @var string */
19
	protected $engine;
20
21
	/**
22
	 * Constructor
23
	 *
24
	 * @param \phpbb\db\driver\driver_interface $db
25
	 */
26
	public function __construct(\phpbb\db\driver\driver_interface $db)
27
	{
28
		$this->db = $db;
29
	}
30
31
	/**
32
	 * {@inheritdoc}
33
	 */
34
	public function get_name()
35
	{
36
		return 'mysqli';
37
	}
38
39
	/**
40
	 * {@inheritdoc}
41
	 */
42
	public function get_type()
43
	{
44
		return 'mysql';
45
	}
46
47
	/**
48
	 * {@inheritdoc}
49
	 */
50
	public function get_query($topic_id, $topic_title, $length, $sensitivity)
51
	{
52
		return array(
53
			'SELECT'	=> "f.forum_id, f.forum_name, t.*,
54
				MATCH (t.topic_title) AGAINST ('" . $this->db->sql_escape($topic_title) . "') AS score",
55
56
			'FROM'		=> array(
57
				TOPICS_TABLE	=> 't',
58
			),
59
			'LEFT_JOIN'	=> array(
60
				array(
61
					'FROM'	=>	array(FORUMS_TABLE	=> 'f'),
62
					'ON'	=> 'f.forum_id = t.forum_id',
63
				),
64
			),
65
			'WHERE'		=> "MATCH (t.topic_title) AGAINST ('" . $this->db->sql_escape($topic_title) . "') >= " . (float) $sensitivity . '
66
				AND t.topic_status <> ' . ITEM_MOVED . '
67
				AND t.topic_visibility = ' . ITEM_APPROVED . '
68
				AND t.topic_time > (UNIX_TIMESTAMP() - ' . (int) $length . ')
69
				AND t.topic_id <> ' . (int) $topic_id,
70
		);
71
	}
72
73
	/**
74
	 * {@inheritdoc}
75
	 */
76
	public function is_supported()
77
	{
78
		// FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to
79
		// http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html
80
		return $this->is_mysql() && ($this->get_engine() === 'myisam' || ($this->get_engine() === 'innodb' && phpbb_version_compare($this->db->sql_server_info(true), '5.6.4', '>=')));
81
	}
82
83
	/**
84
	 * {@inheritdoc}
85
	 */
86
	public function is_fulltext($column = 'topic_title')
87
	{
88
		foreach ($this->get_fulltext_indexes($column) as $index)
89
		{
90
			if ($index === $column)
91
			{
92
				return true;
93
			}
94
		}
95
96
		return false;
97
	}
98
99
	/**
100
	 * {@inheritdoc}
101
	 */
102
	public function get_fulltext_indexes($column = 'topic_title')
103
	{
104
		$indexes = array();
105
106
		if (!$this->is_supported())
107
		{
108
			return $indexes;
109
		}
110
111
		$sql = 'SHOW INDEX
112
			FROM ' . TOPICS_TABLE;
113
		$result = $this->db->sql_query($sql);
114
115
		while ($row = $this->db->sql_fetchrow($result))
116
		{
117
			// Older MySQL versions didn't use Index_type, so fallback to Comment
118
			$index_type = isset($row['Index_type']) ? $row['Index_type'] : $row['Comment'];
119
120
			if ($index_type === 'FULLTEXT' && $row['Key_name'] === $column)
121
			{
122
				$indexes[] = $row['Key_name'];
123
			}
124
		}
125
126
		$this->db->sql_freeresult($result);
127
128
		return $indexes;
129
	}
130
131
	/**
132
	 * {@inheritdoc}
133
	 */
134
	public function create_fulltext_index($column = 'topic_title')
135
	{
136
		if (!$this->is_fulltext($column))
137
		{
138
			// First see if we need to update the table engine to support fulltext indexes
139
			if (!$this->is_supported())
140
			{
141
				$sql = 'ALTER TABLE ' . TOPICS_TABLE . ' ENGINE = ' . $this->db->sql_escape(strtoupper('MYISAM'));
142
				$this->db->sql_query($sql);
143
				$this->set_engine();
144
			}
145
146
			$sql = 'ALTER TABLE ' . TOPICS_TABLE . ' ADD FULLTEXT (' . $column . ')';
147
			$this->db->sql_query($sql);
148
		}
149
	}
150
151
	/**
152
	 * {@inheritdoc}
153
	 */
154
	public function get_engine()
155
	{
156
		return $this->engine !== null ? $this->engine : $this->set_engine();
157
	}
158
159
	/**
160
	 * Set the database storage engine name
161
	 *
162
	 * @access protected
163
	 * @return string The storage engine name
164
	 */
165
	protected function set_engine()
166
	{
167
		$this->engine = '';
168
169
		if ($this->is_mysql())
170
		{
171
			$info = $this->get_table_info();
172
173
			// Modern MySQL uses 'Engine', but older may still use 'Type'
174
			foreach (array('Engine', 'Type') as $name)
175
			{
176
				if (isset($info[$name]))
177
				{
178
					$this->engine = strtolower($info[$name]);
179
					break;
180
				}
181
			}
182
		}
183
184
		return $this->engine;
185
	}
186
187
	/**
188
	 * Get topics table information
189
	 *
190
	 * @access protected
191
	 * @return mixed Array with the table info, false if the table does not exist
192
	 */
193
	protected function get_table_info()
194
	{
195
		$result = $this->db->sql_query('SHOW TABLE STATUS LIKE \'' . TOPICS_TABLE . '\'');
196
		$info = $this->db->sql_fetchrow($result);
197
		$this->db->sql_freeresult($result);
198
199
		return $info;
200
	}
201
202
	/**
203
	 * Check if the database is using MySQL
204
	 *
205
	 * @access public
206
	 * @return bool True if is mysql, false otherwise
207
	 */
208
	protected function is_mysql()
209
	{
210
		return ($this->db->get_sql_layer() === 'mysql4' || $this->db->get_sql_layer() === 'mysqli');
211
	}
212
}
213