php - ¿Guardando HABTM con campos adicionales?
mysql cakephp (6)
Estoy intentando guardar un pedido y los productos en el pedido.
La orden se está guardando, pero los productos no lo están.
Tengo una tabla de orders
y una tabla de products
y una tabla orders_products
.
En el modelo de orden, establecí $hasAndBelongsToMany = ''Product'';
en la tabla orders_products
tengo un par de campos adicionales: order_id
, product_id
plus price
, quantity
para capturar el precio de venta y la cantidad vendida.
Estoy guardando los datos a través de:
$ this-> Order-> saveAll ($ data);
Aquí está lo que $ data es:
Array
(
[Order] => Array
(
[user_email] => [email protected]
[billing_first] => Steve
... //more excluded
[total] => 5000
)
[Product] => Array
(
[0] => Array
(
[id] => 1
[price] => 5000.00
[quantity] => 1
)
)
)
El pedido se guarda en la tabla de pedidos, pero no se guarda nada en la tabla orders_products. Se espera que la tabla orders_products guarde [new_order_id], 1, 5000.00, 1
Recibo este aviso:
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
¿Algunas ideas?
HABTM está sobre vendido. Muchas veces no cumple con las necesidades, como cuando tiene datos adicionales para almacenar. Será mejor que hagas una relación hasMany / belongsTo entre los modelos.
Tomado del libro de CakePHP:
¿Qué hacer cuando HABTM se vuelve complicado?
De forma predeterminada, al guardar una relación HasAndBelongsToMany, Cake eliminará todas las filas en la tabla de unión antes de guardar las nuevas. Por ejemplo, si tiene un Club que tiene 10 Niños asociados. Luego actualiza el Club con 2 niños. El Club solo tendrá 2 niños, no 12.
También tenga en cuenta que si desea agregar más campos a la combinación (cuando se creó o metainformación) esto es posible con las tablas de combinación HABTM, pero es importante comprender que tiene una opción fácil.
HasAndBelongsToMany entre dos modelos es en realidad una abreviatura de tres modelos asociados a través de una asociación hasMany y una belongsTo.
En su caso, sugeriría hacer un modelo de LineItem
y unir todo de esa manera:
-
Order
hasManyLineItem
-
LineItem
pertenece aOrder
,Product
Guardar los datos adicionales en su tabla orders_products
no me parece una buena idea. ¿Qué sucede si un pedido tiene más de 1 producto? ¿Almacena el importe total del pedido para cada entrada en la tabla orders_products
? ¿Por qué no solo almacena esa información en el Order
? Eso tiene mucho más sentido para mí.
Su error parece provenir de un modelo de datos roto.
Otro problema que normalmente encuentro con el uso de SaveAll es que no guarda los registros relacionados. En su ejemplo, la orden se guarda pero OrderProducts (o OrderItems) no se guardan. Lo que suelo hacer es algo como esto:
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'']);
}
Lo que sucede aquí es que la Orden se guarda primero, luego su ID se copia a cada Producto de pedido. Luego se guardan los registros de OrderProduct.
Puede usar la solución anterior, PERO si también tiene que actualizar las tablas principales, debe desvincularla. En mi ejemplo, tengo una tabla Order y una tabla Product . Necesito poner dos campos adicionales para cada producto con respecto a Order.id . Mira este ejemplo:
$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'']);
Bueno, HATBM funciona de una manera muy extraña. Si realmente necesita HATBM, le sugiero que NO cambie una asociación de modelo, sino que use una abreviatura interesante para guardar campos de datos adicionales en la tabla de unión.
Me he encontrado con esto muchas veces y esta es la mejor solución: en realidad, solo para guardar sus campos adicionales puede desvincular todas las relaciones HATBM y agregar un nuevo enlace hasMany "sobre la marcha" apuntando al modelo de unión. En primer lugar, debe desvincular la relación HATBM existente.
$this->Order->unbindModel(array(''hasAndBelongsToMany'' => array(''Product'')));
A continuación, agregue un nuevo encuadernador hasMany "sobre la marcha":
$this->Order->bindModel(array(''hasMany'' => array(''OrdersPost'')));
Entonces, si tus datos son:
$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'';
Como se mencionó anteriormente, HATBM siempre borra todos los registros existentes antes de insertar los nuevos. Así que tal vez deberías cuidarte antes de hacerlo:
$this->Order->saveAll($this->data);
Esto funciona cuando no desea cambiar su modelo de datos, pero aún necesita funcionalidad adicional. Espero que esto ayude. Solución original y créditos AQUÍ
Podría ser que su tabla orders_products no tenga su propia clave principal. Obtendrá este error a menos que su tabla se vea algo como esto
CREATE TABLE orders_products (
id integer,
order_id integer,
product_id integer,
...
Solo ahora tuve el mismo problema. Lo siento, una respuesta tan simple no te llegó antes.