Completed
Push — master ( e3feec...095dae )
by Nazar
04:08
created

CRUD_helpers   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 240
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 99.12%

Importance

Changes 3
Bugs 2 Features 2
Metric Value
c 3
b 2
f 2
dl 0
loc 240
ccs 112
cts 113
cp 0.9912
rs 8.8
wmc 36
lcom 1
cbo 3

7 Methods

Rating   Name   Duplication   Size   Complexity  
A search() 0 13 3
A search_process_parameter() 0 15 4
B search_do() 0 31 4
C search_conditions() 0 27 8
A search_conditions_multilingual() 0 11 2
C search_conditions_join_table() 0 36 8
C search_order_by() 0 34 7
1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2015-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs;
9
/**
10
 * CRUD trait extended with useful additional methods, for example, for searching
11
 *
12
 * Might me used instead of regular CRUD trait
13
 */
14
trait CRUD_helpers {
15
	use
16
		CRUD;
17
	/**
18
	 * Generic search
19
	 *
20
	 * @param mixed[] $search_parameters Array in form [attribute => value];<br>
21
	 *                                   Or [attribute => [value1, value2, value3]];<br>
22
	 *                                   Or [attribute => [from => a, to => b]];<br>
23
	 *                                   Or [attribute => [...]] in case of joined tables, where ... is any of three constructions mentioned above;<br>
24
	 *                                   if `total_count => true` element is present - total number of found rows will be returned instead of rows themselves
25
	 * @param int     $page
26
	 * @param int     $count
27
	 * @param string  $order_by
28
	 * @param bool    $asc
29
	 *
30
	 * @return false|int|int[]|string[] Array of `id` or number of elements
31
	 */
32 12
	protected function search ($search_parameters = [], $page = 1, $count = 100, $order_by = 'id', $asc = false) {
33 12
		$joins       = '';
34 12
		$join_params = [];
35 12
		$join_index  = 0;
36 12
		$where       = [];
37 12
		$params      = [];
38 12
		foreach ($search_parameters as $key => $details) {
39 8
			if (isset($this->data_model[$key])) {
40 8
				$this->search_process_parameter($this->data_model[$key], $key, $details, $where, $params, $joins, $join_params, $join_index);
41
			}
42
		}
43 12
		return $this->search_do('t', @$search_parameters['total_count'], $where, $params, $joins, $join_params, $page, $count, $order_by, $asc);
44
	}
45
	/**
46
	 * @param          $data_model
47
	 * @param          $key
48
	 * @param          $details
49
	 * @param string[] $where
50
	 * @param array    $params
51
	 * @param string   $joins
52
	 * @param array    $join_params
53
	 * @param int      $join_index
54
	 */
55 8
	private function search_process_parameter ($data_model, $key, $details, &$where, &$params, &$joins, &$join_params, &$join_index) {
56 8
		if (isset($data_model['data_model'])) {
57 4
			$this->search_conditions_join_table('t', $key, $details, $joins, $join_params, $join_index);
58
		} else {
59 8
			if (strpos($data_model, 'ml:') === 0) {
60 2
				list($where_local, $params_local) = $this->search_conditions_multilingual('t', $key, $details);
61
			} else {
62 6
				list($where_local, $params_local) = $this->search_conditions('t', $key, $details);
63
			}
64 8
			if ($where_local) {
65 8
				$where[] = $where_local;
66 8
				array_push($params, ...$params_local);
67
			}
68
		}
69 8
	}
70
	/**
71
	 * @param string   $table_alias
72
	 * @param bool     $total_count
73
	 * @param string[] $where
74
	 * @param array    $params
75
	 * @param string   $joins
76
	 * @param array    $join_params
77
	 * @param int      $page
78
	 * @param int      $count
79
	 * @param string   $order_by
80
	 * @param bool     $asc
81
	 *
82
	 * @return false|int|int[]|string[]
83
	 */
84 12
	private function search_do ($table_alias, $total_count, $where, $params, $joins, $join_params, $page, $count, $order_by, $asc) {
85 12
		$first_column = array_keys($this->data_model)[0];
86 12
		$where        = $where ? 'WHERE '.implode(' AND ', $where) : '';
87 12
		if ($total_count) {
88 2
			return (int)$this->db()->qfs(
89
				"SELECT COUNT(*) FROM (
90 2
					SELECT `$table_alias`.`$first_column`
91 2
					FROM `$this->table` AS `$table_alias`
92 2
					$joins
93 2
					$where
94 2
					GROUP BY `$table_alias`.`$first_column`
95 2
				) AS `count`",
96
				array_merge($join_params, $params)
97
			);
98
		}
99 12
		$params[] = $count;
100 12
		$params[] = ($page - 1) * $count;
101 12
		$order_by = $this->search_order_by($table_alias, $order_by, $joins, $join_index);
102 12
		$asc      = $asc ? 'ASC' : 'DESC';
103 12
		$return   = $this->db()->qfas(
104 12
			"SELECT `$table_alias`.`$first_column`
105 12
			FROM `$this->table` AS `$table_alias`
106 12
			$joins
107 12
			$where
108 12
			GROUP BY `$table_alias`.`$first_column`, $order_by
109 12
			ORDER BY $order_by $asc
110 12
			LIMIT ? OFFSET ?",
111
			array_merge($join_params, $params)
112
		);
113 12
		return $this->read_field_post_processing($return, array_values($this->data_model)[0]);
114
	}
115
	/**
116
	 * @param string $table_alias
117
	 * @param string $key
118
	 * @param array  $details
119
	 *
120
	 * @return array First element is string `where` clause, second is an array of parameters
1 ignored issue
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<array|string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
121
	 */
