Сохранение HABTM с дополнительными полями?

Я пытаюсь сохранить заказ и продукты в заказе.

Заказ сохраняется, но продуктов нет.

У меня есть таблица orders таблица products таблица orders_products .

В модели Order я устанавливаю $hasAndBelongsToMany = 'Product';

на таблице orders_products меня есть несколько дополнительных полей: order_id , product_id plus price , quantity чтобы зафиксировать проданную цену и количество проданных.

Я сохраняю данные через:

$ This-> ПОРЯДКА> SaveAll ($ данных);

Вот что такое $ data:

 Array ( [Order] => Array ( [user_email] => st@kr.com [billing_first] => Steve ... //more excluded [total] => 5000 ) [Product] => Array ( [0] => Array ( [id] => 1 [price] => 5000.00 [quantity] => 1 ) ) ) 

Заказ сохраняется в таблице заказов, но ничего не сохраняется в таблице orders_products. Я ожидаю, что таблица orders_products сохранит [new_order_id], 1, 5000.00, 1

Я получаю это уведомление:

 Notice (8): Undefined index: id [CORE/cake/libs/model/model.php, line 1391] Model::__saveMulti() - CORE/cake/libs/model/model.php, line 1391 Model::save() - CORE/cake/libs/model/model.php, line 1355 Model::__save() - CORE/cake/libs/model/model.php, line 1778 Model::saveAll() - CORE/cake/libs/model/model.php, line 1673 CartsController::saveOrder() - APP/controllers/carts_controller.php, line 128 CartsController::checkout() - APP/controllers/carts_controller.php, line 172 Dispatcher::_invoke() - CORE/cake/dispatcher.php, line 204 Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 171 [main] - APP/webroot/index.php, line 83 

Есть идеи?

HABTM перепродана. Много раз он не отвечает потребностям, например, когда у вас есть дополнительные данные для хранения. Вам будет лучше сделать hasMany / belongsTo отношения между моделями.

Взято из книги CakePHP:

Что делать, когда HABTM становится сложным?

По умолчанию при сохранении отношений HasAndBelongsToMany Cake удалит все строки в таблице соединений, прежде чем сохранять новые. Например, если у вас есть Клуб, в котором есть 10 детей. Затем вы обновляете Клуб с 2 детьми. В клубе будет всего 2 ребенка, а не 12.

Также обратите внимание, что если вы хотите добавить больше полей в соединение (когда оно было создано или метаинформация), это возможно с помощью таблиц объединения HABTM, но важно понимать, что у вас есть простой вариант.

HasAndBelongsToMany между двумя моделями в действительности является сокращением для трех моделей, связанных как с hasMany, так и с принадлежностью к ассоциации.

В вашем случае я бы предложил создать модель LineItem и присоединиться ко всему так:

  • Order hasMany LineItem
  • LineItem принадлежит для Order , Product

Другая проблема, с которой я обычно сталкиваюсь при использовании SaveAll, заключается в том, что она не сохраняет связанные записи. В вашем примере заказ сохраняется, но OrderProducts (или OrderItems) не сохраняются. Обычно я делаю что-то вроде этого:

 if ($this->Order->save($this->data)) { for($i=0; $i<sizeof($this->data['OrderProduct']); $i++){ $this->data['OrderProduct'][$i]['order_id'] = $this->Order->id; } $this->Order->OrderProduct->saveAll($this->data['OrderProduct']); } 

Здесь происходит то, что заказ сначала сохраняется, а затем его идентификатор копируется в каждый OrderProduct. Затем записываются записи OrderProduct.

Хорошо HATBM работает очень странно. Если вам действительно нужен HATBM, я бы предложил НЕ изменять ассоциацию модели, но используя интересную стенографию для сохранения дополнительных полей данных в таблице соединений.

Я встречал это много раз, и это лучшее решение: на самом деле, просто для сохранения ваших дополнительных полей вы можете развязать все отношения HATBM и добавить новую привязку hasMany «на лету», указывающую на модель объединения. Во-первых, вы должны отвязать существующее отношение HATBM.

 $this->Order->unbindModel(array('hasAndBelongsToMany' => array('Product'))); 

Затем добавьте новое «на лету» hasMany binding:

 $this->Order->bindModel(array('hasMany' => array('OrdersPost'))); 

Тогда, если ваши данные:

 $this->data['Order']['id'] = '1'; $this->data['OrdersPost'][0]['product_id'] = '15'; $this->data['PostsTag'][0]['price'] = '5000.00'; $this->data['PostsTag'][0]['quantity'] = '1'; $this->data['OrdersPost'][1]['product_id'] = '16'; $this->data['PostsTag'][1]['price'] = '4000.00'; $this->data['PostsTag'][1]['quantity'] = '2'; 

Как упоминалось выше, HATBM всегда стирает все существующие записи, прежде чем вставлять новые. Так что, возможно, вам стоит позаботиться об этом до того, как вы это сделаете:

 $this->Order->saveAll($this->data); 

Это работает, когда вы не хотите менять свой datamodel, но все еще нуждаетесь в дополнительной функциональности. Надеюсь это поможет. Оригинальное решение и кредиты ЗДЕСЬ

Сохранение этих дополнительных данных в таблице orders_products для меня не кажется хорошей идеей. Что делать, если заказ имеет более 1 продукта. orders_products ли вы общую сумму заказа для каждой записи в таблице orders_products ? Почему бы вам просто не сохранить эту информацию в Order ? Это имеет для меня гораздо больше смысла.

Ваша ошибка, похоже, исходит из разбитой модели данных.

Вы можете использовать предыдущее решение, но если вы также должны обновить родительские таблицы, вы должны отменить привязку. В моем примере у меня есть таблица Order и table Product . Мне нужно поместить два дополнительных поля для каждого продукта в отношении Order.id . См. Этот пример:

  $this->Order->create(); $this->Order->unBindModel(array('hasAndBelongsToMany'=>array('Product'))); $f = $this->Order->save($this->data,false); /* Save extra columns in HABTM TABLE */ $this->Order->bindModel(array('hasMany'=>array('OrderProduct'))); $q = array(); if (!isset($this->data['Product'])) { $v = false; } else { $v =true; for($i=0;$i<count($this->data['Product']);$i++) { $this->data['OrderProduct'][$i]['order_id'] = $this->Order->getLastInsertID(); $this->data['OrderProduct'][$i]['product_id'] = $this->data['Product'][$i]; $this->data['OrderProduct'][$i]['quantity'] = $this->data['quantity'][$i]; $this->data['OrderProduct'][$i]['state_id'] = $this->data['State'][$i]; } } $s = $this->Order->OrderProduct->saveAll($this->data['OrderProduct']); 

Возможно, ваша таблица orders_products не имеет собственного первичного ключа. Вы получите эту ошибку, если ваша таблица не выглядит примерно так

 CREATE TABLE orders_products ( id integer, order_id integer, product_id integer, ... 

У меня только сейчас была такая же проблема. Извините, такой простой ответ не дошел до вас раньше.