У меня есть связанный массив, полученный из get, и я хотел сгенерировать «предложение where» строки запроса sql, используя данные в массиве.
$get_array = ['title'=>'abc', 'author'=>'John']
Я создал массив шаблонов с разными строками для разных имен полей, а затем перебрал его через массив get, чтобы сгенерировать массив предложений:
$tpl = ['title' => 'title LIKE ?',
'author' => 'author LIKE ?',
];
$where_clause_array = [];
$binding_array = [];
foreach ($get_array as $field_name => $field_value){
foreach ($tpl as $table_field_title => $tpl_string) {
if ( $field_name == $table_field_title ) {
$where_clause_array[] = $tpl_string;
$binding_array[] = $field_value;
}
}
}
$clause_string = implode(' AND ', $where_clause_array);
В результате я получу строку типа «title LIKE? AND author LIKE?». Но проблема в том, что у меня есть строка предложения, которая принимает два значения вместо одного:
'year_start=>2000', 'year_end=>2017'
'year BETWEEN ? AND ?'
Я не мог понять, как поместить это в цикл.
Прежде чем мы перейдем к моему решению, я хочу отметить, что вам не нужны вложенные foreach
заявления. Вам нужно только один раз пройти по всем ключам в шаблоне, поэтому следующий код получит тот же результат, что и у вас:
foreach ($tpl as $table_field_title => $tpl_string) {
if (array_key_exists($table_field_title, $get_array)) {
$where_clause_array[] = $tpl_string;
$binding_array[] = $get_array[$table_field_title];
}
}
Основываясь на этом, мы просто должны позволить вам сделать вставку в $binding_array
несколько раз в каждой итерации, если у вас есть несколько значений для любого данного параметра.
Так что это сделает работу:
foreach ($tpl as $table_field_title => $tpl_string) {
if (array_key_exists($table_field_title, $get_array)) {
$where_clause_array[] = $tpl_string;
$field_value = $get_array[$table_field_title];
if (gettype($field_value) != 'array') $field_value = Array($field_value);
foreach ($field_value as $value) {
$binding_array[] = $value;
}
}
}
Вам просто нужно настроить свой шаблон:
$tpl = array('title' => 'title LIKE ?', 'author' => 'author LIKE ?', 'dates' => 'year BETWEEN ? AND ?');
и ваши входные данные:
$get_array = array('title' => 'abc', 'author' => 'John', 'dates' => array('2000', '2017'));
Конечный результат будет таким:
$clause_string = implode(' AND ', $where_clause_array);
echo $clause_string . '<br>';
var_dump($binding_array);
// title LIKE ? AND author LIKE ? AND year BETWEEN ? AND ?
// array(4) { [0]=> string(3) "abc" [1]=> string(4) "John" [2]=> string(4) "2000" [3]=> string(4) "2017" }
Вам не нужно использовать BETWEEN. Из-за того, как вы пытаетесь абстрагировать построение запроса, все еще используя ненормализованные имена полей для параметров GET, проще использовать год> =? пункт и еще один год <знак равно пункт отдельно.
Кроме того, если вы собираетесь абстрагировать построение запроса, вам не нужно определять шаблон для каждого поля, просто выберите оператор по умолчанию (например, LIKE) и рассмотрите все остальное как переопределение.
Вот пример кода, который я подготовил для вас, который позволит вам продолжать использовать параметры GET, которые вы используете, в то же время позволяя вам беспокоиться только об определении переопределений (то есть нестандартного поведения):
<?php
$get_array = [
'title' => 'abc',
'author' => 'John',
'year_start' => '2000'
'year_end' => '2017'
];
$overrides = [
'year_start' => ['column' => 'year', 'operator' => '>='],
'year_end' => ['column' => 'year', 'operator' => '<=']
];
$where_clause_array = [];
$binding_array = [];
foreach ($get_array as $field_name => $field_value){
if(isset($overrides[$field_name])){
$override = (object) $overrides[$field_name]; // Use an object as its syntax for accessing properties is shorter than array (e.g. $object->property vs $object['property'])
$column = $override->column ?: $field_name; // If override has a column name use it, otherwise ues the field name in the GET params
$where_clause_array[] = "{$column} {$override->operator} ?";
}
else{
$where_clause_array[] = "{$field_name} LIKE ?"; // We use LIKE as default operator, but we could use = instead and just LIKE in the overrides instead
}
$binding_array[] = $field_value;
}
$clause_string = implode(' AND ', $where_clause_array);
Надеюсь, поможет. Если это так, отметьте ответ на вопрос и дайте мне знать, если у вас есть дополнительные вопросы, я с радостью помогу.
Вы можете использовать функцию array_walk.
Пожалуйста, попробуйте приведенный ниже код, чтобы получить запрос при любых условиях (например, если year_start или year_end имеет значение null):
$test_array = ['title'=>'abc', 'author'=>'John', 'year_start'=>2000, 'year_end'=>2017];
$tpl = array();
array_walk($test_array, function(&$a, $b) use (&$tpl,&$test_array) {
if($b == 'year_start' || $b == 'year_end'){
if($b == 'year_start' && $a){
if($test_array['year_end'] != NULL){
$tpl['dates'] = 'year BETWEEN ? AND ?';
}else{
$tpl['dates'] = 'year > ?';
}
}
if($b == 'year_end' && $a && !isset($tpl['dates'])){
$tpl['dates'] = 'year < ?';
}
}else{
$tpl[$b] = "$b LIKE ?";
}
});
print_r($tpl);