Completed
Push — master ( 757263...aa4637 )
by Nazar
04:41
created

Sections   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 240
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 5
Bugs 2 Features 0
Metric Value
wmc 31
c 5
b 2
f 0
lcom 1
cbo 10
dl 0
loc 240
rs 9.8

11 Methods

Rating   Name   Duplication   Size   Complexity  
A construct() 0 3 1
A cdb() 0 3 1
A get_structure() 0 9 1
B get_structure_internal() 0 31 4
B get() 0 28 5
A get_all() 0 19 4
B get_by_path() 0 16 5
A add() 0 16 2
A set() 0 7 2
B del() 0 33 5
A ml_process() 0 3 1
1
<?php
2
/**
3
 * @package   Blogs
4
 * @category  modules
5
 * @author    Nazar Mokrynskyi <[email protected]>
6
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
7
 * @license   MIT License, see license.txt
8
 */
9
namespace cs\modules\Blogs;
10
use
11
	cs\Cache\Prefix as Cache_prefix,
12
	cs\Config,
13
	cs\Language,
14
	cs\Language\Prefix as Language_prefix,
15
	cs\Text,
16
	cs\User,
17
	cs\CRUD,
18
	cs\Singleton;
19
20
/**
21
 * @method static $this instance($check = false)
22
 */
