保存连接模型

时间:2010-12-27 06:52:13

标签: cakephp has-and-belongs-to-many

我已经读了一段时间的食谱了,但仍然没有得到我应该怎么做:

我原来的问题是: A related Model isn't being validated

来自RabidFire的意见:

  

如果要计算数量   新帖子的类别模型   与(保存)相关联,然后你   需要在beforeSave中执行此操作   正如我所提到的那样。就像你一样   你现在正在设置你的模型   不需要使用多重规则   任何地方。如果你真的,真的想要   验证类别列表   由于某种原因的ID,然后创建一个   加入模型,并验证category_id   那里有多重规则。

现在,我有这些模型,现在正在验证。现在的问题是数据没有保存在连接表中:

class Post extends AppModel {
    var $name = 'Post';
    var $hasMany = array(
        'CategoryPost' => array(
            'className' => 'CategoryPost'
        )
    );
    var $belongsTo = array(
        'Page' => array(
            'className' => 'Page'
        )
    );

class Category extends AppModel {
    var $name = 'Category';
    var $hasMany = array(
        'CategoryPost' => array(
            'className' => 'CategoryPost'
        )
    );

class CategoryPost extends AppModel {
    var $name = 'CategoryPost';
    var $validate = array(
        'category_id' => array(
            'rule'     => array('multiple', array('in' => array(1, 2, 3, 4))),
            'required' => FALSE,
            'message'  => 'Please select one, two or three options'
        )
    );
    var $belongsTo = array(
        'Post' => array(
            'className' => 'Post'
        ),
        'Category' => array(
            'className' => 'Category'
        )
    );

这是新表格:

<div id="content-wrap">
    <div id="main">
            <h2>Add Post</h2>
            <?php echo $this->Session->flash();?>
            <div>
            <?php
            echo $this->Form->create('Post');
            echo $this->Form->input('Post.title');
            echo $this->Form->input('CategoryPost.category_id', array('multiple' => 'checkbox'));
            echo $this->Form->input('Post.body', array('rows' => '3'));

            echo $this->Form->input('Page.meta_keywords');
            echo $this->Form->input('Page.meta_description');

            echo $this->Form->end('Save Post');
            ?>
            </div>
    <!-- main ends -->
    </div>

我从表格中产生的数据如下:

Array
(
    [Post] => Array
        (
            [title] => 1234
            [body] => 

1234

        )

    [CategoryPost] => Array
        (
            [category_id] => Array
                (
                    [0] => 1
                    [1] => 2
                )

        )

    [Page] => Array
        (
            [meta_keywords] => 1234
            [meta_description] => 1234
            [title] => 1234
            [layout] => index
        )

)

更新:控制器操作 //控制器动作

function admin_add() {
    // pr(Debugger::trace());
    $this->set('categories', $this->Post->CategoryPost->Category->find('list'));

    if ( ! empty($this->data)) {

        $this->data['Page']['title'] = $this->data['Post']['title'];
        $this->data['Page']['layout'] = 'index';

        debug($this->data);
        if ($this->Post->saveAll($this->data)) {
            $this->Session->setFlash('Your post has been saved', 'flash_good');
            $this->redirect($this->here);
        }
    }
}

更新#2: 我应该手动执行此操作吗?

问题是连接表中没有保存的东西。有什么我想念的吗?

删除了更新#3

加入表架构:

CREATE TABLE IF NOT EXISTS `category_posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `category_id` int(11) NOT NULL,
  `post_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
);

更新:#4

我会把我的应用程序的所有内容放在这里,希望能够做我想做的事。

// Post Model
class Post extends AppModel {
    var $name = 'Post';
    var $hasMany = array(
        'CategoryPost' => array(
            'className' => 'CategoryPost'
        )
    );
    var $belongsTo = array(
        'Page' => array(
            'className' => 'Page'
        )
    );
    var $actsAs = array('Containable');
    var $virtualFields = array(
        'date_posted' => 'DATE_SUB(Post.created, INTERVAL 7 DAY)'
    );

    var $order = array('Post.modified' => 'desc');
    var $validate = array(
        'title' => array(
            'rule' => 'notEmpty'
        ),
        'body' => array(
            'rule' => 'notEmpty'
        )
    );

    function getFeed() {
        if ($posts = $this->find('all', array('limit' => 20, 'order' => 'Post.created DESC'))) {
            return $posts;
        }
        return FALSE;
    }

    function getRecentPosts() {
        $conditions = array(
            'Post.created < (curdate() + interval 7 day)',
        );
        return $this->find('all', array('limit' => 8, 'conditions' => $conditions));
    }
}


// CategoryPost Model
class CategoryPost extends AppModel {
    var $name = 'CategoryPost';


    var $validate = array(
    'category_id' => array(
        'rule'     => array('multiple', array('in' => array(1, 2, 3, 4))),
        'required' => FALSE,
        'message'  => 'Please select one, two or three options'
    )
    );

    var $belongsTo = array(
        'Post' => array(
            'className' => 'Post'
        ),
        'Category' => array(
            'className' => 'Category'
        )
    );

    var $actsAs = array('Containable');
}

class Page extends AppModel {
    var $name = 'Page';
    var $order = array('Page.modified' => 'desc');

    var $hasOne = array(
        'Post' => array(
            'className' => 'Post'
        ));

    var $hasMany = array(
        'Snippet' => array(
            'className' => 'Snippet'
        ));

