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