CakePHP不保存到数据库

时间:2013-11-10 13:31:03

标签: php mysql sql cakephp

所以我有三个表,即用户,组和users_groups,它们是一个连接表。

--
-- Table structure for table `groups`
--

CREATE TABLE `groups` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `description` text NOT NULL,
  `all_versions_available` tinyint(1) unsigned NOT NULL DEFAULT '1',
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`,`created`,`modified`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=12 ;

-- --------------------------------------------------------

--
-- Table structure for table `users`
--

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(40) NOT NULL,
  `email` varchar(80) NOT NULL,
  `password` varchar(50) NOT NULL,
  `role` varchar(20) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  `fullname` varchar(80) NOT NULL,
  `password_token` varchar(40) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `nickname` (`username`,`email`,`password`),
  KEY `role` (`role`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;

-- --------------------------------------------------------

--
-- Table structure for table `users_groups`
--

CREATE TABLE `users_groups` (
  `user_id` int(11) unsigned NOT NULL,
  `group_id` int(11) unsigned NOT NULL,
  KEY `user_id` (`user_id`,`group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

在我的组和用户模型中实现HABTM之前,我在下面的代码工作正常,现在,我得到了我需要的所有数据,但我无法保存。

所以,我的Group Model看起来像这样:

<?php

class Group extends AppModel {

    public $hasAndBelongsToMany = array(
        'Application' => array(
            'className' => 'Application',
            'joinTable' => 'applications_groups',
            'foreignKey' => 'group_id',
            'associationForeignKey' => 'application_id',
            'unique' => 'keepExisting',
        ),
        'User' => array(
            'className' => 'User',
            'joinTable' => 'users_groups',
            'foreignKey' => 'group_id',
            'associationForeignKey' => 'user_id',
            'unique' => 'keepExisting',
        )
    );

    public $validate = array(
        'name' => array(
            'required' => array(
                'rule' => array('notEmpty'),
                'message' => 'Group name is required'
            )
        )
    );

    public function saveGroup($id, $name, $description) {
        $id = (int)$id;
        if ($id) {
            $this->id = $id;
        }
        else {
            $this->create();
        }
        $this->set('name', $name);
        $this->set('description', $description);
        $this->save();
        return $this;
    }

    public function getAll() {
        $options = array('order' => array('Group.name' => 'ASC'));
        $data = $this->find('all', $options);
        return $data;
    }

    public function getOne($id) {
        $id = (int)$id;
        return $this->find('first', array('conditions' => array('Group.id' => $id)));
    }

}

我的用户模型如下所示:

<?php

class User extends AppModel {

    public $hasAndBelongsToMany = array(
        'Group' => array(
            'className' => 'Group',
            'joinTable' => 'users_groups',
            'foreignKey' => 'group_id',
            'associationForeignKey' => 'user_id',
            'unique' => 'keepExisting',
        )
    );

    public function getOne($id) {
        $this->id = $id;
        $data = $this->read(null, $id);
        unset($data['User']['password']);   
        unset($data['User']['password_token']);
        if (isset($data['User'])) $data['User']['gravatar_url'] = 'http://www.gravatar.com/avatar/'.md5($data['User']['email']).'.jpg';
        return $data;
    }

    private function addGravatars($data) {
        foreach ($data as $key=>$user) {
            $data[$key]['User']['gravatar_url'] = 'http://www.gravatar.com/avatar/'.md5($user['User']['email']).'.jpg';
        }
        return $data;
    }

    public function getAll() {
        $data =  $this->find('all', array('order' => array('User.fullname' => 'ASC')));
        $data = $this->addGravatars($data);
        return $data;
    }

    public function countAll() {
        return $this->find('count');
    }

}

我一直在使用模型作为连接表:

<?php

class UsersGroup extends AppModel {

    public function deleteAllWithGroup($groupId) {

        $id = (int)$groupId;
        return $this->deleteAll(array('UsersGroup.group_id' => $id), false);
    }

    public function saveUsersForGroup($users, $groupId=0) {
        $this->deleteAllWithGroup($groupId);
        $data = array();
        foreach ($users as $id=>$user) {
            $data[] = array('user_id'=>(int)$id, 'group_id'=>$groupId);
        }
        $this->saveMany($data);
    }

}

这是我的群组控制器:

<?php

class GroupsController extends AppController {

    var $uses = array('Group', 'User', 'UsersGroup');

    public function index() {
        $this->set('groups', $this->Group->getAllWithInfo());
    }

    public function edit($id=0) {
        $this->set('group', $this->Group->getOne($id));

        $this->set('usersList', $this->User->getAllWithGroupInfo($id));

        if ($this->request->is('post')) {
            $group = $this->Group->saveGroup($this->request->data['id'], $this->request->data['name'], $this->request->data['description']);

            // Saving users
            if (!isset($this->request->data['user']) || empty($this->request->data['user'])) {
                $this->UsersGroup->deleteAllWithGroup($group->id);
            }
            else $this->UsersGroup->saveUsersForGroup($this->request->data['user'], $group->id);

        }
    }