    var $validate = array(
        'title' => array(
            'rule' => 'notEmpty'
        ),
        'uris' => array(
            'slugged' => array(
                'rule' => '/^[a-z0-9-_]+$/i',
                'message' => 'This field should only contain characters, numbers, dashes and underscores'
            ),
            'uniqueUrl' => array(
                'rule' => array('uniqueUrl'),
                'message' => 'A page has already acquired this url'
            )
        ),
        'meta_keywords' => array(
            'rule' => 'notEmpty'
        ),
        'meta_description' => array(
            'rule' => 'notEmpty'
        ),
        'layout' => array(
            'rule' => 'notEmpty'
        )
    );
}


// Form
<div id="main">
        <h2>Add Post</h2>
        <?php echo $this->Session->flash();?>
        <div>
        <?php
        echo $this->Form->create('Post');
        echo $this->Form->input('Post.title');
        echo $this->Form->input('CategoryPost.category_id', array('multiple' => 'checkbox'));
        echo $this->Form->input('Post.body', array('rows' => '3'));

        echo $this->Form->input('Page.meta_keywords');
        echo $this->Form->input('Page.meta_description');

        echo $this->Form->end('Save Post');
        ?>
        </div>
<!-- main ends -->
</div>


// Posts#admin_add
function admin_add() {
    $this->set('categories', $this->Post->CategoryPost->Category->find('list'));

    if ( ! empty($this->data)) {

        $this->data['Page']['title'] = $this->data['Post']['title'];
        $this->data['Page']['layout'] = 'index';


        if ($this->Post->saveAll($this->data, array('validate' => 'first'))) {
            $this->Session->setFlash('Your post has been saved', 'flash_good');
            $this->redirect(array('action' => 'admin_add'));
        }

    }
}


// Table structure
CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `page_id` int(11) NOT NULL,
  `title` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `uri` varchar(127) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  `body` text COLLATE utf8_unicode_ci,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=163 ;


CREATE TABLE IF NOT EXISTS `pages` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `uris` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `meta_keywords` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `meta_description` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `layout` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=164 ;


CREATE TABLE IF NOT EXISTS `category_posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `category_id` int(11) NOT NULL,
  `post_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=36 ;

2 个答案:

答案 0 :(得分:2)

您的数据未保存,因为您正在尝试将数组保存到字段中。

[CategoryPost] => Array
    (
        [category_id] => Array
            (
                [0] => 1
                [1] => 2
            )
    )

数据的形式应如下所示:

[CategoryPost] => Array
    (
        [0] => Array
            (
                [category_id] => 1
            )
        [1] => Array
            (
                [category_id] => 2
            )
    )

您可以使用以下代码执行此操作:

// Correcting data form of CategoryPost
$categoryPosts = array();
foreach ($this->data['CategoryPost']['category_id'] as $categoryId) {
    $categoryPost = array(
        'category_id' => $categoryId
    );
    array_push($categoryPosts, $categoryPost);
}
$this->data['CategoryPost'] = $categoryPosts;

此代码可以在<{em> saveAll调用之前放在控制器中。如果您发现在多个地方使用此代码,则可以将其重构为模型的beforeSave

function beforeSave() {
    if (isset($this->data['CategoryPost']['category_id']) && is_array($this->data['CategoryPost']['category_id'])) {
        ... // above code
    }
}

发布连接表的模式(表名和字段),以获得更好的替代方案。


好吧,我花了一些脑筋,但我终于明白了。你最后的评论是把一切都放到位。这是一个简单的解决方法:

在您看来:

echo $this->Form->input('CategoryPost.0.category_id', array('multiple' => 'checkbox'));

这应该使数据具有以下形式:

[CategoryPost] => Array
    (
        [0] => Array
            (
                [category_id] => Array
                    (
                        [0] => 1
                        [1] => 2
                    )
            )
    )

需要以这种形式拥有它,因为PostCategoryPost - 之间的 hasMany 关系或它赢了甚至验证。进行此更改后,将调用beforeSave函数。现在对beforeSave进行必要的更改以使其正常工作!调试$this->data会有所帮助。我把这部分留给你,因为我有另一个更好的选择

1)将multiple验证规则转移到Post模型:

class Post extends AppModel { 
    ...
    var $validate = array(
        'category_id' => array(
            'rule'     => array('multiple', array('in' => array(1, 2, 3, 4))),
            'required' => false,
            'message'  => 'Please select one, two or three options'
        )
    );
    ...
}

2)相应地更改视图:

echo $this->Form->input('Post.category_id', array('multiple' => 'checkbox'));

3)将beforeSave转移到Post模型:

function beforeSave() {
    if (isset($this->data['Post']['category_id']) && is_array($this->data['Post']['category_id'])) {
        $categoryPosts = array();
        foreach ($this->data['Post']['category_id'] as $categoryId) {
            $categoryPost = array(
                'category_id' => $categoryId
            );
            array_push($categoryPosts, $categoryPost);
        }
        $this->data['CategoryPost'] = $categoryPosts;
    }
    return true;
}

这应该保持良好和顺利。测试两种替代方案,让我知道它是否有效! :d

答案 1 :(得分:0)

我认为多项选择的元素应该具有如下名称:

echo $ this-&gt; Form-&gt; input('Category',array('multiple'=&gt;'checkbox'));

为了获得更好的结果,请创建视图文件的备份副本,然后使用控制台烘焙脚本重新创建它。