23
class Sections {
24
	use
25
		CRUD,
26
		Singleton;
27
28
	protected $data_model          = [
29
		'id'     => 'int:0',
30
		'parent' => 'int:0',
31
		'title'  => 'ml:text',
32
		'path'   => 'ml:text'
33
	];
34
	protected $table               = '[prefix]blogs_sections';
35
	protected $data_model_ml_group = 'Blogs/sections';
36
	/**
37
	 * @var Cache_prefix
38
	 */
39
	protected $cache;
40
41
	protected function construct () {
42
		$this->cache = new Cache_prefix('Blogs');
43
	}
44
	/**
45
	 * Returns database index
46
	 *
47
	 * @return int
48
	 */
49
	protected function cdb () {
50
		return Config::instance()->module('Blogs')->db('posts');
51
	}
52
	/**
53
	 * Get array of sections structure
54
	 *
55
	 * @return array|false
56
	 */
57
	function get_structure () {
58
		$L = Language::instance();
59
		return $this->cache->get(
60
			"sections/structure/$L->clang",
61
			function () {
62
				return $this->get_structure_internal();
63
			}
64
		);
65
	}
66
	private function get_structure_internal ($parent = 0) {
67
		$structure = [
68
			'id'    => $parent,
69
			'posts' => 0
70
		];
71
		if ($parent != 0) {
72
			$structure = array_merge(
73
				$structure,
74
				$this->get($parent)
75
			);
76
		} else {
77
			$L                  = new Language_prefix('blogs_');
78
			$structure['title'] = $L->root_section;
79
			$structure['posts'] = Posts::instance()->get_for_section_count($structure['id']);
80
		}
81
		$sections              = $this->db()->qfa(
82
			[
83
				"SELECT
84
					`id`,
85
					`path`
86
				FROM `[prefix]blogs_sections`
87
				WHERE `parent` = '%s'",
88
				$parent
89
			]
90
		) ?: [];
91
		$structure['sections'] = [];
92
		foreach ($sections as $section) {
93
			$structure['sections'][$this->ml_process($section['path'])] = $this->get_structure_internal($section['id']);
94
		}
95
		return $structure;
96
	}
97
	/**
98
	 * Get data of specified section
99
	 *
100
	 * @param int|int[] $id
101
	 *
102
	 * @return array|false
103
	 */
104
	function get ($id) {
105
		if (is_array($id)) {
106
			foreach ($id as &$i) {
107
				$i = $this->get($i);
108
			}
109
			return $id;
110
		}
111
		$L  = Language::instance();
112
		$id = (int)$id;
113
		return $this->cache->get(
114
			"sections/$id/$L->clang",
115
			function () use ($id) {
116
				$data = $this->read($id);
117
				if ($data) {
118
					$data['posts']     = Posts::instance()->get_for_section_count($id);
119
					$data['full_path'] = [$data['path']];
120
					$parent            = $data['parent'];
121
					while ($parent != 0) {
122
						$section             = $this->get($parent);
123
						$data['full_path'][] = $section['path'];
124
						$parent              = $section['parent'];
125
					}
126
					$data['full_path'] = implode('/', array_reverse($data['full_path']));
127
				}
128
				return $data;
129
			}
130
		);
131
	}
132
	/**
133
	 * @return array[]
134
	 */
135
	function get_all () {
136
		$L = Language::instance();
137
		return $this->cache->get(
138
			"sections/all/$L->clang",
139
			function () {
140
				$sections = $this->db()->qfa(
141
					"SELECT *
142
					FROM `[prefix]blogs_sections`"
143
				) ?: [];
144
				foreach ($sections as &$section) {
0 ignored issues
show
Bug introduced by
The expression $sections of type integer|string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
145
					$section['id']     = (int)$section['id'];
146
					$section['parent'] = (int)$section['parent'];
147
					$section['title']  = $this->ml_process($section['title']);
148
					$section['path']   = $this->ml_process($section['path']);
149
				}
150
				return $sections;
151
			}
152
		) ?: [];
153
	}
154
	/**
155
	 * Get sections ids for each section in full path
156
	 *
157
	 * @param string|string[] $path
158
	 *
159
	 * @return false|int[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array|false? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
160
	 */
161
	function get_by_path ($path) {
162
		if (!is_array($path)) {
163
			$path = explode('/', $path);
164
		}
165
		$structure = $this->get_structure();
166
		$ids       = [];
167
		foreach ($path as $p) {
168
			if (!isset($structure['sections'][$p])) {
169
				break;
170
			}
171
			array_shift($path);
172
			$structure = $structure['sections'][$p];
173
			$ids[]     = $structure['id'];
174
		}
175
		return $ids ?: false;
176
	}
177
	/**
178
	 * Add new section
179
	 *
180
	 * @param int    $parent
181
	 * @param string $title
182
	 * @param string $path
183
	 *
184
	 * @return false|int Id of created section on success of <b>false</> on failure
185
	 */
186
	function add ($parent, $title, $path) {
187
		$id = $this->create([$parent, $title, $path]);
188
		if ($id) {
189
			$this->db_prime()->q(
190
				"UPDATE `[prefix]blogs_posts_sections`
191
				SET `section` = $id
192
				WHERE `section` = '%d'",
193
				$parent
194
			);
195
			unset(
196
				$this->cache->posts,
197
				$this->cache->sections
198
			);
199
		}
200
		return $id;
201
	}
202
	/**
203
	 * Set data of specified section
204
	 *
205
	 * @param int    $id
206
	 * @param int    $parent
207
	 * @param string $title
208
	 * @param string $path
209
	 *
210
	 * @return bool
211
	 */
212
	function set ($id, $parent, $title, $path) {
213
		$result = $this->update([$id, $parent, $title, $path]);
214
		if ($result) {
215
			unset($this->cache->sections);
216
		}
217
		return $result;
218
	}
219
	/**
220
	 * Delete specified section
221
	 *
222
	 * @param int $id
223
	 *
224
	 * @return bool
225
	 */
226
	function del ($id) {
227
		$id      = (int)$id;
228
		$section = $this->read($id);
229
		if (!$section || !$this->delete($id)) {
230
			return false;
231
		}
232
		$new_posts_section = $this->db_prime()->qfs(
233
			[
234
				"SELECT `id`
235
				FROM `$this->table`
236
				WHERE `parent` = '%s'
237
				LIMIT 1",
238
				$section['parent']
239
			]
240
		) ?: $section['parent'];
241
		$update            = $this->db_prime()->q(
242
			[
243
				"UPDATE `[prefix]blogs_sections`
244
				SET `parent` = '%2\$d'
245
				WHERE `parent` = '%1\$d'",
246
				"UPDATE IGNORE `[prefix]blogs_posts_sections`
247
				SET `section` = '%3\$d'
248
				WHERE `section` = '%1\$d'"
249
			],
250
			$id,
251
			$section['parent'],
252
			$new_posts_section
253
		);
254
		if ($update) {
255
			$this->cache->del('/');
256
		}
257
		return $update;
258
	}
259
	private function ml_process ($text) {
260
		return Text::instance()->process($this->cdb(), $text, true);
261
	}
262
}
263