【问题标题】:Save multiple records for one model in CakePHP在 CakePHP 中为一个模型保存多条记录
【发布时间】:2011-05-14 17:04:37
【问题描述】:

我想为一个模型保存几条记录。如果不是因为问题,使用saveAll() 很容易做到这一点:

我有一个通知表单,我从<select> 和两个字段中选择多个用户,分别用于主题和内容。现在,当我输出 $this->data 包含的内容时,我有:

Array([Notification] => Array
    (
        [user_id] => Array
            (
                [0] => 4
                [1] => 6
            )

        [subject] => subject
        [content] => the-content-here
    )
)

我读过 Cake 1.3 的书,为了保存一个模型的多条记录,你必须有 $this->data 这样的东西:

Array([Article] => Array(
        [0] => Array
            (
                        [title] => title 1
                    )
        [1] => Array
            (
                        [title] => title 2
                    )
            )
)

那么,我如何将主题和内容“分享”给所有选定的用户?

【问题讨论】:

    标签: cakephp save cakephp-1.3


    【解决方案1】:

    首先,这个数据库设计需要规范化。

    在我看来,Notification 可以有许多与之相关的Users。同时,一个User可以有多个Notifications。因此,

    • 引入一个名为 users_notifications 的连接表。
    • 实现 HABTM 关系:通知 hasAndBelongsToMany 用户

    在视图中,您可以简单地使用以下代码自动调出多选表单来抓取用户ID:

    echo $this->Form->input('User');
    

    发送到控制器的数据将采用以下形式:

    Array(
        [Notification] => Array
            (
                [subject] => subject
                [content] => contentcontentcontentcontentcontentcontent
            ),
        [User] => Array
            (
                [User] => Array
                    (
                        [0] => 4
                        [1] => 6
                    )
             )
    )
    

    现在,您所要做的就是调用 saveAll() 函数而不是 save()。

    $this->Notification->saveAll($this->data);
    

    这就是蛋糕的做法!

    【讨论】:

    • 感谢您的回答!我认为拥有一个 Users hasMany Notifications 就足够了。但现在我明白我还需要一个通知 hasMany Users 是为了正确提交表单。不过,只有一个问题:我有一个 Users hasAndBelongsToMany Notifications 关系,并且我有 UsersController 和 NotificationsController。我需要 UsersNotificationsController 吗?或者我会在需要关系的时候使用$this->User->Notification,分别使用$this->Notification->User?
    • 如果您开始增加连接关系的复杂性,您可能需要模型 UsersNotification。
    • 例如:如果你想存储一个用户是否读过一个通知,你的join表变成:id - user_id - notification_id - read。现在,您必须将这种“通过”关系建模为一个单独的实体。你可以在这里阅读更多信息:book.cakephp.org/view/1039/…
    • 再次感谢。不过,我还有一个问题:为什么在表中插入新关联时,连接表中的所有关联都会被删除?这对我来说没有任何意义。为了阻止这种“奇怪”的行为,我必须在我的 HABTM 的关系定义数组中有'unique' = false
    • HABTM 关系基于 Post-Tag 类比,其中帖子具有唯一的标签(相同的标签不会出现两次)。因此,如果您想编辑帖子的标签,这种行为一点也不奇怪! :) 使用 'unique' = false 是正确的方法。在向帖子添加新的单个标签时使用它。
    【解决方案2】:

    这些值必须像这样重复

    Array([Notification] => Array(
            [0] => Array
                (
                            [user_id] => 4
                            [subject] => subjects
                            [content] => content
                        )
            [1] => Array
                (
                            [user_id] => 6
                            [subject] => subject
                            [content] => contents
                        )
                )
    )
    
    
    $this->Notification->saveAll($data['Notification']); // should work
    

    如果你不传递任何列值,这个蛋糕就会忽略它

    【讨论】:

      【解决方案3】:

      您将不得不调整表单的输出以适应Model::saveAll。在您的控制器中:

      function action_name()
      {
          if ($this->data) {
      
              if ($this->Notification->saveMany($this->data)) {
                  // success! :-)
              } else {
                  // failure :-(
              }
          }
      }
      

      在你的模型中:

      function saveMany($data)
      {
          $saveable = array('Notification'=>array());
      
          foreach ($data['Notification']['user_id'] as $user_id) {
      
              $saveable['Notification'][] = Set::merge($data['Notification'], array('user_id' => $user_id));
          }
      
          return $this->saveAll($saveable);
      }
      

      这里的好处是您的控制器仍然对模型的架构一无所知,这是不应该的。

      事实上,您可以在模型中重新定义saveAll,它将正确格式化的输入数组传递给parent::saveAll,但自己处理特殊情况。

      【讨论】:

      • 感谢您的回复。制作一个单独的方法是个好建议,会这样做!
      • 我把这段代码放在我的服务器上,看来 saveAll() 不起作用。新数组看起来很平滑,我将它传递给 saveAll(),但它没有保存任何内容。我删除了此方法中的验证,但没有成功。可能是什么问题?
      【解决方案4】:

      可能有一种更简单的方法,但我使用了这种技术:首先,改变形式,得到这样的数组:

      Array(
          [Notification] => Array
              (
                  [subject] => subject
                  [content] => contentcontentcontentcontentcontentcontent
              ),
          [selected_users] => Array
              (
                  [id] => Array
                      (
                          [0] => 4
                          [1] => 6
                      )
               )
      )
      

      (只需将多选输入的名称更改为 selected_users.id)

      然后循环遍历用户 ID 并单独保存每条记录:

      foreach( $this->data[ 'selected_users' ][ 'id' ] as $userId ) {
          $this->data[ 'Notification' ][ 'user_id' ] = $userId;
          $this->Notification->create();  // initializes a new instance
          $this->Notification->save( $this->data );
      }
      

      【讨论】:

      • 感谢您的回答。我认为这是一种更“蛋糕”的方法。但是,我会走“直截了当”的路。
      猜你喜欢
      • 1970-01-01
      • 2015-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多