保存连接模型

发布于 2024-10-09 10:22:58 字数 9196 浏览 5 评论 0原文

我已经读了这本食谱有一段时间了,但仍然不明白我应该如何做到这一点:

我最初的问题是这样的: 相关模型未经过验证

来自 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 ;

I've been reading the cookbook for a while now and still don't get how I'm supposed to do this:

My original problem was this:
A related Model isn't being validated

From RabidFire's commment:

If you want to count the number of
Category models that a new Post is
associated with (on save), then you
need to do this in the beforeSave
function as I've mentioned. As you've
currently set up your models, you
don't need to use the multiple rule
anywhere. If you really, really want
to validate against a list of Category
IDs for some reason, then create a
join model, and validate category_id
with the multiple rule there.

Now, I have these models and are now validating. The problem now is that data isn't being saved in the Join Table:

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'
        )
    );

This is the new Form:

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

The data I am producing from the form is as follows:

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
        )

)

UPDATE: controller action
//Controller action

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);
        }
    }
}

UPDATE #2:
Should I just do this manually?

The problem is that the join tables doesn't have things saved in it. Is there something I'm missing?

removed update #3

Join Table schema:

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`)
);

Update: #4

I will put everything about my application here in the hopes of getting to do what I want to do.

// 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 ;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忆依然 2024-10-16 10:22:58

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

[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;

此代码可以在 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
                    )
            )
    )

需要采用这种形式,因为 hasMany 之间存在 hasMany 关系。 code>Post 和 CategoryPost - 否则它甚至不会验证。进行此更改后,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

Your data is not being saved because you're trying to save an array into a field.

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

The form of the data should look like this:

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

You could use the following code to do this:

// 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;

This code can be placed in the controller before the saveAll call. If you find that you're using this code in multiple places, you can refactor it into the model's beforeSave:

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

Post the schema of your join table (table name and fields) for a possibly better alternative.


Alright, it took me some brain racking but I finally figured it out. Your last comment kind of put everything in place. Here's the simple fix:

In your view:

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

This should cause the data to be of the following form:

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

You need to have it in this form because of the hasMany relationship between Post and CategoryPost - or it won't even validate. After you make this change, the beforeSave function will be called. NOW make the necessary changes to beforeSave to make it work! Debugging $this->data will help. I leave this part to you, cause I have another better alternative:

1) Shift the multiple validation rule to the Post model:

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) Change the view accordingly:

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

3) Shift the beforeSave to the Post model:

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;
}

This should keep things nice and smooth. Test out both alternatives and let me know if it works! :D

节枝 2024-10-16 10:22:58

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

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

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

I think that the element for multiple choice should have name like this:

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

For better results create a backup copy of your view file and recreate it using the console bake script.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文