Passed
Push — renovate/configure ( 5b5630...69e50f )
by
unknown
16:36
created

cleaner::forum_exists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 2
nop 3
dl 0
loc 11
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\services\blocks;
12
13
class cleaner implements cleaner_interface
14
{
15
	/** @var \phpbb\config\config */
16
	protected $config;
17
18
	/** @var \phpbb\db\driver\driver_interface */
19
	protected $db;
20
21
	/** @var \blitze\sitemaker\services\blocks\manager */
22
	protected $manager;
23
24
	/** @var \blitze\sitemaker\services\blocks\routes */
25
	protected $routes;
26
27
	/** @var \blitze\sitemaker\services\url_checker */
28
	protected $url_checker;
29
30
	/** @var string */
31
	protected $blocks_table;
32
33
	/** @var string */
34
	protected $cblocks_table;
35
36
	/** @var bool */
37
	protected $is_dry_run = false;
38
39
	/** @var array */
40
	protected $orphaned = [];
41
42
	/**
43
	 * Constructor
44
	 *
45
	 * @param \phpbb\config\config							$config				Config object
46
	 * @param \phpbb\db\driver\driver_interface				$db					Database object
47
	 * @param \blitze\sitemaker\services\blocks\manager		$manager			Blocks manager object
48
	 * @param \blitze\sitemaker\services\blocks\routes		$routes				Blocks routes object
49
	 * @param \blitze\sitemaker\services\url_checker		$url_checker		Url checker object
50
	 * @param string										$blocks_table		Name of blocks database table
51
	 * @param string										$cblocks_table		Name of custom blocks database table
52
	 */
53
	public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \blitze\sitemaker\services\blocks\manager $manager, \blitze\sitemaker\services\blocks\routes $routes, \blitze\sitemaker\services\url_checker $url_checker, $blocks_table, $cblocks_table)
54
	{
55
		$this->config = $config;
56
		$this->db = $db;
57
		$this->manager = $manager;
58
		$this->routes = $routes;
59
		$this->url_checker = $url_checker;
60
		$this->blocks_table = $blocks_table;
61
		$this->cblocks_table = $cblocks_table;
62
	}
63
64
	/**
65
	 * @inheritdoc
66
	 */
67
	public function run(array $components)
68
	{
69
		// force order of components here
70
		$components = array_intersect(['styles', 'routes', 'blocks'], $components);
71
72
		foreach ($components as $component)
73
		{
74
			$method = 'clean_' . $component;
75
			if (is_callable(array($this, $method)))
76
			{
77
				call_user_func(array($this, $method));
78
			}
79
		}
80
81
		$this->config->set('sm_orphaned_blocks', '');
82
	}
83
84
	/**
85
	 * @inheritdoc
86
	 */
87
	public function test()
88
	{
89
		$this->is_dry_run = true;
90
		$this->orphaned = [];
91
		$this->run(['blocks', 'routes', 'styles']);
92
		$this->clean_custom_blocks();
93
94
		$this->config->set('sm_orphaned_blocks', sizeof($this->orphaned) ? json_encode($this->orphaned) : '');
95
	}
96
	/**
97
	 * @return null|array
98
	 */
99
	public function get_orphans()
100
	{
101
		return ($this->config['sm_orphaned_blocks']) ? json_decode($this->config['sm_orphaned_blocks'], true) : null;
102
	}
103
104
	/**
105
	 * Removes all block routes and blocks belonging to these routes for styles that no longer exist
106
	 * @return void
107
	 */
108
	protected function clean_styles()
109
	{
110
		$routes_ary	= array_keys($this->manager->get_routes('style'));
111
		$style_ids	= $this->get_style_ids();
112
		$col_widths	= (array) json_decode($this->config['sitemaker_column_widths'], true);
113
114
		foreach ($routes_ary as $style_id)
115
		{
116
			// Style no longer exists => remove all routes and blocks for style
117
			if (!isset($style_ids[$style_id]))
118
			{
119
				$this->orphaned['styles'][] = $style_id;
120
121
				// we let the user confirm that they want to delete blocks for unavailable style as it may be temporary
122
				if (!$this->is_dry_run)
123
				{
124
					$this->manager->delete_blocks_by_style($style_id);
125
					unset($col_widths[$style_id]);
126
				}
127
			}
128
		}
129
130
		$this->config->set('sitemaker_column_widths', json_encode(array_filter($col_widths)));
131
	}
132
133
	/**
134
	 * Removes all blocks for routes that no longer exist
135
	 * @return void
136
	 */
137
	protected function clean_routes()
