Passed
Push — release-3.2.0 ( 8165d1...607af8 )
by Daniel
03:27
created

cleaner::clean_blocks()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 22
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 1
b 0
f 0
nc 9
nop 0
dl 0
loc 22
rs 9.6111
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
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\url_checker */
24
	protected $url_checker;
25
26
	/** @var string */
27
	protected $blocks_table;
28
29
	/** @var string */
30
	protected $cblocks_table;
31
32
	/** @var bool */
33
	protected $is_dry_run = false;
34
35
	/** @var array */
36
	protected $orphaned = [];
37
38
	/**
39
	 * Constructor
40
	 *
41
	 * @param \phpbb\config\config							$config				Config object
42
	 * @param \phpbb\db\driver\driver_interface				$db					Database object
43
	 * @param \blitze\sitemaker\services\blocks\manager		$manager			Blocks manager object
44
	 * @param \blitze\sitemaker\services\url_checker		$url_checker		Url checker object
45
	 * @param string										$blocks_table		Name of blocks database table
46
	 * @param string										$cblocks_table		Name of custom blocks database table
47
	 */
48
	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)
49
	{
50
		$this->config = $config;
51
		$this->db = $db;
52
		$this->manager = $manager;
53
		$this->url_checker = $url_checker;
54
		$this->blocks_table = $blocks_table;
55
		$this->cblocks_table = $cblocks_table;
56
	}
57
58
	/**
59
	 * @param array $components
60
	 * @return void
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
	 * @return array
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
	private 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
	private function clean_routes()
133
	{
134
		$board_url = generate_board_url();
135
		$routes	= $this->manager->get_routes('route');
136
137
		foreach ($routes as $route => $row)
138
		{
139
			$url = $board_url . '/' . $row['route'];
140
141
			// Route no longer exists => remove all blocks for route
142
			if (!$this->url_checker->exists($url))
143
			{
144
				$this->orphaned['routes'][] = $url;
145
146
				// we dry_run this via cron because routes may be temporarily unreachable for any number of reasons
147
				if (!$this->is_dry_run)
148
				{
149
					$this->manager->delete_blocks_by_route($route);
150
				}
151
			}
152
		}
153
	}
154
155
	/**
156
	 * Removes all blocks that (the service) no longer exist
157
	 * @return void
158
	 */
159
	private function clean_blocks()
160
	{
161
		$block_names = $this->manager->get_unique_block_names();
162
163
		$blocks = array();
164
		foreach ($block_names as $block_name)
165
		{
166
			if (!$this->manager->block_exists($block_name))
167
			{
168
				$blocks[] = $block_name;
169
			}
170
		}
171
172
		if (sizeof($blocks))
173
		{
174
			// We dry_run this via cron because the block service might only be temporarily unavailable
175
			// such as when updating (disable/re-enable) the extension that provides the block
176
			if (!$this->is_dry_run)
177
			{
178
				$this->manager->delete_blocks_by_name($blocks);
179
			}
180
			$this->orphaned['blocks'] = $blocks;
181
		}
182
	}
183
184
	/**
185
	 * Removes from custom blocks table, any custom blocks no longer present in blocks table
186
	 * @return void
187
	 */
188
	private function clean_custom_blocks()
189
	{
190
		$sql = $this->db->sql_build_query('SELECT', array(
191
			'SELECT'	=> 'cb.block_id',
192
			'FROM'		=> array(
193
				$this->cblocks_table    => 'cb',
194
			),
195
			'LEFT_JOIN'	=> array(
196
				array(
197
					'FROM'	=> array($this->blocks_table => 'b'),
198
					'ON'	=> 'b.bid = cb.block_id',
199
				)
200
			),
201
			'WHERE'		=> 'b.bid IS NULL'
202
		));
203
		$result = $this->db->sql_query($sql);
204
205
		$block_ids = array();
206
		while ($row = $this->db->sql_fetchrow($result))
207
		{
208
			$block_ids[] = $row['block_id'];
209
		}
210
		$this->db->sql_freeresult($result);
211
212
		if (sizeof($block_ids))
213
		{
214
			$this->db->sql_query('DELETE FROM ' . $this->cblocks_table . ' WHERE ' . $this->db->sql_in_set('block_id', $block_ids));
215
		}
216
	}
217
218
	/**
219
	 * @return array
220
	 */
221
	private function get_style_ids()
222
	{
223
		$sql = 'SELECT style_id, style_name
224
			FROM ' . STYLES_TABLE;
225
		$result = $this->db->sql_query($sql);
226
227
		$style_ids = array();
228
		while ($row = $this->db->sql_fetchrow($result))
229
		{
230
			$style_ids[$row['style_id']] = $row['style_name'];
231
		}
232
		$this->db->sql_freeresult($result);
233
234
		return $style_ids;
235
	}
236
}
237