cleaner::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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