【问题标题】:CakePHP 3.0 Can't save hasMany associated dataCakePHP 3.0 无法保存 hasMany 关联数据
【发布时间】:2014-12-10 10:03:24
【问题描述】:

使用 hasMany 关联保存数据时遇到问题

这是我的桌子

1) post table:每个item都有一个唯一的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() ?>

输入数组结果调试

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

(更新) 调试($post)

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'

}

我不知道我做错了什么

谢谢

【问题讨论】:

  • "can't save ..." 究竟是什么意思?还有debug($post); 显示什么?
  • @ndm 我的意思是 $this->Post->save($post, ['associated' => 'Images']) 的值总是返回 false。我已经更新了我的问题并显示了 debug($post) 的结果
  • 嗯,实体看起来不错,保存后是什么样子的?有没有错误?
  • @ndm 不,只是显示带有错误消息“帖子无法保存。请重试。”的添加表单。保存图像关系时,我认为 story_id 为空。

标签: cakephp model-associations cakephp-3.0


【解决方案1】:

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

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

文档说:

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

应该是这样的:

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

甚至:

$this->hasMany('Images');

【讨论】:

    【解决方案2】:

    我刚刚完成了 3 小时的游览,并保存了 hasMany 内容和主要模型。如果考虑保存许多主要模型的对象和许多相关项目,这种斗争似乎更糟。

    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'
          ]);
      ...
      }
      ...
      }
      

    然后,你在MAIN Entity中设置accessible,这样MAIN模型就可以保存基于“very_weird_calls”索引的关联:

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

    最后一个(但并非最不重要的):控制器保存。这通常是最难克服的部分,因为文档没有详细说明整个过程:

    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' => [ 'associated_data' ] ] ]

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

    请特别注意本示例中给出的名称。 's'-es 和 CamelCases 并非巧合。

    【讨论】:

      【解决方案3】:

      试试这个:

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

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多