实现 PHP 搜索过滤器表单的设计模式
Design pattern for implementing PHP search filter form
我正在用 PHP 编写的网站的搜索功能中实施过滤器。
我的目标是让这个易于管理,因为该项目的规模在接下来的时间里会增长很多。现在搜索页面有一些输入字段,php 通过检查表单按钮的名称是否在 $_POST 数组中来检查表单是否已提交。位于这个搜索页面的右侧,有一个实际搜索结果的列表,一个 foreach 循环的输出是打印到屏幕上的项目列表。为了更清楚地说明,我写了一些代码来解释它的作用,并展示了我自己想出的东西:
<?php
$arrayToDisplay = array(
array("id"=>0,"name"=>"first","lastname"=>"last"),
array("id"=>1,"name"=>"first","lastname"=>"last"),
);
$acceptedName = "";
if(isset($_POST['buttonName'])) {
if(isset($_POST['name'])) {
$acceptedName = sanitize($_POST['name']);
}
}
?>
<form>
<input type="text" name="name">
<input type="submit" name="buttonName">
</form>
<?php
foreach($arrayToDisplay as $person) {
if(exists($acceptedName) && $acceptedName != "") {
if($person["name" == $acceptedname) {
echo $person["id"]." ".$person["name"];
}
}
else {
echo $person["id"]." ".$person["name"];
}
}
?>
这可以对一个值起作用,按名称过滤。但最终这些人对象将有近 50 个属性,搜索过滤器不仅要能够按名称过滤列表,还要过滤各种人的属性。这个解决方案是不可维护的。
是否存在可以在这种情况下使用的现有设计模式?
这个问题有很多方法,有些人认为您 can/should 键入每个表单元素及其相应的处理程序,因为如果您想使用文本框,维护起来会更容易,select 列表、单选按钮等。也就是说,您只是提到使用文本框,所以这里有一种方法可以使用单个数组来驱动整个应用程序。
- 您没有提到您是否打算使用 SQL 来推动您的搜索,所以我假设您会使用它。
- 您可以使用单个数组来驱动您的 HTML 表单和将由传入值生成的查询。
<?php
// This array will drive your form and your query.
$columns = [
'firstname',
'lastname',
'email',
'address_1',
'address_2',
'city'
];
// The form was submitted.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Match posted data to the `$columns` array and filter out any empty values.
$postedData = array_filter(array_intersect_key($_POST, array_flip($columns)));
// We have at least 1 search criteria to use.
if (!empty($postedData)) {
// Generate a list of columns for a WHERE clause. Ex. [`address_1 LIKE ?`, `name LIKE ?`]
$terms = array_map(function ($val) {
return "$val LIKE ? ";
}, array_keys($postedData));
// Generate a list of values wrapped in percent signs. Ex. [`123 King St.`, `%tony%`]
$values = array_map(function ($val) {
return "%$val%";
}, $postedData);
// Change this to `AND ` if needed.
$query = 'SELECT * FROM table WHERE ' . implode('OR ', $terms);
// Just showing you what the generated query and data looks like.
var_dump([
$query,
array_values($values)
]);
// Finally, use them to drive your query.
// $sql = $connection->prepare($query);
// $sql->execute(array_values($values));
}
}
?>
<form method="post">
<?php foreach ($columns as $column): ?>
<label>
<input type="text" name="<?php echo $column; ?>" placeholder="<?php echo $column; ?>">
</label>
<br>
<?php endforeach; ?>
<input type="submit" value="Search">
</form>
示例输出
array (size=2)
0 => string 'SELECT * FROM table WHERE firstname LIKE ? OR email LIKE ? ' (length=59)
1 =>
array (size=2)
0 => string '%Tony%' (length=6)
1 => string '%tony@email.com%' (length=16)
我正在用 PHP 编写的网站的搜索功能中实施过滤器。
我的目标是让这个易于管理,因为该项目的规模在接下来的时间里会增长很多。现在搜索页面有一些输入字段,php 通过检查表单按钮的名称是否在 $_POST 数组中来检查表单是否已提交。位于这个搜索页面的右侧,有一个实际搜索结果的列表,一个 foreach 循环的输出是打印到屏幕上的项目列表。为了更清楚地说明,我写了一些代码来解释它的作用,并展示了我自己想出的东西:
<?php
$arrayToDisplay = array(
array("id"=>0,"name"=>"first","lastname"=>"last"),
array("id"=>1,"name"=>"first","lastname"=>"last"),
);
$acceptedName = "";
if(isset($_POST['buttonName'])) {
if(isset($_POST['name'])) {
$acceptedName = sanitize($_POST['name']);
}
}
?>
<form>
<input type="text" name="name">
<input type="submit" name="buttonName">
</form>
<?php
foreach($arrayToDisplay as $person) {
if(exists($acceptedName) && $acceptedName != "") {
if($person["name" == $acceptedname) {
echo $person["id"]." ".$person["name"];
}
}
else {
echo $person["id"]." ".$person["name"];
}
}
?>
这可以对一个值起作用,按名称过滤。但最终这些人对象将有近 50 个属性,搜索过滤器不仅要能够按名称过滤列表,还要过滤各种人的属性。这个解决方案是不可维护的。
是否存在可以在这种情况下使用的现有设计模式?
这个问题有很多方法,有些人认为您 can/should 键入每个表单元素及其相应的处理程序,因为如果您想使用文本框,维护起来会更容易,select 列表、单选按钮等。也就是说,您只是提到使用文本框,所以这里有一种方法可以使用单个数组来驱动整个应用程序。
- 您没有提到您是否打算使用 SQL 来推动您的搜索,所以我假设您会使用它。
- 您可以使用单个数组来驱动您的 HTML 表单和将由传入值生成的查询。
<?php
// This array will drive your form and your query.
$columns = [
'firstname',
'lastname',
'email',
'address_1',
'address_2',
'city'
];
// The form was submitted.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Match posted data to the `$columns` array and filter out any empty values.
$postedData = array_filter(array_intersect_key($_POST, array_flip($columns)));
// We have at least 1 search criteria to use.
if (!empty($postedData)) {
// Generate a list of columns for a WHERE clause. Ex. [`address_1 LIKE ?`, `name LIKE ?`]
$terms = array_map(function ($val) {
return "$val LIKE ? ";
}, array_keys($postedData));
// Generate a list of values wrapped in percent signs. Ex. [`123 King St.`, `%tony%`]
$values = array_map(function ($val) {
return "%$val%";
}, $postedData);
// Change this to `AND ` if needed.
$query = 'SELECT * FROM table WHERE ' . implode('OR ', $terms);
// Just showing you what the generated query and data looks like.
var_dump([
$query,
array_values($values)
]);
// Finally, use them to drive your query.
// $sql = $connection->prepare($query);
// $sql->execute(array_values($values));
}
}
?>
<form method="post">
<?php foreach ($columns as $column): ?>
<label>
<input type="text" name="<?php echo $column; ?>" placeholder="<?php echo $column; ?>">
</label>
<br>
<?php endforeach; ?>
<input type="submit" value="Search">
</form>
示例输出
array (size=2)
0 => string 'SELECT * FROM table WHERE firstname LIKE ? OR email LIKE ? ' (length=59)
1 =>
array (size=2)
0 => string '%Tony%' (length=6)
1 => string '%tony@email.com%' (length=16)