CakePHP 3.0无法保存hasMany关联数据

时间:2014-12-10 10:03:25

标签: cakephp model-associations cakephp-3.0

使用hasMany关联保存数据时出现问题

这是我的表

1)发布表:每个项目都有唯一的ID。

id | title | ... 
1  | Aloha | ...

2)图像表

id | post_id | image   | ...  
1  | 1       | abc.jpg | ...
2  | 1       | efg.jpg | ...

我的模型(表格)

帖子模型

// PostsTable.php
<?php

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class PostsTable extends Table {
     public function initialize(array $config) {
        $this->table('posts');
        $this->displayField('title');
        $this->primaryKey('id');
        $this->addBehavior('Timestamp');
        $this->hasMany('Images', [
           'foreignKey' => 'id'
        ]);
     }
}

...

图片型号

// ImagesTable.php
<?php

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class ImagesTable extends Table {
     public function initialize(array $config) {
        $this->table('images');
        $this->displayField('id');
        $this->primaryKey('id');
        $this->addBehavior('Timestamp');
        $this->belongsTo('Posts');
     }
}

...

我的控制器

// PostsController.php
...
public function add() {
    $post = $this->Posts->newEntity($this->request->data, [
        'associated' => ['Images']
    ]);

    if ($this->request->is('post')) {
        if ($this->Posts->save($post, ['associated' => ['Images']])) {
            $this->Flash->success('The post has been saved.');
            return $this->redirect(['action' => 'index']);
        } else {
            $this->Flash->error('The post could not be saved. Please, try again.');
        }
    }

    $this->set('post', $post);
}

...

我的模板

// add.ctp
<?= $this->Form->create($post); ?>

<?php echo $this->Form->input('title'); ?>

<?php echo $this->Form->input('images.0.image'); ?>
<?php echo $this->Form->input('images.1.image'); ?>
<?php echo $this->Form->input('images.2.image'); ?>

<?= $this->Form->button(__('Submit'), ['class' => 'button-green']) ?> 

<?= $this->Form->end() ?>

输入数组结果Debug

[
   'title' => 'Hello',
   'images' => [
       (int) 0 => [
           'image' => 'testa.jpeg'
       ],
       (int) 1 => [
           'image' => 'testb.jpeg'
       ],
       (int) 2 => [
           'image' => 'testc.jpeg'
       ]
   ]
]

(更新) 的 调试($交)

object(App\Model\Entity\Story) {

    'new' => true,
    'accessible' => [
        'title' => true,
        'images' => true
    ],
    'properties' => [
        'title' => 'Hello',
        'images' => [
            (int) 0 => object(App\Model\Entity\Image) {

                'new' => true,
                'accessible' => [
                    'post_id' => true,
                    'image' => true,
                    'post' => true
                ],
                'properties' => [
                    'image' => 'testa.jpeg'
                ],
                'dirty' => [
                    'image' => true
                ],
                'original' => [],
                'virtual' => [],
                'errors' => [],
                'repository' => 'Images'

            },
            (int) 1 => object(App\Model\Entity\Image) {

                'new' => true,
                'accessible' => [
                    'post_id' => true,
                    'image' => true,
                    'post' => true
                ],
                'properties' => [
                   'image' => 'testb.jpeg'
                ],
                'dirty' => [
                    'image' => true
                ],
                'original' => [],
                'virtual' => [],
                'errors' => [],
                'repository' => 'Images'

            },
            (int) 2 => object(App\Model\Entity\Image) {

                'new' => true,
                'accessible' => [
                    'post_id' => true,
                    'image' => true,
                    'post' => true
                ],
                'properties' => [
                    'image' => 'testc.jpeg'
                ],
                'dirty' => [
                    'image' => true
                ],
                'original' => [],
                'virtual' => [],
                'errors' => [],
                'repository' => 'Images'

            }
        ]
    ],
    'dirty' => [
        'title' => true,
        'images' => true
    ],
    'original' => [],
    'virtual' => [],
    'errors' => [],
    'repository' => 'Stories'

}

我无法弄清楚我做错了什么

由于

3 个答案:

答案 0 :(得分:2)

我没有查看所有内容,但我看到您的关联声明中存在错误:

$this->hasMany('Images', [
    'foreignKey' => 'id'
]);

文档说:

  

foreignKey:在其他模型中找到的外键的名称。如果您需要定义多个hasMany关系,这将特别方便。此键的默认值是实际模型的下划线,单数名称,后缀为“_id”。

所以它应该是:

$this->hasMany('Images', [
    'foreignKey' => 'post_id'
]);

甚至:

$this->hasMany('Images');

答案 1 :(得分:2)

我刚刚完成了3小时的巡演,并保存了很多内容以及主模型。如果考虑用许多相关项目保存许多主要模型的对象,那么这种斗争似乎更加糟糕。

  1. hasMany关系中的外键是具有_id后缀的当前模型(实体)的单数名称,因此它类似于:

    class MainModel extends Table {
    ...
    public function initialize(array $config) {
    ...
    // remember the "s" at the end of the name
    $this->hasMany('VeryWeirdCalleds', [
            'className' => 'VeryWeirdCalleds',
            'foreignKey' => 'main_model_id',
            'propertyName' => 'very_weird_calleds'
        ]);
    ...
    }
    ...
    }
    
  2. 然后,在MAIN实体中设置accessible,以便MAIN模型可以根据“very_weird_calleds”索引保存关联:

    class MainModel extends Entity {
        protected $_accessible = [
            ...
            'very_weird_calleds' => true,
        ];
    }
    

    最后(但并非最不重要):Controller保存。这通常是最难克服的部分,因为事实上,文档并没有详细阐明整个过程:

    class MainModelsController extends AppController {
    
    public function add($data) {
            $data = [
                [
                    'name' => 'Hello', 
                    'body' => 'Bla bla', 
                    'very_weird_calleds' => [
                        [
                            'name' => 'Very Weird Called'
                        ]
                    ]
                ]
            ];
            foreach ($data as $record) {
                $main = $this->MainModels->newEntity($record);
    
                if(isset($record['images']) && !empty($record['images'])) {
                    foreach($record['images'] as $record_image) {
                        $image = $this->MainModels->VeryWeirdCalleds->newEntity();
                        $image->IMAGE = $record_image['IMAGE'];
                        $import->very_weird_calleds[] = $image;
                    }
                }
                if (!$this->MainModels->save($main)) {
                    $this->Flash->error('The main model could not be saved. Please, try again.');
                }
            }
        }
    

    解释?首先,我们循环遍历以前准备的数据:

    ['main','model','data','association_accessible_property'=&gt; ['associated_data']]]

    然后,我们使用与主模型相同的方法为关联数据创建新条目。最后一点是将那些关联的实体添加到主模型实体。

    请特别注意此示例中给出的名称。 's'-es和CamelCases不是巧合。

答案 2 :(得分:1)

试试这个:

<?php echo $this->Form->input('0.Images.image'); ?>
<?php echo $this->Form->input('1.images.image'); ?>
<?php echo $this->Form->input('2.images.image'); ?>

以前使用int,根据http://book.cakephp.org/3.0/en/views/helpers/form.html#field-naming-conventions