【问题标题】:PHP & Mysql updating many to many relationship with checkbox formPHP & Mysql 用复选框形式更新多对多关系
【发布时间】:2010-10-21 10:05:40
【问题描述】:

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

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

每个用户编辑页面上的表单看起来像这样

<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 ¦
+----+-----------+    

user_projects 表

此表根据它们的 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 技巧的情况下实现这一点。

【问题讨论】:

    标签: php sql checkbox many-to-many


    【解决方案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'];
      
      // "deleting" all entries
      $chb = $db->prepare("UPDATE `user_projects` SET `active`=0 WHERE `user_id`=?");
      $chb->execute(array($uid));
      
      //updating checked checkboxes
      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 用于所有示例

    【讨论】:

      【解决方案2】:

      您可以对操作进行分组并将脚本减少到 3 个查询。

      使用来自 Chad Birch anwser 的 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)); 
      }
      

      【讨论】:

        【解决方案3】:

        由于您的项目数量小到可以在一张表中显示,我完全赞成在提交时重写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,也可以删除它,从而节省表中三分之一的空间。

        【讨论】:

          【解决方案4】:

          好吧,假设每个用户都有资格参与每个项目,那么在您的表单处理页面上,您希望执行以下操作:

          $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 中删除该行。否则什么都不做,他们并没有改变以前的方式。

          希望这很清楚,如果您希望我详细说明,请告诉我。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-26
            • 1970-01-01
            • 2022-01-25
            • 2022-01-22
            • 1970-01-01
            相关资源
            最近更新 更多