Completed
Push — master ( fa65af...9eb297 )
by Nazar
04:25
created

CRUD_helpers::search_do()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 26
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 26
rs 8.5806
cc 4
eloc 21
nc 6
nop 10

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 CMS
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
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array[]|integer|integer[]|string|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.

Loading history...
31
	 */
32
	protected function search ($search_parameters = [], $page = 1, $count = 100, $order_by = 'id', $asc = false) {
33
		if (!isset($this->data_model[$order_by])) {
34
			return false;
35
		}
36
		$joins        = '';
37
		$join_params  = [];
38
		$join_index   = 0;
39
		$where        = [];
40
		$where_params = [];
41
		foreach ($search_parameters as $key => $details) {
42
			if (!isset($this->data_model[$key])) {
43
				continue;
44
			}
45
			if (isset($this->data_model[$key]['data_model'])) {
46
				$this->search_conditions_join_table('t', $key, $details, $joins, $join_params, $join_index);
47
			} else {
48
				$this->search_conditions('t', $key, $details, $where, $where_params);
49
			}
50
		}
51
		return $this->search_do('t', @$search_parameters['total_count'], $where, $where_params, $joins, $join_params, $page, $count, $order_by, $asc);
52
	}
53
	/**
54
	 * @param string   $table_alias
55
	 * @param bool     $total_count
56
	 * @param string[] $where
57
	 * @param array    $where_params
58
	 * @param string   $joins
59
	 * @param array    $join_params
60
	 * @param int      $page
61
	 * @param int      $count
62
	 * @param string   $order_by
63
	 * @param bool     $asc
64
	 *
65
	 * @return false|int|int[]|string[]
0 ignored issues
show
Documentation introduced by
Should the return type not be array[]|false|integer|integer[]|string|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.

Loading history...
66
	 */
67
	private function search_do ($table_alias, $total_count, $where, $where_params, $joins, $join_params, $page, $count, $order_by, $asc) {
68
		$first_column = array_keys($this->data_model)[0];
69
		$where        = $where ? 'WHERE '.implode(' AND ', $where) : '';
70
		if ($total_count) {
71
			return $this->db()->qfs(
72
				"SELECT COUNT(`$table_alias`.`$first_column`)
73
				FROM `$this->table` AS `$table_alias`
74
				$joins
75
				$where",
76
				array_merge($join_params, $where_params)
77
			);
78
		}
79
		$where_params[] = ($page - 1) * $count;
80
		$where_params[] = $count;
81
		$order_by       = $this->search_order_by($table_alias, $order_by, $joins, $join_index);
82
		$asc            = $asc ? 'ASC' : 'DESC';
83
		return $this->db()->qfas(
84
			"SELECT `$table_alias`.`$first_column`
85
			FROM `$this->table` AS `$table_alias`
86
			$joins
87
			$where
88
			ORDER BY $order_by $asc
89
			LIMIT %d, %d",
90
			array_merge($join_params, $where_params)
91
		);
92
	}
93
	/**
94
	 * @param string   $table_alias
95
	 * @param string   $key
96
	 * @param array    $details
97
	 * @param string[] $where
98
	 * @param array    $where_params
99
	 */
100
	private function search_conditions ($table_alias, $key, $details, &$where, &$where_params) {
101
		if (is_scalar($details)) {
102
			$where[]        = "`$table_alias`.`$key` = '%s'";
103
			$where_params[] = $details;
104
		} elseif (is_array($details) && $details) {
105
			if (is_array_indexed($details)) {
106
				$where_tmp = [];
107
				foreach ($details as $d) {
108
					$where_tmp[]    = "`$table_alias`.`$key` = '%s'";
109
					$where_params[] = $d;
110
				}
111
				$where[] = '('.implode(' OR ', $where_tmp).')';
112
				return;
113
			}
114
			if (isset($details['from'])) {
115
				$where[]        = "`$table_alias`.`$key` => '%s'";
116
				$where_params[] = $details['from'];
117
			}
118
			if (isset($details['to'])) {
119
				$where[]        = "`$table_alias`.`$key` <= '%s'";
120
				$where_params[] = $details['to'];
121
			}
122
		}
123
	}
124
	/**
125
	 * @param string           $table_alias
126
	 * @param string           $table
127
	 * @param array|int|string $details
128
	 * @param string           $joins
129
	 * @param array            $join_params
130
	 * @param int              $join_index
131
	 */
132
	private function search_conditions_join_table ($table_alias, $table, $details, &$joins, &$join_params, &$join_index) {
133
		$data_model        = $this->data_model[$table];
134
		$first_column      = array_keys($this->data_model)[0];
135
		$first_column_join = array_keys($data_model['data_model'])[0];
136
		if (is_scalar($details)) {
137
			$details = [
138
				array_keys($data_model['data_model'])[1] => $details
139
			];
140
		}
141
		/**
142
		 * @var array $details
143
		 */
144
		++$join_index;
145
		$joins .=
146
			"INNER JOIN `{$this->table}_$table` AS `j$join_index`
147
			ON
148
				`$table_alias`.`$first_column` = `j$join_index`.`$first_column_join`";
149
		$language_field = isset($data_model['language_field']) ? $data_model['language_field'] : false;
150
		foreach ($details as $field => $value) {
151
			if ($language_field === $field) {
152
				continue;
153
			}
154
			$where_tmp = [];
155
			$this->search_conditions("j$join_index", $field, $value, $where_tmp, $join_params);
156
			$joins .= " AND ".implode(" AND ", $where_tmp);
157
		}
158
		if ($language_field) {
159
			/** @noinspection OffsetOperationsInspection */
160
			$clang = isset($details[$language_field]) ? $details[$language_field] : Language::instance()->clang;
161
			$joins .=
162
				" AND
163
				(
164
					`j$join_index`.`lang`	= '$clang' OR
165
					`j$join_index`.`lang`	= ''
166
				)";
167
		}
168
	}
169
	/**
170
	 * @param string $table_alias
171
	 * @param string $order_by
172
	 * @param string $joins
173
	 * @param int    $join_index
174
	 *
175
	 * @return string
176
	 */
177
	private function search_order_by ($table_alias, $order_by, &$joins, &$join_index) {
178
		$order_by = explode(':', $order_by);
179
		if (!isset($this->data_model[$order_by[0]])) {
180
			/**
181
			 * Non-existing field
182
			 */
183
			$order_by = ['id'];
184
		} elseif (isset($order_by[1])) {
185
			/**
186
			 * Non-existing field in joined table
187
			 */
188
			if (!isset($this->data_model[$order_by[0]]['data_model'][$order_by[1]])) {
189
				$order_by = ['id'];
190
			}
191
		} elseif (isset($this->data_model[$order_by[0]]['data_model'])) {
192
			/**
193
			 * Default field in joined table
194
			 */
195
			$order_by[1] = array_keys($this->data_model[$order_by[0]]['data_model'])[1];
196
		}
197
		if (isset($order_by[1])) {
198
			++$join_index;
199
			$first_column      = array_keys($this->data_model)[0];
200
			$first_column_join = array_keys($this->data_model[$order_by[0]]['data_model'])[0];
201
			$joins .=
202
				"INNER JOIN `{$this->table}_$order_by[0]` AS `j$join_index`
203
				ON
204
					`$table_alias`.`$first_column`	= `j$join_index`.`$first_column_join`";
205
			$order_by = "`j$join_index`.`$order_by[1]`";
206
		} else {
207
			$order_by = "`$table_alias`.`$order_by[0]`";
208
		}
209
		return $order_by;
210
	}
211
}
212