Сохранение HABTM с дополнительными полями? - PullRequest
4 голосов
/ 26 апреля 2011

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

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

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

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

в таблице orders_products У меня есть пара дополнительных полей: order_id, product_id плюс 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

Есть идеи?

Ответы [ 6 ]

9 голосов
/ 26 апреля 2011

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

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

Что делать, когда HABTM усложняется?

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

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

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

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

  • Order hasMany LineItem
  • LineItem относится к Order, Product
2 голосов
/ 27 апреля 2012

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

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

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

Затем добавьте новую привязку "на лету" hasMany:

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

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

1 голос
/ 27 апреля 2011

Другая проблема, с которой я обычно сталкиваюсь при использовании 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 сохраняются.

0 голосов
/ 06 марта 2015

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

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

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

0 голосов
/ 16 марта 2012

Вы можете использовать предыдущее решение, НО, если также необходимо обновить родительские таблицы, вы должны отменить привязку. В моем примере у меня есть таблица Order и таблица 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']);
0 голосов
/ 27 апреля 2011

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

Кажется, ваша ошибка связана с неверной моделью данных.

...