Passed
Push — forum_specific_blocks ( 6a1fa8 )
by Daniel
13:29
created

routes::is_forum_route()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 *
4
 * @package sitemaker
5
 * @copyright (c) 2013 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 routes
13
{
14
	/** @var \phpbb\cache\driver\driver_interface */
15
	protected $cache;
16
17
	/** @var \phpbb\config\config */
18
	protected $config;
19
20
	/** @var \blitze\sitemaker\services\blocks\factory */
21
	protected $block_factory;
22
23
	/** @var \blitze\sitemaker\model\mapper_factory */
24
	protected $mapper_factory;
25
26
	/** @var string */
27
	protected $php_ext;
28
29
	/** @var bool */
30
	protected $is_sub_route = false;
31
32
	/**
33
	 * Constructor
34
	 *
35
	 * @param \phpbb\cache\driver\driver_interface			$cache					Cache driver interface
36
	 * @param \phpbb\config\config							$config					Config object
37
	 * @param \blitze\sitemaker\services\blocks\factory		$block_factory			Blocks factory object
38
	 * @param \blitze\sitemaker\model\mapper_factory		$mapper_factory			Mapper factory object
39
	 * @param string										$php_ext				phpEx
40
	 */
41
	public function __construct(\phpbb\cache\driver\driver_interface $cache, \phpbb\config\config $config, \blitze\sitemaker\services\blocks\factory $block_factory, \blitze\sitemaker\model\mapper_factory $mapper_factory, $php_ext)
42
	{
43
		$this->cache = $cache;
44
		$this->config = $config;
45
		$this->block_factory = $block_factory;
46
		$this->mapper_factory = $mapper_factory;
47
		$this->php_ext = $php_ext;
48
	}
49
50
	/**
51
	 * @param string $current_route
52
	 * @param string $page_dir
53
	 * @param int $style_id
54
	 * @param bool $edit_mode
55
	 * @return array
56
	 */
57
	public function get_route_info($current_route, $page_dir, $style_id, $edit_mode = false)
58
	{
59
		$routes = $this->get_routes_for_style($style_id);
60
		$current_route = str_replace('viewtopic.' . $this->php_ext, 'viewforum.' . $this->php_ext, $current_route);
61
		$route_info = array();
62
63
		// does route have own settings?
64
		if (isset($routes[$current_route]))
65
		{
66
			$route_info = $routes[$current_route];
67
		}
68
69
		if ($edit_mode)
70
		{
71
			$route_info += $this->get_default_route_info($current_route, $style_id);
72
			return $route_info;
73
		}
74
75
		return $this->inherit_route_info($routes, $route_info, $current_route, $page_dir, $style_id);
76
	}
77
78
	/**
79
	 * @param array $route_info
80
	 * @param int $style_id
81
	 * @param bool $edit_mode
82
	 * @return array
83
	 */
84
	public function get_blocks_for_route(array $route_info, $style_id, $edit_mode)
85
	{
86
		$blocks = $this->get_cached_blocks($edit_mode);
87
		$route_id = $route_info['route_id'];
88
89
		return (isset($blocks[$style_id][$route_id])) ? $blocks[$style_id][$route_id] : array();
90
	}
91
92
	/**
93
	 * @param array $df_settings
94
	 * @param array $db_settings
95
	 * @return array
96
	 */
97
	public function sync_settings(array $df_settings, array $db_settings = array())
98
	{
99
		$settings = array();
100
		foreach ($df_settings as $field => $vars)
101
		{
102
			if (!is_array($vars))
103
			{
104
				continue;
105
			}
106
			$settings[$field] = $vars['default'];
107
		}
108
109
		return array_merge($settings, array_intersect_key($db_settings, $settings));
110
	}
111
112
	/**
113
	 * Clear blocks cache
114
	 */
115
	public function clear_cache()
116
	{
117
		$this->cache->destroy('sitemaker_blocks');
118
		$this->cache->destroy('sitemaker_block_routes');
119
	}
120
121
	/**
122
	 * @param array $routes
123
	 * @param array $route_info
124
	 * @param string $current_route
125
	 * @param string $page_dir
126
	 * @param int $style_id
127
	 * @return array
128
	 */
129
	protected function inherit_route_info(array $routes, array $route_info, $current_route, $page_dir, $style_id)
130
	{
131
		// if block does not have own settings, inherit settings from parent route if it exists
132
		// if block has own settings but no blocks, inherit route_id and has_blocks from parent route if it exists
133
		if (empty($route_info['has_blocks']))
134
		{
135
			$parent_route_info = $this->get_parent_route($routes, $current_route, $page_dir);
136
137
			if (sizeof($parent_route_info))
138
			{
139
				$route_info['route_id'] = $parent_route_info['route_id'];
140
				$route_info['has_blocks'] = $parent_route_info['has_blocks'];
141
			}
142
		}
143
144
		// fill in missing fields, while forcing route and style props to current route and style
145
		unset($route_info['style'], $route_info['route']);
146
		$route_info += $this->get_default_route_info($current_route, $style_id);
147
148
		return $this->set_display_route_id($routes, $route_info);
149
	}
150
151
	/**
152
	 * @param string $route
153
	 * @return bool
154
	 */
155
	public function is_forum_route($route)
156
	{
157
		return (strpos($route, 'viewforum.' . $this->php_ext) !== false || strpos($route, 'viewtopic.' . $this->php_ext) !== false);
158
	}
159
160
	/**
161
	 * @param string $current_route
162
	 * @param int $style_id
163
	 * @return array
164
	 */
165
	protected function get_default_route_info($current_route, $style_id)
166
	{
167
		return array(
168
			'route_id'		=> 0,
169
			'ext_name'		=> '',
170
			'route'			=> $current_route,
171
			'style'			=> $style_id,
172
			'hide_blocks'	=> false,
173
			'ex_positions'	=> array(),
174
			'has_blocks'	=> false,
175
			'is_sub_route'	=> $this->is_sub_route,
176
		);
177
	}
178
179
	/**
180
	 * @param array $routes
181
	 * @param string $current_route
182
	 * @param string $page_dir
183
	 * @return array
184
	 */
185
	protected function get_parent_route(array $routes, $current_route, $page_dir)
186
	{
187
		if ($page_dir)
188
		{
189
			$route = ltrim(dirname($page_dir) . '/index.php', './');
190
			return $this->get_parent_route_info($routes, $route);
191
		}
192
		else if ($this->is_forum_route($current_route))
193
		{
194
			$forum_id = explode('?f=', $current_route)[1];
195
			return $this->get_parent_forum_route($forum_id, $routes);
0 ignored issues
show
Bug introduced by
$forum_id of type string is incompatible with the type integer expected by parameter $forum_id of blitze\sitemaker\service...et_parent_forum_route(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

195
			return $this->get_parent_forum_route(/** @scrutinizer ignore-type */ $forum_id, $routes);
Loading history...
196
		}
197
198
		return $this->get_virtual_parent($routes, $current_route);
199
	}
200
201
	/**
202
	 * @param int $forum_id
203
	 * @param array $routes
204
	 * @return array
205
	 */
206
	protected function get_parent_forum_route($forum_id, array $routes)
207
	{
208
		$parent_route = [];
209
		$forumslist = (array) make_forum_select(false, false, true, false, false, false, true);
210
211
		do
212
		{
213
			$forum_id = &$forumslist[$forum_id]['parent_id'];
214
			$route = "viewforum.{$this->php_ext}?f={$forum_id}";
215
216
			if (isset($routes[$route]) && $routes[$route]['has_blocks'])
217
			{
218
				$this->is_sub_route = true;
219
				$parent_route = $routes[$route];
220
			} 
221
		}
222
		while ($forum_id && !$this->is_sub_route);
223
224
		return $parent_route;
225
	}
226
227
	/**
228
	 * @param array $routes_data
229
	 * @param string $current_route
230
	 * @return array
231
	 */
232
	protected function get_virtual_parent(array $routes_data, $current_route)
233
	{
234
		$routes = array_keys($routes_data);
235
236
		// We add the current route to the list and sort it in ascending order
237
		// Its parent will likely come before it in the list
238
		// Eg if current route is 'app.php/content/news' the route list might be:
239
		// ['app.php/content', 'app.php/content/category/cars', 'app.php/content/news', 'index.php']
240
		$routes[] = $current_route;
241
		sort($routes);
242
243
		// We find the position of the current route in the list
244
		$index = (int) array_search($current_route, $routes);
245
246
		// we use it as our starting point and walk backwords to find the immediate parent
247
		// in this case 'app.php/content'
248
		$parent_route = array();
249
		for ($i = $index - 1; $i >= 0; $i--)
250
		{
251
			if (strpos($current_route, $routes[$i]) !== false)
252
			{
253
				$parent_route = $routes_data[$routes[$i]];
254
				$this->is_sub_route = $parent_route['has_blocks'];
255
				break;
256
			}
257
		}
258
259
		return $parent_route;
260
	}
261
262
	/**
263
	 * @param array $routes
264
	 * @param string $route
265
	 * @return array
266
	 */
267
	protected function get_parent_route_info(array $routes, $route)
268
	{
269
		$route_info = array();
270
		if (isset($routes[$route]))
271
		{
272
			$this->is_sub_route = $routes[$route]['has_blocks'];
273
			$route_info = $routes[$route];
274
		}
275
276
		return $route_info;
277
	}
278
279
	/**
280
	 * We get blocks to display by route id, so we update the route id here,
281
	 * to show blocks from default route if current route or it's parent has no blocks
282
	 *
283
	 * @param array $routes
284
	 * @param array $route_info
285
	 * @return array
286
	 */
287
	protected function set_display_route_id(array $routes, array $route_info)
288
	{
289
		$default_route = $this->config['sitemaker_default_layout'];
290
		if (!$route_info['has_blocks'] && isset($routes[$default_route]))
291
		{
292
			$route_info['route_id'] = $routes[$default_route]['route_id'];
293
		}
294
295
		return $route_info;
296
	}
297
298
	/**
299
	 * @param array $condition
300
	 * @return array
301
	 */
302
	protected function get_all_blocks(array $condition)
303
	{
304
		$collection = $this->mapper_factory->create('blocks')->find($condition);
305
306
		$blocks = array();
307
		foreach ($collection as $entity)
308
		{
309
			if (($block_instance = $this->block_factory->get_block($entity->get_name())) !== null)
310
			{
311
				$default_settings = $block_instance->get_config(array());
312
				$settings = $this->sync_settings($default_settings, $entity->get_settings());
313
				$entity->set_settings($settings);
314
315
				$blocks[$entity->get_style()][$entity->get_route_id()][$entity->get_position()][] = $entity;
316
			}
317
		}
318
319
		return $blocks;
320
	}
321
322
	/**
323
	 * @return array|mixed
324
	 */
325
	protected function get_all_routes()
326
	{
327
		if (($all_routes = $this->cache->get('sitemaker_block_routes')) === false)
328
		{
329
			$route_mapper = $this->mapper_factory->create('routes');
330
			$collection = $route_mapper->find();
331
332
			$all_routes = array();
333
			foreach ($collection as $entity)
334
			{
335
				$route = $entity->get_route();
336
				$style = $entity->get_style();
337
				$all_routes[$style][$route] = $entity->to_array();
338
			}
339
340
			$this->cache->put('sitemaker_block_routes', $all_routes);
341
		}
342
343
		return $all_routes;
344
	}
345
346
	/**
347
	 * @param int $style_id
348
	 * @return array
349
	 */
350
	protected function get_routes_for_style($style_id)
351
	{
352
		$all_routes = $this->get_all_routes();
353
		return (isset($all_routes[$style_id])) ? $all_routes[$style_id] : array();
354
	}
355
356
	/**
357
	 * @param bool $edit_mode
358
	 * @return array
359
	 */
360
	protected function get_cached_blocks($edit_mode)
361
	{
362
		if (($blocks = $this->cache->get('sitemaker_blocks')) === false || $edit_mode)
363
		{
364
			$condition = (!$edit_mode) ? array('status', '=', 1) : array();
365
			$blocks = $this->get_all_blocks($condition);
366
			$this->cache_block($blocks, $edit_mode);
367
		}
368
369
		return $blocks;
370
	}
371
372
	/**
373
	 * @param array $blocks
374
	 * @param bool $edit_mode
375
	 */
376
	protected function cache_block(array $blocks, $edit_mode)
377
	{
378
		if ($edit_mode === false)
379
		{
380
			$this->cache->put('sitemaker_blocks', $blocks);
381
		}
382
	}
383
}
384