138
	{
139
		$board_url = generate_board_url();
140
		$routes	= array_keys($this->manager->get_routes('route'));
141
		$forumslist = (array) make_forum_select(false, false, true, false, false, false, true);
142
143
		foreach ($routes as $route)
144
		{
145
			// Route no longer exists => remove all blocks for route
146
			if (!$this->route_exists($route, $board_url, $forumslist))
147
			{
148
				// we dry_run this via cron because routes may be temporarily unreachable for any number of reasons
149
				if (!$this->is_dry_run)
150
				{
151
					$this->manager->delete_blocks_by_route($route);
152
				}
153
			}
154
		}
155
	}
156
157
	/**
158
	 * Removes all blocks that (the service) no longer exist
159
	 * @return void
160
	 */
161
	protected function clean_blocks()
162
	{
163
		$block_names = $this->manager->get_unique_block_names();
164
165
		$blocks = array();
166
		foreach ($block_names as $block_name)
167
		{
168
			if (!$this->manager->block_exists($block_name))
169
			{
170
				$blocks[] = $block_name;
171
			}
172
		}
173
174
		if (sizeof($blocks))
175
		{
176
			// We dry_run this via cron because the block service might only be temporarily unavailable
177
			// such as when updating (disable/re-enable) the extension that provides the block
178
			if (!$this->is_dry_run)
179
			{
180
				$this->manager->delete_blocks_by_name($blocks);
181
			}
182
			$this->orphaned['blocks'] = $blocks;
183
		}
184
	}
185
186
	/**
187
	 * Removes from custom blocks table, any custom blocks no longer present in blocks table
188
	 * @return void
189
	 */
190
	protected function clean_custom_blocks()
191
	{
192
		$sql = $this->db->sql_build_query('SELECT', array(
193
			'SELECT'	=> 'cb.block_id',
194
			'FROM'		=> array(
195
				$this->cblocks_table    => 'cb',
196
			),
197
			'LEFT_JOIN'	=> array(
198
				array(
199
					'FROM'	=> array($this->blocks_table => 'b'),
200
					'ON'	=> 'b.bid = cb.block_id',
201
				)
202
			),
203
			'WHERE'		=> 'b.bid IS NULL'
204
		));
205
		$result = $this->db->sql_query($sql);
206
207
		$block_ids = array();
208
		while ($row = $this->db->sql_fetchrow($result))
209
		{
210
			$block_ids[] = $row['block_id'];
211
		}
212
		$this->db->sql_freeresult($result);
213
214
		if (sizeof($block_ids))
215
		{
216
			$this->db->sql_query('DELETE FROM ' . $this->cblocks_table . ' WHERE ' . $this->db->sql_in_set('block_id', $block_ids));
217
		}
218
	}
219
220
	/**
221
	 * @return array
222
	 */
223
	protected function get_style_ids()
224
	{
225
		$sql = 'SELECT style_id, style_name
226
			FROM ' . STYLES_TABLE;
227
		$result = $this->db->sql_query($sql);
228
229
		$style_ids = array();
230
		while ($row = $this->db->sql_fetchrow($result))
231
		{
232
			$style_ids[$row['style_id']] = $row['style_name'];
233
		}
234
		$this->db->sql_freeresult($result);
235
236
		return $style_ids;
237
	}
238
239
	/**
240
	 * @param string $route
241
	 * @param string $board_url
242
	 * @param array $forumslist
243
	 * @return bool
244
	 */
245
	protected function route_exists($route, $board_url, array $forumslist)
246
	{
247
		if (!$this->routes->is_forum_route($route))
248
		{
249
			return $this->url_exists($route, $board_url);
250
		}
251
252
		return $this->forum_exists($route, $board_url, $forumslist);
253
	}
254
255
	/**
256
	 * @param string $route
257
	 * @param string $board_url
258
	 * @return bool
259
	 */
260
	protected function url_exists($route, $board_url)
261
	{
262
		$url = $board_url . '/' . $route;
263
		if (!$this->url_checker->exists($url))
264
		{
265
			$this->orphaned['routes'][] = $url;
266
			return false;
267
		}
268
269
		return true;
270
	}
271
272
	/**
273
	 * @param string $route
274
	 * @param string $board_url
275
	 * @param array $forumslist
276
	 * @return bool
277
	 */
278
	protected function forum_exists($route, $board_url, array $forumslist)
279
	{
280
		[$file, $forum_id] = explode('?f=', $route);
281
282
		if (!isset($forumslist[$forum_id]))
283
		{
284
			$this->orphaned['routes'][] = $board_url . '/' . $file . '?f=' . $forum_id;
285
			return false;
286
		}
287
288
		return true;
289
	}
290
}
291