122 8
	private function search_conditions ($table_alias, $key, $details) {
123 8
		if (is_scalar($details)) {
124 8
			return ["`$table_alias`.`$key` = ?", [$details]];
125
		}
126 6
		if (is_array($details) && $details) {
127 4
			$where  = [];
128 4
			$params = [];
129 4
			if (is_array_indexed($details)) {
130 4
				foreach ($details as $d) {
131 4
					$where[]  = "`$table_alias`.`$key` = ?";
132 4
					$params[] = $d;
133
				}
134 4
				$where = implode(' OR ', $where);
135 4
				return ["($where)", $params];
136
			}
137 4
			if (isset($details['from'])) {
138 4
				$where[]  = "`$table_alias`.`$key` >= ?";
139 4
				$params[] = $details['from'];
140
			}
141 4
			if (isset($details['to'])) {
142 4
				$where[]  = "`$table_alias`.`$key` <= ?";
143 4
				$params[] = $details['to'];
144
			}
145 4
			return [implode(' AND ', $where), $params];
146
		}
147 2
		return ['', []];
148
	}
149
	/**
150
	 * @param string $table_alias
151
	 * @param string $key
152
	 * @param array  $details
153
	 *
154
	 * @return array First element is string `where` clause, second is an array of parameters
1 ignored issue
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<array|string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
155
	 */
156 2
	private function search_conditions_multilingual ($table_alias, $key, $details) {
157 2
		list($where1, $params1) = $this->search_conditions($table_alias, $key, $details);
158 2
		if ($where1) {
159 2
			list($where2, $params2) = $this->search_conditions('td', 'text', $details);
160
			return [
161 2
				"($where1 OR `$table_alias`.`$key` IN (SELECT `td`.`id_` FROM `xyz_texts_data` AS `td` WHERE $where2))",
162 2
				array_merge($params1, $params2)
163
			];
164
		}
165
		return ['', []];
166
	}
167
	/**
168
	 * @param string           $table_alias
169
	 * @param string           $key
170
	 * @param array|int|string $details
171
	 * @param string           $joins
172
	 * @param array            $join_params
173
	 * @param int              $join_index
174
	 */
175 4
	private function search_conditions_join_table ($table_alias, $key, $details, &$joins, &$join_params, &$join_index) {
176 4
		$data_model        = $this->data_model[$key];
177 4
		$first_column      = array_keys($this->data_model)[0];
178 4
		$first_column_join = array_keys($data_model['data_model'])[0];
179 4
		if (is_scalar($details)) {
180
			$details = [
181 4
				array_keys($data_model['data_model'])[1] => $details
182
			];
183
		}
184 4
		++$join_index;
185
		$joins .=
186 4
			"INNER JOIN `{$this->table}_$key` AS `j$join_index`
187
			ON
188 4
				`$table_alias`.`$first_column` = `j$join_index`.`$first_column_join`";
189 4
		$language_field = isset($data_model['language_field']) ? $data_model['language_field'] : false;
190 4
		foreach ($details as $field => $value) {
191 4
			if ($language_field === $field) {
192 2
				continue;
193
			}
194 4
			list($where, $params) = $this->search_conditions("j$join_index", $field, $value);
195 4
			if ($where) {
196 4
				$joins .= " AND $where";
197 4
				array_push($join_params, ...$params);
198
			}
199
		}
200 4
		if ($language_field) {
201 2
			$clang = isset($details[$language_field]) ? $details[$language_field] : Language::instance()->clang;
202
			$joins .=
203
				" AND
204
				(
205 2
					`j$join_index`.`lang`	= '$clang' OR
206 2
					`j$join_index`.`lang`	= ''
207 2
				)";
208
		}
209 4
		$joins .= "\n";
210 4
	}
211
	/**
212
	 * @param string $table_alias
213
	 * @param string $order_by
214
	 * @param string $joins
215
	 * @param int    $join_index
216
	 *
217
	 * @return string
218
	 */
219 12
	private function search_order_by ($table_alias, $order_by, &$joins, &$join_index) {
220 12
		$order_by = explode(':', $order_by);
221 12
		if (!isset($this->data_model[$order_by[0]])) {
222
			/**
223
			 * Non-existing field
224
			 */
225 2
			$order_by = ['id'];
226 12
		} elseif (isset($order_by[1])) {
227
			/**
228
			 * Non-existing field in joined table
229
			 */
230 2
			if (!isset($this->data_model[$order_by[0]]['data_model'][$order_by[1]])) {
231 2
				$order_by = ['id'];
232
			}
233 12
		} elseif (is_array($this->data_model[$order_by[0]]) && isset($this->data_model[$order_by[0]]['data_model'])) {
234
			/**
235
			 * Default field in joined table
236
			 */
237 2
			$order_by[1] = array_keys($this->data_model[$order_by[0]]['data_model'])[1];
238
		}
239 12
		if (isset($order_by[1])) {
240 2
			++$join_index;
241 2
			$first_column      = array_keys($this->data_model)[0];
242 2
			$first_column_join = array_keys($this->data_model[$order_by[0]]['data_model'])[0];
243
			$joins .=
244 2
				"INNER JOIN `{$this->table}_$order_by[0]` AS `j$join_index`
245
				ON
246 2
					`$table_alias`.`$first_column`	= `j$join_index`.`$first_column_join`";
247 2
			$order_by = "`j$join_index`.`$order_by[1]`";
248
		} else {
249 12
			$order_by = "`$table_alias`.`$order_by[0]`";
250
		}
251 12
		return $order_by;
252
	}
253
}
254