    public function view($id) {
        App::uses('Platforms', 'Lib/Platform');
        $this->setPageIcon('group');
        $this->set('group', $this->Group->getOne($id));
    }

    public function delete($id) {
        $this->Group->delete((int)$id);
        return $this->redirect(array('action' => 'index'));
    }

}

有几个问题,如果我删除HABTM配置,上面的系统是有效的,第二,我没有,由于一些非常具体的原因,没有使用表单助手来生成表单,不幸的是,代码的复杂性(这只是一点点)我不能这样,我必须自己手动命名一切(这是我看到失败的最大可能性),最后当我解雇这段代码时,我得到:

Database Error

Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'deleteAllWithGroup' at line 1

SQL Query: deleteAllWithGroup

Notice: If you want to customize this error message, create app/View/Errors/pdo_error.ctp

SQL error message

所以UsersGroup模型没有被注册,当我甚至删除文件时没有任何变化,它试图使用我以前用来删除旧连接数据的方法的名称作为SQL命令。我已经尝试了所有可能的建议,我在堆栈上找到的数据的命名和结构但是失败了,我得到的最远的是当我只有一个连接项目要保存时,总是数组中的最后一个...

任何人都可以帮忙解决这个问题吗?

干杯,

0

1 个答案:

答案 0 :(得分:3)

是常规的

这里的主要问题似乎是非常规的

造成的

表名

The docs描述以下内容:

  

这个新的连接表的名称需要包括所涉及的两个模型的名称,按字母顺序排列,并用下划线分隔(_)

因此默认情况下,CakePHP会期望将此类关系的连接表称为groups_users

型号名称

鉴于上述情况,该关系的连接模型将为GroupsUser。定义hasAndBelongsToMany关系如下:

public $hasAndBelongsToMany = array(
    'Group' => array(
        'className' => 'Group',
        'joinTable' => 'users_groups',
        'foreignKey' => 'group_id',
        'associationForeignKey' => 'user_id',
        'unique' => 'keepExisting',
    )
);

意味着CakePHP将仍然尝试并使用名为GroupsUser的模型为其提供表名users_groups。要强制使用不同的连接模型,需要定义要使用的模型 - with

public $hasAndBelongsToMany = array(
    'Group' => array(
        'className' => 'Group',
        'joinTable' => 'users_groups',
        'foreignKey' => 'group_id',
        'associationForeignKey' => 'user_id',
        'unique' => 'keepExisting',
        'with' => 'UsersGroup'
    )
);

虽然重命名连接表和连接模型会更好,但是配置可以简化为以下内容,因为其他一切都是默认值:

public $hasAndBelongsToMany = array(
    'Group' => array(
        'unique' => 'keepExisting'
    )
);

调用不存在的模型函数将成为SQL查询

  

错误:SQLSTATE [42000]:语法错误或访问冲突:1064 SQL语法中有错误;检查与MySQL服务器版本对应的手册,以便在第1行的“deleteAllWithGroup”附近使用正确的语法   SQL查询:deleteAllWithGroup

所有这些都证明,是在对实现被调用函数的类上进行了查询。这可以通过检查对象的类来验证:

debug($this->UsersGroup);
// Most likely "AppModel"

请注意,连接模型本身 not 没有定义任何关联,因此这样做:

$this->UsersGroup->unbind(...);

将无效 - 关联是在问题中的模型User和Group上定义的,即使要加载类UsersGroup - 它没有定义任何关联,更不用说与habtm的关系了别的东西(总共需要5张桌子!)

最后,也许最重要的是:这个函数isn't necessary

  

HABTM数据被视为一个完整的集合,每次添加新的数据关联时,数据库中的完整关联行集将被删除并再次创建

修复代码不会导致问题,因此该方法被称为,除之外,无论保存是否成功,连接表记录都会被删除;而CakePHP的逻辑只会在成功时删除连接表记录。

警惕创建瘦包装函数

虽然在模型上创建方法来封装逻辑没有任何问题 - 如果使用现有模型api很容易表达该逻辑,那么所有这些都会使代码更难以读取/调试。像这样的代码:

public function getOne($id) {
    $this->id = $id;
    $data = $this->read(null, $id);
    unset($data['User']['password']);   
    unset($data['User']['password_token']);
    if (isset($data['User'])) $data['User']['gravatar_url'] = 'http://www.gravatar.com/avatar/'.md5($data['User']['email']).'.jpg';
    return $data;
}

可以轻松地使用find('first')调用替换并向用户模型添加afterFind过滤器,以便为返回的结果添加gravatar_url个键。这导致代码更少,更简单。