Completed
Push — master ( 139714...cfaeec )
by Nazar
08:05
created

CRUD_helpers   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 94.74%

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 198
ccs 90
cts 95
cp 0.9474
rs 10
wmc 30
lcom 1
cbo 3

5 Methods

Rating   Name   Duplication   Size   Complexity  
A search() 0 18 4
B search_do() 0 29 4
C search_conditions() 0 24 8
C search_conditions_join_table() 0 37 7
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
1 ignored issue
show
Documentation introduced by
Should the return type not be integer|array|false|double|string? 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...
31
	 */
32 10
	protected function search ($search_parameters = [], $page = 1, $count = 100, $order_by = 'id', $asc = false) {
33 10
		$joins        = '';
34 10
		$join_params  = [];
35 10
		$join_index   = 0;
36 10
		$where        = [];
37 10
		$where_params = [];
38 10
		foreach ($search_parameters as $key => $details) {
39 6
			if (!isset($this->data_model[$key])) {
40 2
				continue;
41
			}
42 6
			if (isset($this->data_model[$key]['data_model'])) {
43 2
				$this->search_conditions_join_table('t', $key, $details, $joins, $join_params, $join_index);
44
			} else {
45 6
				$this->search_conditions('t', $key, $details, $where, $where_params);
46
			}
47
		}
48 10
		return $this->search_do('t', @$search_parameters['total_count'], $where, $where_params, $joins, $join_params, $page, $count, $order_by, $asc);
49
	}
50
	/**
51
	 * @param string   $table_alias
52
	 * @param bool     $total_count
53
	 * @param string[] $where
54
	 * @param array    $where_params
55
	 * @param string   $joins
56
	 * @param array    $join_params
57
	 * @param int      $page
58
	 * @param int      $count
59
	 * @param string   $order_by
60
	 * @param bool     $asc
61
	 *
62
	 * @return false|int|int[]|string[]
63
	 */
64 10
	private function search_do ($table_alias, $total_count, $where, $where_params, $joins, $join_params, $page, $count, $order_by, $asc) {
65 10
		$first_column = array_keys($this->data_model)[0];
66 10
		$where        = $where ? 'WHERE '.implode(' AND ', $where) : '';
67 10
		if ($total_count) {
68 2
			return (int)$this->db()->qfs(
69 2
				"SELECT COUNT(`$table_alias`.`$first_column`)
70 2
				FROM `$this->table` AS `$table_alias`
71 2
				$joins
72 2
				$where
73 2
				GROUP BY `$table_alias`.`$first_column`",
74
				array_merge($join_params, $where_params)
75
			);
76
		}
77 10
		$where_params[] = $count;
78 10
		$where_params[] = ($page - 1) * $count;
79 10
		$order_by       = $this->search_order_by($table_alias, $order_by, $joins, $join_index);
80 10
		$asc            = $asc ? 'ASC' : 'DESC';
81 10
		$return         = $this->db()->qfas(
82 10
			"SELECT `$table_alias`.`$first_column`
83 10
			FROM `$this->table` AS `$table_alias`
84 10
			$joins
85 10
			$where
86 10
			GROUP BY `$table_alias`.`$first_column`
87 10
			ORDER BY $order_by $asc
88 10
			LIMIT %d OFFSET %d",
89
			array_merge($join_params, $where_params)
90
		);
91 10
		return $this->read_field_post_processing($return, array_values($this->data_model)[0]);
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 6
	private function search_conditions ($table_alias, $key, $details, &$where, &$where_params) {
101 6
		if (is_scalar($details)) {
102 6
			$where[]        = "`$table_alias`.`$key` = '%s'";
103 6
			$where_params[] = $details;
104 4
		} elseif (is_array($details) && $details) {
105 2
			if (is_array_indexed($details)) {
106 2
				$where_tmp = [];
107 2
				foreach ($details as $d) {
108 2
					$where_tmp[]    = "`$table_alias`.`$key` = '%s'";
109 2
					$where_params[] = $d;
110
				}
111 2
				$where[] = '('.implode(' OR ', $where_tmp).')';
112 2
				return;
113
			}
114 2
			if (isset($details['from'])) {
115 2
				$where[]        = "`$table_alias`.`$key` >= '%s'";
116 2
				$where_params[] = $details['from'];
117
			}
118 2
			if (isset($details['to'])) {
119 2
				$where[]        = "`$table_alias`.`$key` <= '%s'";
120 2
				$where_params[] = $details['to'];
121
			}
122
		}
123 6
	}
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 2
	private function search_conditions_join_table ($table_alias, $table, $details, &$joins, &$join_params, &$join_index) {
133 2
		$data_model        = $this->data_model[$table];
134 2
		$first_column      = array_keys($this->data_model)[0];
135 2
		$first_column_join = array_keys($data_model['data_model'])[0];
136 2
		if (is_scalar($details)) {
137
			$details = [
138 2
				array_keys($data_model['data_model'])[1] => $details
139
			];
140
		}
141
		/**
142
		 * @var array $details
143
		 */
144 2
		++$join_index;
145
		$joins .=
146 2
			"INNER JOIN `{$this->table}_$table` AS `j$join_index`
147
			ON
148 2
				`$table_alias`.`$first_column` = `j$join_index`.`$first_column_join`";
149 2
		$language_field = isset($data_model['language_field']) ? $data_model['language_field'] : false;
150 2
		foreach ($details as $field => $value) {
151 2
			if ($language_field === $field) {
152
				continue;
153
			}
154 2
			$where_tmp = [];
155 2
			$this->search_conditions("j$join_index", $field, $value, $where_tmp, $join_params);
156 2
			$joins .= ' AND '.implode(' AND ', $where_tmp);
157
		}
158 2
		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 2
	}
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 10
	private function search_order_by ($table_alias, $order_by, &$joins, &$join_index) {
178 10
		$order_by = explode(':', $order_by);
179 10
		if (!isset($this->data_model[$order_by[0]])) {
180
			/**
181
			 * Non-existing field
182
			 */
183 2
			$order_by = ['id'];
184 10
		} elseif (isset($order_by[1])) {
185
			/**
186
			 * Non-existing field in joined table
187
			 */
188 2
			if (!isset($this->data_model[$order_by[0]]['data_model'][$order_by[1]])) {
189 2
				$order_by = ['id'];
190
			}
191 10
		} elseif (is_array($this->data_model[$order_by[0]]) && isset($this->data_model[$order_by[0]]['data_model'])) {
192
			/**
193
			 * Default field in joined table
194
			 */
195 2
			$order_by[1] = array_keys($this->data_model[$order_by[0]]['data_model'])[1];
196
		}
197 10
		if (isset($order_by[1])) {
198 2
			++$join_index;
199 2
			$first_column      = array_keys($this->data_model)[0];
200 2
			$first_column_join = array_keys($this->data_model[$order_by[0]]['data_model'])[0];
201
			$joins .=
202 2
				"INNER JOIN `{$this->table}_$order_by[0]` AS `j$join_index`
203
				ON
204 2
					`$table_alias`.`$first_column`	= `j$join_index`.`$first_column_join`";
205 2
			$order_by = "`j$join_index`.`$order_by[1]`";
206
		} else {
207 10
			$order_by = "`$table_alias`.`$order_by[0]`";
208
		}
209 10
		return $order_by;
210
	}
211
}
212