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

CRUD_helpers::search_process_parameter()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
c 0
b 0
f 0
nc 5
nop 8
dl 0
loc 15
ccs 10
cts 10
cp 1
crap 4
rs 9.2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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