PHP和Mysql使用复选框表单更新多对多关系

8

我有一个多对多的表结构和更新复选框表单。

目标是通过用户项目表(users_project table)将用户表(users table)与项目表(projects table)相关联。这样,每个项目可以有多个用户,每个用户也可以参与多个项目。

在每个用户编辑页面上,表单应该是这样的:

<form action="#" method="post">
    <div>   
        <input type="checkbox" name="project_id[]" id="1" value="1">
        <label for="1">project 1</label>
        <br>

        <input type="checkbox" name="project_id[]" id="2" value="2">
        <label for="2">project 2</label>
        <br>
        <input type="hidden" name="editing">
        <input type="submit" id="submit" value="submit">
    </div>
</form>

以下是三个表的示例。

用户表

+----+-----------+
| id ¦ username  ¦
+----+-----------+
| 1  ¦ user 1    ¦
| 2  ¦ user 2    ¦
+----+-----------+

项目表
+----+-----------+  
¦ id ¦ title     ¦
+----+-----------+  
| 1  ¦ project 1 ¦
| 2  ¦ project 2 ¦
+----+-----------+    

用户项目表

该表基于其ID将上述两个表相关联

+----+-------------+---------+
| id ¦ project_id  ¦ user_id |
+----+-------------+---------+
| 1  ¦           1 ¦       2 |
| 2  ¦           2 ¦       1 |
+----+-------------+---------+

我已经创建了一个复选框表单来添加和编辑这些值。在每个用户页面上,它显示项目表中的所有项目。然后查询user_projects表格并查找匹配列表以向复选框添加勾选。
但是,如何将这些值编辑到数据库中呢?如果用户取消选中先前选中的框或选中空框,我将如何知道并更新到数据库,而不必为用户表中的project_id和user_id循环查询匹配项?
这是我想要最终实现的大致概念。
if ($_POST['editing']) { 
    $totalprojects = $_POST['editing']; 
    $query = " 
        SELECT *  
        FROM user_projects  
        WHERE user_id = user_id 
        AND project_id = project_id 
    "; 
    $result = $mysqli->query($query); 
    $count = $mysqli->affected_rows; 
    for($i=0; $i < $totalprojects; $i++) {  
        if ($count == 1) { 
            if ($box == checked){  
                //do nothing 
            } 
            else { 
                //delete from database 
            } 
        } 
        if ($count == 0) { 
            if ($box == checked){  
                //add to database 
            } 
            else { 
                //do nothing 
            } 
        } 
    } 
} 

这似乎根本不是一个好主意,因为我至少需要查询项目表中每个项目一次数据库。对于我想象中的常见问题,必须有更好的解决方案。我知道我的思路是错误的。

注意:我考虑过只需将数组序列化并将其放入用户列中,但这是不可接受的,因为我将无法将项目与用户相关联,仅将用户与项目相关联,这将失去目的。

我希望能够在没有任何JavaScript技巧的情况下实现此功能。

4个回答

2

由于您的项目数量足够少,可以在一个表格中显示,因此我完全赞成在提交时重写user_projects表的相关部分:

BEGIN TRANSACTION;
DELETE FROM user_projects WHERE user_id = $uid;
INSERT INTO user_projects (project_id, user_id)
    VALUES ($proj1, $uid), ($proj2, $uid), ...;
COMMIT TRANSACTION;

请注意使用扩展的INSERT语法在一条语句中写入关联。如果不需要,也可以删除user_projects.id,从而节省表中三分之一的空间。

1
这是我解决此问题的方法:

  1. 首先,我使用 active 列来检查一个项目是否被删除(0)还是没有被删除(1),因为这比使用 DELETE SQL 语句更安全。

  2. 接下来,你需要将 user_id 和 project_id 列定义为 UNIQUE。

    ALTER TABLE `user_projects` ADD UNIQUE INDEX(user_id, user_project_id)
    
  3. 代码:

    $uid = $_POST['uid'];
    $pids = $_POST['project_id'];
    
    // “删除”所有条目
    $chb = $db->prepare("UPDATE `user_projects` SET `active`=0 WHERE `user_id`=?");
    $chb->execute(array($uid));
    
    // 更新选中的复选框
    foreach ($pids as $pid) {
    $chb = $db->prepare("INSERT INTO `user_projects` VALUES (?, ?, 1) ON DUPLICATE KEY UPDATE `active`=1");
    $chb->execute(array($uid, $pid));
    

    }

-PDO在所有示例中使用


0
假设每个用户都有资格参与每个项目,在您的表单处理页面上,您想要执行以下操作:
$query = 'SELECT p.id AS project_id, u_p.id AS user_project_id '.
            'FROM projects AS p '.
                'LEFT JOIN user_projects AS u_p ON (u_p.project_id = p.id AND u_p.user_id = ?)';

通过左连接,这将为您提供系统中所有项目的列表,如果您正在编辑的用户已经在该项目上,则第二列仅有一个值。对于您提供的示例数据,如果在 user_id 1 上查询,则会得到此结果:

+------------+-----------------+
| project_id | user_project_id |
+------------+-----------------+
|          1 |                 |
|          2 |               2 |
+------------+-----------------+

然后循环遍历此查询的结果,并针对每个结果检查是否为相应的project_id发送了$_POST中的值。如果发送了一个值(复选框被选中)并且该行的user_project_id为空,则插入一行到user_projects以添加此链接。如果未发送值(复选框未选中)并且该行的user_project_id已设置,则使用user_project_id作为键从user_projects中删除该行。否则不执行任何操作,因为它们与之前的方式没有变化。

希望这很清楚,如果您想要更详细的信息,请告诉我。


0

你可以将操作分组,将脚本减少到3个查询。

使用 Chad Birch 的 LEFT JOIN 回答从中检索当前选定的选项。

循环之前:

$delete_ids = array();
$add_ids = array();

循环内部:
// delete from database
$delete_ids[] = $project_id;

并且

// add to database
$add_values[] = '('.$user_id.', '.$project_id.')';

在 for 循环之后:

if (count($delete_ids) > 0) {
  mysql_query('DELETE FROM user_projects WHERE user_id = '.$user_id.' AND project_id IN ('.implode(', ', $delete_ids).')'); 
}

if (count($add_ids) > 0) {
  mysql_query('INSERT INTO user_projects (user_id, project_id) VALUES '.implode($add_values)); 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接